123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- #include "Server.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/socket.h>
- #include <unistd.h>
- #include <string.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/types.h>
- #include <signal.h>
- #include "SocketUtils.h"
- void serverInitDefaults(Server* s)
- {
- s->maxClients = -1;
- s->port = -1;
- s->threads = NULL;
- s->clientSockets = NULL;
- s->loginTries = NULL;
- s->clientUser = NULL;
- s->connectSocket = -1;
-
- s->handler = NULL;
-
- s->banns = 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->loginTries = malloc(sizeof(int) * maxClients);
- s->ips = 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;
- s->loginTries[i] = 0;
- s->ips[i] = 0;
- }
-
- // 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;
- }
-
- s->banns = bannsNew();
-
- 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;
- }
-
- if(s->loginTries != NULL)
- {
- free(s->loginTries);
- s->loginTries = NULL;
- }
-
- if(s->ips != NULL)
- {
- free(s->ips);
- s->ips = 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;
-
- if(s->banns != NULL)
- {
- bannsRemove(s->banns);
- s->banns = 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);
- }
-
- s->loginTries[id] = 0;
- 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));
-
- if(bannsIsBanned(s->banns, clientSocketData.sin_addr.s_addr))
- {
- close(clientSocket);
- printf("Banned user tried joining\n");
- continue;
- }
-
- int i = 0;
- while(1)
- {
- if(s->clientSockets[i] == -1)
- {
- s->ips[i] = clientSocketData.sin_addr.s_addr;
-
- 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;
- }
- }
- int serverRaiseLoginFails(Server* s, int clientId)
- {
- if(clientId < 0 || clientId >= s->maxClients)
- {
- return 0;
- }
- s->loginTries[clientId]++;
- return s->loginTries[clientId] >= 3;
- }
- void serverResetLoginFails(Server* s, int clientId)
- {
- if(clientId < 0 || clientId >= s->maxClients)
- {
- return;
- }
- s->loginTries[clientId] = 0;
- }
- void serverBann(Server* s, int clientId)
- {
- if(clientId < 0 || clientId >= s->maxClients)
- {
- return;
- }
- bannsAdd(s->banns, s->ips[clientId]);
- }
|