/*************************************************************************** ** Eradicated Worlds Mud Polling program ** Author: Peter Eussen 1997 ** Polls muds, writes an mudlist for inside the mud and ** a homepage. **************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/time.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <signal.h> #include <fcntl.h> #include <netdb.h> #include <errno.h> /************************************************************************** ** File name and locations ** MUDLIST : mudlist inside the mud ** CONFIG_FILE: List with all muds that need to be checked. ** WWWMUDLIST : HTML Page *******************************************************/ #define MUDLIST ROOTDIR"/data/INFO/mudlist.i" #define CONFIG_FILE ROOTDIR"/data/mudlist" #define DUMPFILE ROOTDIR"/data/CONFIG/mudlist.stat" #define WWWMUDLIST "/home/www/htdocs/sites.html" #define HTML_HEADER \ "<HTML>\n<BODY bgcolor=\"#BBBBBB\" text=\"#000000\" link=\"#0000ff\" vlink=\"#ff0000\" alink=\"#00a000\"><CENTER><H1>Eradicated Worlds Mudlist</H1></CENTER>\n<HR>\n" #define HTML_FOOTER "</BODY>\n</HTML>\n" #define MAX_MUDNAME 80 /* Size reserved for mud names */ #define MAX_HOSTLEN 125 /* Size reserved for hostname */ #define MAX_IPLEN 15 /* Size reserved for ip number */ #define MAX_URLLEN 255 /* Size reserved for URL */ #define POLL_INTERVAL 4*60*60 /* Time between checks in secs */ #define HOSTLOOKUPFAILURE 4 #define NEWIP 3 /* Internal Usage */ #define UNREACHABLE 2 /* Internal Usage */ #define REACHABLE 1 /* Internal Usage */ #define DOWN 0 /* Internal Usage */ #define MUD_SEND "\n" /* What to send to leave the mud */ #define MUD_OPEN "Opened" /* For HTML */ #define HOST_DOWN "Host Down or non-exsistant" typedef struct _MudStat { char mudname[MAX_MUDNAME+1]; char hostname[MAX_HOSTLEN+1]; char ipnumber[MAX_IPLEN+1]; char homepage[MAX_URLLEN]; int port; time_t last_succes; /* Time of last connect */ time_t last_checked; /* Time of last Poll */ char *status; /* Error message pointer */ int short_stat; /* Up or Down? */ struct _MudStat *next; } MudStat; MudStat *MudList = NULL; extern char *sys_errlist[]; void addto(MudStat *p, MudStat *list); void do_poll(void); void write_stats(void); void write_info(); void write_html(); void try_connect(MudStat *l); void read_file(void); void update_mudlist(int sig); int read_dumpfile(void); void dump_mudlist(int sig); int main(void) { int pid; if (!read_dumpfile()) read_file(); /* Go Background and forget */ switch ((pid = fork())) { case -1: printf("Fork Failed!\n"); return 2; case 0: break; default: printf("Mud Poller Started (pid %d)\n",pid); return 0; } fclose(stdin); fclose(stdout); fclose(stderr); signal(SIGUSR1,update_mudlist); signal(SIGTERM,dump_mudlist); while (1) { do_poll(); /* Do your job */ sleep(POLL_INTERVAL); /* And sleep till next job */ } return 0; } void addMudList(MudStat *p) { MudStat *l = MudList; if (MudList == NULL) { p->next = MudList; MudList = p; return; } while (l->next != NULL) l = l->next; p->next = l->next; l->next = p; } void addto(MudStat *p, MudStat *list) { MudStat *l = list; if (list == NULL) { p->next = list; list = p; return; } while (l->next != NULL) l = l->next; p->next = l->next; l->next = p; } void do_poll(void) { MudStat *l = MudList; while (l != NULL) { try_connect(l); /* Try to connect to this mud */ l = l->next; /* Untill all muds are checked */ } write_stats(); /* Then write new files */ } void try_connect(MudStat *l) { int s,ret; char buffer[100]; struct sockaddr_in client; struct hostent *host; host = gethostbyname(l->hostname); if (host == NULL) { l->last_checked = time(0); l->short_stat = HOSTLOOKUPFAILURE; l->status = HOST_DOWN; return; } bzero((char *)&client,sizeof(client)); client.sin_family = AF_INET; client.sin_port = htons(l->port); client.sin_addr = (*(struct in_addr*)host->h_addr_list[0]); s = socket(AF_INET,SOCK_STREAM,0); ret = connect(s,(struct sockaddr *)&client,sizeof(client)); l->last_checked = time(0); if (ret == -1) { l->status = sys_errlist[errno]; l->short_stat = DOWN; close(s); return; } fcntl(s,F_SETFL,O_NONBLOCK); while (read(s,buffer,100) >= 0); write(s,MUD_SEND,2); close(s); l->last_succes = l->last_checked; l->status = MUD_OPEN; l->short_stat = REACHABLE; /* if (strcmp(host->h_addr_list[0],l->ipnumber) != 0) { l->short_stat = NEWIP; strcpy(l->ipnumber,host->h_addr); } */ } void write_stats(void) { write_info(); /* Write intermal mudlist */ write_html(); /* Write HTML page */ } void write_html() { FILE *fp; MudStat *l = MudList; time_t t=time(NULL); int hadbad = 0,hadgood=0; fp = fopen(WWWMUDLIST,"w"); if (fp == NULL) return; fprintf(fp,HTML_HEADER); fprintf(fp,"<CENTER>Last update of this page was: %s</CENTER><BR>\n",ctime(&t)); while (l != NULL) { if (l->short_stat == REACHABLE) { if (!hadgood) { fprintf(fp,"<CENTER><H2>Reachable Muds</H2></CENTER><P>\n"); hadgood = 1; } fprintf(fp,"<TABLE Width=\"100%%\" Align=left Border=1>\n"); if (l->homepage[0] != '-') fprintf(fp,"<TR>\n" " <TD colspan=4 align=center width=\"100%%\">" "<A HREF=\"%s\">%s Homepage</A>\n</TR>\n", l->homepage,l->mudname); fprintf(fp,"<TR>\n" " <TD width=\"30%%\"><A HREF=\"telnet://%s:%d\">%s</A></TD>\n" " <TD width=\"20%%\">%s</TD>\n" " <TD width=\"40%%\">%s</TD>\n" " <TD width=\"10%%\">%d</TD>\n" "</TR>\n", l->ipnumber,l->port,l->mudname,l->ipnumber,l->hostname,l->port); fprintf(fp,"</TABLE><BR clear=left><BR>\n"); } l = l->next; } l = MudList; while (l != NULL) { if (l->short_stat == DOWN || l->short_stat == HOSTLOOKUPFAILURE) { if (!hadbad) { fprintf(fp,"<P><CENTER><H2>Unreachable Muds</H2></CENTER></P>\n"); hadbad = 1; } fprintf(fp,"<TABLE Width=\"100%%\" Align=left Border=1>\n"); if (l->homepage[0] != '-') fprintf(fp,"<TR>\n" " <TD colspan=4 align=center width=\"100%%\">" "<A HREF=\"%s\">%s Homepage</A>\n</TR>\n", l->homepage,l->mudname); fprintf(fp,"<TR>\n" " <TD width=\"30%%\"><A HREF=\"telnet://%s:%d\">%s</A></TD>\n" " <TD width=\"20%%\">%s</TD>\n" " <TD width=\"40%%\">%s</TD>\n" " <TD width=\"10%%\">%d</TD>\n" "</TR>\n", l->ipnumber,l->port,l->mudname,l->ipnumber,l->hostname,l->port); fprintf(fp,"<TR>\n" " <TD BGCOLOR=\"#FFFFAA\" colspan=2 width=\"50%%\"><B>Last Connect:</B> %s</TD>\n" " <TD BGCOLOR=\"#999999\" colspan=2 width=\"50%%\"><B>Reason:</B> %s</TD>\n" "</TR>\n", l->last_succes == 0 ? "Never" : ctime(&l->last_succes),l->status); fprintf(fp,"</TABLE><BR clear=left><BR>\n"); } l = l->next; } fprintf(fp,HTML_FOOTER); fclose(fp); } void write_info() { FILE *fp; MudStat *l = MudList; time_t t = time(NULL); char *stat = NULL; fp = fopen(MUDLIST,"w"); if (fp == NULL) return; fprintf(fp,"&+b=&+B[&+WMud Name&+B]&+b===========&+B[&+WIP&+B]&+b============&+B[&+WHostname&+B]&+b==================&+B[&+WPort&+B]&+b=&+B[&+WSt&+B]&+b=&*\n"); while (l != NULL) { fprintf(fp,"%-20.20s %-14.14s %-29.29s %.4d ", l->mudname,l->ipnumber,l->hostname,l->port); switch (l->short_stat) { case DOWN: stat = "Dn"; break; case REACHABLE: stat = "Up"; break; case UNREACHABLE: stat = "ND"; break; case NEWIP: stat = "IP"; break; case HOSTLOOKUPFAILURE: stat = "HF"; break; default: stat = "Dn"; } fprintf(fp,"%s\n",stat); l = l->next; } fprintf(fp,"&+b==============================================================================&*\n" " Dn = Down Up = Up ND = Network Down IP = New IP HF = Hostname failure\n"); fprintf(fp,"Last poll: %s\n",ctime(&t)); fclose(fp); } void read_file(void) { FILE *fp; MudStat *l; char line[255+1]; fp = fopen(CONFIG_FILE,"r"); if (fp == NULL) { printf("Can't find config file.\n"); exit(1); } fgets(line,255,fp); while (!feof(fp)) { l = (MudStat *)malloc(sizeof(MudStat)); line[strlen(line)-1] = '\0'; strcpy(l->mudname,line); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->hostname,line); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->ipnumber,line); fgets(line,255,fp); sscanf(line,"%d ",&l->port); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->homepage,line); l->next = NULL; l->last_succes = l->last_checked = 0; l->short_stat = DOWN; addMudList(l); fgets(line,255,fp); } fclose(fp); } void update_mudlist(int sig) { MudStat *l, *n; FILE *fp; int r; char line[255+1]; n = MudList; fp = fopen(CONFIG_FILE,"r"); if (fp == NULL) { printf("Can't find config file.\n"); exit(1); } fgets(line,255,fp); while (!feof(fp)) { line[strlen(line)-1] = '\0'; if ((r = strcasecmp(n->mudname,line)) == 0) { l = n; n = n->next; } else if (r < 0) { l = (MudStat *)malloc(sizeof(MudStat)); l->next = NULL; l->last_succes = l->last_checked = 0; l->short_stat = DOWN; } else { l = MudList; /* No longer in list so delete it */ if (l != n) { while (l->next != n) l = l->next; } l->next = n->next; free(n); n = l->next; l = (MudStat *)malloc(sizeof(MudStat)); l->next = NULL; l->last_succes = l->last_checked = 0; l->short_stat = DOWN; } strcpy(l->mudname,line); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->hostname,line); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->ipnumber,line); fgets(line,255,fp); sscanf(line,"%d ",&l->port); fgets(line,255,fp); line[strlen(line)-1] = '\0'; strcpy(l->homepage,line); addMudList(l); fgets(line,255,fp); } fclose(fp); signal(SIGUSR1,update_mudlist); } int read_dumpfile(void) { FILE *fp; MudStat l, *p; fp = fopen(DUMPFILE,"r"); if (fp == NULL) return 0; printf("Reading data from history logfile.\n"); while (!feof(fp) && fread(&l,sizeof(MudStat),1,fp) == 1) { p = (MudStat *)malloc(sizeof(MudStat)); bcopy((char *)p,(char *)&l,sizeof(MudStat)); p->next = NULL; p->status = NULL; addMudList(p); } fclose(fp); remove(DUMPFILE); return 1; } void dump_mudlist(int sig) { FILE *fp; MudStat *l = MudList; printf("Dump to: "DUMPFILE"\n"); fp = fopen(DUMPFILE,"w"); if (fp == NULL) return; printf("Dumping file.\n"); for (; l != NULL; l = l->next) { fwrite((char *)l,sizeof(MudStat), 1, fp); } fclose(fp); exit(0); }