#include "Server.h" #include #include #include #include #include #include #include #include #include "Stream.h" void serverInitDefaults(Server* s) { s->maxClients = -1; s->port = -1; s->threads = NULL; s->clientSockets = NULL; s->connectSocket = -1; s->hAmount = -1; s->hIndex = -1; s->handlers = NULL; } int serverInit(Server* s, int maxClients, short port) { s->maxClients = maxClients; s->port = port; s->hAmount = 0; s->hIndex = 0; // initialize storage for clients s->threads = malloc(sizeof(pthread_t) * maxClients); s->clientSockets = malloc(sizeof(int) * maxClients); for(int i = 0; i < maxClients; i++) { s->threads[i] = -1; s->clientSockets[i] = -1; } // create the socket for clients to connect s->connectSocket = socket(AF_INET, SOCK_STREAM, 0); if(s->connectSocket == -1) { perror("Cannot create socket"); serverRemove(s); return -1; } // prevents clients from blocking the port if the server exits struct linger sl; sl.l_onoff = 1; sl.l_linger = 0; if(setsockopt(s->connectSocket, SOL_SOCKET, SO_LINGER, &sl, sizeof(struct linger)) == -1) { perror("Cannot set non lingering"); serverRemove(s); return -1; } // specifies data of the port and binds it struct sockaddr_in connectSocketData; memset(&connectSocketData, 0, sizeof(struct sockaddr_in)); connectSocketData.sin_family = AF_INET; connectSocketData.sin_addr.s_addr = INADDR_ANY; connectSocketData.sin_port = htons(port); if(bind(s->connectSocket, (struct sockaddr*) &connectSocketData, sizeof(struct sockaddr_in)) != 0) { perror("Cannot bind socket"); serverRemove(s); return -1; } // mark this socket as handler for connection requests if(listen(s->connectSocket, 5) != 0) { perror("Cannot start listening"); serverRemove(s); return -1; } return 0; } void serverRemove(Server* s) { s->port = -1; if(s->threads != NULL) { for(int i = 0; i < s->maxClients; i++) { if(s->threads[i] != -1) { printf("%d thread\n", i); pthread_cancel(s->threads[i]); pthread_join(s->threads[i], NULL); } } free(s->threads); s->threads = NULL; } if(s->clientSockets != NULL) { for(int i = 0; i < s->maxClients; i++) { if(s->clientSockets[i] != -1) { if(close(s->clientSockets[i]) == -1) { printf("%d", i); perror(" cannot close client socket"); } else { printf("%d closed\n", i); } } } free(s->clientSockets); s->clientSockets = NULL; } s->maxClients = -1; if(s->connectSocket != -1) { if(close(s->connectSocket) != 0) { perror("Cannot close server socket"); } else { printf("connection listener closed\n"); } s->connectSocket = -1; } s->hAmount = -1; s->hIndex = -1; if(s->handlers != NULL) { free(s->handlers); s->handlers = NULL; } } void* clientHandler(void* data) { int id = ((ThreadData*) data)->id; Server* s = ((ThreadData*) data)->server; Stream in; while(strcmp(in.data, "quit") != 0) { int size = recv(s->clientSockets[id], in.data, BUFFER_SIZE - 1, 0); if(size > 0) { in.data[size] = '\0'; int package = ((int) in.data[0]); if(package >= 0 && package < s->hIndex) { printf("Received package %d from %d: %s\n", package, id, in.data); in.index = 1; in.size = size; s->handlers[package](&in); } else { printf("Invalid package %d from %d\n", package, id); } } else if(size == 0) { printf("Client %d closed remote socket\n", id); break; } else { perror("recv error"); break; } } if(close(s->clientSockets[id]) != 0) { printf("%d", id); perror(" cannot close client socket"); } else { printf("%d closed\n", id); } s->clientSockets[id] = -1; return NULL; } void serverWaitForConnection(Server* s) { socklen_t addrlen = sizeof(struct sockaddr_in); char buffer[BUFFER_SIZE]; while(1) { printf("Waiting for connections...\n"); struct sockaddr_in clientSocketData; int clientSocket = accept(s->connectSocket, (struct sockaddr*) &clientSocketData, &addrlen); if(clientSocket >= 0) { printf("Client connected from %s:%d...\n", inet_ntoa(clientSocketData.sin_addr), (int) ntohs(clientSocketData.sin_port)); int i = 0; while(1) { if(s->clientSockets[i] == -1) { if(s->threads[i] != -1) { pthread_cancel(s->threads[i]); pthread_join(s->threads[i], NULL); } ThreadData data; data.id = i; data.server = s; if(pthread_create(&s->threads[i], NULL, clientHandler, (void*) &data) != 0) { perror("Cannot create thread"); strcpy(buffer, "error: cannot create thread\n"); if(send(clientSocket, buffer, strlen(buffer), 0) == -1) { perror("Cannot send error"); } close(clientSocket); } else { s->clientSockets[i] = clientSocket; strcpy(buffer, "Welcome to server, please enter your command:\n"); if(send(clientSocket, buffer, strlen(buffer), 0) == -1) { perror("Cannot send welcome message"); close(clientSocket); s->clientSockets[i] = -1; } } break; } i++; if(i >= s->maxClients) { printf("max clients reached\n"); strcpy(buffer, "error: max clients reached\n"); if(send(clientSocket, buffer, strlen(buffer), 0) == -1) { perror("Cannot send error"); } close(clientSocket); break; } } } } } void serverRegisterHandler(Server* s, StreamFunction f) { if(s->hAmount == s->hIndex) { if(s->hAmount == 0) { s->handlers = malloc(sizeof(StreamFunction)); s->hAmount = 1; } else { s->hAmount *= 2; StreamFunction* functions = malloc(sizeof(StreamFunction) * s->hAmount); for(int i = 0; i < s->hIndex; i++) { functions[i] = s->handlers[i]; } free(s->handlers); s->handlers = functions; } } s->handlers[s->hIndex] = f; s->hIndex++; }