diff options
Diffstat (limited to 'server.c')
-rw-r--r-- | server.c | 567 |
1 files changed, 388 insertions, 179 deletions
@@ -1,11 +1,15 @@ #include "chatty.h" +#include "protocol.h" #include <assert.h> +#include <fcntl.h> #include <netinet/in.h> #include <poll.h> +#include <signal.h> #include <stdarg.h> #include <string.h> #include <sys/socket.h> +#include <sys/stat.h> #include <unistd.h> // timeout on polling @@ -14,276 +18,481 @@ #define MAX_CONNECTIONS 16 // Get number of connections from arena position // NOTE: this is somewhat wrong, because of when disconnections happen -#define FDS_SIZE (fdsArena->pos / sizeof(*fds)) +#define FDS_SIZE (fdsArena.pos / sizeof(struct pollfd)) +#define CLIENTS_SIZE (clientsArena.pos / sizeof(Client)) + +// Enable/Disable saving clients permanently to file +#define IMPORT_ID +// Where to save clients +#define CLIENTS_FILE "_clients" +// Where to write logs +#define LOGFILE "server.log" +// Log to LOGFILE instead of stderr +// #define LOGGING // enum for indexing the fds array enum { FDS_STDIN = 0, FDS_SERVER, FDS_CLIENTS }; -// Has information on clients -// For each pollfd in fds there should be a matching client in clients -// clients[i] <=> fds[i] +// Client information typedef struct { u8 author[AUTHOR_LEN]; // matches author property on other message types - Bool initialized; // boolean + ID id; + struct pollfd* pollunifd; // Index in fds array + struct pollfd* pollbifd; // Index in fds array } Client; +#define CLIENT_FMT "[%s](%lu)" +#define CLIENT_ARG(client) client.author, client.id + +typedef enum { + UNIFD = 0, + BIFD +} ClientFD; + +// TODO: remove +// For handing out new ids to connections. +global_variable u32 nclients = 0; + +// Returns client matching id in clients. +// clientsArena is used to get an upper bound. +// Returns 0 if there was no client found. +Client* +getClientByID(Arena* clientsArena, ID id) +{ + Client* clients = clientsArena->addr; + for (u32 i = 0; i < (clientsArena->pos / sizeof(*clients)); i++) { + if (clients[i].id == id) + return clients + i; + } + return 0; +} + +// Print TextMessage prettily +void +printTextMessage(TextMessage* message, Client* client, u8 wide) +{ + u8 timestamp[TIMESTAMP_LEN] = {0}; + formatTimestamp(timestamp, message->timestamp); + + if (wide) { + setlocale(LC_ALL, ""); + wprintf(L"TextMessage: %s [%s] %ls\n", timestamp, client->author, (wchar_t*)&message->text); + } else { + u8 str[message->len]; + wcstombs((char*)str, (wchar_t*)&message->text, message->len * sizeof(*message->text)); + loggingf("TextMessage: %s [%s] (%d)%s\n", timestamp, client->author, message->len, str); + } +} -// Send anyMessage to all clients in fds from fdsArena except for fds[i]. +// Send header and anyMessage to each connection in fds that is nfds number of connections except +// for connfd. +// Type will filter out only connections matching the type. void -sendToOthers(Arena* fdsArena, struct pollfd* fds, u32 i, HeaderMessage* header, void* anyMessage) +sendToOthers(struct pollfd* fds, u32 nfds, s32 connfd, ClientFD type, HeaderMessage* header, void* anyMessage) { s32 nsend; - for (u32 j = FDS_CLIENTS; j < FDS_SIZE; j++) { - if (fds[j].fd == fds[i].fd) continue; - if (fds[j].fd == -1) continue; - - // send header - u32 nsend_total = 0; - nsend = send(fds[j].fd, header, sizeof(*header), 0); - assert(nsend != -1); - assert(nsend == sizeof(*header)); - nsend_total += nsend; - - // send message - switch (header->type) { - case HEADER_TYPE_PRESENCE: { - PresenceMessage* message = (PresenceMessage*)anyMessage; - nsend = send(fds[j].fd, message, sizeof(*message), 0); - assert(nsend != -1); - assert(nsend == sizeof(*message)); - fprintf(stdout, " Notifying(%d->%d).\n", fds[i].fd, fds[j].fd); - break; - } - case HEADER_TYPE_TEXT: { - TextMessage* message = (TextMessage*)anyMessage; - nsend = send(fds[j].fd, message, TEXTMESSAGE_SIZE, 0); - assert(nsend != -1); - assert(nsend == TEXTMESSAGE_SIZE); - nsend_total += nsend; - nsend = send(fds[j].fd, &message->text, message->len * sizeof(*message->text), 0); - assert(nsend != -1); - assert(nsend == (message->len * sizeof(*message->text))); - nsend_total += nsend; - break; - } - default: - fprintf(stdout, " Cannot retransmit %s\n", headerTypeString(header->type)); - } + for (u32 i = FDS_CLIENTS + type; i < nfds; i += 2) { + if (fds[i].fd == connfd) continue; + if (fds[i].fd == -1) continue; - fprintf(stdout, " Retransmitted(%d->%d) %d bytes.\n", fds[i].fd, fds[j].fd, nsend_total); + nsend = sendAnyMessage(fds[i].fd, header, anyMessage); + loggingf("sendToOthers(%d)|[%s]->%d %d bytes\n", connfd, headerTypeString(header->type), fds[i].fd, nsend); } } +// Send header and anyMessage to each connection in fds that is nfds number of connections. +// Type will filter out only connections matching the type. void -disconnect(Arena* fdsArena, struct pollfd* fds, u32 i, Client* client) +sendToAll(struct pollfd* fds, u32 nfds, ClientFD type, HeaderMessage* header, void* anyMessage) { - fprintf(stdout, "Disconnected(%d). \n", fds[i].fd); - shutdown(fds[i].fd, SHUT_RDWR); - close(fds[i].fd); // send close to client - - // Send disconnection to other connected clients - HeaderMessage header = HEADER_PRESENCEMESSAGE; - PresenceMessage message = { - .type = PRESENCE_TYPE_DISCONNECTED - }; - memcpy(message.author, client->author, AUTHOR_LEN); - sendToOthers(fdsArena, fds, i, &header, &message); - - fds[i].fd = -1; // ignore in the future - client->initialized = False; // deinitialize client + for (u32 i = FDS_CLIENTS + type; i < nfds; i += 2) { + if (fds[i].fd == -1) continue; + s32 nsend = sendAnyMessage(fds[i].fd, header, anyMessage); + loggingf("sendToAll|[%s]->%d %d bytes\n", headerTypeString(header->type), fds[i].fd, nsend); + } } -// Initialize a client that connects for the first time or reconnects. -// Receive HeaderMessage and PresenceMessage from fd and set client with the data from -// PresenceMessage. -// Notify fds in fdsArena. -// TODO: handle wrong messages +// Disconnect a client by closing the matching file descriptors void -initClient(Arena* fdsArena, struct pollfd* fds, s32 fd, Client* client) +disconnect(struct pollfd* pollfd, Client* client) { - s32 nrecv = 0; - s32 nsend = 0; + loggingf("Disconnecting "CLIENT_FMT"\n", CLIENT_ARG((*client))); + if (pollfd[UNIFD].fd != -1) { + close(pollfd[UNIFD].fd); + } + if (pollfd[BIFD].fd != -1) { + close(pollfd[BIFD].fd); + } + pollfd[UNIFD].fd = -1; + pollfd[BIFD].fd = -1; + // TODO: mark as free + if (client) { + client->pollunifd = 0; + client->pollbifd = 0; + } +} - fprintf(stdout, " Adding to clients(%d).\n", fd); +// Disconnects fds+conn from fds with nfds connections, then send a PresenceMessage to other +// clients about disconnection. +void +disconnectAndNotify(Client* client, struct pollfd* fds, u32 nfds, u32 conn) +{ + disconnect(fds + conn, client); + + local_persist HeaderMessage header = HEADER_INIT(HEADER_TYPE_PRESENCE); + PresenceMessage message = {.id = client->id, .type = PRESENCE_TYPE_DISCONNECTED}; + sendToAll(fds, nfds, UNIFD, &header, &message); +} + +// Receive authentication from pollfd->fd and create client out of it. Look in +// clientsArena if it already exists. Otherwise push a new onto the arena and write its information +// to clients_file. +// See "Authentication" in chatty.h +Client* +authenticate(Arena* clientsArena, s32 clients_file, struct pollfd* clientfds) +{ + s32 nrecv = 0; + Client* clients = clientsArena->addr; HeaderMessage header; - nrecv = recv(fd, &header, sizeof(header), 0); - assert(nrecv != -1); - assert(nrecv == sizeof(header)); - if (header.type != HEADER_TYPE_PRESENCE) { - // reject connection - close(fd); - fprintf(stdout, " Got wrong header(%d).\n", fd); - return; + nrecv = recv(clientfds[BIFD].fd, &header, sizeof(header), 0); + if (nrecv != sizeof(header)) { + loggingf("authenticate(%d)|err: %d/%lu bytes\n", clientfds[BIFD].fd, nrecv, sizeof(header)); + return 0; } - fprintf(stdout, " Got header(%d).\n", fd); - - PresenceMessage message; - nrecv = recv(fd, &message, sizeof(message), 0); - assert(nrecv != -1); - assert(nrecv == sizeof(message)); - fprintf(stdout, " Got presence message(%d).\n", fd); - - // Copy author from PresenceMessage. - memcpy(client->author, message.author, AUTHOR_LEN); - - // Notify other clients from this new one - // Reuse header and message - for (u32 j = FDS_CLIENTS; j < FDS_SIZE; j++) { - if (fds[j].fd == fd) - continue; - if (fds[j].fd == -1) - continue; - fprintf(stdout, " Notifying(%d->%d).\n", fd, fds[j].fd); - nsend = send(fds[j].fd, &header, sizeof(header), 0); - assert(nsend != -1); - assert(nsend == sizeof(header)); - nsend = send(fds[j].fd, &message, sizeof(message), 0); - assert(nsend != -1); - assert(nsend == sizeof(message)); + loggingf("authenticate(%d)|" HEADER_FMT "\n", clientfds[BIFD].fd, HEADER_ARG(header)); + + Client* client = 0; + // Scenario 1: Search for existing client + if (header.type == HEADER_TYPE_ID) { + IDMessage message; + nrecv = recv(clientfds[BIFD].fd, &message, sizeof(message), 0); + if (nrecv != sizeof(message)) { + loggingf("authenticate(%d)|err: %d/%lu bytes\n", clientfds[BIFD].fd, nrecv, sizeof(message)); + return 0; + } + + client = getClientByID(clientsArena, message.id); + if (client) { + loggingf("authenticate(%d)|found [%s](%lu)\n", clientfds[BIFD].fd, client->author, client->id); + header.type = HEADER_TYPE_ERROR; + // TODO: allow multiple connections + if (client->pollunifd != 0 || client->pollbifd != 0) { + loggingf("authenticate(%d)|err: already connected\n", clientfds[BIFD].fd); + ErrorMessage error_message = ERROR_INIT(ERROR_TYPE_ALREADYCONNECTED); + sendAnyMessage(clientfds[BIFD].fd, &header, &error_message); + return 0; + } + ErrorMessage error_message = ERROR_INIT(ERROR_TYPE_SUCCESS); + sendAnyMessage(clientfds[BIFD].fd, &header, &error_message); + } else { + loggingf("authenticate(%d)|notfound\n", clientfds[BIFD].fd); + header.type = HEADER_TYPE_ERROR; + ErrorMessage error_message = ERROR_INIT(ERROR_TYPE_NOTFOUND); + sendAnyMessage(clientfds[BIFD].fd, &header, &error_message); + return 0; + } + // Scenario 2: Create a new client + } else if (header.type == HEADER_TYPE_INTRODUCTION) { + IntroductionMessage message; + nrecv = recv(clientfds[BIFD].fd, &message, sizeof(message), 0); + if (nrecv != sizeof(message)) { + loggingf("authenticate(%d)|err: %d/%lu bytes\n", clientfds[BIFD].fd, nrecv, sizeof(message)); + return 0; + } + + // Copy metadata from IntroductionMessage + client = ArenaPush(clientsArena, sizeof(*clients)); + memcpy(client->author, message.author, AUTHOR_LEN); + client->id = nclients; + nclients++; + + // Save client +#ifdef IMPORT_ID + write(clients_file, client, sizeof(*client)); +#endif + loggingf("authenticate(%d)|Added [%s](%lu)\n", clientfds[BIFD].fd, client->author, client->id); + + HeaderMessage header = HEADER_INIT(HEADER_TYPE_ID); + IDMessage id_message = {.id = client->id}; + sendAnyMessage(clientfds[BIFD].fd, &header, &id_message); + } else { + loggingf("authenticate(%d)|Wrong header expected %s or %s\n", clientfds[BIFD].fd, headerTypeString(HEADER_TYPE_INTRODUCTION), headerTypeString(HEADER_TYPE_ID)); + return 0; } + assert(client != 0); + + client->pollunifd = clientfds; + client->pollbifd = clientfds + 1; + + return client; } int -main(void) +main(int argc, char** argv) { - s32 err, serverfd, clientfd; - u32 on = 1; + signal(SIGPIPE, SIG_IGN); + + logfd = 2; + // optional logging + if (argc > 1) { + if (*argv[1] == '-') + if (argv[1][1] == 'l') { + logfd = open(LOGFILE, O_RDWR | O_CREAT | O_TRUNC, 0600); + assert(logfd != -1); + } + } + s32 serverfd; // Start listening on the socket { - serverfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP); + s32 err; + u32 on = 1; + serverfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); assert(serverfd > 2); err = setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, (u8*)&on, sizeof(on)); - assert(err == 0); + assert(!err); const struct sockaddr_in address = { AF_INET, htons(PORT), {0}, + {0}, }; err = bind(serverfd, (const struct sockaddr*)&address, sizeof(address)); - assert(err == 0); + assert(!err); err = listen(serverfd, MAX_CONNECTIONS); - assert(err == 0); + assert(!err); + loggingf("Listening on :%d\n", PORT); } - Arena* msgsArena = ArenaAlloc(Megabytes(128)); // storing received messages - // NOTE: sent messages? - s32 nrecv = 0; // number of bytes received - - Arena* clientsArena = ArenaAlloc(MAX_CONNECTIONS * sizeof(Client)); - Arena* fdsArena = ArenaAlloc(MAX_CONNECTIONS * sizeof(struct pollfd)); - struct pollfd* fds = fdsArena->addr; - Client* clients = clientsArena->addr; + Arena clientsArena; + Arena fdsArena; + Arena msgsArena; + ArenaAlloc(&clientsArena, MAX_CONNECTIONS * sizeof(Client)); + ArenaAlloc(&fdsArena, MAX_CONNECTIONS * 2 * sizeof(struct pollfd)); + ArenaAlloc(&msgsArena, Megabytes(128)); // storing received messages + struct pollfd* fds = fdsArena.addr; + Client* clients = clientsArena.addr; + // Initializing fds struct pollfd* fdsAddr; - struct pollfd newpollfd = {-1, POLLIN, 0}; - + struct pollfd newpollfd = {-1, POLLIN, 0}; // for copying with events already set // initialize fds structure newpollfd.fd = 0; - fdsAddr = ArenaPush(fdsArena, sizeof(*fds)); + fdsAddr = ArenaPush(&fdsArena, sizeof(*fds)); memcpy(fdsAddr, &newpollfd, sizeof(*fds)); // add serverfd newpollfd.fd = serverfd; - fdsAddr = ArenaPush(fdsArena, sizeof(*fds)); + fdsAddr = ArenaPush(&fdsArena, sizeof(*fds)); memcpy(fdsAddr, &newpollfd, sizeof(*fds)); newpollfd.fd = -1; +#ifdef IMPORT_ID + s32 clients_file = open(CLIENTS_FILE, O_RDWR | O_CREAT | O_APPEND, 0600); + assert(clients_file != -1); + struct stat statbuf; + assert(fstat(clients_file, &statbuf) != -1); + + read(clients_file, clients, statbuf.st_size); + if (statbuf.st_size > 0) { + ArenaPush(&clientsArena, statbuf.st_size); + loggingf("Imported %lu client(s)\n", statbuf.st_size / sizeof(*clients)); + nclients += statbuf.st_size / sizeof(*clients); + } + for (u32 i = 0; i < nclients; i++) + loggingf("Imported: " CLIENT_FMT "\n", CLIENT_ARG(clients[i])); +#endif + // Initialize the rest of the fds array for (u32 i = FDS_CLIENTS; i < MAX_CONNECTIONS; i++) fds[i] = newpollfd; + // Reset file descriptors on imported clients + for (u32 i = 0; i < CLIENTS_SIZE; i++) { + clients[i].pollunifd = 0; + clients[i].pollbifd = 0; + } while (1) { - err = poll(fds, FDS_SIZE, TIMEOUT); + s32 err = poll(fds, FDS_SIZE, TIMEOUT); assert(err != -1); if (fds[FDS_STDIN].revents & POLLIN) { - // helps for testing and exiting gracefully - break; + u8 c; // exit on ctrl-d + if (!read(fds[FDS_STDIN].fd, &c, 1)) + break; } else if (fds[FDS_SERVER].revents & POLLIN) { - clientfd = accept(serverfd, NULL, NULL); - assert(clientfd != -1); - assert(clientfd > serverfd); - fprintf(stdout, "New connection(%d).\n", clientfd); - - // If there is a slot in fds with fds[found].fd == -1 use it instead, otherwise allocate - // some space on the arena. - u8 found; - for (found = FDS_CLIENTS; found < FDS_SIZE; found++) - if (fds[found].fd == -1) - break; - if (found == MAX_CONNECTIONS) { - // TODO: reject connection - close(clientfd); - fprintf(stdout, "Max clients reached."); - } else if (found == FDS_SIZE) { - // no more space, allocate - struct pollfd* pollfd = ArenaPush(fdsArena, sizeof(*pollfd)); - pollfd->fd = clientfd; - pollfd->events = POLLIN; + // TODO: what if we are not aligned by 2 anymore? + s32 unifd = accept(serverfd, 0, 0); + s32 bifd = accept(serverfd, 0, 0); + + if (unifd == -1 || bifd == -1) { + loggingf("Error while accepting connection (%d,%d)\n", unifd, bifd); + if (unifd != -1) close(unifd); + if (bifd != -1) close(bifd); + continue; + } else + loggingf("New connection(%d,%d)\n", unifd, bifd); + + // TODO: find empty space in arena + if (nclients + 1 == MAX_CONNECTIONS) { + local_persist HeaderMessage header = HEADER_INIT(HEADER_TYPE_ERROR); + local_persist ErrorMessage message = ERROR_INIT(ERROR_TYPE_TOOMANYCONNECTIONS); + sendAnyMessage(unifd, &header, &message); + if (unifd != -1) + close(unifd); + if (bifd != -1) + close(bifd); + loggingf("Max clients reached. Rejected connection\n"); } else { - // hole found - fds[found].fd = clientfd; - fds[found].events = POLLIN; - fprintf(stdout, "Added pollfd(%d).\n", clientfd); + // no more space, allocate + struct pollfd* clientfds = ArenaPush(&fdsArena, 2 * sizeof(*clientfds)); + clientfds[UNIFD].fd = unifd; + clientfds[UNIFD].events = POLLIN; + clientfds[BIFD].fd = bifd; + clientfds[BIFD].events = POLLIN; + loggingf("Added pollfd(%d,%d)\n", unifd, bifd); } } - // Check for messages from clients - for (u32 i = FDS_CLIENTS; i < FDS_SIZE; i++) { - if (!(fds[i].revents & POLLIN)) - continue; - assert(fds[i].fd != -1); - fprintf(stdout, "Message(%d).\n", fds[i].fd); - Client* client = clients + i; - - // Initialize the client if this is the first time - if (!client->initialized) { - initClient(fdsArena, fds, fds[i].fd, client); - client->initialized = True; - fprintf(stdout, " Added to clients(%d): %s\n", fds[i].fd, client->author); + // Check for messages from clients in their unifd + for (u32 conn = FDS_CLIENTS; conn < FDS_SIZE; conn += 2) { + if (!(fds[conn].revents & POLLIN)) continue; + if (fds[conn].fd == -1) continue; + loggingf("Message unifd (%d)\n", fds[conn].fd); + + // Get client associated with connection + Client* client = 0; + for (u32 j = 0; j < CLIENTS_SIZE; j++) { + if (!clients[j].pollunifd) + continue; + if (clients[j].pollunifd == fds + conn) { + client = clients + j; + break; + } + } + if (!client) { + loggingf("No client associated(%d)\n", fds[conn].fd); + close(fds[conn].fd); continue; } + loggingf("Found client(%lu) [%s] (%d)\n", client->id, client->author, fds[conn].fd); // We received a message, try to parse the header HeaderMessage header; - nrecv = recv(fds[i].fd, &header, sizeof(header), 0); - assert(nrecv != -1); - + s32 nrecv = recv(fds[conn].fd, &header, sizeof(header), 0); if (nrecv == 0) { - disconnect(fdsArena, fds, i, (clients + i)); + disconnectAndNotify(client, fds, FDS_SIZE, conn); + loggingf("Disconnected(%lu) [%s]\n", client->id, client->author); + continue; + } else if (nrecv != sizeof(header)) { + disconnectAndNotify(client, fds, FDS_SIZE, conn); + loggingf("error(%lu) [%s] %d/%lu bytes\n", client->id, client->author, nrecv, sizeof(header)); continue; } - - assert(nrecv == sizeof(header)); - fprintf(stderr, " Received(%d): %d bytes -> " PH_FMT "\n", fds[i].fd, nrecv, PH_ARG(header)); + loggingf("Received(%d) -> " HEADER_FMT "\n", fds[conn].fd, HEADER_ARG(header)); switch (header.type) { - case HEADER_TYPE_TEXT:; - TextMessage* message; - nrecv = recvTextMessage(msgsArena, fds[i].fd, &message); - fprintf(stderr, " Received(%d): %d bytes -> ", fds[i].fd, nrecv); - printTextMessage(message, 0); + case HEADER_TYPE_TEXT: { + TextMessage* text_message = recvTextMessage(&msgsArena, fds[conn].fd); + loggingf("Received(%d)", fds[conn].fd); + printTextMessage(text_message, client, 0); + + sendToOthers(fds, FDS_SIZE, fds[conn].fd, UNIFD, &header, text_message); + } break; + // handle request for information about client id + default: + loggingf("Unhandled '%s' from client(%d)\n", headerTypeString(header.type), fds[conn].fd); + disconnectAndNotify(client, fds, FDS_SIZE, conn); + continue; + } + } - // Send message to all other clients - sendToOthers(fdsArena, fds, i, &header, message); + // Check for messages from clients in their bifd + for (u32 conn = FDS_CLIENTS + BIFD; conn < FDS_SIZE; conn += 2) { + if (!(fds[conn].revents & POLLIN)) continue; + if (fds[conn].fd == -1) continue; + loggingf("Message bifd (%d)\n", fds[conn].fd); + + // Get client associated with connection + Client* client = 0; + for (u32 j = 0; j < CLIENTS_SIZE; j++) { + if (!clients[j].pollbifd) + continue; + if (clients[j].pollbifd == fds + conn) { + client = clients + j; + break; + } + } + if (!client) { + loggingf("No client for connection(%d)\n", fds[conn].fd); +#ifdef IMPORT_ID + client = authenticate(&clientsArena, clients_file, fds + conn - 1); +#else + client = authenticate(&clientsArena, 0, fds + conn - 1); +#endif + // If the client sent an IDMessage but no ID was found authenticate() could return null + if (!client) { + loggingf("Could not initialize client\n"); + disconnect(fds + conn, 0); + } else { // client was added/connected + local_persist HeaderMessage header = HEADER_INIT(HEADER_TYPE_PRESENCE); + PresenceMessage message = {.id = client->id, .type = PRESENCE_TYPE_CONNECTED}; + sendToOthers(fds, FDS_SIZE, fds[conn - BIFD].fd, UNIFD, &header, &message); + } + continue; + } + loggingf("Found client(%lu) [%s] (%d)\n", client->id, client->author, fds[conn].fd); - break; + // We received a message, try to parse the header + HeaderMessage header; + s32 nrecv = recv(fds[conn].fd, &header, sizeof(header), 0); + if (nrecv == 0) { + disconnectAndNotify(client, fds, FDS_SIZE, conn); + loggingf("Disconnected(%lu) [%s]\n", client->id, client->author); + continue; + } else if (nrecv != sizeof(header)) { + disconnectAndNotify(client, fds, FDS_SIZE, conn); + loggingf("error(%lu) [%s] %d/%lu bytes\n", client->id, client->author, nrecv, sizeof(header)); + continue; + } + loggingf("Received(%d) -> " HEADER_FMT "\n", fds[conn].fd, HEADER_ARG(header)); + + switch (header.type) { + case HEADER_TYPE_ID: { + // handle request for information about client id + IDMessage id_message; + nrecv = recv(fds[conn].fd, &id_message, sizeof(id_message), 0); + + Client* client = getClientByID(&clientsArena, id_message.id); + if (!client) { + local_persist HeaderMessage header = HEADER_INIT(HEADER_TYPE_ERROR); + local_persist ErrorMessage error_message = ERROR_INIT(ERROR_TYPE_NOTFOUND); + sendAnyMessage(fds[conn].fd, &header, &error_message); + loggingf("Could not find %lu\n", id_message.id); + break; + } + HeaderMessage header = HEADER_INIT(HEADER_TYPE_INTRODUCTION); + IntroductionMessage introduction_message; + memcpy(introduction_message.author, client->author, AUTHOR_LEN); + + sendAnyMessage(fds[conn].fd, &header, &introduction_message); + } break; default: - fprintf(stdout, " Got unhandled message type '%s' from client %d", headerTypeString(header.type), fds[i].fd); + loggingf("Unhandled '%s' from client(%d)\n", headerTypeString(header.type), fds[conn].fd); + disconnectAndNotify(client, fds, FDS_SIZE, conn); continue; } } } - ArenaRelease(clientsArena); - ArenaRelease(fdsArena); - ArenaRelease(msgsArena); +#ifdef IMPORT_ID + close(clients_file); +#endif return 0; } |