#include <stdio.h> #include <malloc.h> #include <unistd.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/time.h> #include <string.h> #include <stdarg.h> #include <stdlib.h> #include <arpa/inet.h> #include <netdb.h> #include <crypt.h> #define MAX_CONNECT 256 #define AUTH '0' #define MUDLIST '1' #define TELL '3' #define CHAT '4' #define WHO '5' #define RWHO '6' #define INFOMSG '7' #define MSG '8' #define KICK '9' #define AVERSION ':' #define FILEPAGE ';' #define TO_MUD '0' #define TO_ALL '1' #define SEP '\007' #define D "\007" #define WRITELEN 4096 #define SERVER_VERSION "AberChat Server 5.1" #define SERVER_NAME "BetaServer" int listener_fd = -1; class conn { public: struct sockaddr_in addr; int fd; FILE *f; const char *get_name() { return name; }; const char *get_lib() { return lib; }; const char *get_host() { return host; }; const char *get_ip() { return ip; }; const char *get_port() { return port; }; void set_name(const char *n) { name = strdup(n); }; void set_port(const char *n) { port = strdup(n); }; void set_host(const char *n) { host = strdup(n); }; void set_lib(const char *n) { lib = strdup(n); }; void set_ip(const char *n) { ip = strdup(n); }; conn() { name = 0; lib = 0; host = 0; port = 0; ip = 0; buffer = 0; buflen = 0; bufsize = 0; auth = 0; f = 0; fd = -1; } void assocfd() { f = fdopen(fd, "r"); } ~conn() { if (name) free(name); if (lib) free(lib); if (host) free(host); if (port) free(port); if (ip) free(ip); if (buffer) free(buffer); if (f) fclose(f); if (fd != -1) close(fd); } void queue(char *what, int len) { if ((len+buflen)>bufsize) { bufsize = (len+buflen)*2; if (buffer) buffer = (char *)realloc(buffer, bufsize); else buffer = (char *)malloc(bufsize); } memcpy(buffer+buflen, what, len); buflen+=len; } void finished() { char thing[] = {0}; queue(thing, 1); } void dequeue(int fd) { write(fd, buffer, buflen); buflen = 0; } bool auth; private: char *name, *lib, *host, *port, *ip, *buffer; int buflen, bufsize; }; conn *conns[MAX_CONNECT] = {0}; conn *alloc_conn() { int i; for (i=0;i<MAX_CONNECT;i++) { if (!conns[i]) { conns[i] = new conn(); return conns[i]; } } return 0; } void get_connection() { struct sockaddr_in addr; socklen_t what = sizeof addr; int fd = accept(listener_fd, (struct sockaddr*)&addr, &what); if (fd!=-1) { conn *c = alloc_conn(); c->addr = addr; c->fd = fd; c->set_ip(inet_ntoa(c->addr.sin_addr)); c->set_host(inet_ntoa(c->addr.sin_addr)); } } char *get_arg(char *txt) { static char c = '0'; char *ptr; if ((ptr = strchr(txt, SEP))) { *ptr = '\0'; return(++ptr); } else return(&c); } void cprintf(conn *what, const char *format, ...) __attribute__ ((format(printf, 2, 3))); void cprintf(conn *what, const char *format, ...) { va_list pvar; static char buffer[WRITELEN]; va_start(pvar, format); vsprintf(buffer, format, pvar); va_end(pvar); what->queue(buffer, strlen(buffer)); } void authenticate(char *packet, conn **what) { char *name = packet, *lib, *port, *pass; lib = get_arg(name); port = get_arg(lib); pass = get_arg(port); bool found = false; FILE * f = fopen("muds", "r"); if (!f) { fprintf(stderr, "cant open mudsfile.\n"); exit(1); } do { char mudline[1024]; char a_port[128], a_ip[128], a_pass[128], c_pass[128]; fgets(mudline, 1024, f); if (feof(f)) break; sscanf(mudline, "%s %s %s", a_ip, a_port, a_pass); strcpy(c_pass, crypt(a_pass, "Ac")); if (feof(f)) break; if (!strcmp(a_ip, (*what)->get_ip()) && !strcmp(a_port, port) && !strcmp(c_pass, pass)) { found = 1; break; } } while(1); if (found || 1) { // fprintf(stderr, "Yes.\n"); for (int i=0;i<MAX_CONNECT;i++) if (conns[i] && conns[i]->auth) { cprintf(conns[i], "%c" D "%s" D "%s", INFOMSG, name, "Connected!"); conns[i]->finished(); } (*what)->set_name(name); (*what)->set_lib(lib); (*what)->set_port(port); (*what)->auth = true; cprintf(*what, "%c" D "Y", AUTH); (*what)->finished(); } else { // fprintf(stderr, "No.\n"); cprintf(*what, "%c" D "N", AUTH); (*what)->finished(); delete *what; *what = 0; } } int cmp_conn(const void *a, const void *b) { if (a > b) return 1; if (b < a) return -1; return 0; } void mudlist(char *player, conn **what) { conn *muds[MAX_CONNECT]; int len, i; for (i = 0, len = 0 ; i < MAX_CONNECT ; i++) if (conns[i] && conns[i]->auth) muds[len++] = conns[i]; qsort(muds, len, sizeof(conn *), cmp_conn); cprintf(*what, "%c" D "%s", MUDLIST, player); for (i = 0; i<len; i++) { cprintf(*what, D "%s" D "%s" D "%s" D "%s" D "%s", muds[i]->get_name(), muds[i]->get_host(), muds[i]->get_ip(), muds[i]->get_port(), muds[i]->get_lib()); } (*what)->finished(); } inline int min(int a, int b) { if (a < b) return a; return b; } bool eqmud(const char *mudindex, const char *mudname) { if (!strncasecmp(mudindex, "The ", 4)) mudindex+=4; if (!strncasecmp(mudname, "The ", 4)) mudname+=4; if (!strncasecmp(mudindex, mudname, min(strlen(mudindex), strlen(mudname)))) return true; return false; } struct conn *find_mud(const char *text) { for (int i=0;i<MAX_CONNECT;i++) if (conns[i] && conns[i]->auth && eqmud(conns[i]->get_name(), text)) return conns[i]; return NULL; } void version(char *buff, conn **what) { char *player, *cli_ver; player = buff; cli_ver = get_arg(player); cprintf(*what, "%c" D "%s" D "%s" D "%s", AVERSION, player, cli_ver, SERVER_VERSION); (*what)->finished(); } bool has_line(const char *ln) { FILE *f = fopen("pager-files", "r"); if (!f) return false; char buffer[4096]; while (!feof(f)) { fgets(buffer, 4095, f); if (char *p=strchr(buffer, '\n')) *p=0; if (!strcmp(buffer, ln)) { fclose(f); return true; } } fclose(f); return false; } void filepage(char *to_plr, conn **what) { // I despair. Whoever designed this should be shot. char *filename = get_arg(to_plr); char *lt = get_arg(filename); if (!lt) return; if (!has_line(filename)) { cprintf(*what, "%c" D "%s" D "Learn to type, muppet.\n" D "%c", FILEPAGE, to_plr, 0); (*what)->finished(); return; } FILE *f = fopen(filename, "r"); if (!f) { cprintf(*what, "%c" D "%s" D "No such file.\n" D "%c", FILEPAGE, to_plr, 0); (*what)->finished(); return; } int linenum = (atoi(lt)) * 22; char buffer[4096]; cprintf(*what, "%c" D "%s" D, FILEPAGE, to_plr); while (!feof(f) && linenum--) fgets(buffer, 4095, f); if (!feof(f)) for (linenum = 23; linenum > 0 ; linenum--) { if (linenum == 5) { linenum = 5; } fgets(buffer, 4095, f); if (feof(f)) break; cprintf(*what, "%s", buffer); } cprintf(*what, D "%c", feof(f) ? '0' : '1'); (*what)->finished(); fclose(f); } void tomud(char *packet, conn **what) { char *data = get_arg(packet), type, *args; args = data + 2; type = *data; char *mudname = packet; struct conn *c = mudname ? find_mud(mudname) : 0; // fprintf(stderr, "got tomud packet type %i\n", type); if (type != AUTH) { if (!c) { char *player = get_arg(data); if (type == WHO) { player = get_arg(player); } if (char *p=strchr(player, SEP)) *p=0; cprintf(*what, "%c" D "%s" D "%s" D "%s", MSG, player, SERVER_NAME, "No such mud connected."); (*what)->finished(); return; } } switch (type) { case AUTH: authenticate(args, what); break; case MUDLIST: mudlist(args, what); break; case AVERSION: version(args, what); break; case FILEPAGE: filepage(args, what); break; default: if (c) { cprintf(c, "%s", data); c->finished(); } } } void toall(char *data, conn **) { for (int i=0;i<MAX_CONNECT;i++) if (conns[i] && conns[i]->auth) { cprintf(conns[i], "%s", data); conns[i]->finished(); } } void printpacket(const char *a) { char f[4096]; strcpy(f, a); char *p = f; while (*p) { if (*p==SEP) *p = '|'; p++; } } void do_read(conn **what) { char buffer[4096]; int len; memset(buffer, 0, sizeof buffer); len = recv((*what)->fd, buffer, sizeof buffer, 0); if (len < 1) { for (int i=0;i<MAX_CONNECT;i++) if (conns[i] && conns[i]->auth && conns[i] != *what) { cprintf(conns[i], "%c" D "%s" D "%s", INFOMSG, (*what)->get_name(), "Disconnected!"); conns[i]->finished(); } delete *what; *what=0; } else { switch (buffer[0]) { case TO_MUD: tomud(buffer+2, what); break; case TO_ALL: toall(buffer+2, what); break; } } } int main() { struct sockaddr_in addr = { AF_INET, htons(6715), { 0, } }; int yes = 1; listener_fd = socket(AF_INET, SOCK_STREAM, 0); setsockopt(listener_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); bind(listener_fd, (struct sockaddr *)&addr, sizeof addr); listen(listener_fd, 2); while (1) { fd_set rd, ex; int maxfd = listener_fd, i; FD_ZERO(&rd); FD_ZERO(&ex); FD_SET(listener_fd, &rd); FD_SET(listener_fd, &ex); for (i=0;i<MAX_CONNECT;i++) if (conns[i]) { FD_SET(conns[i]->fd, &rd); FD_SET(conns[i]->fd, &ex); if (maxfd < conns[i]->fd) maxfd = conns[i]->fd; } for (i=0;i<MAX_CONNECT;i++) if (conns[i]) conns[i]->dequeue(conns[i]->fd); select(maxfd+1, &rd, 0, &ex, 0); if (FD_ISSET(listener_fd, &rd)) get_connection(); for (i=0;i<MAX_CONNECT;i++) { if (conns[i] && FD_ISSET(conns[i]->fd, &rd)) do_read(&conns[i]); } } }