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); }
void* receive_UDP(void* t) { struct sockaddr_in addr; struct sockaddr_in other_addr; int fd; int nbytes; socklen_t addrlen; char buf[MAXPACKETLEN]; fd = socket(AF_INET,SOCK_DGRAM,0); //fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP); if (fd < 0) { perror("socket"); exit(1); } //setup destination address memset(&addr,0,sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.s_addr=htonl(INADDR_ANY); addr.sin_port=htons(LOCALPORT); //printf("Binding %d\n",LOCALPORT); //bind to receive address if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { perror("bind"); exit(1); } pthread_mutex_unlock(&messaging_mutex);//unlocks lock from create_message_threads while (1) { addrlen = sizeof(other_addr); nbytes = recvfrom(fd,buf,MAXPACKETLEN,0,(struct sockaddr *) &other_addr,&addrlen); // printf("RECEIVED: %s\n",buf); if (nbytes <0) { perror("recvfrom"); exit(1); } packet_t* newpacket = parsePacket(buf); chatmessage_t* message; char newusername[MAXSENDERLEN]; char newip[MAXPACKETBODYLEN]; int newport; node_t* curr = STRAY_SEQ_MSGS->head; //figure out what type of packet this is and act accordingly switch(newpacket->packettype) { case CHAT: //figure out if this corresponds to an existing chatmessage message = find_chatmessage(newpacket->uid); message = process_packet(message,newpacket); if(message->iscomplete && me->isleader) { client_t* sendingclient = find_client_by_uid(newpacket->senderuid); add_elem(sendingclient->unseq_chat_msgs,(void*)message); //assign_sequence(message); } //for now, just print if it's complete if(message->iscomplete) printf("\E[33m%s\E(B\E[m (not sequenced yet):\t%s\n", message->sender, message->messagebody); //check the stray sequencing list. If there's already something in there that matches, remove it and add the message to the priority queue. process_late_sequence(message, newpacket); free_packet(newpacket); break; case SEQUENCE: //This is a sequencing message. Find the corresponding chat message in the unsequenced message list and enqueue it properly message = find_chatmessage(newpacket->uid); //If the corresponding message is not complete, ask the leader for its missing part first. It will be received as a chat. TODO //if no message is found, put this sequencing packet in the stray sequencing list if(message == NULL) { add_elem(STRAY_SEQ_MSGS,newpacket); break; } sequence(message, newpacket); //check if the front of the queue corresponds to our expected current sequence no. If so, print it. If not, we should wait or eventually ping the leader for it. free_packet(newpacket); break; case CHECKUP: if (strcmp(newpacket->packetbody,"ARE_YOU_ALIVE") == 0) { // send udp message to sender saying that this client is still alive client_t* orig_sender = find_client_by_uid(newpacket->senderuid); if (orig_sender != NULL) { send_UDP(CHECKUP, me->username, me->uid,newpacket->uid, "I_AM_ALIVE", orig_sender); } } else if (strcmp(newpacket->packetbody, "I_AM_ALIVE") == 0) { // reset sender's counter back to zero client_t* orig_sender = find_client_by_uid(newpacket->senderuid); if (orig_sender != NULL) { pthread_mutex_lock(&missed_checkups_mutex); orig_sender->missed_checkups = 0; pthread_mutex_unlock(&missed_checkups_mutex); } } else { printf("\nUnrecognized value in checkup message!\n"); } free_packet(newpacket); break; case ELECTION: pthread_mutex_lock(&election_happening_mutex); election_happening = TRUE; pthread_mutex_unlock(&election_happening_mutex); clear_deference(); free(newpacket); break; case VOTE: if (strcmp(newpacket->packetbody, "I_SHOULD_LEAD") == 0) { //iterate over all clients and update their local deference accordingly pthread_mutex_lock(&CLIENTS->mutex); pthread_mutex_lock(&client_deference_mutex); client_t* client; node_t* curr = CLIENTS->head; while(curr != NULL) { client = ((client_t*)curr->elem); if (strcmp(client->deferent_to, "IHAVENOsuperiors") == 0) { // Currently don't have an allegience yet // So I'll either support the sender or myself -- depending on who is more powerful if ((strcmp(client->uid,newpacket->senderuid)) < 0) { // Sender is greater than me, so support the sender and remove my candidates client->isCandidate = FALSE; snprintf(client->deferent_to, sizeof(client->deferent_to), "%s", newpacket->senderuid); } else if ((strcmp(client->uid,newpacket->senderuid)) >= 0) { // I am more powerful than the sender so support myself (and I'm still a candidate) snprintf(client->deferent_to, sizeof(me->deferent_to), "%s", client->uid); } } else { client_t* curr_leader = find_client_by_uid(client->deferent_to); if ((strcmp(curr_leader->uid,newpacket->senderuid)) < 0) { // My previous leader is less than sender's uid // So switch deference to sender snprintf(client->deferent_to, sizeof(client->deferent_to), "%s", newpacket->senderuid); } // else condition means that previous leader is greter than sender // So do nothing } curr = curr->next; } pthread_mutex_unlock(&CLIENTS->mutex); pthread_mutex_unlock(&client_deference_mutex); } free_packet(newpacket); break; case VICTORY: if (TRUE) { client_t* client; pthread_mutex_lock(&CLIENTS->mutex); node_t* curr = CLIENTS->head; while(curr != NULL) { client = ((client_t*)curr->elem); if (strcmp(newpacket->packetbody, client->uid) == 0 && (client->isleader == FALSE)) { pthread_mutex_lock(&seqno_mutex); pthread_mutex_lock(&dump_backlog_mutex); if(client == me) { LEADER_SEQ_NO = SEQ_NO; DUMP_BACKLOG = TRUE; } pthread_mutex_unlock(&dump_backlog_mutex); pthread_mutex_unlock(&seqno_mutex); pthread_mutex_lock(&me_mutex); client->isleader = TRUE; pthread_mutex_unlock(&me_mutex); coup_propogated = TRUE; char uid[MAXUIDLEN]; get_new_uid(uid); multicast_UDP(CONFIRMCOUP,me->username, me->uid, uid, "LONG_LIVE_THE_NEW_KING"); break; } curr = curr->next; } pthread_mutex_unlock(&CLIENTS->mutex); } pthread_mutex_lock(&election_happening_mutex); election_happening = FALSE; pthread_mutex_unlock(&election_happening_mutex); free_packet(newpacket); break; case CONFIRMCOUP: // Update this nodes coup_propogated global pthread_mutex_lock(&coup_propogated_mutex); coup_propogated = TRUE; pthread_mutex_unlock(&coup_propogated_mutex); free_packet(newpacket); break; case QUORUMRESPONSE: // workaround for weird switch scope issues... if (TRUE) { client_t* orig_sender = find_client_by_uid(newpacket->senderuid); client_t* client_to_check = find_client_by_uid(newpacket->packetbody); if (orig_sender != NULL && client_to_check != NULL) { if (client_to_check->missed_checkups >= CHECKUP_DEATH_TIMELIMIT) { send_UDP(CONFIRMDEAD, me->username, me->uid,newpacket->uid, "YEP_THEY_ARE_DEAD", orig_sender); } else { send_UDP(CONFIRMDEAD, me->username, me->uid,newpacket->uid, "NO_THEY_ARE_ALIVE", orig_sender); } } } free_packet(newpacket); break; case CONFIRMDEAD: if (strcmp(newpacket->packetbody,"YEP_THEY_ARE_DEAD") == 0) { num_clients_agree_on_death_call++; } else if (strcmp(newpacket->packetbody,"NO_THEY_ARE_ALIVE") == 0) { num_clients_disagree_on_death_call++; } else { printf("\nUnrecognized value in checkup message!\n"); } free_packet(newpacket); break; case JOIN_REQUEST: //message from someone who wants to join strcpy(newip,strtok(newpacket->packetbody,":")); newport = atoi(strtok(NULL,IPPORTSTRDELIM)); printf("Receiving JOIN_REQUEST from: %s:%d\n",newip,newport); client_t* newguy = create_client(newpacket->sender,newip,newport,FALSE); char marshalledaddresses[MAXCHATMESSAGELEN]; char uid[MAXUIDLEN]; get_new_uid(uid); //if I'm not the leader, send a LEADER_INFO if(!me->isleader) { curr = CLIENTS->head; pthread_mutex_lock(&CLIENTS->mutex); client_t* leader = NULL; while(curr != NULL) { client_t* client = (client_t*)curr->elem; if(client->isleader) { leader = client; break; } curr = curr->next; } if(leader == NULL) //don't respond. Let the new joiner timeout. { // printf("Can't process JOIN_REQUEST. Don't know who the leader is!!!\n"); // send_UDP(LEADER_INFO,me->username,me->uid,uid,"",newguy); free(newguy); free_packet(newpacket); break; } pthread_mutex_unlock(&CLIENTS->mutex); strcpy(marshalledaddresses,leader->username); strcat(marshalledaddresses,":"); strcat(marshalledaddresses,leader->hostname); char portbuf[10]; sprintf(portbuf,":%d",leader->portnum); strcat(marshalledaddresses,portbuf); printf("Sending LEADER_INFO to %s:%d\n",newguy->hostname,newguy->portnum); send_UDP(LEADER_INFO,leader->username,leader->uid,uid,marshalledaddresses,newguy); } else //I'm the leader, so I can send JOIN { // printf("JOIN_REQUEST packet: %s\n",newpacket->packetbody); //check to make sure this client isn't already around char senderuid[MAXSENDERLEN]; sprintf(senderuid,"%s:%d",newip,newport); if(find_client_by_uid(senderuid)) { break; } strcpy(marshalledaddresses,newguy->username); strcat(marshalledaddresses,":"); strcat(marshalledaddresses,newguy->hostname); char portbuf[10]; sprintf(portbuf,":%d",newguy->portnum); strcat(marshalledaddresses,portbuf); pthread_mutex_lock(&CLIENTS->mutex); curr = CLIENTS->head; while(curr != NULL) { strcat(marshalledaddresses,":"); strcat(marshalledaddresses,((client_t*)curr->elem)->username); strcat(marshalledaddresses,":"); strcat(marshalledaddresses,((client_t*)curr->elem)->hostname); // char portbuf[10]; sprintf(portbuf,":%d",((client_t*)curr->elem)->portnum); strcat(marshalledaddresses,portbuf); curr = curr->next; } pthread_mutex_unlock(&CLIENTS->mutex); // printf("JOIN info:\t%s\n",marshalledaddresses); printf("Sending JOIN to %s:%d\n",newguy->hostname,newguy->portnum); send_UDP(JOIN,me->username,me->uid,uid,marshalledaddresses,newguy); multicast_UDP(JOIN,me->username,me->uid,uid,marshalledaddresses); } free(newguy); free_packet(newpacket); break; case EXIT: if (TRUE) { client_t* client_to_kill = find_client_by_uid(newpacket->packetbody); if (client_to_kill != NULL) { print_info_with_senderids(client_to_kill->username,"has gone offline",client_to_kill->uid); } } remove_client_by_uid(newpacket->packetbody); free_packet(newpacket); break; case LEADER_INFO: //if someone asked to join, but they didn't ask the leader, instead of sending a JOIN, send them this. //If you receive this, repeat the JOIN_REQUEST, but to the leader. if(strlen(newpacket->packetbody) == 0) { printf("Got no LEADER_INFO. Trying again.\n"); strcpy(newip,strtok(newpacket->senderuid,IPPORTSTRDELIM)); newport = atoi(strtok(NULL,IPPORTSTRDELIM)); client_t* jointome = create_client("",newip,newport,TRUE); join_chat(jointome); } strtok(newpacket->packetbody,IPPORTSTRDELIM); strcpy(newip,strtok(NULL,IPPORTSTRDELIM)); newport = atoi(strtok(NULL,IPPORTSTRDELIM)); printf("Receiving LEADER_INFO: %s:%d\n",newip,newport); client_t* leader = create_client(newpacket->sender,newip,newport,FALSE); join_chat(leader); free_packet(newpacket); break; case JOIN: //figure out if this corresponds to an existing chatmessage message = find_chatmessage(newpacket->uid); message = process_packet(message,newpacket); if(message->iscomplete) { //read the first one off first strcpy(newusername,strtok(message->messagebody,":")); strcpy(newip,strtok(NULL,":")); newport = atoi(strtok(NULL,IPPORTSTRDELIM)); //announcement that someone has successfully joined client_t* newclient = add_client(newusername,newip,newport,FALSE); if(newport == LOCALPORT && strcmp(LOCALHOSTNAME,newip) == 0) //then I'm the guy who just joined { JOIN_SUCCESSFUL = TRUE; me = newclient; pthread_mutex_unlock(&me_mutex); int usernum = 1; while(1) { char* newusertest = strtok(NULL,":"); if(newusertest == NULL) break; strcpy(newusername,newusertest); strcpy(newip,strtok(NULL,":")); newport = atoi(strtok(NULL,IPPORTSTRDELIM)); client_t* addedclient; if(usernum == 1) { addedclient = add_client(newusername,newip,newport,TRUE); print_info_with_senderids(newusername,"has approved your join request",addedclient->uid); print_info_with_senderids(newusername,"Current Members:",addedclient->uid); } else addedclient = add_client(newusername,newip,newport,FALSE); print_info_with_senderids(newusername,addedclient->uid,addedclient->uid); usernum++; } } else { print_info_with_senderids(newusername,"has joined the chat",newclient->uid); } } if(message->iscomplete && me->isleader) { // printf("Immediately sequencing JOIN\n"); assign_sequence(message); } process_late_sequence(message, newpacket); free_packet(newpacket); break; default: printf("\nUnrecognized packet type: %d\n", newpacket->packettype); free_packet(newpacket); } }//end of while pthread_exit((void *)t); }