#include "Server.h" #include #include #include #include #include #include #include #include #include "Stream.h" #include "SocketUtils.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(1) { streamInit(&in, 1024); int size = receiveAll(s->clientSockets[id], &in); if(size > 0) { char package; if(streamGetChar(&in, &package) == -1) { printf("Invalid package %d from %d\n", (int) package, id); } else { if(package >= 0 && package < s->hIndex) { printf("Received package %d from %d\n", (int) package, id); s->handlers[(int) package](&in); } else { printf("Invalid package %d from %d\n", (int) package, id); } } } else if(size == 0) { printf("Client %d closed remote socket\n", id); streamRemove(&in); break; } else { perror("recv error"); streamRemove(&in); break; } streamRemove(&in); } 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; } int serverSend(int clientSocket, Stream* out) { if(sendAll(clientSocket, out) == -1) { perror("Cannot send data"); return -1; } return 0; } void serverWaitForConnection(Server* s) { socklen_t addrlen = sizeof(struct sockaddr_in); 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"); Stream out; streamInit(&out, 16); streamWriteChar(&out, -1); streamWriteChars(&out, "Cannot create thread\n"); serverSend(clientSocket, &out); streamRemove(&out); close(clientSocket); } else { s->clientSockets[i] = clientSocket; Stream out; streamInit(&out, 64); streamWriteChar(&out, 1); streamWriteChars(&out, "Welcome to the server, please enter your command:\n"); if(serverSend(clientSocket, &out) == -1) { perror("Cannot send welcome message"); close(clientSocket); s->clientSockets[i] = -1; } streamRemove(&out); } break; } i++; if(i >= s->maxClients) { printf("max clients reached\n"); Stream out; streamInit(&out, 16); streamWriteChar(&out, -1); streamWriteChars(&out, "the server is full\n"); serverSend(clientSocket, &out); streamRemove(&out); 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++; }