Vanilla Netrek Server Development Archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[VANILLA-L:1049] Client to Metaserver Recoding, Client Patch V1.0



Here is the working patch for COW 3.0 (2.02) that adds UDP metaserver
support.  It's not finished, but you need it if you are to test your
metaserver patch.  ;-)

Again, comments welcome.

Remember it isn't finished.

This patch;

	- changes -m to use UDP metaserver mode,
	- adds -M for the TCP metaserver mode,
	- fixes command usage accordingly,
	- removes RSA_client from the parsemeta server struct,
	  [it was not used??],
	- adds code to send and receive the UDP protocol, using
	  all available metaservers [may change this].

-- 
James Cameron                              (james.cameron@digital.com)
Digital Equipment Corporation (Australia) Pty. Ltd. A.C.N. 000 446 800
*** main.c.orig	Sun Aug  9 15:08:07 1998
--- main.c	Mon Aug 24 19:11:34 1998
***************
*** 152,176 ****
                break;
  
  #ifdef META
!             case 'm':
                if (usemeta && usemeta != 1)
                  {
!                   fputs("The options -k and -m are mutuall exclusive\n",
                          stderr);
                    err++;
                  }
                usemeta = 1;
                break;
  
!             case 'k':
                if (usemeta && usemeta != 2)
                  {
!                   fputs("The options -k and -m are mutually exclusive\n",
                          stderr);
                    err++;
                  }
                usemeta = 2;
                break;
  #endif
  
  #ifdef RSA
--- 152,186 ----
                break;
  
  #ifdef META
!             case 'm': /* use multiple metaservers by UDP */
                if (usemeta && usemeta != 1)
                  {
!                   fputs("The options -k, -m and -M are mutually exclusive\n",
                          stderr);
                    err++;
                  }
                usemeta = 1;
                break;
  
!             case 'k': /* use metaserver cache from prior -M usage */
                if (usemeta && usemeta != 2)
                  {
!                   fputs("The options -k, -m and -M are mutually exclusive\n",
                          stderr);
                    err++;
                  }
                usemeta = 2;
                break;
+ 
+ 	    case 'M': /* use single metaserver by TCP */
+ 	      if (usemeta && usemeta != 3)
+ 		{
+ 		  fputs("The options -k, -m and -M are mutually exclusive\n",
+ 			stderr);
+ 		  err++;
+ 		}
+ 	      usemeta = 3;
+ 	      break;
  #endif
  
  #ifdef RSA
***************
*** 416,423 ****
    printf(" [-l filename]   Record messages into 'filename'\n");
  
  #ifdef META
!   printf(" [-m]   check metaserver for active servers\n");
!   printf(" [-k]   display known servers\n");
  #endif
  #ifndef WIN32
    printf(" [-n]   use nearest colors in shared colormap\n");
--- 426,434 ----
    printf(" [-l filename]   Record messages into 'filename'\n");
  
  #ifdef META
!   printf(" [-m]   list servers, using UDP/IP to multiple metaservers\n");
!   printf(" [-M]   list servers, using TCP/IP to single metaserver\n");
!   printf(" [-k]   list servers from cache generated by -M\n");
  #endif
  #ifndef WIN32
    printf(" [-n]   use nearest colors in shared colormap\n");
*** parsemeta.c.orig	Sun Aug  9 13:27:56 1998
--- parsemeta.c	Mon Aug 24 19:11:31 1998
***************
*** 56,65 ****
    {
      char    address[LINE];
      int     port;
!     int     time;
      int     players;
      int     status;
-     int     RSA_client;
      char    typeflag;
    };
  
--- 56,64 ----
    {
      char    address[LINE];
      int     port;
!     int     age;
      int     players;
      int     status;
      char    typeflag;
    };
  
***************
*** 164,174 ****
  
    if (serverName)
      {
- 
- #ifdef RSA
-       serverlist[num_servers].RSA_client = RSA_Client;
- #endif
- 
        strcpy(serverlist[num_servers].address, serverName);
        serverlist[num_servers].port = xtrekPort;
        serverlist[num_servers].status = statusDefault;
--- 163,168 ----
***************
*** 229,235 ****
  
        if (sscanf(line, "-h %s -p %d %d %d",
                   slist->address, &(slist->port),
!                  &(slist->time)) != 3)
          {
            continue;
          }
--- 223,229 ----
  
        if (sscanf(line, "-h %s -p %d %d %d",
                   slist->address, &(slist->port),
!                  &(slist->age)) != 3)
          {
            continue;
          }
***************
*** 255,261 ****
  
        /* Read the flags */
  
-       slist->RSA_client = (*(point - 5) == 'R');
        slist->typeflag = *(point - 1);
  
  
--- 249,254 ----
***************
*** 270,276 ****
                    serverlist[num_servers].port,
                    statusStrings[serverlist[num_servers].status],
                    serverlist[num_servers].players,
-                   serverlist[num_servers].RSA_client,
                    serverlist[num_servers].typeflag);
  #endif
  
