void delete_user_from_users(int descriptor){ int ret; ret= sem_wait(&users_sem); ERROR_HELPER(ret,"error on sem_wait to users_sem"); int i; for(i=0; i<num_users; i++){ if(users[i]->socket==descriptor){ free(users[i]); for(;i<num_users-1; i++){ users[i]= users[i+1]; } break; } } if(i<num_users){ printf("Utente elimato da array utenti"); users[num_users-1]=NULL; num_users-=1; ret= sem_post(&users_sem); ERROR_HELPER(ret,"error on sem_post to users_sem"); printf("\n"); print_stats_users(); } else{ ret= sem_post(&users_sem); ERROR_HELPER(ret,"error on sem_post to users_sem"); printf("Utente non ancora registrato. connessione chiusa\n"); } close(descriptor); }
Channel* add_lastChannel(Channel* channel,User* user){ int i,ret; ret= sem_wait(&channels_sem); ERROR_HELPER(ret,"error on sem_wait to channels_sem"); for(i=0; i<MAX_CHANNEL; i++){ if(channels[i]==NULL){ channels[i]= (Channel*) malloc (sizeof(Channel)); memcpy(channels[i],channel,sizeof(Channel)); user->user_channel=channels[i]; Channel* temp=channels[i]; num_channels++; ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); printf("Lo user %s ha creato il canale %s\n",user->username,user->user_channel->channel_name ); return temp; } } ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); printf("Numero canali massimo superato\n"); return NULL; }
int delete_channel(Channel* ch,int descriptor){ int ret; ret= sem_wait(&channels_sem); ERROR_HELPER(ret,"error on sem_wait to channels_sem"); closed_by_admin(ch,descriptor); int i; for(i=0; i<num_channels; i++){ if(strcmp(ch->channel_name,channels[i]->channel_name)==0){ free(channels[i]); for(;i<num_channels-1; i++){ channels[i]= channels[i+1]; } num_channels-=1; channels[num_channels]= NULL; ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); printf("Canale %s cancellato\n", ch->channel_name); print_stats_channels(); return 1; } } ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); return -1; }
Channel* join_chat(User* user){ int descriptor=user->socket; char buffer[BUFFER_SIZE]; char str[BUFFER_SIZE]; int ret; snprintf(str,sizeof(str),"%s",print_channel()); int i,while_flag=1; while(while_flag){ ret= send_message(descriptor,str,NULL); ret= receive_message(descriptor,buffer); if(buffer[0]=='$'){ memset(buffer,0,sizeof(buffer)); snprintf(buffer,sizeof(buffer),"%s",QUIT_CLIENT); send_message(user->socket,buffer,strlen(buffer)); return NULL; } ret= sem_wait(&channels_sem); ERROR_HELPER(ret,"error on sem_wait to channels_sem"); for(i=0; i<num_channels; i++){ if(strcmp(buffer,channels[i]->channel_name)==0){ while_flag=0; break; } } if(while_flag==0){ memset(buffer,0,sizeof(buffer)); memset(str,0,sizeof(str)); break; } memset(str,0,sizeof(str)); snprintf(str,sizeof(str),"%s",ERR_CHAT); strcat(str, print_channel()); ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); } channels[i]->subscribers[channels[i]->sub_num]= (User*) malloc(sizeof(User)); memcpy(channels[i]->subscribers[channels[i]->sub_num],user,sizeof(User)); channels[i]->sub_num+=1; user->user_channel= channels[i]; printf("Aggiunto user %s con descrittore %d alla chat %s\n", channels[i]->subscribers[channels[i]->sub_num-1]->username,channels[i]->subscribers[channels[i]->sub_num-1]->socket,user->user_channel->channel_name); return channels[i]; }
//-----FUNCTIONS---- int already_exists(char buffer[]){ int ret; ret= sem_wait(&channels_sem); ERROR_HELPER(ret,"error on sem_wait to channels_sem"); int i; for(i=0;i<num_channels;i++){ if(strcmp(channels[i]->channel_name,buffer)==0){ snprintf(buffer,BUFFER_SIZE,"%s","Chat name already in use.Type another name.\n"); ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); return 1; } } ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); return 0; }
int add_lastUser(User* user){ int ret; ret= sem_wait(&users_sem); ERROR_HELPER(ret,"error on sem_wait to users_sem"); int i; for(i=0;i<MAX_USERS;i++){ if(users[i]==NULL){ users[i]= (User*) malloc(sizeof(User)); memcpy(users[i],user,sizeof(User)); num_users++; ret= sem_post(&users_sem); ERROR_HELPER(ret,"error on sem_post to users_sem"); return i; } } ret= sem_post(&users_sem); ERROR_HELPER(ret,"error on sem_post to users_sem"); printf("Numero utenti massimo superato\n" ); return -1; }
void delete_user_from_channel(int descriptor,Channel* channel){ int ret; if(channel==NULL){ printf("Utente in nessun canale.Connessione chiusa.\n"); return; } ret= sem_wait(&channels_sem); ERROR_HELPER(ret,"error on sem_wait to channels_sem"); if(isAdmin(descriptor,channel) && channel->sub_num>1){ char buffer[BUFFER_SIZE]; int descriptor= channel->subscribers[1]->socket; channel->admin= descriptor; memset(buffer,0, sizeof(buffer)); snprintf(buffer,sizeof(buffer),"%s","You're the new admin of the chat.\n"); send_message(descriptor,buffer,strlen(buffer)); } int i; for(i=0; i<channel->sub_num; i++){ if(channel->subscribers[i]->socket==descriptor){ free(channel->subscribers[i]); for(;i<channel->sub_num-1; i++){ channel->subscribers[i]= channel->subscribers[i+1]; } break; } } channel->sub_num-=1; if(channel->sub_num==0) delete_channel_by_server(channel); ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); printf("E' stato eseguito un delete_user\n\n"); print_stats_channels(); }
int receive_message(int descriptor, char* buffer){ memset(buffer,0,sizeof(buffer)); int ret; while((ret= recv(descriptor, buffer, BUFFER_SIZE-1, MSG_NOSIGNAL))<=0){ if (errno == EWOULDBLOCK || errno == EPIPE || ret==0){ printf("RECV: User with descriptor %d has crashed. He will be deleted from everything\n",descriptor); delete_user_from_users(descriptor); delete_user_from_channel(descriptor,find_channel(descriptor)); pthread_exit(NULL); } else if (errno == EINTR) continue; else ERROR_HELPER(ret,"error receiving from client"); } buffer[ret]= '\0'; printf("Ricevuto: %s da %d\n", buffer, descriptor); return ret; }
int send_message(int descriptor, char* buffer, int size){ int ret= BUFFER_SIZE; if(size!=NULL) ret= size+1; char msg[ret]; snprintf(msg,sizeof(msg),"%s",buffer); size_t msg_size= strlen(buffer); while((ret= send(descriptor,msg,msg_size,MSG_NOSIGNAL))<=0){ if (errno == EWOULDBLOCK || errno == EPIPE){ printf("SEND: User with descriptor %d has crashed. He will be deleted from everything\n",descriptor); delete_user_from_users(descriptor); delete_user_from_channel(descriptor,find_channel(descriptor)); return errno; } else if (errno == EINTR) continue; else ERROR_HELPER(ret,"Error with send function from server"); } return ret; }
void chat_session(int socket_desc) { int ret; pthread_t chat_threads[2]; ret = pthread_create(&chat_threads[0], NULL, receiveMessage, (void*)socket_desc); GENERIC_ERROR_HELPER(ret, ret, "Cannot create thread for receiving messages"); ret = pthread_create(&chat_threads[1], NULL, sendMessage, (void*)socket_desc); GENERIC_ERROR_HELPER(ret, ret, "Cannot create thread for sending messages"); // wait for termination ret = pthread_join(chat_threads[0], NULL); GENERIC_ERROR_HELPER(ret, ret, "Cannot join on thread for receiving messages"); ret = pthread_join(chat_threads[1], NULL); GENERIC_ERROR_HELPER(ret, ret, "Cannot join on thread for sending messages"); // close socket ret = close(socket_desc); ERROR_HELPER(ret, "Cannot close socket"); }
void* invia(void* arg) { struct_arg_client* args = (struct_arg_client*) arg; int ret; char buf[1024]; while (1) { //printf("send: "); fgets(buf, 1024, stdin); //fgets prende anche il carattere invio size_t buf_len = strlen(buf); if (buf_len == 1) continue; buf[buf_len - 1] = '\0'; //--buf_len; // remove '\n' from the end of the message while ((ret = send(args->desc, buf, buf_len, 0)) < 0) { if (errno == EINTR) continue; if(ret==0) exit(0); ERROR_HELPER(-1, "Cannot write to the socket"); } } }
int main(int argc, char **argv){ //-----SIGNALS HANDLING--- struct sigaction sigint, sighup, sigquit, sigsegv, sigterm, sigpipe; sigemptyset(&sigint.sa_mask); sigint.sa_handler= generic_handler; sigint.sa_flags= SA_SIGINFO; sigaction(SIGINT,&sigint,0); sigemptyset(&sigquit.sa_mask); sigquit.sa_handler= generic_handler; sigquit.sa_flags= SA_SIGINFO; sigaction(SIGQUIT,&sigquit,0); sigemptyset(&sighup.sa_mask); sighup.sa_handler= generic_handler; sighup.sa_flags= SA_SIGINFO; sigaction(SIGHUP,&sighup,0); sigemptyset(&sigsegv.sa_mask); sigsegv.sa_handler= generic_handler; sigsegv.sa_flags= SA_SIGINFO; sigaction(SIGSEGV,&sigsegv,0); sigemptyset(&sigterm.sa_mask); sigterm.sa_handler= generic_handler; sigterm.sa_flags= SA_SIGINFO; sigaction(SIGTERM,&sigterm,0); //----------------------- char buffer[BUFFER_SIZE]; int ret; int receive_sock; struct sockaddr_in server; struct sockaddr_in client; pthread_t tid; //------------------------ if (argc != 2) { printf("Sintassi: <port_number>\n"); exit(EXIT_FAILURE); } num_users=0; num_channels=0; ret= sem_init(&users_sem,0,1); ret= sem_init(&channels_sem,0,1); ERROR_HELPER(ret, "error creating users semaphore"); users=(User**) malloc(MAX_USERS*sizeof(User*)); channels=(Channel**) malloc(MAX_CHANNEL*sizeof(Channel*)); int i; for(i=0;i<MAX_USERS;i++){ users[i]=NULL; } for(i=0;i<MAX_CHANNEL;i++){ channels[i]=NULL; } long tmp= strtol(argv[1],NULL, 0); server_sock= socket(AF_INET, SOCK_STREAM,0); ERROR_HELPER(server_sock,"Error creating the socket"); server.sin_family= AF_INET; server.sin_port= htons(tmp); server.sin_addr.s_addr= htonl(INADDR_ANY); int true = 1; setsockopt(server_sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)); struct timeval timeout; timeout.tv_sec= 300; timeout.tv_usec= 0; ret= bind(server_sock,(struct sockaddr*) &server,sizeof(server)); ERROR_HELPER(ret,"Error binding the socket"); ret= listen(server_sock,BACKLOG); ERROR_HELPER(ret,"Error in listen"); int size_client= sizeof(client); printf("Server running...\n"); while(1){ if( (receive_sock= accept(server_sock,(struct sockaddr *)&client,&size_client)) <0){ if(errno==EINTR) continue; else ERROR_HELPER(receive_sock,"Error while accept"); } if(setsockopt(receive_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout))<0){ printf("errore sock option rcvtimeo\n"); exit(EXIT_FAILURE); } Params* tmp= (Params*) malloc(sizeof(Params)); tmp->descriptor= receive_sock; inet_ntop(AF_INET, &(client.sin_addr), tmp->address, INET_ADDRSTRLEN); ret= pthread_create(&tid,NULL,init_chat,(void*) tmp); ERROR_HELPER(ret,"Error creating the thread"); pthread_detach(tid); } return 0; }
void* init_chat(void* in){ int ret; Params* parameters= (Params*) malloc(sizeof(Params)); parameters= (Params*) in; int descriptor= parameters->descriptor; char address[INET_ADDRSTRLEN]; char buffer[BUFFER_SIZE]; snprintf(address,sizeof(address),"%s",parameters->address); snprintf(buffer,sizeof(buffer),"%s\n",WELCOME_MESSAGE); do{ ret= send_message(descriptor,buffer,NULL); ret= receive_message(descriptor,buffer); if(buffer[0]=='\n' || strlen(buffer)==0 || strlen(buffer)>USERNAME_LENGTH) snprintf(buffer,sizeof(buffer),"%s\n","Not valid username! It has to be at least 1 character and at last 20 characters long\n"); else if(strcmp(buffer,QUIT_COMMAND)==0){ send_message(descriptor,QUIT_INIT,strlen(QUIT_INIT)); ERROR_HELPER(ret,"error with sem_post in init_chat"); pthread_exit(NULL); } else break; } while(1); User* tmp_us= createUser(buffer,descriptor,address); ret=add_lastUser(tmp_us); if(ret==-1){ snprintf(buffer,sizeof(buffer),"%s","Chat is full.Try again later :("); send_message(descriptor,buffer,strlen(buffer)); close(descriptor); pthread_exit(NULL); } printf("Utente %s creato e ret è %d\n", users[ret]->username,ret); while(1){ int user_input= choose_operation(tmp_us); ERROR_HELPER(user_input,"errore choose operation"); switch (user_input) { case 0: print_stats_users(); Channel* tmp_ch=join_chat(tmp_us); ret= sem_post(&channels_sem); ERROR_HELPER(ret,"error on sem_post to channels_sem"); print_stats_channels(); if(tmp_ch==NULL){ ERROR_HELPER(ret,"error on sem_post to channels_sem"); break; } snprintf(buffer,sizeof(buffer),"%s","You joined the chat. Type and press ENTER to send messages to the others!\n"); send_message(descriptor,buffer,NULL); memset(buffer,0,sizeof(buffer)); snprintf(buffer,BUFFER_SIZE,"%s joined the chat\n",tmp_us->username); send_all(tmp_ch,tmp_us,buffer); chat_handler(tmp_ch,tmp_us); break; case 1: memset(buffer,0,sizeof(buffer)); snprintf(buffer,sizeof(buffer),"%s","\nType the name of your new chat.:\n"); do{ ret= send_message(descriptor,buffer,NULL); ret= receive_message(descriptor,buffer); if(buffer[0]=='$'){ ret=cmd_check(buffer,tmp_us); if(ret==QUIT_RET) break; } } while(already_exists(buffer)); if(ret==QUIT_RET) break; Channel* temp_ch= createChannel(buffer, tmp_us); printf("canale %s creato e l'admin è %d\n", temp_ch->channel_name, temp_ch->admin); memset(buffer,0,sizeof(buffer)); snprintf(buffer,sizeof(buffer),"%s","\nYou are in your new chat. Type and press ENTER to send messages to the others!\n\n"); ret= send_message(descriptor,buffer,NULL); memset(buffer,0,sizeof(buffer)); Channel* last_channel= add_lastChannel(temp_ch,tmp_us); if(last_channel==NULL){ snprintf(buffer,sizeof(buffer),"%s","Chat are full right now. Do you want to continue using the chat? (y/n) "); send_message(descriptor,buffer,strlen(buffer)); break; } chat_handler(last_channel,tmp_us); break; case 2: memset(buffer,0,sizeof(buffer)); snprintf(buffer,sizeof(buffer),"%s",QUIT_INIT); send_message(tmp_us->socket,buffer,strlen(buffer)); delete_user_from_users(tmp_us->socket); pthread_exit(NULL); break; } do{ ret= receive_message(descriptor,buffer); if(strlen(buffer)==1){ if(buffer[0]=='n'){ send_message(descriptor,QUIT_INIT,strlen(QUIT_INIT)); delete_user_from_users(descriptor); pthread_exit(NULL); } if(buffer[0]=='y') break; } snprintf(buffer,sizeof(buffer),"%s","Invalid input: choose between y or n!\n"); send_message(descriptor,buffer,strlen(buffer)); }while(1); } send_message(descriptor,QUIT_INIT,strlen(QUIT_INIT)); delete_user_from_users(descriptor); pthread_exit(NULL); }
int main(int argc, char* argv[]) { int ret; void* res1; // variables for handling a socket int socket_desc; struct sockaddr_in server_addr = {0}; // some fields are required to be filled with 0 // create a socket socket_desc = socket(AF_INET, SOCK_STREAM, 0); ERROR_HELPER(socket_desc, "Could not create socket"); // set up parameters for the connection server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(SERVER_PORT); // don't forget about network byte order! // initiate a connection on the socket ret = connect(socket_desc, (struct sockaddr*) &server_addr, sizeof (struct sockaddr_in)); ERROR_HELPER(ret, "Could not create connection"); if (DEBUG) fprintf(stderr, "Connection established!\n"); printf("/create or /join <name_channel>\n"); //thread dedicato per la rcv pthread_t thread_rcv; // put arguments for the new thread into a buffer struct_arg_client* thread_rcv_args = (struct_arg_client*) malloc(sizeof (struct_arg_client)); thread_rcv_args -> desc = socket_desc; if (pthread_create(&thread_rcv, NULL, ricevi, (void*) thread_rcv_args) != 0) { fprintf(stderr, "Can't create a new thread, error %d\n", errno); exit(EXIT_FAILURE); } //thread dedicato per la send pthread_t thread_send; // put arguments for the new thread into a buffer struct_arg_client* thread_send_args = (struct_arg_client*) malloc(sizeof (struct_arg_client)); thread_send_args -> desc = socket_desc; if (pthread_create(&thread_send, NULL, invia, (void*) thread_send_args) != 0) { fprintf(stderr, "Can't create a new thread, error %d\n", errno); exit(EXIT_FAILURE); } pthread_join(thread_rcv, &res1); //printf("Joined thread1 computing send work and thread2 computing rcv work.\nTotal bytes sent: %d bytes\nTotal bytes received: %d bytes\n", (unsigned int) res1, (unsigned int) res2); printf("Finished my job, received %d bytes\n", (unsigned int) res1); // close the socket ret = close(socket_desc); ERROR_HELPER(ret, "Cannot close socket"); if (DEBUG) fprintf(stderr, "Exiting...\n"); exit(EXIT_SUCCESS); }