home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / games / tinymud2.zip / CONC.C < prev    next >
C/C++ Source or Header  |  1990-09-02  |  12KB  |  511 lines

  1. /* tinyMUD port concentrator by Robert Hood */
  2. /* Revision 2.0 */
  3.  
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <sys/param.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h>
  10. #include <sys/time.h>
  11. #include <sys/errno.h>
  12. #include <fcntl.h>
  13. #include <netdb.h>
  14. #include "config.h"
  15.  
  16. void            queue_message(int port, char *data, int len);
  17. void            writelog(const char *fmt,...);
  18.  
  19. #define BUFLEN 65536
  20. #define CONC_MESSAGE "[ Connected to the TinyMUD port concentrator ]\n"
  21. #define PANIC_MESSAGE "\nGoing Down - Bye!\n"
  22.  
  23. struct message
  24. {
  25.   char           *data;
  26.   short           len;
  27.   struct message *next;
  28. };
  29.  
  30. struct conc_list
  31. {
  32.   char            status;
  33.  
  34.   /*
  35.    * Status: 0 = Not connected 1 = Connected 2 = Disconnecting (waiting till
  36.    * queue is empty) 
  37.    */
  38.   struct message *first, *last;
  39. }              *clist;
  40.  
  41. int             mud_sock;
  42. int             sock;
  43. int             pid;
  44.  
  45. int             port = TINYPORT;
  46. int             intport = INTERNAL_PORT;
  47. int             clvl = 1;
  48.  
  49. main(argc, argv)
  50.   int             argc;
  51.   char           *argv[];
  52. {
  53.   int             l;
  54.  
  55.   if (argc > 1)
  56.     port = atoi(argv[1]);
  57.   if (argc > 2)
  58.     intport = atoi(argv[2]);
  59.   if (argc > 3)
  60.     clvl = atoi(argv[3]);
  61.  
  62.   signal(SIGPIPE, SIG_IGN);           /* Ignore I/O signals */
  63.   for (l = 3; l < NOFILE; ++l)           /* Close all files from last process */
  64.     close(l);                   /* except stdin, stdout, stderr */
  65.   pid = 1;
  66.   connect_mud();               /* Connect to interface.c */
  67.   setup();                   /* Setup listen port */
  68.   mainloop();                   /* main loop */
  69. }
  70.  
  71. connect_mud()
  72. {
  73.   int             temp;
  74.   struct sockaddr_in sin;
  75.  
  76.   mud_sock = 0;
  77.   while (mud_sock == 0)
  78.   {
  79.     mud_sock = socket(AF_INET, SOCK_STREAM, 0);
  80.     if (mud_sock < 0)
  81.     {
  82.       perror("socket");
  83.       mud_sock = 0;
  84.     } else
  85.     {
  86.       temp = 1;
  87.       setsockopt(mud_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
  88.       sin.sin_family = AF_INET;
  89.       sin.sin_port = htons(intport);
  90.       sin.sin_addr.s_addr = htonl(0x7F000001);
  91.       temp = connect(mud_sock, (struct sockaddr *) & sin, sizeof(sin));
  92.       if (temp < 0)
  93.       {
  94.     perror("connect");
  95.     close(mud_sock);
  96.     mud_sock = 0;
  97.       }
  98.     }
  99.     if (mud_sock == 0)
  100.     {
  101.       sleep(1);
  102.       fputs("retrying....\n", stderr);
  103.     }
  104.   }
  105.   if (fcntl(mud_sock, F_SETFL, FNDELAY) == -1)
  106.   {
  107.     perror("make_nonblocking: fcntl");
  108.   }
  109.   if (fcntl(mud_sock, F_SETFD, 1) == -1)
  110.   {
  111.     perror("close on execve: fcntl");
  112.   }
  113. #ifdef DEBUG
  114.   fputs("connected!\n", stderr);
  115. #endif
  116. }
  117.  
  118. setup()
  119. {
  120.   int             temp;
  121.   struct sockaddr_in sin;
  122.  
  123.   sock = socket(AF_INET, SOCK_STREAM, 0);
  124.   if (sock < 1)
  125.   {
  126.     perror("socket");
  127.     exit(-1);
  128.   }
  129.   temp = 1;
  130.   setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
  131.   sin.sin_family = AF_INET;
  132.   sin.sin_port = htons(port);
  133.   sin.sin_addr.s_addr = htonl(INADDR_ANY);
  134.  
  135.   temp = bind(sock, (struct sockaddr *) & sin, sizeof(sin));
  136.   if (temp < 0)
  137.   {
  138.     perror("bind");
  139.     exit(1);
  140.   }
  141.   temp = listen(sock, 5);
  142.   if (temp < 0)
  143.   {
  144.     perror("listen");
  145.     exit(1);
  146.   }
  147. }
  148.  
  149. mainloop()
  150. {
  151.   int             found, newsock, lastsock, len, loop;
  152.   int             accepting, current = 0;
  153.   int             temp;
  154.   struct timeval  tv;
  155.   struct sockaddr_in sin;
  156.   struct hostent *hent;
  157.   fd_set          in, out;
  158.   char           *data;
  159.   char           *buf, header[4];
  160.   struct conc_list *cptr;
  161.   struct message *tmsg;
  162.   short           templen;
  163.   char           *mainbuf, *outbuf;
  164.   int             mainlen, outlen;
  165.   int             command;
  166.   int             hlen;
  167.   char           *hostnm;
  168.  
  169.   /* Allocate huge buffer */
  170.   data = (char *)malloc(65536);
  171.   /* Allocate array, one for each possible socket */
  172.   clist = (struct conc_list *) malloc(sizeof(struct conc_list) * NOFILE);
  173.   /* Allocate I/O buffers for main I/O socket */
  174.   mainbuf = (char *)malloc(BUFLEN);
  175.   mainlen = 0;
  176.   outbuf = (char *)malloc(BUFLEN);
  177.   outlen = 0;
  178.   if (!data || !clist || !mainbuf || !outbuf)
  179.   {
  180.     perror("malloc");
  181.     exit(1);
  182.   }
  183.   /* Init array */
  184.   for (loop = 0; loop < NOFILE; ++loop)
  185.   {
  186.     cptr = &(clist[loop]);
  187.     cptr->status = 0;
  188.     cptr->first = 0;
  189.     cptr->last = 0;
  190.   }
  191.  
  192.   /*
  193.    * Accept connections flag ON accepting = 1; /* lastsock for select() 
  194.    */
  195.   lastsock = sock + 1;
  196.   /* mud_sock has already been established */
  197.   clist[mud_sock].status = 1;
  198.   /* Special port # for control messages */
  199.   clist[0].status = 1;
  200.   while (1)
  201.   {
  202.     if (pid < 0)
  203.     {
  204.       pid = vfork();
  205.     }
  206.     if (pid == 0)
  207.     {
  208.       char            pstr[32], istr[32], cstr[32];
  209.       sprintf(pstr, "%d", port);
  210.       sprintf(istr, "%d", intport);
  211.       sprintf(cstr, "%d", clvl + 1);
  212.       execlp("concentrate", "conc", pstr, istr, cstr, 0);
  213.       writelog("CONC %d:ACK!!!!!! exec failed! Exiting...\n", clvl);
  214.       exit(1);
  215.       /* Gee...now what? Should I try again? */
  216.     }
  217.     /* zero out port selector masks */
  218.     FD_ZERO(&in);
  219.     FD_ZERO(&out);
  220.  
  221.     /* set apropriate bit masks for I/O */
  222.     if (accepting)
  223.       FD_SET(sock, &in);
  224.     for (loop = 1; loop < NOFILE; ++loop)
  225.     {
  226.       cptr = &(clist[loop]);
  227.       if (cptr->status)
  228.       {
  229.     FD_SET(loop, &in);
  230.     if (cptr->first)
  231.       FD_SET(loop, &out);
  232.       }
  233.     }
  234.     if (outlen > 0)
  235.       FD_SET(loop, &out);
  236.  
  237.     /* timeout for select */
  238.     tv.tv_sec = 1000;
  239.     tv.tv_usec = 0;
  240.  
  241.     /* look for ports waiting for I/O */
  242.     found = select(lastsock, &in, &out, (fd_set *) 0, &tv);
  243.     /* None found, skip the rest... */
  244.     if (found < 0)
  245.       continue;
  246.     /* New connection? */
  247.     if (accepting && FD_ISSET(sock, &in))
  248.     {
  249.       len = sizeof(sin);
  250.       newsock = accept(sock, (struct sockaddr *) & sin, &len);
  251.       /* This limits the # of connections per concentrator */
  252.       if (newsock >= (NOFILE - 5))
  253.       {
  254.     close(sock);
  255.     accepting = 0;
  256.     pid = -1;
  257.       }
  258.       if (newsock >= lastsock)
  259.     lastsock = newsock + 1;
  260.       cptr = &(clist[newsock]);
  261.       cptr->status = 1;
  262.       cptr->first = 0;
  263.       cptr->last = 0;
  264.       /* set to non-blocking mode */
  265.       if (fcntl(newsock, F_SETFL, FNDELAY) == -1)
  266.       {
  267.     perror("make_nonblocking: fcntl");
  268.       }
  269.       /* set to close on execv */
  270.       if (fcntl(newsock, F_SETFD, 1) == -1)
  271.       {
  272.     perror("close on execv: fcntl");
  273.       }
  274.       temp = 1;
  275.       if (setsockopt(newsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&temp,
  276.              sizeof(temp)) < 0)
  277.       {
  278.     perror("keepalive setsockopt");
  279.       }
  280.       queue_message(newsock, CONC_MESSAGE, sizeof(CONC_MESSAGE) - 1);
  281.       /* build control code for connect */
  282.       data[0] = 0;
  283.       data[1] = 1;               /* connect */
  284.       data[2] = newsock;
  285.       bcopy(&(sin.sin_addr.s_addr), data + 3, 4);
  286.       hent = gethostbyaddr(&(sin.sin_addr.s_addr),
  287.                sizeof(sin.sin_addr.s_addr), AF_INET);
  288.       if (hent)
  289.     strcpy(data + 7, hent->h_name);
  290.       else
  291.     strcpy(data + 7, inet_ntoa(sin.sin_addr.s_addr));
  292.       queue_message(mud_sock, data, 7 + strlen(data + 7));
  293. #ifdef DEBUG
  294.       writelog("CONC %d: USER CONNECT: sock %d, host %s\n", clvl,
  295.            newsock, data + 7);
  296. #endif
  297.     }
  298.     /* recieve data from ports */
  299.     for (loop = 0; loop < NOFILE; ++loop)
  300.     {
  301.       cptr = &(clist[loop]);
  302.       if (cptr->status && FD_ISSET(loop, &in))
  303.       {
  304.     if (loop == 0)
  305.     {
  306.     } else
  307.     if (loop == mud_sock)
  308.     {
  309.       if (mainlen < BUFLEN)
  310.       {
  311.         len = recv(loop, mainbuf + mainlen,
  312.                BUFLEN - mainlen, 0);
  313.         if (len <= 0)
  314.         {
  315.           /* This is quite useless, but what else am I supposed to do? */
  316.           writelog("CONC %d: Lost Connection\n", clvl);
  317.           panic();
  318.         }
  319.         mainlen += len;
  320.       }
  321.       while (mainlen > 2)
  322.       {
  323.         bcopy(mainbuf, &templen, 2);
  324.         if (mainlen >= (templen + 2))
  325.         {
  326.           queue_message(*(mainbuf + 2), mainbuf + 3,
  327.                 templen - 1);
  328.           mainlen = mainlen - templen - 2;
  329.           bcopy(mainbuf + templen + 2, mainbuf, mainlen);
  330.         } else
  331.           break;
  332.       }
  333.     } else
  334.     {
  335.       /* data + 1 so we can add port later w/o a bcopy */
  336.       len = recv(loop, data + 1, 65530, 0);
  337.       if (len == 0)
  338.       {
  339.         disconnect(loop);
  340.       } else
  341.       if (len < 0)
  342.       {
  343.         /* Hmm..... */
  344.         writelog("CONC %d: recv: %s\n", clvl, strerror(errno));
  345.       } else
  346.       {
  347.         /* Add the port # to the data, and send it to interface.c */
  348.         data[0] = loop;
  349.         queue_message(mud_sock, data, len + 1);
  350.       }
  351.     }
  352.       }
  353.     }
  354.     /* Handle output */
  355.     for (loop = 0; loop < NOFILE; ++loop)
  356.     {
  357.       cptr = &(clist[loop]);
  358.       if ((loop == 0) && (cptr->first))
  359.       {
  360.     command = *(cptr->first->data);
  361.     switch (command)
  362.     {
  363.     case 2:               /* disconnect */
  364.       if (clist[*(cptr->first->data + 1)].status)
  365.         clist[*(cptr->first->data + 1)].status = 2;
  366.       else
  367.         writelog("CONC %d: Recieved dissconnect for unknown user\n", clvl);
  368.       break;
  369.     default:
  370.       writelog("CONC %d: Recieved unknown command %d\n", clvl, command);
  371.       break;
  372.     }
  373.     free(cptr->first->data);
  374.     tmsg = cptr->first;
  375.     cptr->first = cptr->first->next;
  376.     free(tmsg);
  377.     if (!cptr->first)
  378.       cptr->last = 0;
  379.       } else
  380.     if ((loop == mud_sock) && FD_ISSET(mud_sock, &out) &&
  381.         ((cptr->first) || (outlen > 0)))
  382.       {
  383.     while ((cptr->first) &&
  384.            ((BUFLEN - outlen) > (cptr->first->len + 2)))
  385.     {
  386.       templen = cptr->first->len;
  387.       bcopy(&(templen), outbuf + outlen, 2);
  388.       bcopy(cptr->first->data, outbuf + outlen + 2, templen);
  389.       outlen += templen + 2;
  390.       free(cptr->first->data);
  391.       tmsg = cptr->first;
  392.       cptr->first = cptr->first->next;
  393.       free(tmsg);
  394.       if (!cptr->first)
  395.         cptr->last = 0;
  396.     }
  397.  
  398.     if (outlen)
  399.     {
  400.       len = send(mud_sock, outbuf, outlen, 0);
  401.       if (len > 0)
  402.       {
  403.         outlen -= len;
  404.         bcopy(outbuf + len, outbuf, outlen);
  405.       }
  406.       else
  407.       {
  408.         panic();
  409.       }
  410.     }
  411.       } else
  412.       if (FD_ISSET(loop, &out) && (cptr->first))
  413.       {
  414.     len = send(loop, cptr->first->data, cptr->first->len, 0);
  415.     free(cptr->first->data);
  416.     tmsg = cptr->first;
  417.     cptr->first = cptr->first->next;
  418.     free(tmsg);
  419.     if (!cptr->first)
  420.       cptr->last = 0;
  421.       }
  422.       /* Test for pending disconnect */
  423.       else
  424.       if ((cptr->status == 2) && (cptr->first == 0))
  425.       {
  426.     cptr->status = 0;
  427.     shutdown(loop, 0);
  428.     close(loop);
  429.       }
  430.     }
  431.     /* Test for emptyness */
  432.     if (!accepting)
  433.     {
  434.       for (loop = mud_sock + 1; loop < NOFILE; ++loop)
  435.     if (clist[loop].status)
  436.       break;
  437.       if (loop == NOFILE)
  438.     exit(0);
  439.     }
  440.   }
  441. }
  442.  
  443. /* Properly disconnect a user */
  444. disconnect(user)
  445.   int             user;
  446. {
  447.   char            header[4];
  448.  
  449.   /* make control message for disconnect */
  450.   header[0] = 0;
  451.   header[1] = 2;               /* disconnect code */
  452.   header[2] = user;
  453.   queue_message(mud_sock, header, 3);
  454.  
  455.   /* shutdown this socket */
  456.   clist[user].status = 0;
  457.   close(user);
  458. #ifdef DEBUG
  459.   writelog("CONC %d: USER DISCONNECT: %d\n", clvl, user);
  460. #endif
  461. }
  462.  
  463. void            queue_message(int port, char *data, int len)
  464. {
  465.   struct message *ptr;
  466.  
  467.   ptr = (struct message *) malloc(sizeof(struct message));
  468.   ptr->data = (char *)malloc(len);
  469.   ptr->len = len;
  470.   bcopy(data, ptr->data, len);
  471.   ptr->next = 0;
  472.   if (clist[port].last == 0)
  473.     clist[port].first = ptr;
  474.   else
  475.     (clist[port].last)->next = ptr;
  476.   clist[port].last = ptr;
  477. }
  478.  
  479. /* Kill off all connections quickly */
  480. panic()
  481. {
  482.   int             loop;
  483.  
  484.   for (loop = 1; loop < NOFILE; ++loop)
  485.   {
  486.     if (clist[loop].status)
  487.     {
  488.       send(loop, PANIC_MESSAGE, sizeof(PANIC_MESSAGE), 0);
  489.       shutdown(loop, 0);
  490.       close(loop);
  491.     }
  492.   }
  493.   exit(1);
  494. }
  495.  
  496. /* Modified to send stuff to the main server for logging */
  497. void            writelog(const char *fmt,...)
  498. {
  499.   va_list         list;
  500.   struct tm      *tm;
  501.   long            t;
  502.   char            buffer[2048];
  503.  
  504.   va_start(list, fmt);
  505.   vsprintf(buffer + 2, fmt, list);
  506.   buffer[0] = 0;
  507.   buffer[1] = 4;               /* remote log command */
  508.   queue_message(mud_sock, buffer, strlen(buffer + 2) + 2);
  509.   va_end(list);
  510. }
  511.