#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "scolor.hpp" using namespace std; struct connected_client { int fd; string name = ""; mutex send_mutex; }; mutex clients_mutex; // Mutex for clients vector clients; struct lurk_connection_message { uint8_t type = 13; uint16_t roomnumber; char name[32]; uint16_t description_length; char *description = 0; ~lurk_connection_message(){ if(description){ free(description); description = 0; } } bool read(int skt){ ssize_t readlen; readlen = recv(skt, &type, 1, MSG_PEEK); if(readlen < 1 || type != 13){ printf("Failed to read connection\n"); return false; } ssize_t header_size = sizeof(struct lurk_connection_message) - sizeof(char*); if(recv(skt, this, header_size, MSG_WAITALL) != header_size) return false; if(description) free(description); description = (char*)malloc(description_length); if(recv(skt, description, description_length, MSG_WAITALL) != description_length) return false; return true; } } __attribute__((packed)); struct lurk_message_message { uint8_t type = 1; uint16_t length; char recipient_name[32]; char sender_name[32]; char *message; ~lurk_message_message(){ if(message){ free(message); message = 0; } } bool write(int skt){ ssize_t expected_size = sizeof(struct lurk_message_message) - sizeof(char*); if(send(skt, this, expected_size, 0) != expected_size) return false; sleep(10); return send(skt, message, length, 0) == length; } bool read(int skt){ ssize_t readlen; readlen = recv(skt, &type, 1, MSG_PEEK); if(readlen < 1 || type != 1){ printf("Failed to read message\n"); return false; } ssize_t header_size = sizeof(struct lurk_message_message) - sizeof(char*); if(recv(skt, this, header_size, MSG_WAITALL) != header_size) return false; if(message) free(message); message = (char*)malloc(length); if(recv(skt, message, length, MSG_WAITALL) != length) return false; return true; } } __attribute__((packed)); struct lurk_character_message { uint8_t type = 10; char name[32]; uint8_t flags = 0xf8; uint16_t attack, defense, regen; int16_t health; uint16_t gold, roomnumber, description_length; char *description = 0; void set_description(const char* d){ description_length = strlen(d); description = (char*)malloc(description_length + 1); strncpy(description, d, description_length); } ~lurk_character_message(){ if(description){ free(description); description = 0; } } bool write(int skt){ ssize_t expected_size = sizeof(struct lurk_character_message) - sizeof(char*); if(send(skt, this, expected_size, 0) != expected_size) return false; return send(skt, description, description_length, 0) == description_length; } bool read(int skt){ ssize_t readlen; readlen = recv(skt, &type, 1, MSG_PEEK); if(readlen < 1 || type != 10){ printf("Failed to read character\n"); return false; } ssize_t header_size = sizeof(struct lurk_character_message) - sizeof(char*); if(recv(skt, this, header_size, MSG_WAITALL) != header_size) return false; description = (char*)malloc(description_length); if(recv(skt, description, description_length, MSG_WAITALL) != description_length) return false; return true; } } __attribute__((packed)); struct lurk_version_message { uint8_t type, major, minor; uint16_t extension_length; bool read(int skt){ ssize_t readlen; readlen = recv(skt, &type, 1, MSG_PEEK); if(readlen < 1 || type != 14){ printf("Failed to read version\n"); return false; } readlen = recv(skt, &type, 5, MSG_WAITALL); return readlen == 5; } } __attribute__((packed)); ostream& operator<<(ostream& out, const lurk_version_message &lvm){ out << "Type: " << (int)lvm.type << endl; out << "Version: " << (int)lvm.major << "." << (int)lvm.minor << endl; out << "Extension Length: " << lvm.extension_length << endl; return out; } struct lurk_game_message { uint8_t type; uint16_t initial_points, stat_limit, description_length; char *description = 0; bool read(int skt) { ssize_t readlen = recv(skt, this, 7, MSG_WAITALL); if(readlen < 7){ printf("Failed to read first 7 bytes, giving up!\n"); return false; } description = (char*)malloc(description_length + 1); description[description_length] = 0; readlen = recv(skt, description, description_length, MSG_WAITALL); if(readlen != description_length){ printf("Failed to read description, giving up\n"); free(description); description = 0; return false; } return true; } ~lurk_game_message(){ if(description) free(description); } } __attribute__((packed)); // Otherwise the compiler will leave padding ostream& operator<<(ostream& out, const lurk_game_message &lgm){ out << "Type: " << (int)lgm.type << endl; out << "Initial Points: " << lgm.initial_points << endl; out << "Stat Limit: " << lgm.stat_limit << endl; out << "Description Length: " << lgm.description_length << endl; out << "Description: " << lgm.description << endl; return out; } char general_buffer[65535]; bool lurk_ignorer(int skt){ // Ignore list char next; recv(skt, &next, 1, MSG_PEEK); if(next == 1) { // Ignore a message recv(skt, general_buffer, 67, MSG_WAITALL); uint16_t description_length = *((uint16_t*)(general_buffer + 1)); recv(skt, general_buffer, description_length, MSG_WAITALL); } else if (next == 7) { // Ignore an error recv(skt, general_buffer, 4, MSG_WAITALL); uint16_t description_length = *((uint16_t*)(general_buffer + 2)); recv(skt, general_buffer, description_length, MSG_WAITALL); } else if (next == 8) { // Ignore an accept recv(skt, general_buffer, 2, MSG_WAITALL); } else if (next == 9) { // Ignore a room recv(skt, general_buffer, 37, MSG_WAITALL); uint16_t description_length = *((uint16_t*)(general_buffer + 35)); recv(skt, general_buffer, description_length, MSG_WAITALL); } return false; } void client_function(int skt){ lurk_character_message lcm; connected_client *our_client = new connected_client(); our_client->fd = skt; clients_mutex.lock(); clients.push_back(our_client); clients_mutex.unlock(); lurk_message_message lmm; while(true){ uint8_t next_type; /* * poll * * for each client with data: * read into a buffer * check to see if the buffer has a complete lurk message * while it does: * process the message * go on to the next client */ if(1 != recv(skt, &next_type, 1, MSG_PEEK)){ printf("Connection seems broken\n"); break; } switch(next_type){ case 1: // We have a message to deliver if(!lmm.read(skt)){ printf("Failed to read message from client %s, fd %d\n", our_client->name, skt); goto close_connection; } if(our_client->name == ""){ printf("Nameless client with fd %d tried to send a message\n", skt); // Send back an error break; } { bool done = false; for(auto &c : clients){ if(!strcmp(lmm.recipient_name, "ALL")){ c->send_mutex.lock(); lmm.write(c->fd); c->send_mutex.unlock(); continue; } // It's not going to all if(lmm.recipient_name == c->name) { c->send_mutex.lock(); lmm.write(c->fd); c->send_mutex.unlock(); done = true; break; } } if(!done && strcmp(lmm.recipient_name, "ALL")){ // Send back an error } } /* If the receipient is all, deliever to everybody on the server * If the receipient is a client on the server, send to that client * If the recipient is not a client on the server, send back an error * * for each client in the server: * If this is the client we're sending to, or we're sending to all * Send the message to that client * If we go through all the clients without finding the one we're sending to and aren't sending to all * Send an error back to our client * */ break; case 10: if(lcm.read(skt)) printf("Just read character %s with description %s\n", lcm.name, lcm.description); our_client->name = lcm.name; break; default: printf("Received unexpected type %d\n", next_type); goto close_connection; break; } } close_connection: // Do whatever we have to in order to remove this client from the server // Remove from the vector of clients clients_mutex.lock(); for(ssize_t i = 0; i < clients.size(); i++){ if(clients[i]->fd == skt){ clients.erase(clients.begin() + i); } } clients_mutex.unlock(); close(skt); } int main(int argc, char ** argv){ struct sockaddr_in sad; sad.sin_port = htons(atoi(argv[1])); sad.sin_family = AF_INET; sad.sin_addr.s_addr = INADDR_ANY; int skt = socket(AF_INET, SOCK_STREAM, 0); if( bind(skt, (struct sockaddr*)(&sad), sizeof(struct sockaddr_in)) ){ // step 2 perror("bind"); return 1; } if( listen(skt, 5) ){ // step 3 perror("listen"); return 1; } while(1){ int client_fd; struct sockaddr_in client_address; socklen_t address_size = sizeof(struct sockaddr_in); client_fd = accept(skt, (struct sockaddr *)(&client_address), &address_size); // step 4 printf("Connection made from address %s\n", inet_ntoa(client_address.sin_addr)); /* Handle the connection here */ thread new_client_thread(client_function, client_fd); new_client_thread.detach(); } close(skt); return 0; }