--- 263,268 ----
***************
*** 279,285 ****
--- 271,523 ----
      }
  }
  
+ #define MAXMETABYTES 2048
+ static int sock;		/* the socket to talk to the metaservers */
+ static int sent = 0;		/* number of solicitations sent		 */
+ static int seen = 0;		/* number of replies seen		 */
+ 
+ static int ReadMetasSend()
+ {
+   struct sockaddr_in address;	/* the address of the metaservers	 */
+   int length;			/* length of the address		 */
+   int bytes;			/* number of bytes received from meta'   */
+   fd_set readfds;		/* the file descriptor set for select()	 */
+   struct timeval timeout;	/* timeout for select() call		 */
+   char packet[MAXMETABYTES];	/* buffer for packet returned by meta'	 */
+   int max_servers;		/* number of servers we have defined	 */
+   
+   if ((getdefault("metaserver")) != NULL)
+     metaserver = getdefault("metaserver");
+   metaport = intDefault("metaport", metaport);
+ 
+   sock = socket(AF_INET, SOCK_DGRAM, 0);
+   if (sock < 0) { perror("ReadMetasSend: socket"); return 0; }
+ 
+   address.sin_addr.s_addr = INADDR_ANY;
+   address.sin_family      = AF_INET;
+   address.sin_port        = 0;
+   if (bind(sock,(struct sockaddr *)&address, sizeof(address)) < 0) {
+     perror("ReadMetasSend: bind");
+     return 0;
+   }
+     
+   address.sin_family = AF_INET;
+   address.sin_port = htons(metaport);
+   /* attempt numeric translation first */
+   if ((address.sin_addr.s_addr = inet_addr(metaserver)) == -1) {
+     struct hostent *hp;
+         
+     /* then translation by name */
+     if ((hp = gethostbyname(metaserver)) == NULL) {
+       /* if it didn't work, return failure and warning */
+       fprintf(stderr,
+ 	"Cannot resolve metaserver address of %s, check for DNS problems?\n",
+ 	metaserver);
+       return 0;
+     } else {
+       int i;
+ 
+       /* resolution worked, send a query to every metaserver listed */
+       for(i=0;;i++) {
+ 
+ 	/* check for end of list of addresses */
+ 	if (hp->h_addr_list[i] == NULL) break;
+ 	address.sin_addr.s_addr = *(long *) hp->h_addr_list[i];
+ 	fprintf(stderr, "Requesting player list from metaserver at %s\n",
+ 		inet_ntoa(address.sin_addr));
+ 	if (sendto(sock, "?", 1, 0, (struct sockaddr *)&address,
+ 		sizeof(address)) < 0) {
+ 	  perror("ReadMetasSend: sendto");
+ 	  return 0;
+ 	}
+ 	sent++;
+       }
+     }
+   } else {
+     /* send only to the metaserver specified by numeric IP address */
+     if (sendto(sock, "?", 1, 0, (struct sockaddr *)&address,
+ 	sizeof(address)) < 0) {
+       perror("ReadMetasSend: sendto");
+       return 0;
+     }
+     sent++;
+   }
+   return 1;
+ }
+ 
+ static int ReadMetasRecv()
+ {
+   struct sockaddr_in address;	/* the address of the metaservers	 */
+   int length;			/* length of the address		 */
+   int bytes;			/* number of bytes received from meta'   */
+   fd_set readfds;		/* the file descriptor set for select()	 */
+   struct timeval timeout;	/* timeout for select() call		 */
+   char packet[MAXMETABYTES];	/* buffer for packet returned by meta'	 */
+   int max_servers;		/* number of servers we have defined	 */
+   
+   /* now await and process replies */
+   while(1) {
+     char *p;
+     int servers, i, j;
+ 
+     FD_ZERO(&readfds);
+     FD_SET(sock, &readfds);
+     timeout.tv_sec=0;
+     timeout.tv_usec=100;
  
+     if (select(FD_SETSIZE, &readfds, NULL, NULL, &timeout) < 0) {
+       perror("ReadMetasRecv: select");
+       return 0;
+     }
+ 
+     /* if the wait timed out, then we give up */
+     if (!FD_ISSET(sock, &readfds)) {
+       /* here placeth logic that sees time for reply is up and asks again */
+       return 0;
+     }
+ 
+     /* so we have data back from a metaserver */
+     length = sizeof(address);
+     bytes = recvfrom(sock, packet, MAXMETABYTES, 0, (struct sockaddr *)&address,
+ 	&length );
+     if (bytes < 0) {
+       perror("ReadMetasRecv: recvfrom");
+       fprintf(stderr, "sock=%d packet=%08.8x length=%d\n", sock, packet,
+ 	MAXMETABYTES );
+       return 0;
+     }
+ 
+     /* terminate the packet received */
+     packet[bytes] = 0;
+     fprintf(stderr, "%s", packet);
+ 
+     /* process the packet, updating our server list */
+ 
+     /* version identifier */
+     p = strtok(packet,",");
+     if (p == NULL) continue;
+     if (p[0] != 'r') continue;
+ 
+     /* number of servers */
+     p = strtok(NULL,"\n");
+     if (p == NULL) continue;
+     servers = atoi(p);
+ 
+     /* sanity check on number of servers */
+     if (servers > 2048) continue;
+     if (servers < 0) continue;
+ 
+     fprintf(stderr, "Metaserver at %s responded with %d server%s\n",
+ 	inet_ntoa(address.sin_addr),
+ 	servers,
+ 	servers == 1 ? "" : "s" );
+ 
+     /* allocate or extend a server list */
+     if (serverlist == NULL) {
+       serverlist = (struct servers *) malloc(
+ 	sizeof(struct servers) * servers);
+     } else {
+       serverlist = (struct servers *) realloc(serverlist, 
+ 	sizeof(struct servers) * ( servers + num_servers ));
+     }
+ 
+     /* for each server listed by this metaserver packet */
+     for(i=0;i<servers;i++) {
+       struct servers *sp = serverlist;
+       char *address, type;
+       int port, status, age, players, queue;
+ 
+       address = strtok(NULL,",");	/* hostname */
+       if (address == NULL) continue;
+ 
+       p = strtok(NULL,",");		/* port */
+       if (p == NULL) continue;
+       port = atoi(p);
+ 
+       p = strtok(NULL,",");		/* status */
+       if (p == NULL) continue;
+       status = atoi(p);
+ 
+       /* ignore servers here based on status */
+ 
+       p = strtok(NULL,",");		/* age (of data in seconds) */
+       if (p == NULL) continue;
+       age = atoi(p);
+ 
+       p = strtok(NULL,",");		/* players */
+       if (p == NULL) continue;
+       players = atoi(p);
+ 
+       p = strtok(NULL,",");		/* queue size */
+       if (p == NULL) continue;
+       queue = atoi(p);
+ 
+       p = strtok(NULL,"\n");		/* server type */
+       if (p == NULL) continue;
+       type = p[0];
+ 
+       /* find in current server list? */
+       for(j=0;j<num_servers;j++) {
+         sp = serverlist + j;
+         if ((!strcmp(sp->address,address)) && (sp->port == port)) {
+           fprintf(stderr, "%s:%d already listed\n", address, port);
+           break;
+         }
+       }
+ 
+       /* if it was found, check age */
+       if (j != num_servers) {
+ 	if (age > sp->age) continue;
+       } else {
+         /* not found, store it at the end of the list */
+         sp = serverlist + j;
+         fprintf(stderr, "%s:%d new\n", address, port);
+ 	strncpy(sp->address,address,LINE);
+ 	sp->port = port;
+ 	sp->age = age;
+ 	num_servers++;
+       }
+ 
+ /* from meta.h of metaserver code */
+ #define SS_WORKING 0
+ #define SS_QUEUE 1
+ #define SS_OPEN 2
+ #define SS_EMPTY 3
+ #define SS_NOCONN 4
+ #define SS_INIT 5
+ 
+       switch (status) {
+         case SS_QUEUE:
+ 	  sp->status = statusWait;
+ 	  sp->players = queue;
+ 	  break;
+ 	case SS_OPEN:
+ 	  sp->status = statusOpen;
+ 	  sp->players = players;
+ 	  break;
+ 	case SS_EMPTY:
+ 	  sp->status = statusNobody;
+ 	  sp->players = 0;
+ 	  break;
+ 	case SS_NOCONN:			/* no connection */
+ 	case SS_WORKING:		/* metaserver should not return this */
+ 	case SS_INIT:			/* nor this */
+ 	default:
+ 	  sp->status = statusNoConnect;
+ 	  sp->players = 0;
+ 	  break;
+       }
+       sp->typeflag = type;
+     }
+     /* finished processing the packet */
+ 
+     /* count the number of replies we have received */
+     seen++;
+ 
+     /* if we have seen the same number of replies to what we sent, end */
+     if (sent == seen) return 1;
+   }
+ }
  
  static int ReadFromMeta(int statusLevel)
  /* Read from the meta-server.  Return TRUE on success and FALSE on failure. */
