Leaked source code of windows server 2003
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.

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