proxy.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 12k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*****************************************************************************
  2.  *
  3.  *  PROXYcc
  4.  *
  5.  *  Copyright (c) 1997 Microsoft Corporation.  All Rights Reserved.
  6.  *
  7.  *  Abstract:
  8.  *
  9.  *      Does all the bookkeeping part of proxying.
  10.  *
  11.  *****************************************************************************/
  12. #include "msnspa.h"
  13. /*****************************************************************************
  14.  *
  15.  *      init_send_socket
  16.  *
  17.  *      Create a socket that talks to the real world.
  18.  *
  19.  *****************************************************************************/
  20. SOCKET INTERNAL
  21. init_send_socket(SOCKET scfd, LPCSTR pszHost, u_short port, LPCSTR pszErrMsg)
  22. {
  23.     SOCKET s;
  24.     struct hostent *phe;
  25.     struct sockaddr_in saddr;
  26.     /*
  27.      * Find out who the target is.
  28.      */
  29.     ZeroMemory(&saddr, sizeof(saddr));
  30.     phe = gethostbyname(pszHost);
  31.     if (!phe) {
  32.         Squirt("Couldn't build address of gateway");
  33.         send(scfd, pszErrMsg, lstrlen(pszErrMsg), 0);
  34.         s = INVALID_SOCKET;
  35.         goto done;
  36.     }
  37.     /*
  38.      * Build the socket address packet for the open.
  39.      */
  40.     saddr.sin_family = AF_INET;
  41.     saddr.sin_port = htons(port);
  42.     CopyMemory(&saddr.sin_addr, phe->h_addr, phe->h_length);
  43.     /*
  44.      * Open sesame.
  45.      */
  46.     s = socket(AF_INET, SOCK_STREAM, 0);
  47.     if (s == INVALID_SOCKET) {
  48.         Squirt("Couldn't create send socketrn");
  49.         send(scfd, pszErrMsg, lstrlen(pszErrMsg), 0);
  50.         s = INVALID_SOCKET;
  51.         goto done;
  52.     }
  53.     /*
  54.      * One ringy-dingy...
  55.      */
  56.     if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr))) {
  57.         Squirt("Couldn't connect");
  58.         closesocket(s);
  59.         send(scfd, pszErrMsg, lstrlen(pszErrMsg), 0);
  60.         s = INVALID_SOCKET;
  61.         goto done;
  62.     }
  63. done:;
  64.     return s;
  65. }
  66. /*****************************************************************************
  67.  *
  68.  *      set_sock_opt_int
  69.  *
  70.  *  Set an integer socket option or die trying.
  71.  *
  72.  *****************************************************************************/
  73. void
  74. set_sock_opt_int(SOCKET s, int optname, int val)
  75. {
  76.     if (setsockopt(s, SOL_SOCKET, optname, (PV)&val, sizeof(val)) == -1) {
  77.         Die("set sock opt");
  78.     }
  79. }
  80. /*****************************************************************************
  81.  *
  82.  *      create_listen_socket
  83.  *
  84.  *      Start listening on a port.
  85.  *
  86.  *****************************************************************************/
  87. SOCKET INTERNAL
  88. create_listen_socket(u_short port)
  89. {
  90.     SOCKET isckdes;
  91.     struct hostent *phe;                /* my host entry table */
  92.     struct sockaddr_in saddr;           /* my socket address */
  93.     char hostname[64];
  94.     /*
  95.      * Find out who I am.
  96.      */
  97.     gethostname(hostname, 64);
  98.     phe = gethostbyname(hostname); /* Get my own hostent */
  99.     if (!phe) {
  100.         Die("Couldn't build address of localhost");
  101.         return INVALID_SOCKET;
  102.     }
  103.     /*
  104.      * Build the socket address packet for the open.
  105.      */
  106.     ZeroMemory(&saddr, sizeof(saddr));  /* start fresh */
  107.     CopyMemory(&saddr.sin_addr, phe->h_addr, phe->h_length); /* Copy the IP */
  108.     saddr.sin_family = AF_INET;
  109.     saddr.sin_addr.s_addr = htonl(INADDR_ANY);
  110.     saddr.sin_port = htons(port); /* Listen on this port */
  111.     /*
  112.      * Open sesame.
  113.      */
  114.     isckdes = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  115.     if (isckdes == INVALID_SOCKET) {
  116.         Die("Couldn't create listen socket");
  117.         return INVALID_SOCKET;
  118.     }
  119.     /*
  120.      * Set some socket options.
  121.      */
  122.     set_sock_opt_int(isckdes, SO_REUSEADDR, 1);
  123.     set_sock_opt_int(isckdes, SO_KEEPALIVE, 1);
  124.     /*
  125.      * All right, let's bind to it already.
  126.      */
  127.     if (bind(isckdes, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
  128.         Die("Couldn't bind to recv. socket");
  129.     }
  130.     return isckdes;
  131. }
  132. /*****************************************************************************
  133.  *
  134.  *      ProxyPeekCommand
  135.  *
  136.  *      Study the incoming command to see if it is something we
  137.  *      have a canned response to.
  138.  *
  139.  *****************************************************************************/
  140. BOOL INTERNAL
  141. ProxyPeekCommand(PCONNECTIONSTATE pcxs)
  142. {
  143.     PPROXYINFO pproxy = pcxs->pproxy;
  144.     /*
  145.      *  Now peek to see if we got a specific ignorable
  146.      *  four-letter command from
  147.      *  the client.  If so, then spit back the canned response.
  148.      */
  149.     if (pcxs->nread > 4 && pcxs->buf[4] == ' ') {
  150.         char szWord[5];
  151.         szWord[0] = pcxs->buf[0];
  152.         szWord[1] = pcxs->buf[1];
  153.         szWord[2] = pcxs->buf[2];
  154.         szWord[3] = pcxs->buf[3];
  155.         szWord[4] = 0;
  156.         /*
  157.          *  Are the first four letters an ignored command?
  158.          */
  159.         if (lstrcmpi(szWord, pproxy->szIgnore1) == 0 ||
  160.             lstrcmpi(szWord, pproxy->szIgnore2) == 0) {
  161.             /*
  162.              *  Then spit back the canned response.
  163.              */
  164.             if (sendsz(pcxs->scfd, pproxy->pszResponse) == SOCKET_ERROR) {
  165.                 Squirt("Write failed" EOL);
  166.             }
  167.             return TRUE;
  168.         }
  169.     }
  170.     return FALSE;
  171. }
  172. /*****************************************************************************
  173.  *
  174.  *      PROXYTHREADSTATE
  175.  *
  176.  *      Tiny chunk of memory used to transfer proxy state between
  177.  *      the ProxyThread() and the ProxyWorkerThread().
  178.  *
  179.  *****************************************************************************/
  180. typedef struct PROXYTHREADSTATE {
  181.     PPROXYINFO pproxy;                  /* Who we are */
  182.     SOCKET scfd;                        /* Newly-accepted socket to client */
  183. } PROXYTHREADSTATE, *PPROXYTHREADSTATE;
  184. /*****************************************************************************
  185.  *
  186.  *      ProxyWorkerThread
  187.  *
  188.  *      Hold two phones together.
  189.  *
  190.  *****************************************************************************/
  191. DWORD WINAPI
  192. ProxyWorkerThread(LPVOID pvRef)
  193. {
  194.     PPROXYTHREADSTATE ppts = pvRef;
  195.     CONNECTIONSTATE cxs;
  196.     cxs.scfd = ppts->scfd;
  197.     cxs.pproxy = ppts->pproxy;
  198.     LocalFree(ppts);
  199.     Squirt("Connection %d..." EOL, GetCurrentThreadId());
  200.     ++*cxs.pproxy->piUsers;
  201.     UI_UpdateCounts();
  202.     /* open the target socket */
  203.     cxs.ssfd = init_send_socket(cxs.scfd,
  204.                                 cxs.pproxy->pszHost,
  205.                                 cxs.pproxy->serverport,
  206.                                 cxs.pproxy->pszError);
  207.     if (cxs.ssfd != INVALID_SOCKET) {
  208. #if 0
  209.         Squirt("ssfd = %d; scfd = %d, &ssfd = %08x" EOL,
  210.                cxs.ssfd, cxs.scfd, &cxs.ssfd);
  211. #endif
  212.         if (!cxs.pproxy->Negotiate(cxs.ssfd)) {
  213.             sendsz(cxs.scfd, cxs.pproxy->pszErrorPwd);
  214.             goto byebye;
  215.         }
  216.         sendsz(cxs.scfd, cxs.pproxy->pszResponse);
  217.         for (;;) {
  218.             fd_set fdrd, fder;
  219.             SOCKET sfrom, sto;
  220.             fdrd.fd_count = 2;
  221.             fdrd.fd_array[0] = cxs.ssfd;
  222.             fdrd.fd_array[1] = cxs.scfd;
  223.             fder.fd_count = 2;
  224.             fder.fd_array[0] = cxs.ssfd;
  225.             fder.fd_array[1] = cxs.scfd;
  226.             cxs.nread = select(32, &fdrd, 0, &fder, 0);
  227.             if (cxs.nread != SOCKET_ERROR) {
  228.                 char *ptszSrc;
  229.                 char *ptszDst;
  230.                 if (fder.fd_count) {        /* error on a socket, e.g., EOF */
  231.                     break;                  /* outta here */
  232.                 }
  233.                 if (fdrd.fd_count == 0) {   /* Huh?? */
  234.                     continue;
  235.                 }
  236.                 if (fdrd.fd_array[0] == cxs.scfd) {
  237.                     sfrom = cxs.scfd; sto = cxs.ssfd;
  238.                 } else if (fdrd.fd_array[0] == cxs.ssfd) {
  239.                     sfrom = cxs.ssfd; sto = cxs.scfd;
  240.                 } else {
  241.                     continue;
  242.                 }
  243.                 cxs.nread = recv(sfrom, cxs.buf, BUFSIZE, 0); /* read a hunk */
  244.                 if (cxs.nread > 0) {
  245.                     /*
  246.                      *  If it's from the client, then peek at it
  247.                      *  in case we need to munge it.
  248.                      */
  249.                     if (sfrom == cxs.scfd) {
  250.                         if (ProxyPeekCommand(&cxs)) {
  251.                             continue;
  252.                         }
  253.                     }
  254.                     if (send(sto, cxs.buf, cxs.nread, 0) == SOCKET_ERROR) {
  255.                         Squirt("Write failed" EOL);
  256.                     }
  257. #ifdef DBG
  258.                     cxs.buf[cxs.nread] = 0;
  259.                     if (sto == cxs.scfd) {
  260.                         /*
  261.                          *  Walk the buffer studying each line.
  262.                          */
  263.                         int ich = 0;
  264.                         while (ich < cxs.nread) {
  265.                             int ichEnd;
  266.                             DWORD dwFirst;
  267.                             for (ichEnd = ich;
  268.                                  ichEnd < cxs.nread &&
  269.                                  cxs.buf[ichEnd] != 'n'; ichEnd++) {
  270.                             }
  271.                             dwFirst = *(LPDWORD)&cxs.buf[ich];
  272.                             #define PLUSOK      0x004B4F2B
  273.                             #define DASHERR     0x5252452D
  274.                             #define SUBJECT     0x6A627553
  275.                             if ((dwFirst & 0x00FFFFFF) == PLUSOK ||
  276.                                 dwFirst == DASHERR ||
  277.                                 dwFirst == SUBJECT) {
  278.                                 cxs.buf[ichEnd] = 0;
  279.                                 Squirt("<%sn", &cxs.buf[ich]);
  280.                             }
  281.                             ich = ichEnd + 1;
  282.                         }
  283.                     } else {
  284.                         Squirt(">%s", cxs.buf);
  285.                     }
  286. #endif
  287.                 } else {                /* EOF */
  288.                     break;
  289.                 }
  290.             } else {                    /* Panic */
  291.                 Squirt("select %d", WSAGetLastError());
  292.                 break;
  293.             }
  294.         }
  295.     byebye:;
  296.         Sleep(250);                     /* wait for socket to drain */
  297.         closesocket(cxs.ssfd);
  298.     }
  299.     closesocket(cxs.scfd);
  300.     Squirt("End connection %d..." EOL, GetCurrentThreadId());
  301.     --*cxs.pproxy->piUsers;
  302.     UI_UpdateCounts();
  303.     return 0;
  304. }
  305. /*****************************************************************************
  306.  *
  307.  *      ProxyThread
  308.  *
  309.  *      Thread procedure for proxies.
  310.  *
  311.  *****************************************************************************/
  312. DWORD CALLBACK
  313. ProxyThread(LPVOID pvRef)
  314. {
  315.     PPROXYINFO pproxy = pvRef;
  316.     SOCKET ic_sck;
  317.     SOCKET scfd;
  318.     ic_sck = create_listen_socket(pproxy->localport);
  319.     for (;;) {
  320.         HANDLE hThread;
  321.         DWORD dwThid;
  322.         PPROXYTHREADSTATE ppts;
  323.         Squirt("listening..." EOL);
  324.         if (listen(ic_sck, SOMAXCONN) == -1) {
  325.             Squirt("listen failed %d" EOL, WSAGetLastError());
  326.             // BUGBUG -- Win95 sucks.  Close the socket and try again
  327.             closesocket(ic_sck);
  328.             ic_sck = create_listen_socket(pproxy->localport);
  329.             continue;
  330.         }
  331.         /*
  332.          *  OLD COMMENT
  333.          *
  334.          * We ought to put a timeout in here, and then
  335.          * if there are no connections, reap any zombies
  336.          * and go back to listening... so if we've blocked some
  337.          * sockets other people don't get refused... -- mikeg
  338.          */
  339.         Squirt("accept waiting..." EOL);
  340.         scfd = accept(ic_sck, NULL, NULL); /* wait for a connection */
  341.         if (scfd == INVALID_SOCKET) {
  342.             Squirt("accept failed %d" EOL, WSAGetLastError());
  343.             break;
  344.         }
  345.         ppts = LocalAlloc(LMEM_FIXED, sizeof(PROXYTHREADSTATE));
  346.         if (ppts) {
  347.             ppts->pproxy = pproxy;
  348.             ppts->scfd = scfd;
  349.             hThread = CreateThread(0, 0, ProxyWorkerThread, ppts, 0, &dwThid);
  350.             if (hThread) {
  351.                 CloseHandle(hThread);
  352.             } else {
  353.                 Squirt("Can't spawn worker thread; tossing connection" EOL);
  354.                 closesocket(scfd);
  355.             }
  356.         } else {
  357.             Squirt("Out of memory; tossing connection" EOL);
  358.             closesocket(scfd);
  359.         }
  360.     }
  361.     closesocket(ic_sck);
  362.     return 0;
  363. }