***************
*** 460,470 ****
  
  
  void    parsemeta(int metaType)
! /* Read and Parse the meta-server information, either from the meta- server
!  * (if metaType = 1) or from the cache (if metaType = 2).
   * 
   * NOTE: This function sets the variable "num_servers" which is later used to
!  * decide the hight of the meta-server window. */
  {
    int     statusLevel;
  
--- 698,708 ----
  
  
  void    parsemeta(int metaType)
! /* Read and Parse the metaserver information, either from the metaservers
!  * by UDP (1), from a single metaserver by TCP (3), or from the cache (2).
   * 
   * NOTE: This function sets the variable "num_servers" which is later used to
!  * decide the height of the metaserver window. */
  {
    int     statusLevel;
  
***************
*** 475,495 ****
    else if (statusLevel >= statusNull)
      statusLevel = statusNull - 1;
  
! 
!   if (metaType == 1)                             /* Read from the Meta-server */
      {
!       if (ReadFromMeta(statusLevel) || ReadFromCache(statusLevel))
          return;
! 
!       terminate(0);
!     }
! 
!   if (metaType == 2)                             /* Read from the Cache first */
!     {
!       if (ReadFromCache(statusLevel) || ReadFromMeta(statusLevel))
!         return;
! 
!       terminate(0);
      }
  }
  
--- 713,734 ----
    else if (statusLevel >= statusNull)
      statusLevel = statusNull - 1;
  
!   switch (metaType)
      {
!       case 1:
!         ReadMetasSend();
! 	ReadMetasRecv();
          return;
! 	terminate(0);
! 	break;
!       case 2:
! 	if (ReadFromCache(statusLevel) || ReadFromMeta(statusLevel)) return;
! 	terminate(0);
! 	break;
!       case 3:
! 	if (ReadFromMeta(statusLevel) || ReadFromCache(statusLevel)) return;
! 	terminate(0);
! 	break;
      }
  }
  
