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

585 lines
17 KiB

  1. /*++
  2. Copyright (c) 1999, Microsoft Corporation
  3. Module Name:
  4. sample\socket.c
  5. Assumes an IPv4 IPADDRESS for now...
  6. Abstract:
  7. The file contains functions to deal with sockets.
  8. Assumes an IPv4 IPADDRESS for now...
  9. --*/
  10. #include "pchsample.h"
  11. #pragma hdrstop
  12. #define START_SAMPLE_IO() ENTER_SAMPLE_API()
  13. #define FINISH_SAMPLE_IO() LEAVE_SAMPLE_API()
  14. ////////////////////////////////////////
  15. // CALLBACKFUNCTIONS
  16. ////////////////////////////////////////
  17. VOID
  18. WINAPI
  19. SocketCallbackSendCompletion (
  20. IN DWORD dwErr,
  21. IN DWORD dwNumSent,
  22. IN LPOVERLAPPED lpOverlapped
  23. )
  24. /*++
  25. Routine Description
  26. This routine is invoked by the I/O system upon completion of an
  27. operation. Runs in the context of an RTUTILS.DLL worker thread.
  28. Locks
  29. None.
  30. Arguments:
  31. dwErr system-supplied error code
  32. dwNumSent system-supplied byte-count
  33. lpOverlapped caller-supplied context area
  34. Return Value:
  35. None.
  36. --*/
  37. {
  38. PPACKET pPacket = CONTAINING_RECORD(lpOverlapped, PACKET, oOverlapped);
  39. TRACE3(ENTER, "Entering SocketCallbackSendCompletion: %u %u 0x%08x",
  40. dwErr, dwNumSent, lpOverlapped);
  41. PacketDisplay(pPacket);
  42. if ((dwErr != NO_ERROR) or // operation aborted
  43. (dwNumSent != pPacket->wsaBuffer.len)) // data not sent entirely
  44. {
  45. TRACE1(NETWORK, "Error %u sending packet", dwErr);
  46. LOGERR0(SENDTO_FAILED, dwErr);
  47. }
  48. PacketDestroy(pPacket); // destroy the packet structure
  49. TRACE0(LEAVE, "Leaving SocketCallbackSendCompletion");
  50. FINISH_SAMPLE_IO();
  51. }
  52. ////////////////////////////////////////
  53. // APIFUNCTIONS
  54. ////////////////////////////////////////
  55. DWORD
  56. SocketCreate (
  57. IN IPADDRESS ipAddress,
  58. IN HANDLE hEvent,
  59. OUT SOCKET *psSocket)
  60. /*++
  61. Routine Description
  62. Creates a socket.
  63. Locks
  64. None
  65. Arguments
  66. ipAddress ip address to bind the socket to
  67. hEvent the event to set when a packet arrives
  68. psSocket address of the socket to create
  69. Return Value
  70. NO_ERROR success
  71. Error Code o/w
  72. --*/
  73. {
  74. DWORD dwErr = NO_ERROR;
  75. PCHAR pszBuffer;
  76. SOCKADDR_IN sinSockAddr;
  77. BOOL bDontLinger, bReuse, bLoopback;
  78. struct linger lLinger = { 0, 0 };
  79. UCHAR ucTTL;
  80. struct ip_mreq imMulticast;
  81. // validate parameters
  82. if ((!psSocket or (*psSocket != INVALID_SOCKET)) or
  83. !IP_VALID(ipAddress) or
  84. (hEvent is INVALID_HANDLE_VALUE))
  85. return ERROR_INVALID_PARAMETER;
  86. // default return value
  87. *psSocket = INVALID_SOCKET;
  88. pszBuffer = INET_NTOA(ipAddress);
  89. do // breakout loop
  90. {
  91. // create socket
  92. *psSocket = WSASocket(AF_INET, // address family
  93. SOCK_RAW, // type
  94. PROTO_IP_SAMPLE, // protocol
  95. NULL,
  96. 0,
  97. WSA_FLAG_OVERLAPPED);
  98. if(*psSocket is INVALID_SOCKET)
  99. {
  100. dwErr = WSAGetLastError();
  101. TRACE0(NETWORK, "Could not create socket");
  102. break;
  103. }
  104. // associate the socket with our I/O completion port. the callback
  105. // function is invoked when an overlapped I/O operation completes.
  106. // this would be the send operation!
  107. dwErr = SetIoCompletionProc((HANDLE) *psSocket,
  108. SocketCallbackSendCompletion);
  109. if (dwErr != NO_ERROR)
  110. {
  111. TRACE0(NETWORK, "Could not associate callback function");
  112. break;
  113. }
  114. // set SO_LINGER to off
  115. // do not linger on close waiting for unsent data to be sent
  116. bDontLinger = TRUE;
  117. if (setsockopt(*psSocket,
  118. SOL_SOCKET,
  119. SO_DONTLINGER,
  120. (const char *) &bDontLinger,
  121. sizeof(BOOL)) is SOCKET_ERROR)
  122. {
  123. TRACE2(NETWORK,
  124. "Error %u setting linger option on %s, continuing...",
  125. WSAGetLastError(), pszBuffer);
  126. }
  127. // set to SO_REUSEADDR
  128. // allow socket to be bound to an address that is already in use
  129. bReuse = TRUE;
  130. if (setsockopt(*psSocket,
  131. SOL_SOCKET,
  132. SO_REUSEADDR,
  133. (const char *) &bReuse,
  134. sizeof(BOOL)) is SOCKET_ERROR)
  135. {
  136. TRACE2(NETWORK,
  137. "Error %u seting reuse option on %s, continuing...",
  138. WSAGetLastError(), pszBuffer);
  139. }
  140. // bind to the specified IPv4 addresses
  141. ZeroMemory(&sinSockAddr, sizeof(SOCKADDR_IN));
  142. sinSockAddr.sin_family = AF_INET;
  143. sinSockAddr.sin_addr.s_addr = ipAddress;
  144. sinSockAddr.sin_port = 0;
  145. if (bind(*psSocket, (LPSOCKADDR) &sinSockAddr, sizeof(SOCKADDR_IN))
  146. is SOCKET_ERROR)
  147. {
  148. dwErr = WSAGetLastError();
  149. TRACE0(NETWORK, "Could not bind socket");
  150. LOGERR1(BIND_IF_FAILED, pszBuffer, dwErr);
  151. break;
  152. }
  153. // allow multicast traffic to be sent out this interface
  154. if (setsockopt(*psSocket,
  155. IPPROTO_IP,
  156. IP_MULTICAST_IF,
  157. (const char *) &sinSockAddr.sin_addr,
  158. sizeof(IN_ADDR)) is SOCKET_ERROR)
  159. {
  160. dwErr = WSAGetLastError();
  161. TRACE2(NETWORK,
  162. "Error %u setting interface %s as multicast...",
  163. dwErr, pszBuffer);
  164. LOGERR1(SET_MCAST_IF_FAILED, pszBuffer, dwErr);
  165. break;
  166. }
  167. // set loopback to ignore self generated packets.
  168. bLoopback = FALSE;
  169. if (setsockopt(*psSocket,
  170. IPPROTO_IP,
  171. IP_MULTICAST_LOOP,
  172. (const char *) &bLoopback,
  173. sizeof(BOOL)) is SOCKET_ERROR)
  174. {
  175. TRACE2(NETWORK,
  176. "Error %u setting loopback to FALSE on %s, continuing...",
  177. WSAGetLastError(), pszBuffer);
  178. }
  179. // set TTL to 1 to restrict packet to within subnet (default anyway)
  180. ucTTL = 1;
  181. if (setsockopt(*psSocket,
  182. IPPROTO_IP,
  183. IP_MULTICAST_TTL,
  184. (const char *) &ucTTL,
  185. sizeof(UCHAR)) is SOCKET_ERROR)
  186. {
  187. TRACE2(NETWORK,
  188. "Error %u setting mcast ttl to 1 on %s, continuing...",
  189. WSAGetLastError(), pszBuffer);
  190. }
  191. // join the multicast session on SAMPLE_PROTOCOL_MULTICAST_GROUP.
  192. imMulticast.imr_multiaddr.s_addr = SAMPLE_PROTOCOL_MULTICAST_GROUP;
  193. imMulticast.imr_interface.s_addr = ipAddress;
  194. if (setsockopt(*psSocket,
  195. IPPROTO_IP,
  196. IP_ADD_MEMBERSHIP,
  197. (const char *) &imMulticast,
  198. sizeof(struct ip_mreq)) is SOCKET_ERROR)
  199. {
  200. dwErr = WSAGetLastError();
  201. TRACE0(NETWORK, "Could not join multicast group on socket");
  202. LOGERR1(JOIN_GROUP_FAILED, pszBuffer, dwErr);
  203. break;
  204. }
  205. // associate hReceiveEvent with the receive network event
  206. if (WSAEventSelect(*psSocket, (WSAEVENT) hEvent, FD_READ)
  207. is SOCKET_ERROR)
  208. {
  209. dwErr = WSAGetLastError();
  210. TRACE1(NETWORK, "Error %u calling WSAEventSelect()", dwErr);
  211. LOGERR0(EVENTSELECT_FAILED, dwErr);
  212. break;
  213. }
  214. } while(FALSE);
  215. if (dwErr != NO_ERROR)
  216. {
  217. TRACE2(NETWORK, "Error %u creating socket for %s", dwErr, pszBuffer);
  218. LOGERR0(CREATE_SOCKET_FAILED, dwErr);
  219. SocketDestroy(*psSocket);
  220. *psSocket = INVALID_SOCKET;
  221. }
  222. return dwErr;
  223. }
  224. DWORD
  225. SocketDestroy (
  226. IN SOCKET sSocket)
  227. /*++
  228. Routine Description
  229. Closes a socket.
  230. Locks
  231. None
  232. Arguments
  233. sSocket the socket to close
  234. Return Value
  235. NO_ERROR success
  236. Error Code o/w
  237. --*/
  238. {
  239. DWORD dwErr = NO_ERROR;
  240. if (sSocket is INVALID_SOCKET)
  241. return NO_ERROR;
  242. /*
  243. // closing a socket with closesocket also cancels the association and
  244. // selection of network events specified in WSAEventSelect. redundant!
  245. if (WSAEventSelect(sSocket, (WSAEVENT) NULL, 0) is SOCKET_ERROR)
  246. {
  247. dwErr = WSAGetLastError();
  248. TRACE1(NETWORK, "Error %u clearing socket-event association", dwErr);
  249. LOGERR0(EVENTSELECT_FAILED, dwErr);
  250. }
  251. */
  252. // close the socket
  253. if (closesocket(sSocket) != NO_ERROR)
  254. {
  255. dwErr = WSAGetLastError();
  256. TRACE1(NETWORK, "Error %u closing socket", dwErr);
  257. LOGERR0(DESTROY_SOCKET_FAILED, dwErr);
  258. }
  259. return dwErr;
  260. }
  261. DWORD
  262. SocketSend (
  263. IN SOCKET sSocket,
  264. IN IPADDRESS ipDestination,
  265. IN PPACKET pPacket)
  266. /*++
  267. Routine Description
  268. Send a packet to its destination and destroy it.
  269. Asynchronous.
  270. Locks
  271. None
  272. Arguments
  273. sSocket the socket to send the packet over
  274. ipDestination the packet's destination
  275. pPacket the packet to send out
  276. Return Value
  277. NO_ERROR success
  278. Error Code o/w
  279. --*/
  280. {
  281. DWORD dwErr = NO_ERROR;
  282. SOCKADDR_IN sinDestination;
  283. DWORD dwScratch;
  284. if (!START_SAMPLE_IO()) { return ERROR_CAN_NOT_COMPLETE; }
  285. // validate parameters
  286. if ((sSocket is INVALID_SOCKET) or !pPacket)
  287. return ERROR_INVALID_PARAMETER;
  288. ZeroMemory(&sinDestination, sizeof(SOCKADDR_IN));
  289. sinDestination.sin_family = AF_INET;
  290. sinDestination.sin_addr.s_addr = ipDestination;
  291. sinDestination.sin_port = 0;
  292. dwErr = WSASendTo(sSocket,
  293. &(pPacket->wsaBuffer), // buffer and length
  294. 1, // only one wsabuf exists
  295. &dwScratch, // unused
  296. 0, // no flags
  297. (PSOCKADDR) &sinDestination,
  298. sizeof(SOCKADDR_IN),
  299. &pPacket->oOverlapped, // context upon completion
  300. NULL); // no completion routine
  301. // completion routine (SocketCallbackSendCompletion) queued
  302. if (((dwErr is SOCKET_ERROR) and (WSAGetLastError() is WSA_IO_PENDING)) or
  303. (dwErr is NO_ERROR))
  304. {
  305. return NO_ERROR;
  306. }
  307. // completion routine (SocketCallbackSendCompletion) not queued
  308. dwErr = WSAGetLastError();
  309. TRACE1(NETWORK, "Error %u sending packet", dwErr);
  310. LOGERR0(SENDTO_FAILED, dwErr);
  311. FINISH_SAMPLE_IO();
  312. return dwErr;
  313. }
  314. DWORD
  315. SocketReceive (
  316. IN SOCKET sSocket,
  317. IN PPACKET pPacket)
  318. /*++
  319. Routine Description
  320. Receive a packet on a socket.
  321. This routine is written so that it could dynamically allocate a buffer,
  322. not knowing a priori the maximum size of the protocol's packet. It is
  323. synchronous, treating sSocket as a non overlapped socket.
  324. Locks
  325. None
  326. Arguments
  327. sSocket the socket to send the packet over
  328. pPacket the packet to send out
  329. Return Value
  330. NO_ERROR success
  331. Error Code o/w
  332. --*/
  333. #define IPv4_PREVIEW_SIZE 4
  334. #define IPv4_LENGTH_OFFSET 2
  335. {
  336. DWORD dwErr = NO_ERROR;
  337. BYTE rgbyPreview[IPv4_PREVIEW_SIZE];
  338. DWORD dwNumReceived, dwFlags;
  339. INT iSourceLength;
  340. SOCKADDR_IN sinSource;
  341. DWORD dwPacketLength;
  342. // validate parameters
  343. if ((sSocket is INVALID_SOCKET) or !pPacket)
  344. return ERROR_INVALID_PARAMETER;
  345. do // breakout loop
  346. {
  347. // read enuf to figure length
  348. pPacket->wsaBuffer.buf = rgbyPreview;
  349. pPacket->wsaBuffer.len = IPv4_PREVIEW_SIZE;
  350. dwFlags = MSG_PEEK;
  351. iSourceLength = sizeof(SOCKADDR_IN);
  352. dwErr = WSARecvFrom(sSocket,
  353. &(pPacket->wsaBuffer), // buffer and length
  354. 1, // only one wsabuf exists
  355. &dwNumReceived, // # bytes received
  356. &dwFlags, // flags
  357. (PSOCKADDR) &sinSource,
  358. &iSourceLength,
  359. NULL, // no context
  360. NULL); // no completion routine
  361. if (dwErr != SOCKET_ERROR) // there should have been an error
  362. break;
  363. dwErr = WSAGetLastError();
  364. if (dwErr != WSAEMSGSIZE) // of this kind
  365. break;
  366. if (dwNumReceived != pPacket->wsaBuffer.len)
  367. {
  368. dwErr = ERROR_CAN_NOT_COMPLETE;
  369. break;
  370. }
  371. // calculate the packet length
  372. dwPacketLength = ntohs(*((PUSHORT)(rgbyPreview + IPv4_LENGTH_OFFSET)));
  373. if (dwPacketLength > MAX_PACKET_LENGTH)
  374. {
  375. dwErr = ERROR_CAN_NOT_COMPLETE;
  376. break;
  377. }
  378. // read the entire packet, the buffer could be dynamically allocated
  379. pPacket->wsaBuffer.buf = pPacket->rgbyBuffer;
  380. pPacket->wsaBuffer.len = dwPacketLength;
  381. dwFlags = 0;
  382. iSourceLength = sizeof(SOCKADDR_IN);
  383. dwErr = WSARecvFrom(sSocket,
  384. &(pPacket->wsaBuffer), // buffer and length
  385. 1, // only one wsabuf exists
  386. &dwNumReceived, // # bytes received
  387. &dwFlags, // flags
  388. (PSOCKADDR) &sinSource,
  389. &iSourceLength,
  390. NULL, // no context
  391. NULL); // no completion routine
  392. if (dwErr is SOCKET_ERROR)
  393. {
  394. dwErr = WSAGetLastError();
  395. break;
  396. }
  397. if (dwPacketLength != dwNumReceived)
  398. {
  399. dwErr = ERROR_CAN_NOT_COMPLETE;
  400. break;
  401. }
  402. pPacket->ipSource = sinSource.sin_addr.s_addr;
  403. pPacket->wsaBuffer.len = dwNumReceived;
  404. dwErr = NO_ERROR;
  405. } while (FALSE);
  406. if (dwErr != NO_ERROR)
  407. {
  408. TRACE1(NETWORK, "Error %u receiving packet", dwErr);
  409. LOGERR0(RECVFROM_FAILED, dwErr);
  410. }
  411. return dwErr;
  412. }
  413. BOOL
  414. SocketReceiveEvent (
  415. IN SOCKET sSocket)
  416. /*++
  417. Routine Description
  418. Indicates whether a receive event occured on a socket. The recording
  419. of network events commences when WSAEventSelect is called with a
  420. nonzero lNetworkEvents parameter (i.e. the socket is activated) and
  421. remains in effect until another call is made to WSAEventSelect with the
  422. lNetworkEvents parameter set to zero (i.e. the socket is deactivated).
  423. Locks
  424. None
  425. Arguments
  426. sSocket the socket to check for packet reception
  427. Return Value
  428. TRUE receive event did occur
  429. FALSE o/w
  430. --*/
  431. {
  432. DWORD dwErr = NO_ERROR;
  433. WSANETWORKEVENTS wsaEvent;
  434. // validate parameters
  435. if (sSocket is INVALID_SOCKET)
  436. return ERROR_INVALID_PARAMETER;
  437. do // breakout loop
  438. {
  439. // enumerate network events to see if any packets have arrived on
  440. dwErr = WSAEnumNetworkEvents(sSocket, NULL, &wsaEvent);
  441. if (dwErr != NO_ERROR)
  442. {
  443. TRACE1(NETWORK, "Error %u enumerating network events", dwErr);
  444. LOGERR0(ENUM_NETWORK_EVENTS_FAILED, dwErr);
  445. break;
  446. }
  447. // see if the input bit is set
  448. if (!(wsaEvent.lNetworkEvents & FD_READ))
  449. {
  450. dwErr = SOCKET_ERROR;
  451. break;
  452. }
  453. // the input bit is set, now see if there was an error
  454. dwErr = wsaEvent.iErrorCode[FD_READ_BIT];
  455. if (dwErr != NO_ERROR)
  456. {
  457. TRACE1(NETWORK, "Error %u in input record", dwErr);
  458. LOGERR0(INPUT_RECORD_ERROR, dwErr);
  459. break;
  460. }
  461. } while (FALSE);
  462. if (dwErr is NO_ERROR)
  463. return TRUE;
  464. return FALSE;
  465. }