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.

3666 lines
96 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. sockets.c
  5. Abstract:
  6. Implements the network interface for the home net transport.
  7. Author:
  8. Jim Schmidt (jimschm) 01-Jul-2000
  9. Revision History:
  10. <full name> (<alias>) <date> <comments>
  11. --*/
  12. //
  13. // Includes
  14. //
  15. #include "pch.h"
  16. #include <winsock2.h>
  17. #include <wsipx.h>
  18. #include <wsnwlink.h>
  19. #include <wsnetbs.h>
  20. #include <nb30.h>
  21. #include <ws2tcpip.h>
  22. #include <lmcons.h>
  23. #include <lmaccess.h>
  24. #include <lmwksta.h>
  25. #include "homenetp.h"
  26. #define DBG_HOMENET "HomeNet"
  27. //
  28. // Strings
  29. //
  30. #define S_64CHARTAG TEXT("usmt-v2@01234567890123456789012345678901234567890123456789012345")
  31. //
  32. // Constants
  33. //
  34. #define IDLE_TIMEOUT 45
  35. #define TCPIP_BROADCAST_PORT 2048
  36. #define IPX_BROADCAST_PORT 1150
  37. #define NETBIOS_BROADCAST_PORT 0x50
  38. #define TCPIP_CONNECT_PORT 2049
  39. #define IPX_CONNECT_PORT 1151
  40. #define NETBIOS_CONNECT_PORT 0x51
  41. #define NAME_SIZE 64
  42. #define NAME_SIZE_PLUS_NUL 65
  43. #define NAME_SIZE_PLUS_COMMA 65
  44. #define NAME_SIZE_PLUS_COMMA_PLUS_NUL 66
  45. #define MIN_MESSAGE_SIZE (NAME_SIZE_PLUS_COMMA_PLUS_NUL + 2)
  46. //
  47. // Macros
  48. //
  49. // none
  50. //
  51. // Types
  52. //
  53. typedef INT (WSAIOCTL)(
  54. SOCKET s,
  55. DWORD IoControlCode,
  56. PVOID InBuffer,
  57. DWORD InBufferSize,
  58. PVOID OutBuffer,
  59. DWORD OutBufferSize,
  60. PDWORD BytesReturned,
  61. WSAOVERLAPPED *Overlapped,
  62. LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine
  63. );
  64. typedef WSAIOCTL *PWSAIOCTL;
  65. typedef struct {
  66. SOCKET Socket;
  67. BYTE BroadcastAddress[MAX_SOCKADDR];
  68. INT AddressLen;
  69. INT Family;
  70. INT Protocol;
  71. } BROADCASTSOCKET, *PBROADCASTSOCKET;
  72. typedef struct {
  73. SOCKET Socket;
  74. INT Family;
  75. INT Protocol;
  76. BOOL Datagram;
  77. } LISTENSOCKET, *PLISTENSOCKET;
  78. typedef struct {
  79. PBROADCASTSOCKET BroadcastSockets;
  80. INT BroadcastCount;
  81. PLISTENSOCKET ListenSockets;
  82. INT ListenCount;
  83. CONNECTIONSOCKET ConnectionSocket;
  84. PGROWBUFFER AddressArray;
  85. UINT Timeout;
  86. } BROADCASTARGS, *PBROADCASTARGS;
  87. typedef NET_API_STATUS(WINAPI NETWKSTAGETINFO)(PWSTR, DWORD, PBYTE *);
  88. typedef NETWKSTAGETINFO *PNETWKSTAGETINFO;
  89. typedef NET_API_STATUS(WINAPI NETAPIBUFFERFREE)(PVOID);
  90. typedef NETAPIBUFFERFREE *PNETAPIBUFFERFREE;
  91. //
  92. // Globals
  93. //
  94. HANDLE g_StopHandle;
  95. HANDLE g_ConnectionDone;
  96. CHAR g_GlobalKey [GLOBALKEY_SIZE + 1];
  97. //
  98. // Macro expansion list
  99. //
  100. // none
  101. //
  102. // Private function prototypes
  103. //
  104. // none
  105. //
  106. // Macro expansion definition
  107. //
  108. // none
  109. //
  110. // Code
  111. //
  112. PBROADCASTSOCKET
  113. pOpenOneBroadcastSocket (
  114. IN OUT PGROWBUFFER BroadcastSockets,
  115. IN SOCKADDR *SockAddr,
  116. IN INT SockAddrLen,
  117. IN INT Family,
  118. IN INT Protocol,
  119. IN PCTSTR DebugText
  120. )
  121. /*++
  122. Routine Description:
  123. pOpenOneBroadcastSocket opens a socket for the specified
  124. family/protocol/address combination, sets the socket into SO_REUSEADDR and
  125. SO_BROADCAST mode, and puts the socket information in the array stored in
  126. the caller's grow buffer.
  127. The socket opened will be used for broadcast send or receive.
  128. Arguments:
  129. BroadcastSockets - Specifies the grow buffer that holds the array of
  130. BROADCASTSOCKET elements. Receives an additional entry
  131. on success.
  132. SockAddr - Specifies the protocol-specific socket address structure
  133. (cast to SOCKADDR), giving the broadcast address.
  134. SockAddrLen - Specifies the length of SockAddr, in bytes
  135. Family - Specifies the protocol family (AF_IPX, AF_INET)
  136. Protocol - Specifies the protocol (IPPROTO_UDP, NSPROTO_IPX, -lana)
  137. DebugText - Specifies the protocol in text form for debug messages
  138. Return Value:
  139. A pointer to the new BROADCASTSOCKET element allocated from BroadcastSockets,
  140. or NULL if the socket could not be opened.
  141. NOTE: BroadcastSockets->Buf will potentially change on success. Do not rely
  142. on this address.
  143. --*/
  144. {
  145. PBROADCASTSOCKET broadcastSocket;
  146. BOOL b;
  147. broadcastSocket = (PBROADCASTSOCKET) GbGrow (BroadcastSockets, sizeof (BROADCASTSOCKET));
  148. broadcastSocket->Socket = socket (Family, SOCK_DGRAM, Protocol);
  149. if (broadcastSocket->Socket != INVALID_SOCKET) {
  150. b = TRUE;
  151. setsockopt (broadcastSocket->Socket, SOL_SOCKET, SO_BROADCAST, (PBYTE) &b, sizeof (b));
  152. setsockopt (broadcastSocket->Socket, SOL_SOCKET, SO_REUSEADDR, (PBYTE) &b, sizeof (b));
  153. if (bind (broadcastSocket->Socket, SockAddr, SockAddrLen)) {
  154. DEBUGMSG ((DBG_ERROR, "Can't bind to %s socket", DebugText));
  155. closesocket (broadcastSocket->Socket);
  156. broadcastSocket->Socket = INVALID_SOCKET;
  157. }
  158. }
  159. if (broadcastSocket->Socket == INVALID_SOCKET) {
  160. BroadcastSockets->End -= sizeof (BROADCASTSOCKET);
  161. broadcastSocket = NULL;
  162. } else {
  163. DEBUGMSG ((
  164. DBG_HOMENET,
  165. "%s is available for broadcast on socket %u",
  166. DebugText,
  167. (BroadcastSockets->End / sizeof (BROADCASTSOCKET)) - 1
  168. ));
  169. broadcastSocket->AddressLen = SockAddrLen;
  170. MYASSERT (SockAddrLen <= MAX_SOCKADDR);
  171. CopyMemory (broadcastSocket->BroadcastAddress, (PBYTE) SockAddr, SockAddrLen);
  172. broadcastSocket->Family = Family;
  173. broadcastSocket->Protocol = Protocol;
  174. }
  175. return broadcastSocket;
  176. }
  177. INT
  178. pOpenBroadcastSockets (
  179. OUT PGROWBUFFER BroadcastSockets
  180. )
  181. /*++
  182. Routine Description:
  183. pOpenBroadcastSockets opens a broadcast socket on each supported protocol.
  184. Arguments:
  185. BroadcastSockets - Receives an array of BROADCASTSOCKET elements (one for
  186. each protocol). IMPORTANT: This parameter must be
  187. zero-initialized by the caller.
  188. Return Value:
  189. The number of elements in BroadcastSockets, or zero on failure.
  190. --*/
  191. {
  192. SOCKADDR_IPX ipxAddr;
  193. SOCKADDR_IN tcpipAddr;
  194. PBROADCASTSOCKET broadcastSocket;
  195. MYASSERT (!BroadcastSockets->Buf && !BroadcastSockets->End);
  196. //
  197. // Open sockets for broadcasts
  198. //
  199. // IPX
  200. ZeroMemory (&ipxAddr, sizeof (ipxAddr));
  201. ipxAddr.sa_family = AF_IPX;
  202. ipxAddr.sa_socket = IPX_BROADCAST_PORT;
  203. broadcastSocket = pOpenOneBroadcastSocket (
  204. BroadcastSockets,
  205. (SOCKADDR *) &ipxAddr,
  206. sizeof (ipxAddr),
  207. AF_IPX,
  208. NSPROTO_IPX,
  209. TEXT("IPX")
  210. );
  211. if (broadcastSocket) {
  212. memset (ipxAddr.sa_nodenum, 0xFF, 6);
  213. CopyMemory (broadcastSocket->BroadcastAddress, &ipxAddr, sizeof (ipxAddr));
  214. }
  215. // TCP/IP
  216. ZeroMemory (&tcpipAddr, sizeof (tcpipAddr));
  217. tcpipAddr.sin_family = AF_INET;
  218. tcpipAddr.sin_addr.s_addr = htonl (INADDR_ANY);
  219. tcpipAddr.sin_port = TCPIP_BROADCAST_PORT;
  220. broadcastSocket = pOpenOneBroadcastSocket (
  221. BroadcastSockets,
  222. (SOCKADDR *) &tcpipAddr,
  223. sizeof (tcpipAddr),
  224. AF_INET,
  225. IPPROTO_UDP,
  226. TEXT("UDP")
  227. );
  228. if (broadcastSocket) {
  229. tcpipAddr.sin_addr.s_addr = htonl (INADDR_BROADCAST);
  230. CopyMemory (broadcastSocket->BroadcastAddress, &tcpipAddr, sizeof (tcpipAddr));
  231. }
  232. return BroadcastSockets->End / sizeof (BROADCASTSOCKET);
  233. }
  234. PLISTENSOCKET
  235. pOpenOneListenSocket (
  236. IN OUT PGROWBUFFER ListenSockets,
  237. IN SOCKADDR *SockAddr,
  238. IN INT SockAddrLen,
  239. IN INT Family,
  240. IN BOOL Multicast,
  241. IN INT Protocol,
  242. IN PCTSTR DebugText
  243. )
  244. /*++
  245. Routine Description:
  246. pOpenOneListenSocket opens a socket for the specified
  247. family/protocol/address combination, sets the socket into SO_REUSEADDR mode,
  248. and puts the socket information in the array stored in the caller's grow
  249. buffer. If Multicast is specified, then SO_BROADCAST is also set.
  250. Otherwise, the socket is set to listen for one connection.
  251. The socket opened will be used to accept connections.
  252. Arguments:
  253. ListenSockets - Specifies the grow buffer that holds the array of
  254. LISTENSOCKET elements. Receives an additional entry on
  255. success.
  256. SockAddr - Specifies the protocol-specific socket address structure
  257. (cast to SOCKADDR), giving the local address for binding.
  258. SockAddrLen - Specifies the length of SockAddr, in bytes
  259. Family - Specifies the protocol family (AF_IPX, AF_INET)
  260. Multicast - Specifies TRUE if the protocol family does not support
  261. streaming sockets, but instead uses datagrams for all data
  262. transfer. (NetBIOS for example is a multicast protocol.)
  263. NOTE: UNSUPPORTED because NetBIOS is not implemented anymore
  264. Protocol - Specifies the protocol (IPPROTO_UDP, NSPROTO_IPX, -lana)
  265. DebugText - Specifies the protocol in text form for debug messages
  266. Return Value:
  267. A pointer to the new LISTENSOCKET element allocated from ListenSockets, or
  268. NULL if the socket could not be opened.
  269. NOTE: ListenSockets->Buf will potentially change on success. Do not rely on
  270. this address.
  271. --*/
  272. {
  273. PLISTENSOCKET listenSocket;
  274. BOOL b;
  275. listenSocket = (PLISTENSOCKET) GbGrow (ListenSockets, sizeof (LISTENSOCKET));
  276. listenSocket->Socket = socket (Family, Multicast ? SOCK_DGRAM : SOCK_STREAM, Protocol);
  277. listenSocket->Datagram = Multicast;
  278. listenSocket->Family = Family;
  279. listenSocket->Protocol = Protocol;
  280. if (listenSocket->Socket != INVALID_SOCKET) {
  281. b = TRUE;
  282. setsockopt (listenSocket->Socket, SOL_SOCKET, SO_REUSEADDR, (PBYTE) &b, sizeof (b));
  283. if (Multicast) {
  284. setsockopt (listenSocket->Socket, SOL_SOCKET, SO_BROADCAST, (PBYTE) &b, sizeof (b));
  285. }
  286. if (bind (listenSocket->Socket, SockAddr, SockAddrLen) ||
  287. (!Multicast && listen (listenSocket->Socket, 1))
  288. ) {
  289. DEBUGMSG ((DBG_ERROR, "Can't bind/listen to %s socket", DebugText));
  290. closesocket (listenSocket->Socket);
  291. listenSocket->Socket = INVALID_SOCKET;
  292. }
  293. }
  294. if (listenSocket->Socket == INVALID_SOCKET) {
  295. ListenSockets->End -= sizeof (LISTENSOCKET);
  296. listenSocket = NULL;
  297. } else {
  298. DEBUGMSG ((
  299. DBG_HOMENET,
  300. "%s is availble for connection on socket %u",
  301. DebugText,
  302. (ListenSockets->End / sizeof (LISTENSOCKET)) - 1
  303. ));
  304. }
  305. return listenSocket;
  306. }
  307. INT
  308. pOpenListenSockets (
  309. OUT PGROWBUFFER ListenSockets
  310. )
  311. /*++
  312. Routine Description:
  313. pOpenListenSockets opens a connection socket on each supported protocol.
  314. Arguments:
  315. ListenSockets - Receives an array of LISTENSOCKET elements (one for each
  316. protocol). IMPORTANT: This parameter must be
  317. zero-initialized by the caller.
  318. Return Value:
  319. The number of elements in ListenSockets, or zero on failure.
  320. --*/
  321. {
  322. SOCKADDR_IPX ipxAddr;
  323. SOCKADDR_IN tcpipAddr;
  324. MYASSERT (!ListenSockets->Buf && !ListenSockets->End);
  325. //
  326. // Open sockets to accept inbound connections
  327. //
  328. // SPX
  329. ZeroMemory (&ipxAddr, sizeof (ipxAddr));
  330. ipxAddr.sa_family = AF_IPX;
  331. ipxAddr.sa_socket = IPX_CONNECT_PORT;
  332. pOpenOneListenSocket (
  333. ListenSockets,
  334. (SOCKADDR *) &ipxAddr,
  335. sizeof (ipxAddr),
  336. AF_IPX,
  337. FALSE,
  338. NSPROTO_SPX,
  339. TEXT("SPX")
  340. );
  341. // TCP/IP
  342. ZeroMemory (&tcpipAddr, sizeof (tcpipAddr));
  343. tcpipAddr.sin_family = AF_INET;
  344. tcpipAddr.sin_port = TCPIP_CONNECT_PORT;
  345. pOpenOneListenSocket (
  346. ListenSockets,
  347. (SOCKADDR *) &tcpipAddr,
  348. sizeof (tcpipAddr),
  349. AF_INET,
  350. FALSE,
  351. IPPROTO_TCP,
  352. TEXT("TCP")
  353. );
  354. return ListenSockets->End / sizeof (LISTENSOCKET);
  355. }
  356. PCTSTR
  357. pGetNameFromMessage (
  358. IN PCWSTR Message
  359. )
  360. /*++
  361. Routine Description:
  362. pGetNameFromMessage extracts the computer name from a broadcast.
  363. Arguments:
  364. Message - Specifies the encoded message.
  365. Return Value:
  366. The computer name encoded in the message, or NULL if the message is garbage.
  367. --*/
  368. {
  369. PCTSTR message = NULL;
  370. PCTSTR orgMessage = NULL;
  371. TCHAR sigStr [sizeof (TEXT("0xFFFFFFFF"))];
  372. DWORD signature = 0;
  373. PCTSTR p;
  374. PCTSTR name = NULL;
  375. INT len;
  376. CHARTYPE ch;
  377. PCTSTR tag = S_64CHARTAG; // must be 64 chars
  378. TCHAR alternateTag[NAME_SIZE_PLUS_NUL];
  379. TCHAR prefix[NAME_SIZE_PLUS_COMMA_PLUS_NUL];
  380. PTSTR q, r;
  381. #ifdef UNICODE
  382. orgMessage = Message;
  383. #else
  384. orgMessage = ConvertWtoA (Message);
  385. #endif
  386. if (!orgMessage) {
  387. return name;
  388. }
  389. message = orgMessage;
  390. __try {
  391. p = _tcschr (message, TEXT(','));
  392. if (!p) {
  393. DEBUGMSG ((DBG_HOMENET, "Invalid Signature"));
  394. __leave;
  395. }
  396. ZeroMemory (sigStr, sizeof (sigStr));
  397. CopyMemory (sigStr, message, min (sizeof (sigStr) - 1, ((UINT)(p - message)) * sizeof (TCHAR)));
  398. _stscanf (sigStr, TEXT("0x%08X"), &signature);
  399. if (signature != HOMENETTR_SIG) {
  400. DEBUGMSG ((DBG_HOMENET, "Signature does not match"));
  401. __leave;
  402. }
  403. message = _tcsinc (p);
  404. if (!message) {
  405. DEBUGMSG ((DBG_HOMENET, "Invalid Signature"));
  406. __leave;
  407. }
  408. if (IsmCopyEnvironmentString (PLATFORM_SOURCE, NULL, TRANSPORT_ENVVAR_HOMENET_TAG, alternateTag)) {
  409. q = GetEndOfString (alternateTag);
  410. r = alternateTag + NAME_SIZE;
  411. while (q < r) {
  412. *q++ = TEXT('@');
  413. }
  414. *r = 0;
  415. tag = alternateTag;
  416. }
  417. DEBUGMSG ((DBG_HOMENET, "Comparing our tag %s against message %s", tag, message));
  418. StringCopy (prefix, tag);
  419. StringCat (prefix, TEXT(","));
  420. if (StringIPrefix (message, prefix)) {
  421. p = message + NAME_SIZE_PLUS_COMMA;
  422. len = 0;
  423. while (*p) {
  424. ch = (CHARTYPE) _tcsnextc (p);
  425. p = _tcsinc (p);
  426. if (ch == TEXT(',')) {
  427. break;
  428. }
  429. if (ch < TEXT('0') || ch > TEXT('9')) {
  430. break;
  431. }
  432. len = len * 10 + (ch - TEXT('0'));
  433. }
  434. if (ch == TEXT(',') && len < MAX_COMPUTER_NAME) {
  435. name = p;
  436. while (*p && len) {
  437. if (*p < 32) {
  438. break;
  439. }
  440. p++;
  441. len--;
  442. }
  443. if (len || *p) {
  444. name = NULL;
  445. }
  446. }
  447. }
  448. ELSE_DEBUGMSG ((DBG_HOMENET, "TAG does not match"));
  449. }
  450. __finally {
  451. #ifndef UNICODE
  452. if (orgMessage) {
  453. FreeConvertedStr (orgMessage);
  454. orgMessage = NULL;
  455. }
  456. #endif
  457. }
  458. return name;
  459. }
  460. VOID
  461. pTranslateBroadcastAddrToConnectAddr (
  462. IN INT Family,
  463. IN OUT PINT Protocol,
  464. IN OUT PBOOL Datagram,
  465. IN OUT SOCKADDR *SockAddr
  466. )
  467. /*++
  468. Routine Description:
  469. pTranslateBroadcastAddrToConnectAddr transforms a broadcast address into a
  470. connection address. The broadcast address is typically obtained from a
  471. datagram response, and must be transformed before accepting a sequenced
  472. connection.
  473. Arguments:
  474. Family - Specifies the protocol family
  475. Protocol - Specifies the datagram protocol; receives the sequenced packet
  476. protocol if available
  477. Datagram - Specifies a pointer to FALSE, receives TRUE if the protocol does
  478. not support sequenced connections.
  479. SockAddr - Specifies the peer socket address. Receives the updated address
  480. (a different port is used for connections).
  481. Return Value:
  482. None.
  483. --*/
  484. {
  485. SOCKADDR_IPX *ipxAddr;
  486. SOCKADDR_IN *tcpipAddr;
  487. switch (Family) {
  488. case AF_INET:
  489. *Protocol = IPPROTO_TCP;
  490. tcpipAddr = (SOCKADDR_IN *) SockAddr;
  491. tcpipAddr->sin_port = TCPIP_CONNECT_PORT;
  492. break;
  493. case AF_IPX:
  494. *Protocol = NSPROTO_SPX;
  495. ipxAddr = (SOCKADDR_IPX *) SockAddr;
  496. ipxAddr->sa_socket = IPX_CONNECT_PORT;
  497. break;
  498. }
  499. }
  500. VOID
  501. pResetPort (
  502. IN INT Family,
  503. IN OUT SOCKADDR *SockAddr
  504. )
  505. /*++
  506. Routine Description:
  507. pResetPort sets the port to zero for TCP/IP, so that the system will pick
  508. an unused port for the local address. This is used when connecting.
  509. Arguments:
  510. Family - Specifies the protocol family (such as AF_INET)
  511. SockAddr - Specifies the address to reset
  512. Return Value:
  513. None.
  514. --*/
  515. {
  516. SOCKADDR_IN *tcpipAddr;
  517. switch (Family) {
  518. case AF_INET:
  519. tcpipAddr = (SOCKADDR_IN *) SockAddr;
  520. tcpipAddr->sin_port = 0;
  521. break;
  522. }
  523. }
  524. INT
  525. pSourceBroadcast (
  526. IN OUT PBROADCASTARGS Args
  527. )
  528. /*++
  529. Routine Description:
  530. pSourceBroadcast implements the name resolution mechanism for the source
  531. end of the connection. This involves checking for cancel, collecting
  532. inbound datagrams from all transports, and parsing the datagrams to obtain
  533. the server name.
  534. Arguments:
  535. Args - Specifies a structure containing all of the parameters, such as
  536. the socket array and socket addresses.
  537. Return Value:
  538. The number of server addresses collected, or 0 if the collection was
  539. cancelled.
  540. --*/
  541. {
  542. INT i;
  543. INT bytesIn;
  544. DWORD rc;
  545. WCHAR message[256];
  546. FD_SET set;
  547. TIMEVAL zero = {0,0};
  548. INT waitCycle = -1;
  549. BOOL result = FALSE;
  550. PCTSTR name;
  551. PCONNECTADDRESS address;
  552. PCONNECTADDRESS end;
  553. PBROADCASTSOCKET broadcastSocket;
  554. BYTE remoteAddr[MAX_SOCKADDR];
  555. INT remoteAddrLen;
  556. DWORD startTick = GetTickCount();
  557. for (;;) {
  558. //
  559. // Check cancel
  560. //
  561. if (g_StopHandle) {
  562. rc = WaitForSingleObject (g_StopHandle, 0);
  563. } else {
  564. rc = WAIT_FAILED;
  565. }
  566. if (rc == WAIT_OBJECT_0 || IsmCheckCancel()) {
  567. result = FALSE;
  568. break;
  569. }
  570. //
  571. // Check time to live
  572. //
  573. if (Args->Timeout) {
  574. if (((GetTickCount() - startTick) / 1000) >= Args->Timeout) {
  575. DEBUGMSG ((DBG_HOMENET, "Name search timed out"));
  576. break;
  577. }
  578. }
  579. if (waitCycle > -1) {
  580. waitCycle--;
  581. if (!waitCycle) {
  582. break;
  583. }
  584. }
  585. //
  586. // Check for a message
  587. //
  588. FD_ZERO (&set);
  589. for (i = 0 ; i < Args->BroadcastCount ; i++) {
  590. FD_SET (Args->BroadcastSockets[i].Socket, &set);
  591. }
  592. i = select (0, &set, NULL, NULL, &zero);
  593. if (i > 0) {
  594. for (i = 0 ; i < Args->BroadcastCount ; i++) {
  595. broadcastSocket = &Args->BroadcastSockets[i];
  596. if (FD_ISSET (broadcastSocket->Socket, &set)) {
  597. remoteAddrLen = MAX_SOCKADDR;
  598. bytesIn = recvfrom (
  599. broadcastSocket->Socket,
  600. (PSTR) message,
  601. 254 * sizeof (WCHAR),
  602. 0,
  603. (SOCKADDR *) remoteAddr,
  604. &remoteAddrLen
  605. );
  606. if (bytesIn >= (MIN_MESSAGE_SIZE * sizeof (WCHAR))) {
  607. message[bytesIn] = 0;
  608. message[bytesIn + 1] = 0;
  609. //
  610. // Parse the inbound text. It must be in the format of
  611. //
  612. // <signature>,<tag>,<tchars>,<name>
  613. //
  614. // <tag> must be 64 characters, and is usmt-v2 by default
  615. // (followed by fill numbers).
  616. //
  617. name = pGetNameFromMessage (message);
  618. if (name) {
  619. // once we receive something, wait 5 additional seconds for other inbound datagrams
  620. if (waitCycle == -1) {
  621. waitCycle = 20;
  622. }
  623. result = TRUE;
  624. //
  625. // Scan the address list for the name
  626. //
  627. address = (PCONNECTADDRESS) Args->AddressArray->Buf;
  628. end = (PCONNECTADDRESS) (Args->AddressArray->Buf + Args->AddressArray->End);
  629. while (address < end) {
  630. if (StringIMatch (address->DestinationName, name)) {
  631. if (address->Family == broadcastSocket->Family) {
  632. break;
  633. }
  634. }
  635. address++;
  636. }
  637. if (address >= end) {
  638. //
  639. // New computer name; add to the address list
  640. //
  641. address = (PCONNECTADDRESS) GbGrow (Args->AddressArray, sizeof (CONNECTADDRESS));
  642. address->RemoteAddressLen = remoteAddrLen;
  643. CopyMemory (address->RemoteAddress, remoteAddr, remoteAddrLen);
  644. address->LocalAddressLen = MAX_SOCKADDR;
  645. if (getsockname (
  646. broadcastSocket->Socket,
  647. (SOCKADDR *) address->LocalAddress,
  648. &address->LocalAddressLen
  649. )) {
  650. address->LocalAddressLen = broadcastSocket->AddressLen;
  651. ZeroMemory (address->LocalAddress, broadcastSocket->AddressLen);
  652. DEBUGMSG ((DBG_HOMENET, "Failed to get local socket name; using nul name instead"));
  653. }
  654. address->Family = broadcastSocket->Family;
  655. address->Protocol = broadcastSocket->Protocol;
  656. address->Datagram = FALSE;
  657. pTranslateBroadcastAddrToConnectAddr (
  658. address->Family,
  659. &address->Protocol,
  660. &address->Datagram,
  661. (SOCKADDR *) &address->RemoteAddress
  662. );
  663. StringCopy (address->DestinationName, name);
  664. DEBUGMSG ((DBG_HOMENET, "Destination found: %s (protocol %i)", name, address->Family));
  665. }
  666. }
  667. ELSE_DEBUGMSGW ((DBG_HOMENET, "garbage found: %s", message));
  668. }
  669. }
  670. }
  671. }
  672. Sleep (250);
  673. }
  674. return result ? Args->AddressArray->End / sizeof (CONNECTADDRESS) : 0;
  675. }
  676. BOOL
  677. pIsAddrFromLocalSubnet (
  678. IN SOCKET Socket,
  679. IN INT Family,
  680. IN SOCKADDR *Address,
  681. IN INT AddressLength
  682. )
  683. {
  684. SOCKADDR_IPX *ipxAddr;
  685. SOCKADDR_IN *tcpipAddr;
  686. BOOL result = TRUE;
  687. IPX_ADDRESS_DATA ipxLocalAddr;
  688. INT size;
  689. PWSAIOCTL wsaIoctlFn;
  690. HANDLE lib;
  691. INT rc;
  692. INTERFACE_INFO info[32];
  693. DWORD bytesRead;
  694. INT i;
  695. INT j;
  696. SOCKADDR_IN localAddr;
  697. PBYTE localNetPtr;
  698. PBYTE remoteNetPtr;
  699. PBYTE subnetMaskPtr;
  700. INT k;
  701. switch (Family) {
  702. case AF_INET:
  703. tcpipAddr = (SOCKADDR_IN *) Address;
  704. i = sizeof (localAddr);
  705. if (getsockname (Socket, (SOCKADDR *) &localAddr, &i)) {
  706. DEBUGMSG ((DBG_ERROR, "Can't get local socket addr"));
  707. break;
  708. }
  709. lib = LoadLibrary (TEXT("ws2_32.dll"));
  710. if (lib) {
  711. wsaIoctlFn = (PWSAIOCTL) GetProcAddress (lib, "WSAIoctl");
  712. if (wsaIoctlFn) {
  713. rc = wsaIoctlFn (
  714. Socket,
  715. SIO_GET_INTERFACE_LIST,
  716. NULL,
  717. 0,
  718. info,
  719. sizeof (info),
  720. &bytesRead,
  721. NULL,
  722. NULL
  723. );
  724. if (rc != SOCKET_ERROR) {
  725. j = (INT) (bytesRead / sizeof (INTERFACE_INFO));
  726. for (i = 0 ; i < j ; i++) {
  727. if (!memcmp (
  728. &localAddr.sin_addr,
  729. &info[i].iiAddress.AddressIn.sin_addr,
  730. sizeof (struct in_addr)
  731. )) {
  732. localNetPtr = (PBYTE) &localAddr.sin_addr;
  733. remoteNetPtr = (PBYTE) &info[i].iiAddress.AddressIn.sin_addr;
  734. subnetMaskPtr = (PBYTE) &info[i].iiNetmask.AddressIn.sin_addr;
  735. for (k = 0 ; k < sizeof (struct in_addr) ; k++) {
  736. localNetPtr[k] &= subnetMaskPtr[k];
  737. remoteNetPtr[k] &= subnetMaskPtr[k];
  738. if (localNetPtr[k] != remoteNetPtr[k]) {
  739. break;
  740. }
  741. }
  742. if (k < sizeof (struct in_addr)) {
  743. LOG ((LOG_WARNING, (PCSTR) MSG_REFUSE_OUTSIDE_CONNECTION));
  744. } else {
  745. DEBUGMSG ((DBG_HOMENET, "Found interface on the same subnet!"));
  746. }
  747. break;
  748. }
  749. }
  750. }
  751. ELSE_DEBUGMSG ((DBG_ERROR, "WSAIoctl failed"));
  752. }
  753. ELSE_DEBUGMSG ((DBG_WARNING, "Can't load WSAIoctl"));
  754. FreeLibrary (lib);
  755. }
  756. ELSE_DEBUGMSG ((DBG_WARNING, "Can't load ws2_32.dll"));
  757. break;
  758. case AF_IPX:
  759. ipxAddr = (SOCKADDR_IPX *) Address;
  760. //
  761. // Compare the specified address against the local address of the socket
  762. //
  763. size = sizeof (ipxLocalAddr);
  764. if (!getsockopt (Socket, NSPROTO_IPX, IPX_GETNETINFO, (PBYTE) &ipxLocalAddr, &size)) {
  765. if (memcmp (ipxAddr->sa_netnum, ipxLocalAddr.netnum, 4)) {
  766. if (ipxAddr->sa_netnum[0] || ipxAddr->sa_netnum[1] ||
  767. ipxAddr->sa_netnum[2] || ipxAddr->sa_netnum[3]
  768. ) {
  769. LOG ((LOG_WARNING, (PCSTR) MSG_REFUSE_OUTSIDE_CONNECTION_IPX));
  770. result = FALSE;
  771. }
  772. }
  773. }
  774. break;
  775. }
  776. return result;
  777. }
  778. BOOL
  779. pDestinationBroadcast (
  780. IN OUT PBROADCASTARGS Args
  781. )
  782. /*++
  783. Routine Description:
  784. pDestinationBroadcast implements the name resolution mechanism for the
  785. destination end of the connection. This involves checking for cancel, and
  786. sending out regular datagrams to all transports to provide the server name.
  787. At the same time, listen connections are monitored, and the datagram traffic
  788. is stopped once one connection is accepted.
  789. Arguments:
  790. Args - Specifies a structure containing all of the parameters, such as the
  791. socket array and socket addresses. Receives the connection address.
  792. Return Value:
  793. TRUE if a connection was accepted, or FALSE if cancel was detected.
  794. --*/
  795. {
  796. INT i;
  797. DWORD rc;
  798. INT socketNum = 0;
  799. WCHAR message[256];
  800. TCHAR name[128];
  801. UINT size;
  802. FD_SET set;
  803. TIMEVAL zero = {0,0};
  804. PBROADCASTSOCKET broadcastSocket;
  805. BOOL result = FALSE;
  806. PCTSTR tag = S_64CHARTAG; // must be 64 chars
  807. TCHAR alternateTag[NAME_SIZE_PLUS_NUL];
  808. PTSTR p, q;
  809. LINGER linger;
  810. size = MAX_COMPUTER_NAME;
  811. GetComputerName (name, &size);
  812. //
  813. // Get the tag that is registered in the environment
  814. //
  815. if (IsmCopyEnvironmentString (PLATFORM_DESTINATION, NULL, TRANSPORT_ENVVAR_HOMENET_TAG, alternateTag)) {
  816. p = GetEndOfString (alternateTag);
  817. q = alternateTag + NAME_SIZE;
  818. if (p) {
  819. while (p < q) {
  820. *p++ = TEXT('@');
  821. }
  822. }
  823. *q = 0;
  824. tag = alternateTag;
  825. }
  826. DEBUGMSG ((DBG_HOMENET, "Broadcasting using the following tag: %s", tag));
  827. #ifdef UNICODE
  828. size = wsprintfW (message, L"0x%08X,%s,%u,%s", HOMENETTR_SIG, tag, TcharCount (name), name);
  829. #else
  830. size = wsprintfW (message, L"0x%08X,%S,%u,%S", HOMENETTR_SIG, tag, TcharCount (name), name);
  831. #endif
  832. size = (size + 1) * sizeof (WCHAR);
  833. for (;;) {
  834. //
  835. // Check cancel
  836. //
  837. if (g_StopHandle) {
  838. rc = WaitForSingleObject (g_StopHandle, 0);
  839. } else {
  840. rc = WAIT_FAILED;
  841. }
  842. if (rc == WAIT_OBJECT_0 || IsmCheckCancel()) {
  843. break;
  844. }
  845. if (g_BackgroundThreadTerminate) {
  846. rc = WaitForSingleObject (g_BackgroundThreadTerminate, 0);
  847. if (rc == WAIT_OBJECT_0) {
  848. break;
  849. }
  850. }
  851. //
  852. // Send out the message
  853. //
  854. broadcastSocket = &Args->BroadcastSockets[socketNum];
  855. i = sendto (
  856. broadcastSocket->Socket,
  857. (PSTR) message,
  858. size,
  859. 0,
  860. (SOCKADDR *) broadcastSocket->BroadcastAddress,
  861. broadcastSocket->AddressLen
  862. );
  863. if (i == SOCKET_ERROR) {
  864. DEBUGMSG ((DBG_VERBOSE, "Error sending on socket %u: %u", socketNum, WSAGetLastError()));
  865. } else {
  866. Sleep (350);
  867. DEBUGMSG ((DBG_HOMENET, "Sent data on socket %u", socketNum));
  868. }
  869. socketNum++;
  870. if (socketNum >= Args->BroadcastCount) {
  871. socketNum = 0;
  872. }
  873. //
  874. // Check for an inbound connection
  875. //
  876. FD_ZERO (&set);
  877. for (i = 0 ; i < Args->ListenCount ; i++) {
  878. FD_SET (Args->ListenSockets[i].Socket, &set);
  879. }
  880. i = select (0, &set, NULL, NULL, &zero);
  881. if (i > 0) {
  882. DEBUGMSG ((DBG_HOMENET, "Connection request count = %i", i));
  883. for (i = 0 ; i < Args->ListenCount ; i++) {
  884. if (FD_ISSET (Args->ListenSockets[i].Socket, &set)) {
  885. Args->ConnectionSocket.RemoteAddressLen = MAX_SOCKADDR;
  886. if (!Args->ListenSockets[i].Datagram) {
  887. Args->ConnectionSocket.Socket = accept (
  888. Args->ListenSockets[i].Socket,
  889. (SOCKADDR *) Args->ConnectionSocket.RemoteAddress,
  890. &Args->ConnectionSocket.RemoteAddressLen
  891. );
  892. //
  893. // Verify socket connection is on the subnet only
  894. //
  895. if (!pIsAddrFromLocalSubnet (
  896. Args->ConnectionSocket.Socket,
  897. Args->ListenSockets[i].Family,
  898. (SOCKADDR *) Args->ConnectionSocket.RemoteAddress,
  899. Args->ConnectionSocket.RemoteAddressLen
  900. )) {
  901. LOG ((LOG_WARNING, (PCSTR) MSG_OUTSIDE_OF_LOCAL_SUBNET));
  902. closesocket (Args->ConnectionSocket.Socket);
  903. Args->ConnectionSocket.Socket = INVALID_SOCKET;
  904. } else {
  905. linger.l_onoff = 1;
  906. linger.l_linger = IDLE_TIMEOUT;
  907. setsockopt (
  908. Args->ConnectionSocket.Socket,
  909. SOL_SOCKET,
  910. SO_LINGER,
  911. (PBYTE) &linger,
  912. sizeof (linger)
  913. );
  914. DEBUGMSG ((DBG_HOMENET, "Connection requested"));
  915. }
  916. } else {
  917. DEBUGMSG ((DBG_HOMENET, "Accepting datagram connection"));
  918. if (DuplicateHandle (
  919. GetCurrentProcess(),
  920. (HANDLE) Args->ListenSockets[i].Socket,
  921. GetCurrentProcess(),
  922. (HANDLE *) &Args->ConnectionSocket.Socket,
  923. 0,
  924. FALSE,
  925. DUPLICATE_SAME_ACCESS
  926. )) {
  927. getpeername (
  928. Args->ConnectionSocket.Socket,
  929. (SOCKADDR *) Args->ConnectionSocket.RemoteAddress,
  930. &Args->ConnectionSocket.RemoteAddressLen
  931. );
  932. } else {
  933. DEBUGMSG ((DBG_ERROR, "Can't duplicate socket handle"));
  934. Args->ConnectionSocket.Socket = INVALID_SOCKET;
  935. }
  936. }
  937. if (Args->ConnectionSocket.Socket != INVALID_SOCKET) {
  938. Args->ConnectionSocket.Family = Args->ListenSockets[i].Family;
  939. Args->ConnectionSocket.Protocol = Args->ListenSockets[i].Protocol;
  940. Args->ConnectionSocket.Datagram = Args->ListenSockets[i].Datagram;
  941. ZeroMemory (&Args->ConnectionSocket.DatagramPool, sizeof (DATAGRAM_POOL));
  942. if (Args->ConnectionSocket.Datagram) {
  943. Args->ConnectionSocket.DatagramPool.Pool = PmCreatePool();
  944. Args->ConnectionSocket.DatagramPool.LastPacketNumber = (UINT) -1;
  945. }
  946. Args->ConnectionSocket.LocalAddressLen = MAX_SOCKADDR;
  947. if (getsockname (
  948. Args->ConnectionSocket.Socket,
  949. (SOCKADDR *) Args->ConnectionSocket.LocalAddress,
  950. &Args->ConnectionSocket.LocalAddressLen
  951. )) {
  952. Args->ConnectionSocket.LocalAddressLen = broadcastSocket->AddressLen;
  953. ZeroMemory (Args->ConnectionSocket.LocalAddress, broadcastSocket->AddressLen);
  954. DEBUGMSG ((DBG_HOMENET, "Failed to get local socket name; using nul name instead"));
  955. }
  956. DEBUGMSG ((DBG_HOMENET, "Connection accepted"));
  957. result = TRUE;
  958. break;
  959. } else {
  960. DEBUGMSG ((DBG_ERROR, "select indicated connection, but accept failed"));
  961. }
  962. }
  963. }
  964. if (result) {
  965. break;
  966. }
  967. }
  968. }
  969. return result;
  970. }
  971. BOOL
  972. pGetDomainUserName (
  973. OUT PTSTR UserNameBuf // 65 char buffer
  974. )
  975. {
  976. HKEY domainLogonKey;
  977. PDWORD data;
  978. BOOL result = TRUE;
  979. DWORD size;
  980. NET_API_STATUS rc;
  981. PWKSTA_INFO_102 buffer;
  982. HANDLE netApi32Lib;
  983. PNETWKSTAGETINFO netWkstaGetInfo;
  984. PNETAPIBUFFERFREE netApiBufferFree;
  985. BYTE sid[256];
  986. DWORD sidSize;
  987. WCHAR domain[256];
  988. DWORD domainSize;
  989. SID_NAME_USE use;
  990. if (!ISNT()) {
  991. //
  992. // Require the Log On To Domain setting to be checked
  993. //
  994. SetLastError (ERROR_SUCCESS);
  995. domainLogonKey = OpenRegKeyStr (TEXT("HKLM\\Network\\Logon"));
  996. if (!domainLogonKey) {
  997. DEBUGMSG ((DBG_HOMENET, "No HKLM\\Network\\Logon key"));
  998. return FALSE;
  999. }
  1000. data = (PDWORD) GetRegValueBinary (domainLogonKey, TEXT("LMLogon"));
  1001. if (!data) {
  1002. DEBUGMSG ((DBG_HOMENET, "No LMLogon value"));
  1003. result = FALSE;
  1004. } else {
  1005. if (!(*data)) {
  1006. DEBUGMSG ((DBG_HOMENET, "Domain logon is not enabled"));
  1007. result = FALSE;
  1008. }
  1009. FreeAlloc (data);
  1010. }
  1011. CloseRegKey (domainLogonKey);
  1012. } else {
  1013. //
  1014. // Require domain membership
  1015. //
  1016. netApi32Lib = LoadLibrary (TEXT("netapi32.dll"));
  1017. if (netApi32Lib) {
  1018. netWkstaGetInfo = (PNETWKSTAGETINFO) GetProcAddress (netApi32Lib, "NetWkstaGetInfo");
  1019. netApiBufferFree = (PNETAPIBUFFERFREE) GetProcAddress (netApi32Lib, "NetApiBufferFree");
  1020. } else {
  1021. netWkstaGetInfo = NULL;
  1022. netApiBufferFree = NULL;
  1023. }
  1024. if (!netWkstaGetInfo || !netApiBufferFree) {
  1025. DEBUGMSG ((DBG_HOMENET, "Can't get net wksta apis"));
  1026. result = FALSE;
  1027. } else {
  1028. rc = netWkstaGetInfo (NULL, 102, (PBYTE *) &buffer);
  1029. if (rc == NO_ERROR) {
  1030. result = buffer->wki102_langroup && (buffer->wki102_langroup[0] != 0);
  1031. if (result) {
  1032. DEBUGMSGW ((DBG_HOMENET, "Getting account type of %s", buffer->wki102_langroup));
  1033. sidSize = ARRAYSIZE(sid);
  1034. domainSize = ARRAYSIZE(domain);
  1035. result = LookupAccountNameW (
  1036. NULL,
  1037. buffer->wki102_langroup,
  1038. sid,
  1039. &sidSize,
  1040. domain,
  1041. &domainSize,
  1042. &use
  1043. );
  1044. DEBUGMSG ((DBG_HOMENET, "Account type result is %u (use=%u)", result, use));
  1045. }
  1046. ELSE_DEBUGMSG ((DBG_HOMENET, "No langroup specified"));
  1047. netApiBufferFree (buffer);
  1048. } else {
  1049. DEBUGMSG ((DBG_HOMENET, "Can't get net wksta info"));
  1050. result = FALSE;
  1051. }
  1052. }
  1053. if (netApi32Lib) {
  1054. FreeLibrary (netApi32Lib);
  1055. }
  1056. }
  1057. //
  1058. // Make sure a user name is specified
  1059. //
  1060. if (result) {
  1061. size = NAME_SIZE_PLUS_NUL;
  1062. if (!GetUserName (UserNameBuf, &size)) {
  1063. result = FALSE;
  1064. } else if (*UserNameBuf == 0) {
  1065. result = FALSE;
  1066. }
  1067. if (result) {
  1068. DEBUGMSG ((DBG_HOMENET, "Domain user: %s", UserNameBuf));
  1069. } else {
  1070. DEBUGMSG ((DBG_HOMENET, "Not on domain"));
  1071. }
  1072. }
  1073. return result;
  1074. }
  1075. INT
  1076. pNameResolver (
  1077. IN MIG_PLATFORMTYPEID Platform,
  1078. OUT PGROWBUFFER AddressBuffer,
  1079. IN UINT SourceTimeout,
  1080. OUT PCONNECTIONSOCKET ConnectionSocket
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. pNameResolver implements the name resolution protocol. The source side
  1085. collects datagrams, looking for a destination to choose from. The
  1086. destination side sends out broadcasts to announce themselves, and accepts a
  1087. connection from the source.
  1088. At the end of name resolution, an event is signaled. This is used for
  1089. coordination with cancel.
  1090. Arguments:
  1091. AddressBuffer - Receives the array of addresses that is used on the
  1092. source side to collect a list of destinations.
  1093. This buffer must be zero-initialized by the caller.
  1094. This argument is NULL on the destination side.
  1095. SourceTimeout - Specifies the number of seconds to wait for a broadcast,
  1096. or zero to wait forever. The timeout only affects the
  1097. source side.
  1098. ConnectionSocket - Receives the connection socket and address information
  1099. that is used on the destination side. This argument
  1100. is NULL on the source side.
  1101. Return Value:
  1102. Source Side: The number of addresses in AddressBuffer, or zero if an error
  1103. occurred
  1104. Destination Side: 1 indicating that ConnectionSocket is valid, or zero if
  1105. an error occurred.
  1106. --*/
  1107. {
  1108. BROADCASTARGS args;
  1109. INT i;
  1110. INT result = 0;
  1111. BOOL b;
  1112. BOOL connected = FALSE;
  1113. GROWBUFFER broadcastSockets = INIT_GROWBUFFER;
  1114. GROWBUFFER listenSockets = INIT_GROWBUFFER;
  1115. INT broadcastSocketCount;
  1116. INT listenSocketCount = 0;
  1117. BOOL destinationMode;
  1118. TCHAR envTag[NAME_SIZE_PLUS_NUL];
  1119. __try {
  1120. //
  1121. // If tag is not set, then force it to the user name if domains are enabled
  1122. //
  1123. if (!IsmCopyEnvironmentString (Platform, NULL, TRANSPORT_ENVVAR_HOMENET_TAG, envTag)) {
  1124. if (pGetDomainUserName (envTag)) {
  1125. IsmSetEnvironmentString (Platform, NULL, TRANSPORT_ENVVAR_HOMENET_TAG, envTag);
  1126. }
  1127. }
  1128. if (!AddressBuffer && ConnectionSocket) {
  1129. destinationMode = TRUE;
  1130. } else if (AddressBuffer && !ConnectionSocket) {
  1131. destinationMode = FALSE;
  1132. } else {
  1133. MYASSERT (FALSE);
  1134. __leave;
  1135. }
  1136. //
  1137. // In source mode, we collect datagrams sent by destinations on the network. After
  1138. // the first datagram is received, collection continues for 15 seconds. At
  1139. // that point, we have a list of socket addresses, protocol, and destination names.
  1140. //
  1141. // In destination mode, we send out periodic broadcasts, and we wait until a source
  1142. // connects or the cancel event is signaled.
  1143. //
  1144. broadcastSocketCount = pOpenBroadcastSockets (&broadcastSockets);
  1145. if (!broadcastSocketCount) {
  1146. __leave;
  1147. }
  1148. if (destinationMode) {
  1149. listenSocketCount = pOpenListenSockets (&listenSockets);
  1150. if (!listenSocketCount) {
  1151. DEBUGMSG ((DBG_ERROR, "Able to set up broadcast sockets but not connection sockets"));
  1152. __leave;
  1153. }
  1154. }
  1155. // call mode-specific routine
  1156. ZeroMemory (&args, sizeof (args));
  1157. args.AddressArray = AddressBuffer;
  1158. args.BroadcastSockets = (PBROADCASTSOCKET) broadcastSockets.Buf;
  1159. args.BroadcastCount = broadcastSocketCount;
  1160. args.ListenSockets = (PLISTENSOCKET) listenSockets.Buf;
  1161. args.ListenCount = listenSocketCount;
  1162. args.Timeout = SourceTimeout;
  1163. b = destinationMode ? pDestinationBroadcast (&args) : pSourceBroadcast (&args);
  1164. //
  1165. // Clean up all sockets
  1166. //
  1167. PushError();
  1168. for (i = 0 ; i < args.BroadcastCount ; i++) {
  1169. closesocket (args.BroadcastSockets[i].Socket);
  1170. }
  1171. if (destinationMode) {
  1172. for (i = 0 ; i < args.ListenCount ; i++) {
  1173. closesocket (args.ListenSockets[i].Socket);
  1174. }
  1175. }
  1176. PopError();
  1177. if (b) {
  1178. if (destinationMode) {
  1179. CopyMemory (ConnectionSocket, &args.ConnectionSocket, sizeof (CONNECTIONSOCKET));
  1180. result = 1;
  1181. } else {
  1182. result = AddressBuffer->End / sizeof (CONNECTADDRESS);
  1183. }
  1184. }
  1185. }
  1186. __finally {
  1187. PushError();
  1188. GbFree (&broadcastSockets);
  1189. GbFree (&listenSockets);
  1190. if (g_ConnectionDone) {
  1191. SetEvent (g_ConnectionDone);
  1192. }
  1193. PopError();
  1194. }
  1195. return result;
  1196. }
  1197. INT
  1198. pSendWithTimeout (
  1199. IN SOCKET Socket,
  1200. IN PCBYTE Data,
  1201. IN UINT DataLen,
  1202. IN INT Flags
  1203. )
  1204. {
  1205. FD_SET writeSet;
  1206. FD_SET errorSet;
  1207. TIMEVAL timeout = {1,0};
  1208. UINT timeToLive = GetTickCount() + IDLE_TIMEOUT * 1000;
  1209. INT result;
  1210. //
  1211. // Wait up to IDLE_TIMEOUT seconds for the socket to be sendable
  1212. //
  1213. do {
  1214. FD_ZERO (&writeSet);
  1215. FD_SET (Socket, &writeSet);
  1216. FD_ZERO (&errorSet);
  1217. FD_SET (Socket, &errorSet);
  1218. //
  1219. // Check the ISM cancel flag
  1220. //
  1221. if (IsmCheckCancel ()) {
  1222. SetLastError (ERROR_CANCELLED);
  1223. return SOCKET_ERROR;
  1224. }
  1225. //
  1226. // Wait 1 second for the socket to be writable
  1227. //
  1228. result = select (0, NULL, &writeSet, &errorSet, &timeout);
  1229. if (result) {
  1230. if (FD_ISSET (Socket, &writeSet)) {
  1231. return send (Socket, Data, DataLen, Flags);
  1232. }
  1233. LOG ((LOG_ERROR, (PCSTR) MSG_SOCKET_HAS_ERROR));
  1234. return SOCKET_ERROR;
  1235. }
  1236. } while ((timeToLive - GetTickCount()) < IDLE_TIMEOUT * 1000);
  1237. LOG ((LOG_ERROR, (PCSTR) MSG_SOCKET_SEND_TIMEOUT));
  1238. return SOCKET_ERROR;
  1239. }
  1240. BOOL
  1241. pSendExactData (
  1242. IN SOCKET Socket,
  1243. IN PCBYTE Data,
  1244. IN UINT DataLen
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. pSendExactData sends data to the specified socket.
  1249. [TODO: need to support datagram mode]
  1250. Arguments:
  1251. Socket - Specifies the socket to send data to
  1252. Data - Specifies the data to send
  1253. DataLen - Specifies the number of bytes in Data
  1254. Return Value:
  1255. TRUE if the data was sent, FALSE otherwise.
  1256. --*/
  1257. {
  1258. INT result;
  1259. PCBYTE pos;
  1260. UINT bytesLeft;
  1261. UINT packetSize;
  1262. bytesLeft = DataLen;
  1263. pos = Data;
  1264. while (bytesLeft) {
  1265. if (IsmCheckCancel()) {
  1266. return FALSE;
  1267. }
  1268. packetSize = min (1024, bytesLeft);
  1269. result = pSendWithTimeout (Socket, pos, packetSize, 0);
  1270. if (result > 0) {
  1271. bytesLeft -= (UINT) result;
  1272. pos += result;
  1273. } else {
  1274. if (GetLastError() == WSAENOBUFS) {
  1275. Sleep (100);
  1276. } else {
  1277. return FALSE;
  1278. }
  1279. }
  1280. }
  1281. return bytesLeft == 0;
  1282. }
  1283. BOOL
  1284. pSendDatagramData (
  1285. IN SOCKET Socket,
  1286. IN PDATAGRAM_POOL DatagramPool,
  1287. IN PCBYTE Data,
  1288. IN UINT DataLen
  1289. )
  1290. /*++
  1291. Routine Description:
  1292. pSendDatagramData puts data on the wire in the form of small, numbered
  1293. packets. The packets can potentially scatter and be received out of order,
  1294. so the packets are numbered such that they can be reassembled properly.
  1295. It is assumed that the datagram protocol is reliable (datagrams are not
  1296. dropped), and that the underlying protocol implements the naggle algorithm
  1297. to cache packets for efficiency.
  1298. Arguments:
  1299. Socket - Specifies the datagram socket to send data on
  1300. DatagramPool - Specifies a structure that is used to track packets
  1301. Data - Specifies the data to send
  1302. DataLen - Specifies the length of the data to send
  1303. Return Value:
  1304. TRUE if data was sent, FALSE otherwise
  1305. --*/
  1306. {
  1307. PDATAGRAM_PACKET header;
  1308. BYTE buffer[512];
  1309. PBYTE dataPtr;
  1310. UINT bytesSent = 0;
  1311. UINT bytesToSend;
  1312. header = (PDATAGRAM_PACKET) buffer;
  1313. dataPtr = (PBYTE) (&header[1]);
  1314. do {
  1315. bytesToSend = DataLen - bytesSent;
  1316. bytesToSend = min (bytesToSend, 256);
  1317. header->PacketNumber = DatagramPool->SendSequenceNumber;
  1318. DatagramPool->SendSequenceNumber++;
  1319. header->DataLength = (WORD) bytesToSend;
  1320. CopyMemory (dataPtr, Data, bytesToSend);
  1321. if (!pSendExactData (
  1322. Socket,
  1323. (PBYTE) header,
  1324. bytesToSend + sizeof (DATAGRAM_PACKET)
  1325. )) {
  1326. break;
  1327. }
  1328. Data += bytesToSend;
  1329. bytesSent += bytesToSend;
  1330. } while (bytesSent < DataLen);
  1331. return bytesSent == DataLen;
  1332. }
  1333. BOOL
  1334. pSendData (
  1335. IN SOCKET Socket,
  1336. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  1337. IN PCBYTE Data,
  1338. IN UINT DataLen
  1339. )
  1340. {
  1341. if (!DatagramPool) {
  1342. return pSendExactData (Socket, Data, DataLen);
  1343. }
  1344. return pSendDatagramData (Socket, DatagramPool, Data, DataLen);
  1345. }
  1346. INT
  1347. pRecvWithTimeout (
  1348. IN SOCKET Socket,
  1349. IN PBYTE Data,
  1350. IN UINT DataLen,
  1351. IN INT Flags,
  1352. IN UINT Timeout OPTIONAL
  1353. )
  1354. /*++
  1355. Routine Description:
  1356. pRecvWithTimeout implements a basic socket recv call with a IDLE_TIMEOUT second
  1357. timeout and with a check for the ISM cancel flag.
  1358. Arguments:
  1359. Socket - Specifies the socket to recv from
  1360. Data - Specifies the data buffer
  1361. DataLen - Specifies the length of data buffer
  1362. Flags - Specifies zero for normal recv, or MSG_PEEK
  1363. Return Value:
  1364. The number of bytes read, or SOCKET_ERROR. GetLastError contains the reason
  1365. for failure.
  1366. --*/
  1367. {
  1368. FD_SET readSet;
  1369. FD_SET errorSet;
  1370. TIMEVAL timeout = {1,0};
  1371. INT timeToLive;
  1372. INT result;
  1373. if (Timeout == 0) {
  1374. Timeout = IDLE_TIMEOUT * 1000;
  1375. }
  1376. timeToLive = GetTickCount() + Timeout;
  1377. //
  1378. // Wait up to IDLE_TIMEOUT seconds for the socket to have data
  1379. //
  1380. do {
  1381. FD_ZERO (&readSet);
  1382. FD_SET (Socket, &readSet);
  1383. FD_ZERO (&errorSet);
  1384. FD_SET (Socket, &errorSet);
  1385. //
  1386. // Check the ISM cancel flag
  1387. //
  1388. if (IsmCheckCancel ()) {
  1389. SetLastError (ERROR_CANCELLED);
  1390. return SOCKET_ERROR;
  1391. }
  1392. //
  1393. // Wait 1 second for the socket to be readable
  1394. //
  1395. result = select (0, &readSet, NULL, &errorSet, &timeout);
  1396. if (result) {
  1397. if (FD_ISSET (Socket, &readSet)) {
  1398. result = recv (Socket, Data, DataLen, Flags);
  1399. return result;
  1400. }
  1401. if (FD_ISSET (Socket, &errorSet)) {
  1402. LOG ((LOG_ERROR, (PCSTR) MSG_SOCKET_HAS_ERROR));
  1403. return SOCKET_ERROR;
  1404. }
  1405. DEBUGMSG ((DBG_HOMENET, "select returned %i but socket is not in readSet or errorSet", result));
  1406. }
  1407. } while ((timeToLive - GetTickCount()) < Timeout);
  1408. LOG ((LOG_ERROR, (PCSTR) MSG_SOCKET_RECV_TIMEOUT));
  1409. return SOCKET_ERROR;
  1410. }
  1411. PBYTE
  1412. pReceiveExactData (
  1413. IN SOCKET Socket,
  1414. IN OUT PGROWBUFFER Buffer, OPTIONAL
  1415. OUT PBYTE AlternateBuffer, OPTIONAL
  1416. IN UINT BytesToReceive,
  1417. IN UINT Timeout OPTIONAL
  1418. )
  1419. /*++
  1420. Routine Description:
  1421. pReceiveExactData allocates a buffer from the caller-specified grow buffer,
  1422. and receives data until the buffer is full, or until receive fails.
  1423. Arguments:
  1424. Socket - Specifies the socket to receive data on. The socket must
  1425. be in blocking mode.
  1426. Buffer - Specifies the buffer to allocate from; the end pointer is
  1427. reset to zero. Receives the data from the wire.
  1428. AlternateBuffer - Specifies the buffer to put data into
  1429. BytesToReceive - Specifies the number of bytes to get from the socket. All
  1430. bytes must be read before this function returns.
  1431. Return Value:
  1432. TRUE if the buffer was completed, or FALSE if receive failed.
  1433. NOTE: Either Buffer or AlternateBuffer must be specified. If both are
  1434. specified, Buffer is used.
  1435. --*/
  1436. {
  1437. PBYTE recvBuf;
  1438. PBYTE bufPos;
  1439. UINT bytesSoFar = 0;
  1440. INT result;
  1441. UINT readSize;
  1442. if (Buffer) {
  1443. Buffer->End = 0;
  1444. recvBuf = GbGrow (Buffer, BytesToReceive);
  1445. } else {
  1446. recvBuf = AlternateBuffer;
  1447. }
  1448. bufPos = recvBuf;
  1449. do {
  1450. if (IsmCheckCancel()) {
  1451. return FALSE;
  1452. }
  1453. readSize = BytesToReceive - bytesSoFar;
  1454. result = pRecvWithTimeout (Socket, bufPos, readSize, 0, Timeout);
  1455. if (!result) {
  1456. // connection broken
  1457. SetLastError (ERROR_CANCELLED);
  1458. break;
  1459. }
  1460. if (result == SOCKET_ERROR) {
  1461. DEBUGMSG ((DBG_ERROR, "Error reading from socket"));
  1462. break;
  1463. }
  1464. bufPos += result;
  1465. bytesSoFar += result;
  1466. } while (bytesSoFar < BytesToReceive);
  1467. MYASSERT (bytesSoFar <= BytesToReceive);
  1468. return bytesSoFar == BytesToReceive ? recvBuf : NULL;
  1469. }
  1470. PBYTE
  1471. pReceiveDatagramData (
  1472. IN SOCKET Socket,
  1473. IN PDATAGRAM_POOL DatagramPool,
  1474. IN OUT PGROWBUFFER Buffer, OPTIONAL
  1475. OUT PBYTE AlternateBuffer, OPTIONAL
  1476. IN UINT BytesToReceive,
  1477. IN UINT Timeout OPTIONAL
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. pReceiveDatagramData checks the datagram queue for data, allocates a
  1482. receive buffer, and fills the buffer with the data from the wire. If
  1483. necessary, this function will fill the queue, until there is enough data to
  1484. fill the caller's buffer.
  1485. Arguments:
  1486. Socket - Specifies the datagram socket
  1487. DatagramPool - Specifies the structure containing the receive pool and
  1488. other sequencing info
  1489. Buffer - Specifies the buffer to allocate from; the end pointer is
  1490. reset to zero. Receives the data from the wire.
  1491. AlternateBuffer - Specifies the buffer to put data into
  1492. BytesToReceive - Specifies the number of bytes to get from the socket. All
  1493. bytes must be read before this function returns.
  1494. Return Value:
  1495. TRUE if the buffer was completed, or FALSE if receive failed.
  1496. NOTE: Either Buffer or AlternateBuffer must be specified. If both are
  1497. specified, Buffer is used.
  1498. --*/
  1499. {
  1500. PDATAGRAM_POOL_ITEM itemHeader;
  1501. PDATAGRAM_POOL_ITEM prevItem, nextItem;
  1502. BYTE buffer[512];
  1503. PBYTE dataPtr;
  1504. PBYTE recvBuf;
  1505. PBYTE bufPos;
  1506. UINT bytesSoFar = 0;
  1507. UINT bytesLeft;
  1508. INT result;
  1509. PDATAGRAM_POOL_ITEM item;
  1510. UINT newPacketNum;
  1511. UINT currentPacketNum;
  1512. ULONG available;
  1513. PBYTE bigBuf = NULL;
  1514. PBYTE p;
  1515. if (Buffer) {
  1516. Buffer->End = 0;
  1517. recvBuf = GbGrow (Buffer, BytesToReceive);
  1518. } else {
  1519. recvBuf = AlternateBuffer;
  1520. }
  1521. bufPos = recvBuf;
  1522. itemHeader = (PDATAGRAM_POOL_ITEM) buffer;
  1523. dataPtr = (PBYTE) (&itemHeader[1]);
  1524. for (;;) {
  1525. //
  1526. // Take all available data out of the pool
  1527. //
  1528. item = DatagramPool->FirstItem;
  1529. bytesLeft = BytesToReceive - bytesSoFar;
  1530. while (item) {
  1531. if (item->Header.PacketNumber == DatagramPool->RecvSequenceNumber) {
  1532. //
  1533. // Two cases:
  1534. //
  1535. // 1. Want entire packet
  1536. // 2. Want partial packet
  1537. //
  1538. if (bytesLeft >= item->Header.DataLength) {
  1539. // entire packet
  1540. CopyMemory (bufPos, item->PacketData, item->Header.DataLength);
  1541. MYASSERT (!item->Prev);
  1542. if (item->Next) {
  1543. item->Next->Prev = NULL;
  1544. }
  1545. DatagramPool->FirstItem = item->Next;
  1546. bytesSoFar += item->Header.DataLength;
  1547. PmReleaseMemory (DatagramPool->Pool, item);
  1548. DatagramPool->RecvSequenceNumber++;
  1549. } else {
  1550. // partial packet
  1551. CopyMemory (bufPos, item->PacketData, bytesLeft);
  1552. item->PacketData += bytesLeft;
  1553. item->Header.DataLength -= (WORD) bytesLeft;
  1554. bytesSoFar += bytesLeft;
  1555. }
  1556. if (BytesToReceive == bytesSoFar) {
  1557. return recvBuf;
  1558. }
  1559. }
  1560. item = item->Next;
  1561. }
  1562. //
  1563. // Data is not available in the pool. Receive one packet and then try again.
  1564. //
  1565. ioctlsocket (Socket, FIONREAD, &available);
  1566. if (!available) {
  1567. Sleep (100);
  1568. continue;
  1569. }
  1570. bigBuf = PmGetMemory (DatagramPool->Pool, available);
  1571. result = pRecvWithTimeout (Socket, bigBuf, available, 0, Timeout);
  1572. if (result == INVALID_SOCKET) {
  1573. DEBUGMSG ((DBG_ERROR, "Can't receive datagram"));
  1574. break;
  1575. }
  1576. p = bigBuf;
  1577. while (result > 0) {
  1578. if (result < sizeof (DATAGRAM_PACKET)) {
  1579. DEBUGMSG ((DBG_ERROR, "Datagram header is too small"));
  1580. break;
  1581. }
  1582. CopyMemory (&itemHeader->Header, p, sizeof (DATAGRAM_PACKET));
  1583. p += sizeof (DATAGRAM_PACKET);
  1584. result -= sizeof (DATAGRAM_PACKET);
  1585. if (itemHeader->Header.DataLength > 256) {
  1586. DEBUGMSG ((DBG_ERROR, "Datagram contains garbage"));
  1587. break;
  1588. }
  1589. if (result < itemHeader->Header.DataLength) {
  1590. DEBUGMSG ((DBG_ERROR, "Datagram data is too small"));
  1591. break;
  1592. }
  1593. CopyMemory (dataPtr, p, itemHeader->Header.DataLength);
  1594. p += itemHeader->Header.DataLength;
  1595. result -= itemHeader->Header.DataLength;
  1596. if ((UINT) itemHeader->Header.PacketNumber == DatagramPool->LastPacketNumber) {
  1597. continue;
  1598. }
  1599. DatagramPool->LastPacketNumber = itemHeader->Header.PacketNumber;
  1600. //
  1601. // Put the packet in the item linked list, sorted by packet number
  1602. //
  1603. item = (PDATAGRAM_POOL_ITEM) PmDuplicateMemory (
  1604. DatagramPool->Pool,
  1605. (PCBYTE) itemHeader,
  1606. itemHeader->Header.DataLength + sizeof (DATAGRAM_POOL_ITEM)
  1607. );
  1608. item->PacketData = (PBYTE) (&item[1]);
  1609. prevItem = NULL;
  1610. nextItem = DatagramPool->FirstItem;
  1611. while (nextItem) {
  1612. //
  1613. // Account for wrapping; assume a packet number difference no more
  1614. // than 16383 out-of-sequence packets in the queue (about 4M of
  1615. // data)
  1616. //
  1617. if (nextItem->Header.PacketNumber >= 49152 && item->Header.PacketNumber < 16384) {
  1618. newPacketNum = (UINT) item->Header.PacketNumber + 65536;
  1619. currentPacketNum = (UINT) nextItem->Header.PacketNumber;
  1620. } else if (nextItem->Header.PacketNumber < 16384 && item->Header.PacketNumber >= 49152) {
  1621. newPacketNum = (UINT) item->Header.PacketNumber;
  1622. currentPacketNum = (UINT) nextItem->Header.PacketNumber + 65536;
  1623. } else {
  1624. newPacketNum = (UINT) item->Header.PacketNumber;
  1625. currentPacketNum = (UINT) nextItem->Header.PacketNumber;
  1626. }
  1627. if (newPacketNum < currentPacketNum) {
  1628. break;
  1629. }
  1630. prevItem = nextItem;
  1631. nextItem = nextItem->Next;
  1632. }
  1633. item->Next = nextItem;
  1634. item->Prev = prevItem;
  1635. if (!prevItem) {
  1636. DatagramPool->FirstItem = item;
  1637. }
  1638. }
  1639. PmReleaseMemory (DatagramPool->Pool, bigBuf);
  1640. }
  1641. return bytesSoFar == BytesToReceive ? recvBuf : NULL;
  1642. }
  1643. PBYTE
  1644. pReceiveData (
  1645. IN SOCKET Socket,
  1646. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  1647. IN OUT PGROWBUFFER Buffer, OPTIONAL
  1648. OUT PBYTE AlternateBuffer, OPTIONAL
  1649. IN UINT BytesToReceive,
  1650. IN UINT Timeout OPTIONAL
  1651. )
  1652. {
  1653. if (!DatagramPool) {
  1654. return pReceiveExactData (Socket, Buffer, AlternateBuffer, BytesToReceive, Timeout);
  1655. }
  1656. return pReceiveDatagramData (Socket, DatagramPool, Buffer, AlternateBuffer, BytesToReceive, Timeout);
  1657. }
  1658. BOOL
  1659. pSendFile (
  1660. IN SOCKET Socket,
  1661. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  1662. IN PCTSTR LocalFileName, OPTIONAL
  1663. IN PCTSTR DestFileName OPTIONAL
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. pSendFile sends a file on the wire.
  1668. Arguments:
  1669. Socket - Specifies the socket to send the file on
  1670. DatagramPool - Specifies the datagram pool for sockets that are connecitonless
  1671. LocalFileName - Specifies the path to the local file
  1672. DestFileName - Specifies the subpath that is sent to the destination. The
  1673. destination uses the subpath to construct its corresponding
  1674. file name.
  1675. Return Value:
  1676. TRUE if the file was sent, FALSE otherwise.
  1677. --*/
  1678. {
  1679. PCWSTR destFileName = NULL;
  1680. INT len;
  1681. GROWBUFFER data = INIT_GROWBUFFER;
  1682. BOOL result = FALSE;
  1683. HANDLE file = NULL;
  1684. LONGLONG fileSize;
  1685. DWORD msg;
  1686. HCRYPTPROV hProv = 0;
  1687. HCRYPTKEY hKey = 0;
  1688. HCRYPTHASH hHash = 0;
  1689. __try {
  1690. //
  1691. // Build the encrypt stuff
  1692. //
  1693. if ((!CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ||
  1694. (!CryptCreateHash (hProv, CALG_MD5, 0, 0, &hHash)) ||
  1695. (!CryptHashData (hHash, (PBYTE)g_GlobalKey, ByteCountA (g_GlobalKey), 0)) ||
  1696. (!CryptDeriveKey (hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, &hKey))
  1697. ) {
  1698. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1699. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1700. __leave;
  1701. }
  1702. //
  1703. // Try to open the file
  1704. //
  1705. fileSize = BfGetFileSize (LocalFileName);
  1706. file = BfOpenReadFile (LocalFileName);
  1707. if (!file) {
  1708. // nothing to do
  1709. __leave;
  1710. }
  1711. //
  1712. // Send the message "FILE"
  1713. //
  1714. msg = MESSAGE_FILE;
  1715. if (!pSendData (Socket, DatagramPool, (PBYTE) &msg, sizeof (msg))) {
  1716. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1717. DEBUGMSG ((DBG_ERROR, "Can't send MSG_FILE"));
  1718. __leave;
  1719. }
  1720. //
  1721. // If no file was specified, send length of zero
  1722. //
  1723. if (!LocalFileName || !DestFileName) {
  1724. len = 0;
  1725. if (!pSendData (Socket, DatagramPool, (PBYTE) &len, 4)) {
  1726. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1727. DEBUGMSG ((DBG_ERROR, "Can't send nul file length"));
  1728. __leave;
  1729. }
  1730. result = TRUE;
  1731. __leave;
  1732. }
  1733. //
  1734. // Send the file name and file size
  1735. //
  1736. #ifdef UNICODE
  1737. destFileName = DuplicatePathString (DestFileName, 0);
  1738. #else
  1739. destFileName = ConvertAtoW (DestFileName);
  1740. #endif
  1741. len = ByteCountW (destFileName);
  1742. if (!pSendData (Socket, DatagramPool, (PBYTE) &len, 4)) {
  1743. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1744. DEBUGMSG ((DBG_ERROR, "Can't send file length"));
  1745. __leave;
  1746. }
  1747. // Encrypt the name of the file
  1748. if (!CryptEncrypt(hKey, 0, TRUE, 0, (PBYTE)destFileName, &len, len)) {
  1749. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1750. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1751. __leave;
  1752. }
  1753. if (!pSendData (Socket, DatagramPool, (PBYTE) destFileName, len)) {
  1754. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1755. DEBUGMSG ((DBG_ERROR, "Can't send file name"));
  1756. __leave;
  1757. }
  1758. if (!pSendData (Socket, DatagramPool, (PBYTE) &fileSize, 8)) {
  1759. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1760. DEBUGMSG ((DBG_ERROR, "Can't send file size"));
  1761. __leave;
  1762. }
  1763. //
  1764. // Send the data 64K at a time
  1765. //
  1766. GbGrow (&data, 0x10000);
  1767. while (fileSize) {
  1768. if (fileSize > 0x10000) {
  1769. len = 0x10000;
  1770. if (!BfReadFile (file, data.Buf, len)) {
  1771. DEBUGMSG ((DBG_ERROR, "Can't read from file"));
  1772. __leave;
  1773. }
  1774. // Encrypt the buffer
  1775. if (!CryptEncrypt(hKey, 0, FALSE, 0, data.Buf, &len, len)) {
  1776. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1777. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1778. __leave;
  1779. }
  1780. if (!pSendData (Socket, DatagramPool, data.Buf, len)) {
  1781. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1782. DEBUGMSG ((DBG_ERROR, "Can't send file data"));
  1783. __leave;
  1784. }
  1785. fileSize -= 0x10000;
  1786. } else {
  1787. len = (INT)fileSize;
  1788. if (!BfReadFile (file, data.Buf, (UINT) fileSize)) {
  1789. DEBUGMSG ((DBG_ERROR, "Can't read from file"));
  1790. __leave;
  1791. }
  1792. // Encrypt the buffer (last piece so set the last to TRUE)
  1793. if (!CryptEncrypt(hKey, 0, TRUE, 0, data.Buf, &len, len)) {
  1794. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1795. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1796. __leave;
  1797. }
  1798. if (!pSendData (Socket, DatagramPool, data.Buf, (UINT) len)) {
  1799. SetLastError (ERROR_NETWORK_UNREACHABLE);
  1800. DEBUGMSG ((DBG_ERROR, "Can't send file data"));
  1801. __leave;
  1802. }
  1803. fileSize = 0;
  1804. }
  1805. }
  1806. //
  1807. // Done!
  1808. //
  1809. result = TRUE;
  1810. DEBUGMSG ((DBG_HOMENET, "Sent %s", LocalFileName));
  1811. }
  1812. __finally {
  1813. if (hKey) {
  1814. CryptDestroyKey(hKey);
  1815. hKey = 0;
  1816. }
  1817. if (hHash) {
  1818. CryptDestroyHash(hHash);
  1819. hHash = 0;
  1820. }
  1821. if (hProv) {
  1822. CryptReleaseContext(hProv,0);
  1823. hProv = 0;
  1824. }
  1825. GbFree (&data);
  1826. if (file) {
  1827. CloseHandle (file);
  1828. }
  1829. if (destFileName) {
  1830. #ifndef UNICODE
  1831. FreeConvertedStr (destFileName);
  1832. #else
  1833. FreePathString (destFileName);
  1834. #endif
  1835. destFileName = NULL;
  1836. }
  1837. }
  1838. return result;
  1839. }
  1840. BOOL
  1841. pReceiveFile (
  1842. IN SOCKET Socket,
  1843. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  1844. IN PCTSTR LocalFileRoot,
  1845. IN UINT Timeout OPTIONAL
  1846. )
  1847. /*++
  1848. Routine Description:
  1849. pReceiveStreamFile obtains a file from the socket. The file is stored in
  1850. g_StorageRoot. The subpath and file name is obtained from the data on the
  1851. wire.
  1852. NOTE: The caller must pull off the message DWORD before calling
  1853. pReceiveStreamFile. This is unlike the send, which puts the message
  1854. on the wire automatically.
  1855. Arguments:
  1856. Socket - Specifies the socket to receive from.
  1857. DatagramPool - Specifies the packet pool for a datagram-based socket
  1858. LocalFileRoot - Specifies the local root path for the file
  1859. Return Value:
  1860. TRUE if the file was received, FALSE otherwise.
  1861. --*/
  1862. {
  1863. TCHAR fileName[MAX_PATH * 2];
  1864. INT len;
  1865. GROWBUFFER data = INIT_GROWBUFFER;
  1866. BOOL result = FALSE;
  1867. PTSTR p;
  1868. HANDLE file = NULL;
  1869. LONGLONG fileSize;
  1870. HCRYPTPROV hProv = 0;
  1871. HCRYPTKEY hKey = 0;
  1872. HCRYPTHASH hHash = 0;
  1873. __try {
  1874. //
  1875. // Build the encrypt stuff
  1876. //
  1877. if ((!CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ||
  1878. (!CryptCreateHash (hProv, CALG_MD5, 0, 0, &hHash)) ||
  1879. (!CryptHashData (hHash, (PBYTE)g_GlobalKey, ByteCountA (g_GlobalKey), 0)) ||
  1880. (!CryptDeriveKey (hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, &hKey))
  1881. ) {
  1882. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1883. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1884. __leave;
  1885. }
  1886. //
  1887. // Wait for file name
  1888. //
  1889. if (!pReceiveData (Socket, DatagramPool, &data, NULL, 4, Timeout)) {
  1890. __leave;
  1891. }
  1892. len = *((PDWORD) data.Buf);
  1893. if (!len) {
  1894. result = TRUE;
  1895. __leave;
  1896. }
  1897. if (len >= (MAX_PATH * sizeof (TCHAR))) {
  1898. __leave;
  1899. }
  1900. if (!pReceiveData (Socket, DatagramPool, &data, NULL, len, Timeout)) {
  1901. __leave;
  1902. }
  1903. // Decrypt the file name
  1904. if (!CryptDecrypt(hKey, 0, TRUE, 0, data.Buf, &len)) {
  1905. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1906. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1907. __leave;
  1908. }
  1909. StringCopy (fileName, LocalFileRoot);
  1910. GbGrow (&data, sizeof (TCHAR) * 2);
  1911. p = (PTSTR) data.Buf;
  1912. p[len / sizeof (TCHAR)] = 0;
  1913. p[(len / sizeof (TCHAR)) + 1] = 0;
  1914. StringCopy (AppendWack (fileName), p);
  1915. //
  1916. // Get the file size
  1917. //
  1918. if (!pReceiveData (Socket, DatagramPool, &data, NULL, 8, Timeout)) {
  1919. __leave;
  1920. }
  1921. fileSize = *((PLONGLONG) data.Buf);
  1922. DEBUGMSG ((DBG_HOMENET, "Receiving %s", fileName));
  1923. //
  1924. // Create the file
  1925. //
  1926. file = BfCreateFile (fileName);
  1927. if (file == INVALID_HANDLE_VALUE) {
  1928. PushError ();
  1929. DEBUGMSG ((DBG_ERROR, "Can't create %s", fileName));
  1930. PopError ();
  1931. __leave;
  1932. }
  1933. //
  1934. // Fetch the data 64K at a time
  1935. //
  1936. while (fileSize) {
  1937. if (fileSize > 0x10000) {
  1938. if (!pReceiveData (Socket, DatagramPool, &data, NULL, 0x10000, Timeout)) {
  1939. __leave;
  1940. }
  1941. len = data.End;
  1942. // Decrypt the file name
  1943. if (!CryptDecrypt(hKey, 0, FALSE, 0, data.Buf, &len)) {
  1944. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1945. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1946. __leave;
  1947. }
  1948. if (!BfWriteFile (file, data.Buf, len)) {
  1949. PushError ();
  1950. DEBUGMSG ((DBG_ERROR, "Can't write to file"));
  1951. PopError ();
  1952. __leave;
  1953. }
  1954. fileSize -= data.End;
  1955. } else {
  1956. if (!pReceiveData (Socket, DatagramPool, &data, NULL, (UINT) fileSize, Timeout)) {
  1957. __leave;
  1958. }
  1959. len = data.End;
  1960. // Decrypt the file name
  1961. if (!CryptDecrypt(hKey, 0, TRUE, 0, data.Buf, &len)) {
  1962. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  1963. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  1964. __leave;
  1965. }
  1966. if (!BfWriteFile (file, data.Buf, len)) {
  1967. PushError ();
  1968. DEBUGMSG ((DBG_ERROR, "Can't write to file"));
  1969. PopError ();
  1970. __leave;
  1971. }
  1972. fileSize = 0;
  1973. }
  1974. }
  1975. //
  1976. // Done!
  1977. //
  1978. result = TRUE;
  1979. DEBUGMSG ((DBG_HOMENET, "Received %s", fileName));
  1980. }
  1981. __finally {
  1982. PushError ();
  1983. if (hKey) {
  1984. CryptDestroyKey(hKey);
  1985. hKey = 0;
  1986. }
  1987. if (hHash) {
  1988. CryptDestroyHash(hHash);
  1989. hHash = 0;
  1990. }
  1991. if (hProv) {
  1992. CryptReleaseContext(hProv,0);
  1993. hProv = 0;
  1994. }
  1995. GbFree (&data);
  1996. if (file) {
  1997. CloseHandle (file);
  1998. if (!result) {
  1999. DeleteFile (fileName);
  2000. }
  2001. }
  2002. PopError ();
  2003. }
  2004. return result;
  2005. }
  2006. BOOL
  2007. pSendEncryptedData (
  2008. IN SOCKET Socket,
  2009. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  2010. IN PCBYTE Data,
  2011. IN UINT DataSize
  2012. )
  2013. /*++
  2014. Routine Description:
  2015. pSendEncryptedFile sends a file on the wire.
  2016. Arguments:
  2017. Socket - Specifies the socket to send the file on
  2018. DatagramPool - Specifies the datagram pool for sockets that are connecitonless
  2019. Data - Buffer to be sent
  2020. DataSize - Size of data to be sent
  2021. Return Value:
  2022. TRUE if the buffer was sent, FALSE otherwise.
  2023. --*/
  2024. {
  2025. INT len;
  2026. GROWBUFFER encData = INIT_GROWBUFFER;
  2027. BOOL result = FALSE;
  2028. DWORD msg;
  2029. HCRYPTPROV hProv = 0;
  2030. HCRYPTKEY hKey = 0;
  2031. HCRYPTHASH hHash = 0;
  2032. __try {
  2033. //
  2034. // Build the encrypt stuff
  2035. //
  2036. if ((!CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ||
  2037. (!CryptCreateHash (hProv, CALG_MD5, 0, 0, &hHash)) ||
  2038. (!CryptHashData (hHash, (PBYTE)g_GlobalKey, ByteCountA (g_GlobalKey), 0)) ||
  2039. (!CryptDeriveKey (hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, &hKey))
  2040. ) {
  2041. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  2042. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  2043. __leave;
  2044. }
  2045. //
  2046. // Send the message "DATA"
  2047. //
  2048. msg = MESSAGE_DATA;
  2049. if (!pSendData (Socket, DatagramPool, (PBYTE) &msg, sizeof (msg))) {
  2050. DEBUGMSG ((DBG_ERROR, "Can't send MSG_FILE"));
  2051. __leave;
  2052. }
  2053. //
  2054. // Send the size of data
  2055. //
  2056. if (!pSendData (Socket, DatagramPool, (PBYTE) &DataSize, 4)) {
  2057. DEBUGMSG ((DBG_ERROR, "Can't send file length"));
  2058. __leave;
  2059. }
  2060. //
  2061. // Send the data
  2062. //
  2063. GbGrow (&encData, DataSize);
  2064. CopyMemory (encData.Buf, Data, DataSize);
  2065. // Encrypt the buffer
  2066. if (!CryptEncrypt(hKey, 0, TRUE, 0, encData.Buf, &DataSize, DataSize)) {
  2067. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  2068. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  2069. __leave;
  2070. }
  2071. if (!pSendData (Socket, DatagramPool, encData.Buf, DataSize)) {
  2072. DEBUGMSG ((DBG_ERROR, "Can't send file data"));
  2073. __leave;
  2074. }
  2075. //
  2076. // Done!
  2077. //
  2078. result = TRUE;
  2079. }
  2080. __finally {
  2081. if (hKey) {
  2082. CryptDestroyKey(hKey);
  2083. hKey = 0;
  2084. }
  2085. if (hHash) {
  2086. CryptDestroyHash(hHash);
  2087. hHash = 0;
  2088. }
  2089. if (hProv) {
  2090. CryptReleaseContext(hProv,0);
  2091. hProv = 0;
  2092. }
  2093. GbFree (&encData);
  2094. }
  2095. return result;
  2096. }
  2097. BOOL
  2098. pReceiveEncryptedData (
  2099. IN SOCKET Socket,
  2100. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  2101. IN PBYTE *Buffer,
  2102. IN UINT Timeout OPTIONAL
  2103. )
  2104. /*++
  2105. Routine Description:
  2106. pReceiveEncryptedData obtains a buffer from the socket. The data is stored in
  2107. Buffer.
  2108. NOTE: The caller must pull off the message DWORD before calling
  2109. pReceiveEncryptedData. This is unlike the send, which puts the message
  2110. on the wire automatically.
  2111. Arguments:
  2112. Socket - Specifies the socket to receive from.
  2113. DatagramPool - Specifies the packet pool for a datagram-based socket
  2114. Buffer - Specifies a pointer to a PBYTE
  2115. Return Value:
  2116. TRUE if the file was received, FALSE otherwise.
  2117. --*/
  2118. {
  2119. GROWBUFFER data = INIT_GROWBUFFER;
  2120. DWORD dataSize;
  2121. BOOL result = FALSE;
  2122. HCRYPTPROV hProv = 0;
  2123. HCRYPTKEY hKey = 0;
  2124. HCRYPTHASH hHash = 0;
  2125. __try {
  2126. //
  2127. // Build the encrypt stuff
  2128. //
  2129. if ((!CryptAcquireContext (&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) ||
  2130. (!CryptCreateHash (hProv, CALG_MD5, 0, 0, &hHash)) ||
  2131. (!CryptHashData (hHash, (PBYTE)g_GlobalKey, ByteCountA (g_GlobalKey), 0)) ||
  2132. (!CryptDeriveKey (hProv, CALG_RC4, hHash, CRYPT_EXPORTABLE, &hKey))
  2133. ) {
  2134. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  2135. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  2136. __leave;
  2137. }
  2138. //
  2139. // Wait for file name
  2140. //
  2141. if (!pReceiveData (Socket, DatagramPool, &data, NULL, 4, Timeout)) {
  2142. __leave;
  2143. }
  2144. dataSize = *((PDWORD) data.Buf);
  2145. if (!dataSize) {
  2146. result = TRUE;
  2147. __leave;
  2148. }
  2149. if (!pReceiveData (Socket, DatagramPool, &data, NULL, dataSize, Timeout)) {
  2150. __leave;
  2151. }
  2152. // Decrypt the content
  2153. if (!CryptDecrypt(hKey, 0, TRUE, 0, data.Buf, &dataSize)) {
  2154. SetLastError (ERROR_NO_SECURITY_ON_OBJECT);
  2155. LOG ((LOG_ERROR, (PCSTR) MSG_ENCRYPTION_FAILED));
  2156. __leave;
  2157. }
  2158. // Now allocate the result
  2159. *Buffer = HeapAlloc (g_hHeap, 0, dataSize);
  2160. if (*Buffer) {
  2161. CopyMemory (*Buffer, data.Buf, dataSize);
  2162. result = TRUE;
  2163. }
  2164. }
  2165. __finally {
  2166. if (hKey) {
  2167. CryptDestroyKey(hKey);
  2168. hKey = 0;
  2169. }
  2170. if (hHash) {
  2171. CryptDestroyHash(hHash);
  2172. hHash = 0;
  2173. }
  2174. if (hProv) {
  2175. CryptReleaseContext(hProv,0);
  2176. hProv = 0;
  2177. }
  2178. GbFree (&data);
  2179. }
  2180. return result;
  2181. }
  2182. BOOL
  2183. pSendMetrics (
  2184. IN SOCKET Socket,
  2185. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  2186. IN OUT PTRANSFERMETRICS Metrics
  2187. )
  2188. /*++
  2189. Routine Description:
  2190. pSendMetrics sends transport data (such as the number of files or number of
  2191. bytes to expect). This is the first bit of information sent to the
  2192. destination.
  2193. Arguments:
  2194. Socket - Specifies the socket to send the data to.
  2195. DatagramPool - Specifies the structure for datagram mode
  2196. Metrics - Specifies a pointer to the metrics structure to send. The
  2197. metrics structure member StructSize is updated before the struct
  2198. is sent.
  2199. Return Value:
  2200. TRUE if the metrics struct was sent, FALSE otherwise.
  2201. --*/
  2202. {
  2203. Metrics->StructSize = sizeof (TRANSFERMETRICS);
  2204. if (!pSendData (Socket, DatagramPool, (PBYTE) Metrics, sizeof (TRANSFERMETRICS))) {
  2205. DEBUGMSG ((DBG_ERROR, "Failed to send data"));
  2206. return FALSE;
  2207. }
  2208. return TRUE;
  2209. }
  2210. BOOL
  2211. pReceiveMetrics (
  2212. IN SOCKET Socket,
  2213. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  2214. OUT PTRANSFERMETRICS Metrics
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. pReceiveMetrics obtains a TRANSFERMETRICS structure from the wire. This is
  2219. the first bit of information received by the destination. It provides the
  2220. number of files, total number of file bytes, and other information.
  2221. Arguments:
  2222. Socket - Specifies the socket to receive data on.
  2223. DatagramPool - Specifies the structure used for datagram data reception
  2224. Metrics - Receives the metrics from the wire.
  2225. Return Value:
  2226. TRUE if the metrics structure was received properly, FALSE otherwise.
  2227. --*/
  2228. {
  2229. GROWBUFFER data = INIT_GROWBUFFER;
  2230. BOOL result = FALSE;
  2231. __try {
  2232. if (!pReceiveData (Socket, DatagramPool, NULL, (PBYTE) Metrics, sizeof (TRANSFERMETRICS), 0)) {
  2233. __leave;
  2234. }
  2235. if (Metrics->StructSize != sizeof (TRANSFERMETRICS)) {
  2236. DEBUGMSG ((DBG_ERROR, "Invalid transfer metrics received"));
  2237. __leave;
  2238. }
  2239. if (Metrics->Signature != HOMENETTR_SIG) {
  2240. DEBUGMSG ((DBG_ERROR, "Invalid transfer signature received"));
  2241. __leave;
  2242. }
  2243. result = TRUE;
  2244. }
  2245. __finally {
  2246. GbFree (&data);
  2247. }
  2248. return result;
  2249. }
  2250. DWORD
  2251. pReceiveMessage (
  2252. IN SOCKET Socket,
  2253. IN PDATAGRAM_POOL DatagramPool, OPTIONAL
  2254. IN UINT Timeout OPTIONAL
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. pReceiveMessage obtains the next DWORD from the socket and returns it to
  2259. the caller. This DWORD provides a message, indicating what action to
  2260. take next.
  2261. Arguments:
  2262. Socket - Specifies the socket to receive data on
  2263. DatagramPool - Specifies the structure used for datagram data reception
  2264. Return Value:
  2265. The message, or 0 if no message is available.
  2266. --*/
  2267. {
  2268. DWORD msg = 0;
  2269. if (!pReceiveData (Socket, DatagramPool, NULL, (PBYTE) &msg, sizeof (DWORD), Timeout)) {
  2270. msg = 0;
  2271. }
  2272. return msg;
  2273. }
  2274. BOOL
  2275. pConnectToDestination (
  2276. IN PCONNECTADDRESS Address,
  2277. OUT PCONNECTIONSOCKET Connection
  2278. )
  2279. {
  2280. BOOL result = FALSE;
  2281. BOOL b;
  2282. LINGER lingerStruct;
  2283. CopyMemory (Connection->LocalAddress, Address->LocalAddress, Address->LocalAddressLen);
  2284. Connection->LocalAddressLen = Address->LocalAddressLen;
  2285. CopyMemory (Connection->RemoteAddress, Address->RemoteAddress, Address->RemoteAddressLen);
  2286. Connection->RemoteAddressLen = Address->RemoteAddressLen;
  2287. Connection->Socket = socket (
  2288. Address->Family,
  2289. Address->Datagram ? SOCK_DGRAM : SOCK_STREAM,
  2290. Address->Protocol
  2291. );
  2292. if (Connection->Socket == INVALID_SOCKET) {
  2293. DEBUGMSG ((DBG_ERROR, "Can't create socket for connection"));
  2294. return FALSE;
  2295. }
  2296. __try {
  2297. b = TRUE;
  2298. setsockopt (Connection->Socket, SOL_SOCKET, SO_REUSEADDR, (PBYTE) &b, sizeof (b));
  2299. b = TRUE;
  2300. setsockopt (Connection->Socket, SOL_SOCKET, SO_KEEPALIVE, (PBYTE) &b, sizeof (b));
  2301. lingerStruct.l_onoff = 1;
  2302. lingerStruct.l_linger = 90;
  2303. setsockopt (Connection->Socket, SOL_SOCKET, SO_LINGER, (PBYTE) &lingerStruct, sizeof (lingerStruct));
  2304. pResetPort (Address->Family, (SOCKADDR *) Address->LocalAddress);
  2305. if (bind (Connection->Socket, (SOCKADDR *) Address->LocalAddress, Address->LocalAddressLen)) {
  2306. DEBUGMSG ((DBG_ERROR, "Failed to bind to connection socket"));
  2307. __leave;
  2308. }
  2309. if (connect (Connection->Socket, (SOCKADDR *) Address->RemoteAddress, Address->RemoteAddressLen)) {
  2310. DEBUGMSG ((DBG_ERROR, "Failed to connect to socket"));
  2311. __leave;
  2312. }
  2313. Connection->Family = Address->Family;
  2314. Connection->Protocol = Address->Protocol;
  2315. Connection->Datagram = Address->Datagram;
  2316. ZeroMemory (&Connection->DatagramPool, sizeof (DATAGRAM_POOL));
  2317. if (Connection->Datagram) {
  2318. Connection->DatagramPool.Pool = PmCreatePool();
  2319. Connection->DatagramPool.LastPacketNumber = (UINT) -1;
  2320. }
  2321. result = TRUE;
  2322. }
  2323. __finally {
  2324. if (!result && Connection->Socket != INVALID_SOCKET) {
  2325. closesocket (Connection->Socket);
  2326. Connection->Socket = INVALID_SOCKET;
  2327. }
  2328. }
  2329. return result;
  2330. }
  2331. BOOL
  2332. FindDestination (
  2333. OUT PCONNECTADDRESS Address,
  2334. IN UINT Timeout, OPTIONAL
  2335. IN BOOL IgnoreMultipleDests
  2336. )
  2337. /*++
  2338. Routine Description:
  2339. FindDestination invokes the name resolution algorithm to locate a
  2340. destination. It selects the best transport to communicate on, and returns
  2341. the address. The caller can use the return address to make a connection.
  2342. Arguments:
  2343. Address - Receives the address of the destination
  2344. Timeout - Specifies the number of seconds to wait for the first
  2345. destination broadcast, or zero to wait forever.
  2346. IgnoreMultipleDests - Specifies TRUE if multiple destinations should be
  2347. ignored (taking the first one as the connection),
  2348. or FALSE if a message should be passed to the UI
  2349. to resolve the conflict.
  2350. Return Value:
  2351. TRUE if a destination was found, FALSE otherwise.
  2352. --*/
  2353. {
  2354. GROWBUFFER destinationAddresses = INIT_GROWBUFFER;
  2355. INT destinationCount;
  2356. PCONNECTADDRESS addressArray;
  2357. INT i;
  2358. PCTSTR firstName;
  2359. BOOL result = FALSE;
  2360. GROWBUFFER destNames = INIT_GROWBUFFER;
  2361. MULTISZ_ENUM e;
  2362. BOOL duplicate;
  2363. BOOL oneValid;
  2364. ULONG_PTR response;
  2365. __try {
  2366. destinationCount = pNameResolver (PLATFORM_SOURCE, &destinationAddresses, Timeout, NULL);
  2367. if (!destinationCount) {
  2368. __leave;
  2369. }
  2370. addressArray = (PCONNECTADDRESS) destinationAddresses.Buf;
  2371. //
  2372. // Determine which address to use. Rules are:
  2373. //
  2374. // 1. Must have only one destination to choose from
  2375. // 2. Pick TCP/IP, then IPX. [, then NetBIOS -- no longer supported]
  2376. //
  2377. if (destinationCount > 1) {
  2378. firstName = addressArray[0].DestinationName;
  2379. for (i = 1 ; i < destinationCount ; i++) {
  2380. if (!StringIMatch (firstName, addressArray[i].DestinationName)) {
  2381. break;
  2382. }
  2383. }
  2384. if (i < destinationCount) {
  2385. DEBUGMSG ((DBG_WARNING, "Multiple destinations found on the subnet"));
  2386. //
  2387. // put all destinations in an ISM environment variable, then call the
  2388. // UI to allow it to resolve the conflict, and finally make sure
  2389. // the one remaining destination is the only one used.
  2390. //
  2391. GbMultiSzAppend (&destNames, firstName);
  2392. for (i = 1 ; i < destinationCount ; i++) {
  2393. if (EnumFirstMultiSz (&e, (PCTSTR) destNames.Buf)) {
  2394. duplicate = FALSE;
  2395. do {
  2396. if (StringIMatch (e.CurrentString, addressArray[i].DestinationName)) {
  2397. duplicate = TRUE;
  2398. break;
  2399. }
  2400. } while (EnumNextMultiSz (&e));
  2401. }
  2402. if (!duplicate) {
  2403. GbMultiSzAppend (&destNames, addressArray[i].DestinationName);
  2404. }
  2405. }
  2406. IsmSetEnvironmentMultiSz (
  2407. PLATFORM_DESTINATION,
  2408. NULL,
  2409. TRANSPORT_ENVVAR_HOMENET_DESTINATIONS,
  2410. (PCTSTR) destNames.Buf
  2411. );
  2412. //
  2413. // Tell the UI. The UI must return TRUE and also update
  2414. // TRANSPORT_ENVVAR_HOMENET_DESTINATIONS so that the selected
  2415. // destination is the only member of the multi-sz.
  2416. //
  2417. if (!IgnoreMultipleDests) {
  2418. response = IsmSendMessageToApp (TRANSPORTMESSAGE_MULTIPLE_DESTS, 0);
  2419. if (IsmCheckCancel()) {
  2420. __leave;
  2421. }
  2422. if (!response) {
  2423. DEBUGMSG ((DBG_VERBOSE, "Multiple destinations were not resolved; can't continue"));
  2424. __leave;
  2425. }
  2426. if (!IsmGetEnvironmentMultiSz (
  2427. PLATFORM_DESTINATION,
  2428. NULL,
  2429. TRANSPORT_ENVVAR_HOMENET_DESTINATIONS,
  2430. (PTSTR) destNames.Buf,
  2431. destNames.End,
  2432. NULL
  2433. )) {
  2434. DEBUGMSG ((DBG_ERROR, "Can't get resolved destinations"));
  2435. __leave;
  2436. }
  2437. }
  2438. //
  2439. // Reset all Family members for names not selected
  2440. //
  2441. oneValid = FALSE;
  2442. for (i = 0 ; i < destinationCount ; i++) {
  2443. if (!StringIMatch (addressArray[i].DestinationName, (PCTSTR) destNames.Buf)) {
  2444. addressArray[i].Family = 0;
  2445. } else {
  2446. oneValid = TRUE;
  2447. }
  2448. }
  2449. if (!oneValid) {
  2450. DEBUGMSG ((DBG_ERROR, "Resolved destination does not exist"));
  2451. __leave;
  2452. }
  2453. }
  2454. }
  2455. //
  2456. // Select the best protocol
  2457. //
  2458. for (i = 0 ; i < destinationCount ; i++) {
  2459. if (addressArray[i].Family == AF_INET) {
  2460. break;
  2461. }
  2462. }
  2463. if (i == destinationCount) {
  2464. for (i = 0 ; i < destinationCount ; i++) {
  2465. if (addressArray[i].Family == AF_IPX) {
  2466. break;
  2467. }
  2468. }
  2469. if (i == destinationCount) {
  2470. for (i = 0 ; i < destinationCount ; i++) {
  2471. if (addressArray[i].Family == AF_NETBIOS) {
  2472. //break;
  2473. }
  2474. }
  2475. if (i == destinationCount) {
  2476. DEBUGMSG ((DBG_WHOOPS, "Connection is from unsupported protocol"));
  2477. __leave;
  2478. }
  2479. }
  2480. }
  2481. DEBUGMSG ((
  2482. DBG_HOMENET,
  2483. "Destination connection is %s (protocol %i)",
  2484. addressArray[i].DestinationName,
  2485. addressArray[i].Protocol
  2486. ));
  2487. CopyMemory (Address, &addressArray[i], sizeof (CONNECTADDRESS));
  2488. result = TRUE;
  2489. }
  2490. __finally {
  2491. PushError();
  2492. GbFree (&destinationAddresses);
  2493. GbFree (&destNames);
  2494. PopError();
  2495. }
  2496. return result;
  2497. }
  2498. BOOL
  2499. TestConnection (
  2500. IN PCONNECTADDRESS Address
  2501. )
  2502. /*++
  2503. Routine Description:
  2504. TestConnection establishes a connection to the destination specified
  2505. by Address. Will immediately disconnect since this was just a connection
  2506. test.
  2507. Arguments:
  2508. Address - Specifies the address of the destination, as returned by
  2509. FindDestination.
  2510. Return Value:
  2511. TRUE if a connection could be established to the destination, FALSE otherwise.
  2512. --*/
  2513. {
  2514. CONNECTIONSOCKET connection;
  2515. BOOL result = FALSE;
  2516. ZeroMemory (&connection, sizeof (CONNECTIONSOCKET));
  2517. connection.Socket = INVALID_SOCKET;
  2518. connection.KeepAliveSpacing = 30000;
  2519. connection.LastSend = GetTickCount();
  2520. __try {
  2521. if (!pConnectToDestination (Address, &connection)) {
  2522. __leave;
  2523. }
  2524. DEBUGMSG ((DBG_HOMENET, "TestConnection: Connected!"));
  2525. result = TRUE;
  2526. }
  2527. __finally {
  2528. if (connection.Socket != INVALID_SOCKET) {
  2529. closesocket (connection.Socket);
  2530. connection.Socket = INVALID_SOCKET;
  2531. }
  2532. if (connection.Datagram) {
  2533. PmDestroyPool (connection.DatagramPool.Pool);
  2534. connection.Datagram = FALSE;
  2535. }
  2536. }
  2537. return result;
  2538. }
  2539. BOOL
  2540. ConnectToDestination (
  2541. IN PCONNECTADDRESS Address,
  2542. IN PTRANSFERMETRICS Metrics,
  2543. OUT PCONNECTIONSOCKET Connection
  2544. )
  2545. /*++
  2546. Routine Description:
  2547. ConnectToDestination establishes a connection to the destination specified
  2548. by Address. Once connected, the Metrics structure is passed to the
  2549. destination. The caller receives the Connection structure for addtional
  2550. communication.
  2551. Arguments:
  2552. Address - Specifies the address of the destination, as returned by
  2553. FindDestination.
  2554. Metrics - Specifies the metrics structure that provides basic
  2555. information such as the number of files to expect.
  2556. Connection - Receives the connection to the destination, to be used in
  2557. additional data transfer.
  2558. Return Value:
  2559. TRUE if a connection was established to the destination, FALSE otherwise.
  2560. --*/
  2561. {
  2562. BOOL result = FALSE;
  2563. ZeroMemory (Connection, sizeof (CONNECTIONSOCKET));
  2564. Connection->Socket = INVALID_SOCKET;
  2565. Connection->KeepAliveSpacing = 30000;
  2566. Connection->LastSend = GetTickCount();
  2567. __try {
  2568. if (!pConnectToDestination (Address, Connection)) {
  2569. __leave;
  2570. }
  2571. DEBUGMSG ((DBG_HOMENET, "Connected!"));
  2572. if (!pSendMetrics (
  2573. Connection->Socket,
  2574. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2575. Metrics
  2576. )) {
  2577. DEBUGMSG ((DBG_HOMENET, "Can't send metrics to destination"));
  2578. __leave;
  2579. }
  2580. result = TRUE;
  2581. }
  2582. __finally {
  2583. if (!result) {
  2584. if (Connection->Socket != INVALID_SOCKET) {
  2585. closesocket (Connection->Socket);
  2586. Connection->Socket = INVALID_SOCKET;
  2587. }
  2588. }
  2589. }
  2590. return result;
  2591. }
  2592. DWORD
  2593. SendMessageToDestination (
  2594. IN PCONNECTIONSOCKET Connection,
  2595. IN DWORD Message
  2596. )
  2597. {
  2598. Connection->LastSend = GetTickCount();
  2599. return pSendData (
  2600. Connection->Socket,
  2601. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2602. (PBYTE) &Message,
  2603. sizeof (DWORD)
  2604. );
  2605. }
  2606. BOOL
  2607. SendFileToDestination (
  2608. IN PCONNECTIONSOCKET Connection,
  2609. IN PCTSTR LocalPath, OPTIONAL
  2610. IN PCTSTR DestSubPath OPTIONAL
  2611. )
  2612. /*++
  2613. Routine Description:
  2614. SendFileToDestination sends a file to the connection specified.
  2615. If LocalPath is NULL, then no file will be sent. This is used to skip files
  2616. that cannot be accessed locally.
  2617. If DestSubPath is NULL, then the file name in LocalPath will be used
  2618. as DestSubPath.
  2619. Arguments:
  2620. Connection - Specifies the connection to send the file to, as returned by
  2621. ConnectToDestination.
  2622. LocalPath - Specifies the local path of the file to send
  2623. DestSubPath - Specifies the sub path to send to the destination (so it can
  2624. reconstruct a path)
  2625. Return Value:
  2626. TRUE if the file was sent, FALSE otherwise.
  2627. --*/
  2628. {
  2629. if (LocalPath && !DestSubPath) {
  2630. DestSubPath = GetFileNameFromPath (LocalPath);
  2631. }
  2632. return pSendFile (
  2633. Connection->Socket,
  2634. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2635. LocalPath,
  2636. DestSubPath
  2637. );
  2638. }
  2639. BOOL
  2640. SendDataToDestination (
  2641. IN PCONNECTIONSOCKET Connection,
  2642. IN PCBYTE Data,
  2643. IN UINT DataSize
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. SendDataToDestination sends a buffer to the connection specified.
  2648. Arguments:
  2649. Connection - Specifies the connection to send the file to, as returned by
  2650. ConnectToDestination.
  2651. Data - Specifies the buffer to send
  2652. DataSize - Specifies the data size
  2653. Return Value:
  2654. TRUE if the file was sent, FALSE otherwise.
  2655. --*/
  2656. {
  2657. return pSendEncryptedData (
  2658. Connection->Socket,
  2659. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2660. Data,
  2661. DataSize
  2662. );
  2663. }
  2664. VOID
  2665. CloseConnection (
  2666. IN PCONNECTIONSOCKET Connection
  2667. )
  2668. {
  2669. if (Connection->Socket != INVALID_SOCKET) {
  2670. closesocket (Connection->Socket);
  2671. Connection->Socket = INVALID_SOCKET;
  2672. }
  2673. if (Connection->Datagram) {
  2674. PmDestroyPool (Connection->DatagramPool.Pool);
  2675. Connection->Datagram = FALSE;
  2676. }
  2677. }
  2678. BOOL
  2679. ConnectToSource (
  2680. OUT PCONNECTIONSOCKET Connection,
  2681. OUT PTRANSFERMETRICS Metrics
  2682. )
  2683. /*++
  2684. Routine Description:
  2685. ConnectToSource locates the source machine and accepts a connection from
  2686. it. To locate the source machine, broadcast messages are sent out on all
  2687. available transports. The source machine collects the broadcasts, then
  2688. selects the best transport, and connects to the destination machine. After
  2689. the connection completes, this function returns the connection to the
  2690. caller.
  2691. Arguments:
  2692. Connection - Receives the connection to the source machine. This connection
  2693. structure is then used to obtain data from the source.
  2694. Metrics - Recieves the metrics from the source machine, indicating what
  2695. data is going to be sent.
  2696. Return Value:
  2697. TRUE if a connection was accepted, FALSE otherwise.
  2698. --*/
  2699. {
  2700. ZeroMemory (Connection, sizeof (CONNECTIONSOCKET));
  2701. Connection->Socket = INVALID_SOCKET;
  2702. for (;;) {
  2703. if (!pNameResolver (PLATFORM_DESTINATION, NULL, 0, Connection)) {
  2704. return FALSE;
  2705. }
  2706. if (pReceiveMetrics (
  2707. Connection->Socket,
  2708. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2709. Metrics
  2710. )) {
  2711. return TRUE;
  2712. }
  2713. CloseConnection (Connection);
  2714. }
  2715. return TRUE;
  2716. }
  2717. DWORD
  2718. ReceiveFromSource (
  2719. IN PCONNECTIONSOCKET Connection,
  2720. IN PCTSTR LocalFileRoot,
  2721. OUT PBYTE *Buffer,
  2722. IN UINT Timeout OPTIONAL
  2723. )
  2724. /*++
  2725. Routine Description:
  2726. ReceiveFromSource obtains whatever data is being sent from the source. If the data
  2727. is a file, the file is saved into the directory indicated by LocalFileRoot.
  2728. If the data is encrypted buffer we will allocate Buffer and return the decrypted
  2729. data there.
  2730. Arguments:
  2731. Connection - Specifies the connection to send the file to, as returned by
  2732. ConnectToDestination.
  2733. LocalFileRoot - Specifies the root of the local path of the file to save. The
  2734. actual file name and optional subpath comes from the destination.
  2735. Buffer - Specifies the buffer to be allocated and filled with decrypted data.
  2736. Return Value:
  2737. The message ID received, or 0 if no message was recieved.
  2738. --*/
  2739. {
  2740. DWORD msg;
  2741. BOOL retry;
  2742. do {
  2743. retry = FALSE;
  2744. msg = pReceiveMessage (Connection->Socket, Connection->Datagram ? &Connection->DatagramPool : NULL, Timeout);
  2745. DEBUGMSG ((DBG_HOMENET, "Message from source: %u", msg));
  2746. switch (msg) {
  2747. case MESSAGE_FILE:
  2748. BfCreateDirectory (LocalFileRoot);
  2749. if (!pReceiveFile (
  2750. Connection->Socket,
  2751. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2752. LocalFileRoot,
  2753. Timeout
  2754. )) {
  2755. msg = 0;
  2756. }
  2757. break;
  2758. case MESSAGE_DATA:
  2759. if (!pReceiveEncryptedData (
  2760. Connection->Socket,
  2761. Connection->Datagram ? &Connection->DatagramPool : NULL,
  2762. Buffer,
  2763. Timeout
  2764. )) {
  2765. msg = 0;
  2766. }
  2767. break;
  2768. case MESSAGE_KEEP_ALIVE:
  2769. retry = TRUE;
  2770. break;
  2771. }
  2772. } while (retry);
  2773. return msg;
  2774. }