***************
*** 546,561 ****
            break;
          }
      }
  
    W_WriteText(metaWin, 0, i, color, buf, strlen(buf), 0);
  }
  
  
! void    metawindow(void)
  /* Show the meta server menu window */
  {
    int     i;
  
    for (i = 0; i < num_servers; i++)
      metarefresh(i, textColor);
  
--- 785,805 ----
            break;
          }
      }
+   fprintf(stderr,"%s in\n", buf);
  
    W_WriteText(metaWin, 0, i, color, buf, strlen(buf), 0);
+   fprintf(stderr,"%s ok\n", buf);
  }
  
  
! void    metawindow(int metaType)
  /* Show the meta server menu window */
  {
    int     i;
  
+   /* optimisation; check here for metaserver replies */
+   if (metaType == 1) ReadMetasRecv();
+ 
    for (i = 0; i < num_servers; i++)
      metarefresh(i, textColor);
  
***************
*** 600,609 ****
            printf("Attempting to observe on port %d...\n",xtrekPort);
        }
        serverName = strdup(slist->address);
- 
- #ifdef RSA
-       RSA_Client = slist->RSA_client;
- #endif
  
        metarefresh(data->y, W_Yellow);
        W_Flush();
--- 844,849 ----
*** parsemeta.h.orig	Wed Aug 12 17:50:13 1998
--- parsemeta.h	Mon Aug 24 19:11:37 1998
***************
*** 24,30 ****
   */
  
   
! void metawindow(void);
  /*
   *  Show the meta server menu window
   */
--- 24,30 ----
   */
  
   
! void metawindow(int metaType);
  /*
   *  Show the meta server menu window
   */
*** newwin.c.orig	Mon Aug 24 19:15:14 1998
--- newwin.c	Tue Aug 18 18:06:54 1998
***************
*** 335,341 ****
  
  #ifdef META
    if (checkMapped("MetaServer List"))
!     metawindow();
  #endif
  
    if (checkMapped("review_all"))
--- 335,341 ----
  
  #ifdef META
    if (checkMapped("MetaServer List"))
!     metawindow(-1);
  #endif
  
    if (checkMapped("review_all"))

References: