Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

437 lines
12 KiB

  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 socket\r\n");
  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("<%s\n", &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. // APPCOMPAT: For Win95, 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. }