#include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define CHARACTER_HEADER_SIZE 48 struct character{ char type; char name[32]; unsigned unused : 3; unsigned ready : 1; unsigned started : 1; unsigned monster : 1; unsigned join_battle : 1; unsigned alive : 1; uint16_t attack; uint16_t defense; uint16_t regen; int16_t health; uint16_t gold; uint16_t room; uint16_t description_length; char* description; } __attribute__((packed)); int skt; // Global. This is the socket that the server will listen on struct character* read_character(int); void free_character(struct character*); vector phished_characters; mutex phished_characters_lock; void free_all_characters(){ for(auto c : phished_characters) free_character(c); } void close_server(int signal_number){ printf("Closing down the server\n"); for(auto c : phished_characters){ printf("%s: (%d, %d, %d) %s ", c->name, c->attack, c->defense, c->regen, c->description); printf("(alive: %d, join_battle: %d, monster: %d, started: %d, ready: %d)\n", c->alive, c->join_battle, c->monster, c->started, c->ready); } close(skt); } struct message_header { uint8_t type = 1; uint16_t length; char sender[32]; char receiver[32]; } __attribute__((packed)); bool send_message(int fd, const char* sender, const char* receiver, const char* message){ struct message_header mh; mh.length = strlen(message); strcpy(mh.sender, sender); strcpy(mh.receiver, receiver); if(sizeof(mh) != write(fd, &mh, sizeof(mh))) return 0; if(mh.length != write(fd, message, mh.length)) return 0; return 1; } char buffer[1024]; /* recv(fd, buffer, sizeof(piece_one) + sizeof(piece_two), MSG_WAITALL); memcpy(&piece_one, buffer, sizeof(piece_one)); memcpy(&piece_two, buffer + sizeof(piece_two), sizeof(piece_two)); */ struct character* read_character(int fd){ uint8_t type; if(1 != read(fd, &type, 1)) return 0; if(type != 10){ printf("Type = %d\n", type); return 0; } // type must be 10 struct character *c = (struct character*)malloc(sizeof(struct character)); c->type = 10; size_t readlen = recv(fd, &c->name, CHARACTER_HEADER_SIZE - 1, MSG_WAITALL); // -1 for type c->description = (char*)malloc(c->description_length); recv(fd, c->description, c->description_length, MSG_WAITALL); return c; // Can't be a local variable. Must use malloc or new } // Frees heap-allocated characters // Don't try it on a stack-allocated character void free_character(struct character* c){ free(c->description); free(c); } struct version { uint8_t type = 14; uint8_t major, minor; uint16_t extensions = 0; } __attribute__((packed)); bool send_version(int fd, unsigned char major, unsigned char minor){ struct version v; v.major = major; v.minor = minor; return 5 == write(fd, &v, 5); } struct game { uint8_t type = 11; uint16_t initial_points, stat_limit, description_length; char description[1024]; } __attribute__((packed)); bool send_game(int fd){ struct game g; g.initial_points = 800; g.stat_limit = 1200; strcpy(g.description, "This is a best lurk game ever. You'll really enjoy it. So you should set up your favorite character ever"); g.description_length = strlen(g.description); size_t send_size = 7 + g.description_length; return send_size == write(fd, &g, send_size); } void handle_client(int client_fd){ send_version(client_fd, 2, 3); send_game(client_fd); struct character *sent_character; while(!(sent_character = read_character(client_fd))); phished_characters_lock.lock(); phished_characters.push_back(sent_character); phished_characters_lock.unlock(); send_message(client_fd, "Us", "You", "j00 b33n h4xor0d"); close(client_fd); struct character *c = sent_character; // optimizer can take care of it printf("%s: (%d, %d, %d) %s\n", c->name, c->attack, c->defense, c->regen, c->description); /* for(;;){ read type from network socket if type is a change room { lock the player's mutex read the room to change to from the player's socket change the room the player is in unlock the player's mutex for each player in that room EXCEPT THE ONE THAT JUST ENTERED { lock that player's mutex send the player a message saying that the new player has entered the room if sending failed: break out of this loop (Don't do this! Don't exit without unlocking unlock that player's mutex } unlock the player's mutex } if type is fight { lock the fight mutex for each player in the room lock the player's mutex assemble a list of parties that are involved in the fight (monsters, players with join battle) figure out how much damage each one took figure out if anybody died send out results to each player that was involved in the fight And others? Maybe send a celebratory message if a boss was defeated? for each player in the room unlock the player's mutex unlock the fight mutex } } */ } int main(int argc, char ** argv){ struct sockaddr_in sad; if(argc < 2) sad.sin_port = htons(5141); else sad.sin_port = htons(atoi(argv[1])); sad.sin_addr.s_addr = INADDR_ANY; sad.sin_family = AF_INET; skt = socket(AF_INET, SOCK_STREAM, 0); if(skt == -1){ perror("socket"); return 1; } struct sigaction close_action; close_action.sa_handler = close_server; if(sigaction(SIGINT, &close_action, 0)){ perror("sigaction"); return 1; } if( bind(skt, (struct sockaddr *)(&sad), sizeof(struct sockaddr_in)) ){ perror("bind"); return 1; } if( listen(skt, 5) ){ perror("listen"); return 1; } int client_fd; struct sockaddr_in client_address; socklen_t address_size = sizeof(struct sockaddr_in); vector threads; for(;;){ client_fd = accept(skt, (struct sockaddr *)(&client_address), &address_size); if(client_fd == -1){ perror("accept"); break; } printf("Connection made from address %s\n", inet_ntoa(client_address.sin_addr)); threads.push_back(thread(handle_client, client_fd)); } free_all_characters(); return 0; }