|
@@ -0,0 +1,297 @@
|
|
|
+#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 "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;
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ s->connectSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
+ if(s->connectSocket == -1)
|
|
|
+ {
|
|
|
+ perror("Cannot create socket");
|
|
|
+ serverRemove(s);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ 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++;
|
|
|
+}
|