Code:
/*server4.c*/
#include <stdio.h>//fprintf,puts,gets,fclose,stderr,printf etc
#include <stdlib.h>//exit function
#include <string.h>//strncmp,strcpy,memset,strtok etc
#include <errno.h>//defines the integer variable errno
#include <netdb.h>//gethostbyname()
#include <unistd.h>//close()
#include <pthread.h>//gnu and posix thread library
#include <arpa/inet.h>//makes the in_addr structure available
#include <netinet/in.h>//defines the in_addr structure
#include <sys/types.h>//pthread_t,pthread_mutex_t etc
#include <sys/socket.h>//recvd,send,bind,connect,listen etc
#define IP "127.0.0.1"//localhost.localdomain
#define PORT 8080//listening port
#define BACKLOG 10//maximum time to wait while
//accepting connections
#define CLIENTS 10//maximum number of clients the
//server can accept
#define BUFFSIZE 1024*1024*10//maximum size of the message
//that can be sent by any client(10 MB)
#define ALIASLEN 32//maximum size of the alias length
//a client can take
#define OPTLEN 16//maximum size of the commands
//a client can issue viz. login [alias],
//send [message],whisp [client] [message],
//logout, exit.
struct PACKET {
char option[OPTLEN]; // instruction
char alias[ALIASLEN]; // client's alias
char buff[BUFFSIZE]; // payload
} ;
//struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
//struct PACKET *spacket = (struct PACKET *)malloc(sizeof(struct PACKET));
struct THREADINFO {
pthread_t thread_ID; // thread's pointer
int sockfd; // socket file descriptor
char alias[ALIASLEN]; // client's alias
};
/*a node for a linked list which will have the
fields contained in THREADINFO*/
struct LLNODE {
struct THREADINFO threadinfo;
struct LLNODE *next;
};
/*a linked list having nodes of type LLNODE*/
struct LLIST {
struct LLNODE *head, *tail;
int size;
};
/*function to compare types of nodes which will actually be
packets from different clients.the socket file descriptor
of each client will vary and the function will return
the difference of the socket file descriptor which will be 0
if there is no difference and not 0 if there is a difference*/
int compare(struct THREADINFO *a, struct THREADINFO *b) {
return a->sockfd - b->sockfd;
}
/*initialising the linked list so that it doesnot
contain garbage values*/
void list_init(struct LLIST *ll) {
ll->head = ll->tail = NULL;
ll->size = 0;
}
/*inserting nodes into the linked list that is adding clients
to the list of clients who will concurrently communicate with
the server. since it is a linked list naturally the clients'
records would be dynamically allocated on the servers' memory.
*/
int list_insert(struct LLIST *ll, struct THREADINFO *thr_info) {
if(ll->size == CLIENTS) return -1;//if the list is already full
if(ll->head == NULL) {//if the list is empty
//allocate and create a node in the linked list
ll->head = (struct LLNODE *)malloc(sizeof(struct LLNODE));
ll->head->threadinfo = *thr_info;
ll->head->next = NULL;
ll->tail = ll->head;//it is a singly linked list
}
else {//if the singly linke list is not empty
//add a node or client to the list
ll->tail->next = (struct LLNODE *)malloc(sizeof(struct LLNODE));
ll->tail->next->threadinfo = *thr_info;
ll->tail->next->next = NULL;
ll->tail = ll->tail->next;//make the last node the tail
}
ll->size++;//in either case above there is one node added
//incrementing the size by unity
return 0;
}
/*the function for deleting a node from the singly linked list
of clients*/
int list_delete(struct LLIST *ll, struct THREADINFO *thr_info) {
struct LLNODE *curr, *temp;
if(ll->head == NULL) return -1;//if the list is empty
//if 2 clients have the same socket file descriptor meaning
//that they are the same clients delete one of them
if(compare(thr_info, &ll->head->threadinfo) == 0) {
temp = ll->head;//storing the head's pointer to a temporary
//variable so that we don't lose it
ll->head = ll->head->next;//traversing to the next node
if(ll->head == NULL) ll->tail = ll->head;//if we have traversed
//to the last node we
//put its pointer on
//the tail
free(temp);//the memory of the deleted node is deallocated
ll->size--;//size gets decremented by unity
return 0;
}
//if the list is not empty we traverse the list searching for a
//client's socket descriptor with any other client's socket
//socket descriptor and delete it if found.
for(curr = ll->head; curr->next != NULL; curr = curr->next) {
if(compare(thr_info, &curr->next->threadinfo) == 0) {
temp = curr->next;
if(temp == ll->tail) ll->tail = curr;
curr->next = curr->next->next;
free(temp);
ll->size--;
return 0;
}
}
return -1;
}
/*displays which socket descriptor of the singly linked list corresponds
to which client identified by the alias used by the client*/
void list_dump(struct LLIST *ll) {
struct LLNODE *curr;
struct THREADINFO *thr_info;
printf("Connection count: %d\n", ll->size);
for(curr = ll->head; curr != NULL; curr = curr->next) {
thr_info = &curr->threadinfo;
printf("[%d] %s\n", thr_info->sockfd, thr_info->alias);
}
}
int sockfd, newfd;
struct THREADINFO thread_info[CLIENTS];
struct LLIST client_list;
pthread_mutex_t clientlist_mutex;
void *io_handler(void *param);
void *client_handler(void *fd);
int main(int argc, char **argv) {
int err_ret, sin_size;
struct sockaddr_in serv_addr, client_addr;
pthread_t interrupt;
/* initialize linked list */
list_init(&client_list);
/* initiate mutex */
pthread_mutex_init(&clientlist_mutex, NULL);
/* open a socket */
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
err_ret = errno;
fprintf(stderr, "socket() failed...\n");
return err_ret;
}
/* set initial values */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = inet_addr(IP);
memset(&(serv_addr.sin_zero), 0, 8);
/* bind address with socket */
if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
err_ret = errno;
fprintf(stderr, "bind() failed...\n");
return err_ret;
}
/* start listening for connection */
if(listen(sockfd, BACKLOG) == -1) {
err_ret = errno;
fprintf(stderr, "listen() failed...\n");
return err_ret;
}
/* initiate interrupt handler for IO controlling */
printf("Starting admin interface...\n");
if(pthread_create(&interrupt, NULL, io_handler, NULL) != 0) {
err_ret = errno;
fprintf(stderr, "pthread_create() failed...\n");
return err_ret;
}
/* keep accepting connections */
printf("Starting socket listener...\n");
while(1) {
sin_size = sizeof(struct sockaddr_in);
if((newfd = accept(sockfd, (struct sockaddr *)&client_addr, (socklen_t*)&sin_size)) == -1) {
err_ret = errno;
fprintf(stderr, "accept() failed...\n");
return err_ret;
}
else {
if(client_list.size == CLIENTS) {
fprintf(stderr, "Connection full, request rejected...\n");
continue;
}
printf("Connection requested received...\n");
struct THREADINFO threadinfo;
threadinfo.sockfd = newfd;
//if no alias is given anonymous is automatically
//assigned to the client.
strcpy(threadinfo.alias, "Anonymous");
pthread_mutex_lock(&clientlist_mutex);
//only one client or node can enter the singly
//linked list at a time which is now a list
//of threads.
list_insert(&client_list, &threadinfo);
//after the insertion the mutually exclusive lock
//(mutex lock as defined in pthread) is unlocked
//and more threads get access right to write into
//the singly linked list
pthread_mutex_unlock(&clientlist_mutex);
pthread_create(&threadinfo.thread_ID, NULL, client_handler, (void *)&threadinfo);
}
}
return 0;
}
void *io_handler(void *param) {
char option[OPTLEN];
while(scanf("%s", option)==1) {
if(!strcmp(option, "exit")) {
/* clean up */
printf("Terminating server...\n");
pthread_mutex_destroy(&clientlist_mutex);
close(sockfd);
exit(0);
}
//diplay the list of clients connected to
//the server at present
else if(!strcmp(option, "list")) {
pthread_mutex_lock(&clientlist_mutex);
list_dump(&client_list);
pthread_mutex_unlock(&clientlist_mutex);
}
else {
fprintf(stderr, "Unknown command: %s...\n", option);
}
}
return NULL;
}
void *client_handler(void *fd) {
struct THREADINFO threadinfo = *(struct THREADINFO *)fd;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
struct LLNODE *curr;
int bytes, sent;
while(1) {
bytes = recv(threadinfo.sockfd, (void *)&packet, sizeof(struct PACKET), 0);
if(!bytes) {
fprintf(stderr, "Connection lost from [%d] %s...\n", threadinfo.sockfd, threadinfo.alias);
pthread_mutex_lock(&clientlist_mutex);
//mutex locks when deleting a client
//that is no two clients can be deleted
//together. Deletion which is a write
//process must be mutually exclusive.
list_delete(&client_list, &threadinfo);
pthread_mutex_unlock(&clientlist_mutex);
break;
}
printf("[%d] %s %s %s\n", threadinfo.sockfd, packet->option, packet->alias, packet->buff);
if(!strcmp(packet->option, "alias")) {//command for handling changing the alias
printf("Set alias to %s\n", packet->alias);
pthread_mutex_lock(&clientlist_mutex);
for(curr = client_list.head; curr != NULL; curr = curr->next) {
if(compare(&curr->threadinfo, &threadinfo) == 0) {//if 2 nodes
//have same socket descriptor
//but have different aliases
//make the aliases same
strcpy(curr->threadinfo.alias, packet->alias);
strcpy(threadinfo.alias, packet->alias);
break;
}
}
pthread_mutex_unlock(&clientlist_mutex);
}
else if(!strcmp(packet->option, "whisp")) {//command for handling private messages
int i;
char target[ALIASLEN];
for(i = 0; packet->buff[i] != ' '; i++); packet->buff[i++] = 0;
strcpy(target, packet->buff);
pthread_mutex_lock(&clientlist_mutex);
for(curr = client_list.head; curr != NULL; curr = curr->next) {//itearate through the client singly linked list to locate the client to which the private message
//is intended. after locating then send the message
if(strcmp(target, curr->threadinfo.alias) == 0) {
//struct PACKET spacket;
struct PACKET *spacket = (struct PACKET *)malloc(sizeof(struct PACKET));
memset(&spacket, 0, sizeof(struct PACKET));
if(!compare(&curr->threadinfo, &threadinfo)) continue;//if the comparison returns false continue traversing the singly linked list otherwise do the below
//instructions.if the comparison returns true that means that the threads have the same socket file descriptor and are the same clients and then donot carry out the string copies below once and check the first if condition under the for loop.
strcpy(spacket->option, "msg");
strcpy(spacket->alias, packet->alias);
strcpy(spacket->buff, &packet->buff[i]);
sent = send(curr->threadinfo.sockfd, (void *)&spacket, sizeof(struct PACKET), 0);//send the packet to the intended unicast client
}
}
pthread_mutex_unlock(&clientlist_mutex);//now unlock all the threads or clients in the singly linked list since the write operation of sending a packet has finished//and that the write operation which always requires to be done mutually exclusively has finished.
}
else if(!strcmp(packet->option, "whispf")) {//command for handling private messages
int i;
char target[ALIASLEN];
for(i = 0; packet->buff[i] != ' '; i++); packet->buff[i++] = 0;
strcpy(target, packet->buff);
pthread_mutex_lock(&clientlist_mutex);
for(curr = client_list.head; curr != NULL; curr = curr->next) {//itearate through the client singly linked list to locate the client to which the private message
//is intended. after locating then send the message
if(strcmp(target, curr->threadinfo.alias) == 0) {
//struct PACKET spacket;
struct PACKET *spacket = (struct PACKET *)malloc(sizeof(struct PACKET));
memset(&spacket, 0, sizeof(struct PACKET));
if(!compare(&curr->threadinfo, &threadinfo)) continue;//if the comparison returns false continue traversing the singly linked list otherwise do the below
//instructions.if the comparison returns true that means that the threads have the same socket file descriptor and are the same clients and then donot carry out the string copies below once and check the first if condition under the for loop.
strcpy(spacket->option, "msg");
strcpy(spacket->alias, packet->alias);
strcpy(spacket->buff, &packet->buff[i]);
sent = send(curr->threadinfo.sockfd, (void *)&spacket, sizeof(struct PACKET), 0);//send the packet to the intended unicast client
}
}
pthread_mutex_unlock(&clientlist_mutex);//now unlock all the threads or clients in the singly linked list since the write operation of sending a packet has finished//and that the write operation which always requires to be done mutually exclusively has finished.
}
else if(!strcmp(packet->option, "send")) {//command for handling broadcast message
pthread_mutex_lock(&clientlist_mutex);
for(curr = client_list.head; curr != NULL; curr = curr->next) {
//struct PACKET spacket;
struct PACKET *spacket = (struct PACKET *)malloc(sizeof(struct PACKET));
memset(&spacket, 0, sizeof(struct PACKET));
if(!compare(&curr->threadinfo, &threadinfo)) continue;
strcpy(spacket->option, "msg");
strcpy(spacket->alias, packet->alias);
strcpy(spacket->buff, packet->buff);
sent = send(curr->threadinfo.sockfd, (void *)&spacket, sizeof(struct PACKET), 0);//send the packet to all the clients
}
pthread_mutex_unlock(&clientlist_mutex);
}
else if(!strcmp(packet->option, "sendf")) {//command for handling broadcast message
pthread_mutex_lock(&clientlist_mutex);
for(curr = client_list.head; curr != NULL; curr = curr->next) {
//struct PACKET spacket;
struct PACKET *spacket = (struct PACKET *)malloc(sizeof(struct PACKET));
memset(&spacket, 0, sizeof(struct PACKET));
if(!compare(&curr->threadinfo, &threadinfo)) continue;
strcpy(spacket->option, "msg");
strcpy(spacket->alias, packet->alias);
strcpy(spacket->buff, packet->buff);
sent = send(curr->threadinfo.sockfd, (void *)&spacket, sizeof(struct PACKET), 0);//send the packet to all the clients
}
pthread_mutex_unlock(&clientlist_mutex);
}
else if(!strcmp(packet->option, "exit")) {//command for exiting the server
printf("[%d] %s has disconnected...\n", threadinfo.sockfd, threadinfo.alias);
pthread_mutex_lock(&clientlist_mutex);
list_delete(&client_list, &threadinfo);
pthread_mutex_unlock(&clientlist_mutex);
break;
}
else {
fprintf(stderr, "Garbage data from [%d] %s...\n", threadinfo.sockfd, threadinfo.alias);
}
}
/* clean up */
close(threadinfo.sockfd);
return NULL;
}
the client code is as follows:-
Code:
/*client4.c*/
#include <stdio.h>//fprintf,puts,gets,fgets,printf,stderr stream etc
#include <stdlib.h>//exit function
#include <string.h>//strncmp,strcpy,memset,strtok etc
#include <errno.h>//defines the integer variable errno
#include <netdb.h>//gethostbyname()
#include <unistd.h>//close()
#include <pthread.h>//gnu and posix thread library
#include <arpa/inet.h>//makes the in_addr structure available
#include <netinet/in.h>//defines the in_addr structure
#include <sys/types.h>//pthread_t,pthread_mutex_t etc
#include <sys/socket.h>//recvd,send,bind,connect,listen etc
#define SERVERIP "127.0.0.1"//localhost->localdomain
#define SERVERPORT 8080//listening port
#define BUFFSIZE 10240//buffer for use in general(files of atmost 10MB can
//be sent
#define ALIASLEN 32//length of the name to be used
#define OPTLEN 16//length of the options to be used
#define LINEBUFF 2048//buffer for each line(messages as long as 2KB can be sent
//which will include the options+alias+text message)
struct PACKET {
char option[OPTLEN]; // instruction
char alias[ALIASLEN]; // client's alias
char buff[BUFFSIZE]; // payload
};
//struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
struct USER {
int sockfd; // user's socket descriptor
char alias[ALIASLEN]; // user's name
};
struct THREADINFO {
pthread_t thread_ID; // thread's pointer
int sockfd; // socket file descriptor
};
int isconnected, sockfd;
char option[LINEBUFF];
struct USER me;
int connect_with_server();
void setalias(struct USER *me);//function prototype for name selection
void logout(struct USER *me);//function prototype for logout option
void login(struct USER *me);//function prototype for login option
void *receiver(void *param);//receive message or files
void sendtoall(struct USER *me, char *msg);//function prototype to broadcast
void sendtoallf(struct USER *me, char *msg);//broadcast file
void sendtoalias(struct USER *me, char * target, char *msg);//to unicast
void sendtoaliasf(struct USER *me, char * target, char *msg);//unicast file
int main(int argc, char **argv) {
int sockfd, aliaslen;
memset(&me, 0, sizeof(struct USER));//it fills the first n bytes of the memory
//area pointed to by s with the constant byte
//c(basically string copying into a larger
//string)
while(fgets(option,sizeof(option),stdin)) {
if(!strncmp(option, "exit", 4)) {//code for the exit option
logout(&me);
break;
}
if(!strncmp(option, "help", 4)) {//code for the help.txt to display help
FILE *fin = fopen("help.txt", "r");
if(fin != NULL) {
while(fgets(option, LINEBUFF-1, fin)) puts(option);
fclose(fin);
}
else {
fprintf(stderr, "Help file not found...\n");
}
}
else if(!strncmp(option, "login", 5)) {
char *ptr = strtok(option, " ");//the strtok() takes a string and breaks
//down the string to a number of smaller
//strings of length specified in the
//second parameter->the function returns
//a pointer to the last token found in the
//string->null pointer is returned if no
//tokens are left to retrieve->ptr has value
//n
ptr = strtok(0, " ");//ptr has now value 0 or null in its address
memset(me.alias, 0, sizeof(char) * ALIASLEN);//set the alias
if(ptr != NULL) {//traverse through all the letters of the alias or name
aliaslen = strlen(ptr);
//if the length of the name exceeds the set limit
//take only the name upto the length permissible
//by making the last token as the length of the limit
//0 or null and copy that broken substring to user's
//alias->however here the option "login" is only dealt
//with-> that is if we type say "loginna" then only
//"login" will be accepted automatically->
if(aliaslen > ALIASLEN) ptr[ALIASLEN] = 0;
strcpy(me.alias, ptr);
}
else {
strcpy(me.alias, "Anonymous");//if no alias is specified
//set it as anonymous
}
login(&me);
}
else if(!strncmp(option, "alias", 5)) {//here the option of name
//is dealt with and the same
//logic applies as with "login"
//option as mentioned above->
char *ptr = strtok(option, " ");
ptr = strtok(0, " ");
memset(me.alias, 0, sizeof(char) * ALIASLEN);
if(ptr != NULL) {
aliaslen = strlen(ptr);
if(aliaslen > ALIASLEN) ptr[ALIASLEN] = 0;
strcpy(me.alias, ptr);
setalias(&me);
}
}
else if(!strncmp(option, "whisp", 5)) {//the whisp option to unicast
char *ptr = strtok(option, " ");
char temp[ALIASLEN];
ptr = strtok(0, " ");
memset(temp, 0, sizeof(char) * ALIASLEN);
if(ptr != NULL) {
aliaslen = strlen(ptr);
if(aliaslen > ALIASLEN) ptr[ALIASLEN] = 0;
strcpy(temp, ptr);//copy pointer to temp variable which if length
//ALIASLEN already defined in the beginning
while(*ptr) ptr++; ptr++;//get the address of the last string
//token
while(*ptr <= ' ') ptr++;//if blank character is encountered
//still get the last address of the token
sendtoalias(&me, temp, ptr);//send the user address, the alias
//and part of the excess length alias
//in the message to one particular
//user
}
}
else if(!strncmp(option, "whispf", 6)) {//the whisp option to unicast files
char *ptr = strtok(option, " ");
char temp[ALIASLEN];
ptr = strtok(0, " ");
memset(temp, 0, sizeof(char) * ALIASLEN);
if(ptr != NULL) {
aliaslen = strlen(ptr);
if(aliaslen > ALIASLEN) ptr[ALIASLEN] = 0;
strcpy(temp, ptr);//copy pointer to temp variable which if length
//ALIASLEN already defined in the beginning
while(*ptr) ptr++; ptr++;//get the address of the last string
//token
while(*ptr <= ' ') ptr++;//if blank character is encountered
//still get the last address of the token
sendtoaliasf(&me, temp, ptr);//send the user address, the alias
//and part of the excess length alias
//in the message to one particular
//user
}
}
else if(!strncmp(option, "send", 4)) {
sendtoall(&me, &option[5]);
}
else if(!strncmp(option, "sendf", 5)) {
sendtoallf(&me, &option[5]);
}
else if(!strncmp(option, "logout", 6)) {
logout(&me);
}
else fprintf(stderr, "Unknown option->->->\n");
}
return 0;
}
void login(struct USER *me) {
int recvd;
if(isconnected) {
fprintf(stderr, "You are already connected to server at %s:%d\n", SERVERIP, SERVERPORT);
return;
}
sockfd = connect_with_server();
if(sockfd >= 0) {
isconnected = 1;//its a flag variable to keep track whether a
//client is connected or not?
me->sockfd = sockfd;
if(strcmp(me->alias, "Anonymous")) setalias(me);
printf("Logged in as %s\n", me->alias);
printf("Receiver started [%d]...\n", sockfd);
struct THREADINFO threadinfo;
//for one client one thread is created
pthread_create(&threadinfo.thread_ID, NULL, receiver, (void *)&threadinfo);
}
else {
fprintf(stderr, "Connection rejected...\n");
}
}
int connect_with_server() {
int newfd, err_ret;
struct sockaddr_in serv_addr;
struct hostent *to;
/* generate address */
if((to = gethostbyname(SERVERIP))==NULL) {
err_ret = errno;
fprintf(stderr, "gethostbyname() error...\n");
return err_ret;
}
/* open a socket */
if((newfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
err_ret = errno;
fprintf(stderr, "socket() error...\n");
return err_ret;
}
/* set initial values */
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(SERVERPORT);
serv_addr.sin_addr = *((struct in_addr *)to->h_addr);
memset(&(serv_addr.sin_zero), 0, 8);
/* try to connect with server */
if(connect(newfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
err_ret = errno;
fprintf(stderr, "connect() error...\n");
return err_ret;
}
else {
printf("Connected to server at %s:%d\n", SERVERIP, SERVERPORT);
return newfd;
}
}
void logout(struct USER *me) {
int sent;
//struct PACKET packet;
//packet=(struct PACKET *)malloc(sizeof(struct PACKET));
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
memset(&packet, 0, sizeof(struct PACKET));
strcpy(packet->option, "exit");
strcpy(packet->alias, me->alias);
/* send request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
isconnected = 0;
}
void setalias(struct USER *me) {
int sent;
//struct PACKET packet;
//packet=(struct PACKET *)malloc(sizeof(struct PACKET));
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
memset(&packet, 0, sizeof(struct PACKET));
strcpy(packet->option, "alias");
strcpy(packet->alias, me->alias);
/* send request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
}
void *receiver(void *param) {
int recvd;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
FILE *file;
char *buffer;
unsigned long fileLen;
char *filename;
printf("Waiting here [%d]...\n", sockfd);
while(isconnected) {
recvd = recv(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
if(!recvd) {//if recvd is false connection not established
fprintf(stderr, "Connection lost from server...\n");
isconnected = 0;
close(sockfd);
break;
}
if(recvd > 0) {//if recvd returns true(which could be 1 or any number
//greater than 1) print the message to be sent on the terminal
//if the packet->buff is greater than 512 bytes it is automatically treated
//as a file and fwrite() is invoked->however this maynot always be the case as
//texts can be as long as 2 KB as defined in the LINEBUFF meaning that text
// messages could be as big as that-> so how will one send a file?one could
//first during the conversation agree with the opposite chatter that a file
//would be sent-> then if the filesize is less than 512 bytes->->->make it
//larger than that and send it which will then be treated as a file->as for
//texts which exceed 512 bytes one could simply send more than one message
//by breaking a single message which are all less than 512 bytes->->->:-)->
//another important note here is that the chatters must agree upon the
//extension of the file to be used and the binary file received/sent
//must be modified to have that extension-> this is particularly important
//on windows machines->
if(sizeof(packet->buff)>512)
{
printf("\n Enter a name for the file:");
scanf("%s",&filename);
file = fopen(filename, "wb");//open file with user specified name in write-binary
//mode
if (!file)
{
fprintf(stderr, "can't open file %s", filename);
}
//this part is not necessary while doing fwrite()
/*
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
exit(1);
}*/
buffer=packet->buff;
fileLen=sizeof(packet->buff);
buffer=(char *)malloc(fileLen+1);
fwrite(buffer, fileLen, 1, file);
fclose(file);
}
printf("[%s]: %s\n", packet->alias, packet->buff);
}
memset(&packet, 0, sizeof(struct PACKET));
}
return NULL;
}
void sendtoall(struct USER *me, char *msg) {
int sent;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
msg[BUFFSIZE] = 0;//initailize the msg variable
/*copy all the values to the variables of the
client as defined the struct packet which
is actually "this" client */
memset(&packet, 0, sizeof(struct PACKET));//initiation by copying 0 into the first
//n=sizeof(struct PACKET) n memory
//blocks of the variable packet
strcpy(packet->option, "send");
strcpy(packet->alias, me->alias);
strcpy(packet->buff, msg);
/* send the data to the server and
also the request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
}
void sendtoallf(struct USER *me, char *msg) {//multicast a file
int sent;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
FILE *file;
char *buffer;
unsigned long fileLen;
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
msg[BUFFSIZE] = 0;//initailize the msg variable
/*copy all the values to the variables of the
client as defined the struct packet which
is actually "this" client */
file = fopen(msg, "rb");//name/path of the file is in msg and mode is read-binary
if (!file)
{
fprintf(stderr, "can't open file %s", msg);
return;
}
//get the length of the file
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);
//allocate the buffer
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
return;
}
fread(buffer, fileLen, 1, file);
fclose(file);
memset(&packet, 0, sizeof(struct PACKET));//initiation
strcpy(packet->option, "send");
strcpy(packet->alias, me->alias);
strcpy(packet->buff, buffer);
/* send the data to the server and
also the request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
}
void sendtoalias(struct USER *me, char *target, char *msg) {
int sent, targetlen;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
if(target == NULL) {//if no alias to whom message is to be
//sent is specified return or get out of this
//function
return;
}
if(msg == NULL) {
return;
}
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
msg[BUFFSIZE] = 0;
targetlen = strlen(target);
memset(&packet, 0, sizeof(struct PACKET));
strcpy(packet->option, "whisp");
strcpy(packet->alias, me->alias);
strcpy(packet->buff, target);
strcpy(&packet->buff[targetlen], " ");//leave a space between the alias and the
//message since excess length alias will
//treated as message while passing the
//parameters
strcpy(&packet->buff[targetlen+1], msg);
/* send the message and request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
}
void sendtoaliasf(struct USER *me, char *target, char *msg) {//function to unicast
//a file
int sent, targetlen;
//struct PACKET packet;
struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
FILE *file;
char *buffer;
unsigned long fileLen;
if(target == NULL) {//if no alias to whom message is to be
//sent is specified return or get out of this
//function
return;
}
if(msg == NULL) {
return;
}
if(!isconnected) {
fprintf(stderr, "You are not connected...\n");
return;
}
msg[BUFFSIZE] = 0;
targetlen = strlen(target);
file = fopen(msg, "rb");
if (!file)
{
fprintf(stderr, "can't open file %s", msg);
return;
}
fseek(file, 0, SEEK_END);
fileLen=ftell(file);
fseek(file, 0, SEEK_SET);
buffer=(char *)malloc(fileLen+1);
if (!buffer)
{
fprintf(stderr, "Memory error!");
fclose(file);
return;
}
fread(buffer, fileLen, 1, file);
fclose(file);
memset(&packet, 0, sizeof(struct PACKET));
strcpy(packet->option, "whisp");
strcpy(packet->alias, me->alias);
strcpy(packet->buff, target);
strcpy(&packet->buff[targetlen], " ");//leave a space between the alias and the
//message since excess length alias will
//treated as message while passing the
//parameters
strcpy(&packet->buff[targetlen+1], buffer);
/* send the message and request to close this connetion */
sent = send(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
}