/udp_chat_server/Server.c
https://bitbucket.org/schnika/chat-server-client · C · 475 lines · 363 code · 79 blank · 33 comment · 59 complexity · 6c384b95d68d0c41628c9526d1d04dc0 MD5 · raw file
- #include "Server.h"
- /* accept or decline a connection request.
- * A new user gets accepted when the choosen name is not in the user list
- */
- void
- sendSV_CON_REP()
- {
- ID = 2;
- uint8_t accepted = 1;
- uint16_t name_length;
- memcpy(&name_length, CL_CON_REQ + 1, sizeof(uint16_t));
- name_length = ntohs(name_length);
- char *name = malloc(name_length);
- strncpy(name, CL_CON_REQ + 3, name_length);
- /* Check if username already in list */
- if(find_username(name) == 1)
- {
- add_user(name);
- accepted = 0;
- }else accepted = 1;
- SV_CON_REP = malloc(sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint16_t));
- memcpy(SV_CON_REP, &ID, sizeof(uint8_t));
- memcpy(SV_CON_REP + 1, &accepted, sizeof(uint8_t));
- uint16_t cl_port = user->new_sv_sock_addr.sin_port;
- memcpy(SV_CON_REP + 2, &cl_port, sizeof(uint16_t));
- err = sendto(server_socket, SV_CON_REP, 4, 0, &from, sizeof(struct sockaddr_in));
- if (err == -1)
- printf("ERROR: Cannot send SV_CON_REP to client.\n");
- if(accepted == 0)
- {
- sendSV_CON_AMSG();
- }
- }
- /* inform all users about the new client */
- void
- sendSV_CON_AMSG()
- {
- ID = 3;
- SV_CON_AMSG = malloc(strlen(user->name)+3);
- uint16_t name_length = htons(strlen(user->name));
- memcpy(SV_CON_AMSG, &ID, sizeof(uint8_t));
- memcpy(SV_CON_AMSG + 1, &name_length, sizeof(uint16_t));
- strncpy(SV_CON_AMSG + 3, user->name, strlen(user->name));
- sendToAll(SV_CON_AMSG, 3 + strlen(user->name));
- }
- /* build a recieved user message end send it to all users */
- void
- sendSV_AMSG(struct user *sender)
- {
- ID = 5;
- uint16_t name_length = htons(strlen(sender->name));
-
- uint32_t msg_length;
- memcpy(&msg_length, CL_MSG+1, sizeof(uint32_t));
- msg_length = ntohl(msg_length);
- char *msg = malloc(msg_length);
- strncpy(msg, CL_MSG+5, msg_length);
- SV_AMSG = malloc(7 + strlen(msg) + strlen(sender->name));
-
- msg_length = htonl(msg_length);
- memcpy(SV_AMSG, &ID, 1);
- memcpy(SV_AMSG+1, &name_length, 2);
- memcpy(SV_AMSG+3, sender->name, strlen(sender->name));
- memcpy(SV_AMSG+3+strlen(sender->name), &msg_length, 4);
- memcpy(SV_AMSG+7+strlen(sender->name), msg, ntohl(msg_length));
-
- sendToAll(SV_AMSG, 7 + strlen(sender->name) + ntohl(msg_length));
- }
- /* build char* SV_DISC_REP as response to CL_DISC_REQ */
- void
- sendSV_DISC_REP(struct user *sender)
- {
- ID = 7;
- SV_DISC_REP = malloc(1);
- memcpy(SV_DISC_REP, &ID, 1);
- int count;
- for (count = 0; count < 2; count ++)
- {
- to.sin_family = AF_INET;
- to.sin_port = htons(sender->port);
- to.sin_addr.s_addr = inet_addr(sender->IP);
- err = sendto(sender->sv_socket, SV_DISC_REP, 1, 0, &to, sizeof(struct sockaddr_in));
- if (err == -1)
- {
- printf("ERROR: Cannot send SV_DISC_REP to client.\n");
- count += 1;
- sleep(5);
- }
- else
- sendSV_DISC_AMSG(sender->name);
- remove_user(sender);
- break;
-
- }
- }
- /* build char *SV_DISC_AMSG to inform about client disconnect */
- void
- sendSV_DISC_AMSG(char *name)
- {
- ID = 8;
- uint16_t name_length;
- name_length = strlen(name);
- name_length = htons(name_length);
- SV_DISC_AMSG = malloc(3 + strlen(name));
- memcpy(SV_DISC_AMSG, &ID, 1);
- memcpy(SV_DISC_AMSG+1, &name_length, 2);
- strncpy(SV_DISC_AMSG+3, name, strlen(name));
- sendToAll(SV_DISC_AMSG, 3 + strlen(name));
-
- }
- /* send messages to all users in the list */
- void
- sendToAll(char *msg, int msg_length)
- {
- struct user *receiver = user;
- int i;
- for (i = 0; i < usercount; i++)
- {
- to.sin_family = AF_INET;
- to.sin_port = htons(receiver->port);
- to.sin_addr.s_addr = inet_addr(receiver->IP);
- err = sendto(receiver->sv_socket, msg, msg_length, 0, &to, sizeof(struct sockaddr_in));
- if (err == -1)
- printf("ERROR: Cannot send msg (ID: %i) to client.\n", atoi(msg[0]));
- receiver = receiver->next;
- }
- }
- /* remove user from list, clear the associated socket and free allocated space */
- void
- remove_user(struct user *leaver)
- {
- struct user *tmp;
- tmp = user;
- int i;
- for (i = 0; i < usercount; i++)
- {
- if(tmp->name == leaver->name)
- {
- close(tmp->sv_socket);
- free(tmp);
- usercount --;
- break;
- }
- else if (tmp->next->name == leaver->name)
- {
- tmp->next = leaver->next;
- close(leaver->sv_socket);
- free(tmp->next);;
- usercount --;
- break;
- }
- else
- tmp = tmp->next;
- }
- }
- /*
- * checks wether username exists
- * @param name - the username to look for
- * return 1 - username doesn't exist
- * return 0 - username already exists
- */
- int
- find_username(char *name)
- {
- struct user *tmp = malloc(sizeof(struct user *));
- if(usercount == 0)
- {
- return 1;
- }
- else
- {
- tmp = user;
- while(tmp->next != NULL)
- {
- if(strncmp(tmp->name, name, strnlen(name)) == 0)
- {
- return 0;
- }
- tmp = tmp->next;
- }
- return 1;
- }
- }
- /* add user
- * @param name = username of the new_user user
- */
- void
- add_user(char *name)
- {
- new_user = malloc(sizeof(struct user));
-
- // set name
- strncpy(new_user->name, name, strlen(name));
- new_user->rep_counter;
- new_user->sv_socket = socket(AF_INET, SOCK_DGRAM, 0);
- strncpy(new_user->IP,inet_ntoa(from.sin_addr), strlen(inet_ntoa(from.sin_addr)));
- new_user->port = ntohs(from.sin_port);
- struct sockaddr_in sv_sock_add;
- sv_sock_add.sin_family = AF_INET;
- sv_sock_add.sin_port = 0;
- sv_sock_add.sin_addr.s_addr = inet_addr("127.0.0.1");
- new_user->new_sv_sock_addr = sv_sock_add;
- /* new_user port for the new_user client socket */
- err = bind(new_user->sv_socket, (struct sockaddr *) &new_user->new_sv_sock_addr, sizeof(struct sockaddr_in));
- if(err < 0)
- {
- perror("Bind error");
- }
- // set next user
- new_user->next = user;
- user = new_user;
- usercount += 1;
- }
- /* Portnumber validation */
- int
- isValidPort(char *str)
- {
- in_port_t tmp_port;
- tmp_port = atoi(str);
- if(tmp_port < 1024 || tmp_port > 65535)
- {
- printf("Invalid port number. Port hast do be between 1024 and 65535.\n");
- return 0;
- }
- printf("Valid port: %u\n", tmp_port);
- return 1;
- }
- /* Initialize field descriptors */
- void
- init_fds()
- {
- FD_ZERO(&readset);
- FD_SET(server_socket, &readset);
-
- struct user *tmp;
- tmp = user;
-
- highsock = server_socket;
- int i;
- for (i = 0; i<usercount; i++)
- {
- FD_SET(tmp->sv_socket, &readset);
- if (tmp->sv_socket > highsock)
- highsock = tmp->sv_socket;
- tmp = tmp->next;
- }
- }
- int main(int argc, char**argv)
- {
- /* Init user */
- user = malloc(sizeof(struct user));
- user = NULL;
- usercount = 0;
- time_to_wait = malloc(sizeof(struct timeval *));
- time_to_wait->tv_sec = 5;
- time_to_wait->tv_usec = 0;
- struct timeval *time_now = malloc(sizeof(struct timeval *));
- struct timeval *last_res = malloc(sizeof(struct timeval *));
- struct timeval *time_diff = malloc(sizeof(struct timeval *));
-
- int error;
- int flen;
- int rep_len;
- int c;
- int index;
- opterr = 0;
- while ((c = getopt(argc, argv, "p:")) != -1)
- switch(c)
- {
- case 'p':
- if (isValidPort(optarg) != 0)
- {
- serv_port = atoi(optarg);
- break;
- }
- return 1;
- case '?':
- if (optopt == 'p')
- fprintf (stderr, "Option -%c requires an argument.\n", optopt);
- else if (isprint (optopt))
- fprintf (stderr, "Unknown option `-%c'.\n", optopt);
- else
- fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
- return 1;
- default:
- abort ();
- }
-
- server_socket = socket(AF_INET, SOCK_DGRAM, 0);
-
- if (server_socket < 1)
- {
- perror("Create socket");
- } printf("Socket created!\n");
-
- /* set port and ip*/
- server_socket_address.sin_family = AF_INET;
- server_socket_address.sin_port = htons(serv_port);
- server_socket_address.sin_addr.s_addr = inet_addr("127.0.0.1");
- printf("IP Adresse: %s Port: %u\n", inet_ntoa(server_socket_address.sin_addr), ntohs(server_socket_address.sin_port));
- error = bind(server_socket, (struct sockaddr *) &server_socket_address, sizeof(struct sockaddr_in));
-
- if(error < 0)
- {
- perror("Bind error");
- } else printf("Socket bound!\n");
- int res;
- int sock;
- time_now->tv_sec = time(NULL);
- while(1)
- {
- ID = 0;
- init_fds();
- cl_rep_buffer = malloc(64);
- res = select(highsock + 1, &readset, NULL, NULL, time_to_wait);
- /* select error*/
- if (res == -1)
- {
- perror("Select Error.");
- }
- /* timeout. increase rep_counter for each connected user */
- else if (res == 0)
- {
- time_to_wait->tv_sec = 5;
- ID = 9;
- SV_PING_REQ = malloc(1);
- memcpy(SV_PING_REQ, &ID, sizeof(uint8_t));
- struct user *tmp;
- tmp = user;
- int i;
- for(i = 0; i<usercount; i++)
- {
- sendToAll(SV_PING_REQ, 1);
- tmp->rep_counter += 1;
- if(tmp->rep_counter == 4)
- {
- printf("Verbindung zu User %s unterbrochen. Nutzr wird vom Server entfernt.\n", tmp->name);
- remove_user(tmp);
- }
- }
- }
-
- else if (res > 0)
- {
- last_res->tv_sec = time(NULL);
-
- /* calc time diff */
- timersub(time_now, last_res, time_diff);
- timersub(time_to_wait, time_diff, time_to_wait);
- if (FD_ISSET(server_socket, &readset))
- {
- rep_len = recvfrom(server_socket, cl_rep_buffer, 64, 0, (struct sockaddr*) &from, &flen);
- memcpy(&ID, cl_rep_buffer, sizeof(uint8_t));
- if (ID == 1)
- {
- printf("Anfrage gestellt.\n");
- CL_CON_REQ = malloc(rep_len);
- memcpy(CL_CON_REQ, cl_rep_buffer, rep_len);
- sendSV_CON_REP();
- }
- else
- {
- printf("Falsche Anfrage gestellt.\n");
- }
- }
-
-
- struct user *tmp;
- tmp = user;
- int i;
-
- for (i = 0; i < usercount; i++)
- {
- if(FD_ISSET(tmp->sv_socket, &readset))
- {
- rep_len = recvfrom(tmp->sv_socket, cl_rep_buffer, 64, 0, (struct sockaddr*) &from, &flen);
- if(rep_len < 0)
- break;
- memcpy(&ID, cl_rep_buffer, sizeof(uint8_t));
- switch(ID)
- {
-
- /* CL_MSG */
- case 4:
- {
- CL_MSG = malloc(rep_len);
- memcpy(CL_MSG, cl_rep_buffer, rep_len);
- sendSV_AMSG(tmp);
- break;
- }
- /* CL_DISC_REQ */
- case 6:
- {
- CL_DISC_REQ = malloc(rep_len);
- memcpy(CL_DISC_REQ, cl_rep_buffer, rep_len);
- sendSV_DISC_REP(tmp);
- break;
- }
- /* CL_PING_REP */
- case 10:
- {
- // reset rep_counter
- tmp->rep_counter = 0;
- }
- default:
- {
- break;
- }
- }
- }
- tmp = tmp->next;
- }
- }
-
- }
- }