#include "commands.h" #include "sys/ipc.h" #include #include #include #include #include #include #include #include #define send(queue_id, msgbuf_ptr) \ msgsnd(queue_id, msgbuf_ptr, sizeof(*(msgbuf_ptr)) - sizeof(long), 0) typedef struct { char *id; bool logged_in; char *muted_clients; char nickname[16]; int queue_id; } Client; typedef struct { Client **clients; char name[16]; int client_count; } Group; int main(int argc, char **argv) { // TODO: Load config file with clients and groups int client_count = 1; int group_count = 3; Client *clients = malloc(sizeof(Client) * 9); Group *groups = malloc(sizeof(Group) * 3); clients[0] = (Client){ .id = "the_only_one", .logged_in = false, .muted_clients = NULL, .nickname = "Kregielnia", }; // key_t key = ftok(argv[0], 555); int server_queue_id = msgget(IPC_PRIVATE, 0666 | IPC_CREAT); if (server_queue_id == -1) { perror("msgget failed"); return 1; } int id_file_handle = open("/home/piotr/server_queue_id", O_WRONLY | O_CREAT | O_TRUNC, 0666); if (!id_file_handle) { perror("Failed to open file"); return 1; } if (write(id_file_handle, &server_queue_id, sizeof(int)) == -1) { perror("Failed to write server queue id to file"); return 1; } close(id_file_handle); // TODO: Fork here, for the heartbeat process than can sleep msgbuf_t msgbuf; while (1) { // Read from the ipc, then handle the command int read_status = msgrcv(server_queue_id, &msgbuf, sizeof(msgbuf) - sizeof(long), 0, 0); switch (msgbuf.mtype) { case Login: printf("Received login request for id: %s\n", msgbuf.command); Client *client = NULL; for (int i = 0; i < 1; i++) { if (strncmp(clients[i].id, msgbuf.command, COMMAND_LENGTH) == 0) { client = &clients[i]; break; } } // Reuse the buffer to get the client's message queue id int msg_queue_id = atoi(msgbuf.message); if (client == NULL) { printf("User not found: %s\n", msgbuf.command); msgbuf_t response = { .mtype = Login, .stype = ERR_USER_NOT_FOUND, }; send(msg_queue_id, &response); continue; } if (client->logged_in) { printf("User already logged in: %s\n", msgbuf.command); msgbuf_t response = { .mtype = Login, .stype = ERR_ALREADY_LOGGED_IN, }; send(msg_queue_id, &response); continue; } client->logged_in = true; client->queue_id = msg_queue_id; msgbuf_t response = { .mtype = Login, .stype = ACK_ACCEPTED, }; printf("User accepted: %s\n", msgbuf.command); send(msg_queue_id, &response); break; case Message: printf("Recieved message, checking which client\n"); // Find the client that sent the message then forward it to all the // specified recipients client = NULL; for (int i = 0; i < client_count; i++) { if (strncmp(clients[i].id, msgbuf.sender, COMMAND_LENGTH) == 0) { client = &clients[i]; break; } } printf("Received message from client id %s: %s\n", msgbuf.sender, msgbuf.message); if (client == NULL || !client->logged_in) { // Client not found or not logged in printf("Client not found or not logged in"); msgbuf_t response = { .mtype = Message, .stype = ERR_NOT_LOGGED_IN, }; send(read_status, &response); continue; } printf("Forwarding message: %s\n", msgbuf.message); // TODO: Find the actual recipients, for now broadcast msgbuf_t forward_msg = { .mtype = Message, }; strncpy(forward_msg.message, msgbuf.message, MESSAGE_LENGTH); // Yes, the client sending the message also receives it for (int i = 0; i < client_count; i++) { if (clients[i].logged_in) { send(clients[i].queue_id, &forward_msg); } } forward_msg.stype = ACK_ACCEPTED; forward_msg.mtype = Signal; send(client->queue_id, &forward_msg); // TODO: Accepted and Delivered ack break; case Logout: case Hearbeat: case List_clients: break; case Mute: case Unmute: break; case Signal: // Signals are sent from server to client, not the other way around // so we ignore them here lol break; } } return 0; }