home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / src / serverms.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2007-05-24  |  6.0 KB  |  199 lines

  1. // all server side masterserver and pinging functionality
  2.  
  3. #include "cube.h"
  4.  
  5. #ifdef STANDALONE
  6. bool resolverwait(const char *name, ENetAddress *address)
  7. {
  8.     return enet_address_set_host(address, name) >= 0;
  9. }
  10.  
  11. int connectwithtimeout(ENetSocket sock, char *hostname, ENetAddress &remoteaddress)
  12. {
  13.     int result = enet_socket_connect(sock, &remoteaddress);
  14.     if(result<0) enet_socket_destroy(sock);
  15.     return result;
  16. }
  17. #endif
  18.  
  19. ENetSocket httpgetsend(ENetAddress &remoteaddress, char *hostname, char *req, char *ref, char *agent, ENetAddress *localaddress = NULL)
  20. {
  21.     if(remoteaddress.host==ENET_HOST_ANY)
  22.     {
  23. #ifdef STANDALONE
  24.         printf("looking up %s...\n", hostname);
  25. #endif
  26.         if(!resolverwait(hostname, &remoteaddress)) return ENET_SOCKET_NULL;
  27.     }
  28.     ENetSocket sock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, localaddress);
  29.     if(sock==ENET_SOCKET_NULL || connectwithtimeout(sock, hostname, remoteaddress)<0)
  30.     {
  31. #ifdef STANDALONE
  32.         printf(sock==ENET_SOCKET_NULL ? "could not open socket\n" : "could not connect\n");
  33. #endif
  34.         return ENET_SOCKET_NULL;
  35.     }
  36.     ENetBuffer buf;
  37.     s_sprintfd(httpget)("GET %s HTTP/1.0\nHost: %s\nReferer: %s\nUser-Agent: %s\n\n", req, hostname, ref, agent);
  38.     buf.data = httpget;
  39.     buf.dataLength = strlen((char *)buf.data);
  40. #ifdef STANDALONE
  41.     printf("sending request to %s...\n", hostname);
  42. #endif
  43.     enet_socket_send(sock, NULL, &buf, 1);
  44.     return sock;
  45. }
  46.  
  47. bool httpgetreceive(ENetSocket sock, ENetBuffer &buf, int timeout = 0)
  48. {   
  49.     if(sock==ENET_SOCKET_NULL) return false;
  50.     enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
  51.     if(enet_socket_wait(sock, &events, timeout) >= 0 && events)
  52.     {
  53.         int len = enet_socket_receive(sock, NULL, &buf, 1);
  54.         if(len<=0)
  55.         {
  56.             enet_socket_destroy(sock);
  57.             return false;
  58.         }
  59.         buf.data = ((char *)buf.data)+len;
  60.         ((char*)buf.data)[0] = 0;
  61.         buf.dataLength -= len;
  62.     }
  63.     return true;
  64. }
  65.  
  66. uchar *stripheader(uchar *b)
  67. {
  68.     char *s = strstr((char *)b, "\n\r\n");
  69.     if(!s) s = strstr((char *)b, "\n\n");
  70.     return s ? (uchar *)s : b;
  71. }
  72.  
  73. ENetSocket mssock = ENET_SOCKET_NULL;
  74. ENetAddress msaddress = { ENET_HOST_ANY, ENET_PORT_ANY };
  75. ENetAddress masterserver = { ENET_HOST_ANY, 80 };
  76. int updmaster = 0;
  77. string masterbase;
  78. string masterpath;
  79. uchar masterrep[MAXTRANS];
  80. ENetBuffer masterb;
  81.  
  82. void updatemasterserver(int seconds)
  83. {
  84.     if(seconds>updmaster)       // send alive signal to masterserver every hour of uptime
  85.     {
  86.         s_sprintfd(path)("%sregister.do?action=add", masterpath);
  87.         s_sprintfd(agent)("AssaultCube Server %d", AC_VERSION);
  88.         mssock = httpgetsend(masterserver, masterbase, path, "assaultcubeserver", agent, &msaddress);
  89.         masterrep[0] = 0;
  90.         masterb.data = masterrep;
  91.         masterb.dataLength = MAXTRANS-1;
  92.         updmaster = seconds+60*60;
  93.     }
  94.  
  95. void checkmasterreply()
  96. {
  97.     if(mssock!=ENET_SOCKET_NULL && !httpgetreceive(mssock, masterb))
  98.     {
  99.         mssock = ENET_SOCKET_NULL;
  100.         printf("masterserver reply: %s\n", stripheader(masterrep));
  101.     }
  102. }
  103.  
  104. #ifndef STANDALONE
  105.  
  106. #define RETRIEVELIMIT 20000
  107.  
  108. uchar *retrieveservers(uchar *buf, int buflen)
  109. {
  110.     buf[0] = '\0';
  111.  
  112.     s_sprintfd(path)("%sretrieve.do?item=list", masterpath);
  113.     s_sprintfd(agent)("AssaultCube Client %d", AC_VERSION);
  114.     ENetAddress address = masterserver;
  115.     ENetSocket sock = httpgetsend(address, masterbase, path, "assaultcubeclient", agent);
  116.     if(sock==ENET_SOCKET_NULL) return buf;
  117.     /* only cache this if connection succeeds */
  118.     masterserver = address;
  119.  
  120.     s_sprintfd(text)("retrieving servers from %s... (esc to abort)", masterbase);
  121.     show_out_of_renderloop_progress(0, text);
  122.  
  123.     ENetBuffer eb;
  124.     eb.data = buf;
  125.     eb.dataLength = buflen-1;
  126.  
  127.     int starttime = SDL_GetTicks(), timeout = 0;
  128.     while(httpgetreceive(sock, eb, 250))
  129.     {
  130.         timeout = SDL_GetTicks() - starttime;
  131.         show_out_of_renderloop_progress(min(float(timeout)/RETRIEVELIMIT, 1), text);
  132.         SDL_Event event;
  133.         while(SDL_PollEvent(&event))
  134.         {
  135.             if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) timeout = RETRIEVELIMIT + 1;
  136.         }
  137.         if(timeout > RETRIEVELIMIT)
  138.         {
  139.             buf[0] = '\0';
  140.             enet_socket_destroy(sock);
  141.             return buf;
  142.         }
  143.     }
  144.  
  145.     return stripheader(buf);
  146. }
  147. #endif
  148.  
  149. ENetSocket pongsock = ENET_SOCKET_NULL;
  150. string serverdesc;
  151.  
  152. void serverms(int mode, int numplayers, int minremain, char *smapname, int seconds)        
  153. {
  154.     checkmasterreply();
  155.     updatemasterserver(seconds);
  156.  
  157.     // reply all server info requests
  158.     ENetBuffer buf;
  159.     ENetAddress addr;
  160.     uchar pong[MAXTRANS];
  161.     int len;
  162.     enet_uint32 events = ENET_SOCKET_WAIT_RECEIVE;
  163.     buf.data = pong;
  164.     while(enet_socket_wait(pongsock, &events, 0) >= 0 && events)
  165.     {
  166.         buf.dataLength = sizeof(pong);
  167.         len = enet_socket_receive(pongsock, &addr, &buf, 1);
  168.         if(len < 0) return;
  169.         ucharbuf p(&pong[len], sizeof(pong)-len);
  170.         putint(p, PROTOCOL_VERSION);
  171.         putint(p, mode);
  172.         putint(p, numplayers);
  173.         putint(p, minremain);
  174.         sendstring(smapname, p);
  175.         sendstring(serverdesc, p);
  176.         putint(p, maxclients);
  177.         buf.dataLength = len + p.length();
  178.         enet_socket_send(pongsock, &addr, &buf, 1);
  179.     }
  180. }      
  181.  
  182. void servermsinit(const char *master, char *ip, char *sdesc, bool listen)
  183. {
  184.     const char *mid = strstr(master, "/");
  185.     if(!mid) mid = master;
  186.     s_strcpy(masterpath, mid);
  187.     s_strncpy(masterbase, master, mid-master+1);
  188.     s_strcpy(serverdesc, sdesc);
  189.  
  190.     if(listen)
  191.     {
  192.         ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT };
  193.         pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address);
  194.         if(pongsock == ENET_SOCKET_NULL) fatal("could not create server info socket\n");
  195.         if(*ip && enet_address_set_host(&msaddress, ip)<0) printf("WARNING: server ip not resolved");
  196.     }
  197. }
  198.