#include "Server.h" #include #include #include #include #include #include #include #include #include #include "SocketUtils.h" void serverInitDefaults(Server* s) { s->maxClients = -1; s->port = -1; s->threads = NULL; s->clientSockets = NULL; s->clientUser = NULL; s->connectSocket = -1; s->handler = NULL; s->directory = NULL; } int serverInit(Server* s, int maxClients, short port, char* directory) { s->maxClients = maxClients; s->port = port; s->directory = directory; if(chdir(directory) == -1) { perror("cannot change directory"); serverRemove(s); return -1; } // initialize storage for clients s->threads = malloc(sizeof(pthread_t) * maxClients); s->clientSockets = malloc(sizeof(int) * maxClients); s->clientUser = malloc(sizeof(char*) * maxClients); for(int i = 0; i < maxClients; i++) { s->threads[i] = -1; s->clientSockets[i] = -1; s->clientUser[i] = NULL; } // 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; } if(s->clientUser != NULL) { for(int i = 0; i < s->maxClients; i++) { if(s->clientUser[i] != NULL) { free(s->clientUser[i]); s->clientUser[i] = NULL; } } free(s->clientUser); s->clientUser = 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->handler = NULL; } static 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) { if(s->handler(id, s->clientSockets[id], &in)) { break; } } 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); } serverFreeUser(s, id); s->clientSockets[id] = -1; return NULL; } int serverSend(int clientSocket, Stream* out) { if(sendAll(clientSocket, out) == -1) { 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 one of these commands:\n"); streamWriteChars(&out, "- HELP\n"); streamWriteChars(&out, "- SEND\n"); streamWriteChars(&out, "- LIST\n"); streamWriteChars(&out, "- READ\n"); streamWriteChars(&out, "- DEL\n"); streamWriteChars(&out, "- QUIT\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, ServerStreamFunction f) { s->handler = f; } int serverSetUser(Server* s, int clientId, char* name) { if(clientId < 0 || clientId >= s->maxClients) { return -1; } int l = strlen(name) + 1; s->clientUser[clientId] = malloc(sizeof(char) * l); strncpy(s->clientUser[clientId], name, l); return 0; } char* serverGetUser(Server* s, int clientId) { if(clientId < 0 || clientId >= s->maxClients) { return NULL; } return s->clientUser[clientId]; } void serverFreeUser(Server* s, int clientId) { if(clientId < 0 || clientId >= s->maxClients) { return; } if(s->clientUser[clientId] != NULL) { free(s->clientUser[clientId]); s->clientUser[clientId] = NULL; } }