Thread: tcp chat multiple concurrent clients and 1 server to accomodate file transfer also.

  1. #1
    Registered User
    Join Date
    Oct 2009
    Posts
    27

    tcp chat multiple concurrent clients and 1 server to accomodate file transfer also.

    i guess as the title indicates the program is a chat application...the program ran flawlessly until i introduced the functions sendtoallf(...) and sendtoaliasf(....) to facilitate file transfer and the server.c and client.c were suitably modified. to accomodate larger files i increased the BUFFSIZE to 1024*1024*10 and the LINEBUFF to 1024*2 and allocated memory using malloc for the structs of types PACKET. now in gcc i get segmentation error while running client.c.please help me find the error....
    i was unable to put the code in the post in the first attempt itself...so i am attaching the client.c and server.c files which are however named server4.c and client4.c....

    the server code is as follows:-
    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);
        }
    Attached Files Attached Files

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Wow, so many mistakes.

    Where to begin....

    > //struct PACKET packet;
    > struct PACKET *packet = (struct PACKET *)malloc(sizeof(struct PACKET));
    >...
    > recvd = recv(sockfd, (void *)&packet, sizeof(struct PACKET), 0);
    What exactly were you thinking of here?
    There was no reason to replace packet with a pointer to some allocated memory.
    In doing so, you've TOTALLY changed what (void *)&packet means.
    So now rather than writing into some valid memory, you trash the pointer, and any memory in the vicinity of the pointer.

    There are several other places where you've inexplicably changed a variable into a pointer, and broken any later &var code.

    You seem to be 'sizeof' happy in many places in the code, in some expectation that it's going to give you a variable answer - it isn't.

    If you want to know the effective size of a buffer, in terms of what is valid data, then you need to use the return result of send() / recv() / fread() / fwrite() or whatever.


    Code:
                    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);
            }
    The one thing which could do with being a malloc'ed pointer isn't.
    The problem is, as soon as this code hits the closing brace, threadinfo goes out of scope.
    So although the first thing client_handler does is make a copy, it's probably too late.

    malloc the threadinfo here, and free it in the thread, when it has finished with it. The called thread needs to own the lifetime of the object from the moment pthread_create returns.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. UDP two clients and server chat in Linux C
    By pasierdamian in forum C Programming
    Replies: 6
    Last Post: 11-17-2015, 06:07 PM
  2. TCP Sockets: multiple clients - one server
    By Printisor in forum C Programming
    Replies: 4
    Last Post: 11-01-2007, 10:34 AM
  3. multiple Clients, single server program
    By sam4sam in forum Networking/Device Communication
    Replies: 2
    Last Post: 04-24-2007, 09:40 AM
  4. Server with multiple clients
    By Thantos in forum Networking/Device Communication
    Replies: 20
    Last Post: 09-02-2003, 05:52 PM
  5. server with multiple clients
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 02-23-2002, 09:15 PM

Tags for this Thread