#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; void handle_client(int client_fd, struct sockaddr_in client_address); struct client_info { thread client_thread; int client_fd; struct sockaddr_in client_address; bool active = true; client_info(int cfd, struct sockaddr_in ca) : client_fd(cfd), client_address(ca), client_thread(handle_client, cfd, ca) {} }; vector client_list; mutex client_list_mutex; mutex add_mutex; map animal_counts; uint64_t main_count = 0; struct version { uint8_t type, major, minor; uint16_t extlen; } __attribute__((packed)); version our_version = {14, 4, 1, 0}; struct game { uint8_t type; uint16_t initial, limit, desclen; char description[50]; } __attribute__((packed)); game our_game = {11, 30, 90, 8, "Chat Server. Send a character with your name, then message (type 1) to chat."}; struct character { uint8_t type; char name[32]; uint8_t flags; uint16_t attack, defense, regen; int16_t health; uint16_t gold, roomnumber, desclen; /* We'll put the description somewhere else */ }__attribute__((packed)); void handle_client(int client_fd, struct sockaddr_in client_address){ /* Handle client behavior here */ character us; char *our_description; ssize_t readlen; /* TODO: Check to see if write returned the number of bytes we expected to write */ write(client_fd, &our_version, sizeof(version)); write(client_fd, &our_game, 15); printf("Waiting for character description with %d bytes\n", sizeof(character)); recv(client_fd, &us, sizeof(character), MSG_WAITALL); our_description = (char*)malloc(us.desclen + 1); our_description[us.desclen] = 0; printf("Client description length %d, waiting for description\n", us.desclen); recv(client_fd, our_description, us.desclen, MSG_WAITALL); printf("Got client %s with description %s\n", us.name, our_description); /* This part is related to disconnection. Applies broadly. */ client_list_mutex.lock(); for(int i = 0; i < client_list.size(); i++) if(client_list[i].client_fd == client_fd){ client_list[i].active = false; break; } client_list_mutex.unlock(); close(client_fd); } /* We need a cleanup routine */ void cleanup(){ for(;;){ client_list_mutex.lock(); for(int i = 0; i < client_list.size(); i++) if(!client_list[i].active) { client_list[i].client_thread.join(); client_list.erase(client_list.begin() + i); } client_list_mutex.unlock(); sleep(1); } } int main(int argc, char ** argv){ uint16_t port = 5143; struct sockaddr_in sad; sad.sin_port = htons(port); sad.sin_addr.s_addr = INADDR_ANY; sad.sin_family = AF_INET; int skt = socket(AF_INET, SOCK_STREAM, 0); // Step 1 if(skt == -1){ perror("socket"); return 1; } while( bind(skt, (struct sockaddr*)(&sad), sizeof(struct sockaddr_in)) ){ // step 2 perror("bind"); port += 1; sad.sin_port = htons(port); if(port > 5150) return 1; printf("Trying port %d\n", port); } if( listen(skt, 5) ){ // step 3 perror("listen"); return 1; } thread cleanup_thread(cleanup); /* This loop will accept clients onto the server. Each client will have a file descriptor */ 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)); /* Start a thread to handle this client */ client_list_mutex.lock(); client_list.push_back(client_info(client_fd, client_address)); client_list_mutex.unlock(); } return 0; }