#include #include #include #include #include #include #include #include #include #include #include char debug_mode = 0; struct client_args { int fd; struct in_addr ip; char ip_string[16]; }; #define WORDCOUNT 104334 char words[WORDCOUNT][32]; // Not very efficient; some words are shorter than this void *client_function(void* arg){ struct client_args *ca = arg; size_t lb_len = 128000; uint8_t long_buffer[lb_len]; dprintf(1, "Connection made from address %s\n", ca->ip_string); // Write a lurk type 14 and an 11 uint8_t type[6] = {14, 2, 3, 0, 0, 11}; write(ca->fd, type, 6); usleep(10000); uint16_t next_number; // Initial Points next_number = random() % 1000; write(ca->fd, &next_number, 2); usleep(1000); // Stat limit next_number = random() % 1000; write(ca->fd, &next_number, 2); usleep(1000); char description[1024]; sprintf(description, "%s %s %s %s %s", words[random() % WORDCOUNT], words[random() % WORDCOUNT], words[random() % WORDCOUNT], words[random() % WORDCOUNT], words[random() % WORDCOUNT]); next_number = strlen(description); write(ca->fd, &next_number, 2); usleep(1000); write(ca->fd, description, 10); usleep(10000); write(ca->fd, description + 10, next_number - 10); usleep(1000); // We expect a character, and that's all we expect! uint8_t cbuffer[65535 + 48]; uint16_t *short_cbuffer = (uint16_t*)cbuffer; ssize_t readlen = recv(ca->fd, cbuffer, 48, MSG_WAITALL); if(readlen != 48) goto done; readlen = recv(ca->fd, cbuffer + 48, *((uint16_t*)(cbuffer + 46)), MSG_WAITALL); dprintf(1, "Got character %s\n", cbuffer + 1); // Assuming there'll be a null at some point uint8_t accept[] = {8, 10}; short_cbuffer[20] = 30000; short_cbuffer[21] = 40000; short_cbuffer[22] = 0; cbuffer[33] = 0xc8; write(ca->fd, accept, 2); write(ca->fd, cbuffer, 10); usleep(10000); write(ca->fd, cbuffer + 10, short_cbuffer[23] + 48 - 10); char start; readlen = read(ca->fd, &start, 1); if(readlen != 1) goto done; /* * A room * The client's own character message * A connection * Some monsters * Maybe other clients */ size_t lb_place = 0; void buffer_append_8(uint8_t new_thing){ long_buffer[lb_place] = new_thing; lb_place++; } void buffer_append_16(uint16_t new_thing){ memcpy(long_buffer + lb_place, &new_thing, 2); lb_place += 2; } void buffer_append(void* data, size_t dlen){ if(lb_place + dlen > lb_len){ dprintf(1, "Warning: Buffer overfill requested\n"); return; } memcpy(long_buffer + lb_place, data, dlen); lb_place += dlen; } int buffer_append_size_and_file(char *name){ int file_fd = open(name, O_RDONLY); ssize_t readlen = read(file_fd, long_buffer + lb_place + 2, lb_len - lb_place - 2); int retval = 0; if(readlen < 1){ dprintf(1, "Warning: File %s failed to read\n", name); retval = 1; } else if(readlen > 65535){ dprintf(1, "Warning: File %s was more than 65535 bytes\n", name); retval = 2; } else { *((uint16_t*)(long_buffer + lb_place)) = readlen; lb_place += 2; lb_place += readlen; } close(file_fd); return retval; } void buffer_send(){ write(ca->fd, long_buffer, lb_place); lb_place = 0; } buffer_append_8(9); buffer_append_16(50000); buffer_append("The room we are sending now", 32); buffer_append_16(5); buffer_append("Large", 5); short_cbuffer[22] = 50000; buffer_append(cbuffer, 48 + short_cbuffer[23]); buffer_append_8(13); buffer_append_16(65000); buffer_append("Australia", 32); buffer_append_size_and_file("/tmp/poem"); buffer_send(); done: dprintf(1, "Done with client on fd %d\n", ca->fd); close(ca->fd); free(ca); return 0; } int child(int skt){ while(1){ /* Accept a network connection */ 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); /* Start a thread to handle the new network connection */ pthread_t thread_reference; struct client_args *ca = malloc(sizeof(struct client_args)); ca->fd = client_fd; ca->ip = client_address.sin_addr; strcpy(ca->ip_string, inet_ntoa(ca->ip)); pthread_create(&thread_reference, 0, client_function, ca); } return 0; } int main(int argc, char ** argv){ /* Argument Processing */ if(argc > 1 && !strcmp(argv[1], "--debug")) debug_mode = 1; if(argc > 2 && !strcmp(argv[2], "--debug")) debug_mode = 1; struct sockaddr_in sad; if(argc > 1 && strcmp(argv[1], "--debug")) sad.sin_port = htons(atoi(argv[1])); else sad.sin_port = htons(5143); sad.sin_addr.s_addr = INADDR_ANY; sad.sin_family = AF_INET; /* Set up words array so we can pick random words */ srandom(time(0)); FILE *wordfile = fopen("/usr/share/dict/american-english", "r"); char *current_word = malloc(32); for(int i = 0; i < WORDCOUNT; i++){ size_t wordlen = 32; getline(¤t_word, &wordlen, wordfile); current_word[strlen(current_word) - 1] = 0; strcpy(words[i], current_word); } free(current_word); fclose(wordfile); /* Network server setup */ int skt = socket(AF_INET, SOCK_STREAM, 0); // Step 1 if(skt == -1){ perror("socket"); return 1; } 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; } /* Network server setup succeeded, time to daemonize if debug wasn't set */ int logfile_fd; if(!debug_mode){ close(0); close(1); close(2); logfile_fd = open("random_lurk_server_log", O_WRONLY | O_CREAT | O_TRUNC, 0644); dup2(logfile_fd, 1); dup2(logfile_fd, 2); } chdir("/"); // Wikipedia points out a lot of daemons do this if(debug_mode) child(skt); else { pid_t pid = fork(); if(pid) { // parent process return 0; } else { // child process child(skt); } } return 0; }