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.

598 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Sockopt.c
  5. Abstract:
  6. This module contains support for the getsockopt( ) and setsockopt( )
  7. WinSock APIs.
  8. Author:
  9. David Treadwell (davidtr) 31-Mar-1992
  10. Revision History:
  11. --*/
  12. #define WINSOCK_API_LINKAGE
  13. #define getsockopt getsockopt_v11
  14. #define setsockopt setsockopt_v11
  15. #include <windows.h>
  16. #include <winsock2.h>
  17. #include <ws2tcpip.h>
  18. //
  19. // The versions of WSOCK32.DLL that shiped with NT 3.1, NT 3.5, NT 3.51,
  20. // TCP/IP-32 for WFW, and Win95 all use the "Steve Deering" values for the
  21. // IP Multicast options. Unfortunately, the TCP/IP subgroup of the Windows
  22. // Sockets 2.0 standards effort chose to use the BSD values for these options.
  23. // Since these values overlap considerably, we have a rather unfortunate
  24. // situation.
  25. //
  26. // Here's how we'll deal with this.
  27. //
  28. // Applications built using WINSOCK2.H & WS2TCPIP.H will use the BSD
  29. // values as #defined in WS2TCPIP.H. These applications will link with
  30. // WS2_32.DLL, and life is swell.
  31. //
  32. // Applications built using WINSOCK.H will use the Steve Deering values
  33. // as #defined in WINSOCK.H. These applications will link with WSOCK32.DLL,
  34. // which will map these options to the BSD values before passing them
  35. // down to WS2_32.DLL. Life is still swell.
  36. //
  37. // These are the "old" Steve Deering values that must be mapped:
  38. //
  39. #define OLD_IP_MULTICAST_IF 2
  40. #define OLD_IP_MULTICAST_TTL 3
  41. #define OLD_IP_MULTICAST_LOOP 4
  42. #define OLD_IP_ADD_MEMBERSHIP 5
  43. #define OLD_IP_DROP_MEMBERSHIP 6
  44. #define OLD_IP_TTL 7
  45. #define OLD_IP_TOS 8
  46. #define OLD_IP_DONTFRAGMENT 9
  47. #define TCP_BSDURGENT 0x7000
  48. INT
  49. MapOldIpMulticastOptionToBsdValue(
  50. INT OptionName
  51. );
  52. int PASCAL
  53. getsockopt(
  54. IN SOCKET Handle,
  55. IN int Level,
  56. IN int OptionName,
  57. char *OptionValue,
  58. int *OptionLength
  59. )
  60. /*++
  61. Routine Description:
  62. getsockopt() retrieves the current value for a socket option
  63. associated with a socket of any type, in any state, and stores the
  64. result in optval. Options may exist at multiple protocol levels,
  65. but they are always present at the uppermost "socket'' level.
  66. Options affect socket operations, such as whether an operation
  67. blocks or not, the routing of packets, out-of-band data transfer,
  68. etc.
  69. The value associated with the selected option is returned in the
  70. buffer optval. The integer pointed to by optlen should originally
  71. contain the size of this buffer; on return, it will be set to the
  72. size of the value returned. For SO_LINGER, this will be the size of
  73. a struct linger; for all other options it will be the size of an
  74. integer.
  75. If the option was never set with setsockopt(), then getsockopt()
  76. returns the default value for the option.
  77. The following options are supported for
  78. getsockopt(). The Type identifies the type of
  79. data addressed by optval.
  80. Value Type Meaning
  81. SO_ACCEPTCONN BOOL Socket is listen()ing.
  82. SO_BROADCAST BOOL Socket is configured for the transmission
  83. of broadcast messages.
  84. SO_DEBUG BOOL Debugging is enabled.
  85. SO_DONTLINGER BOOL If true, the SO_LINGER option is disabled.
  86. SO_DONTROUTE BOOL Routing is disabled.
  87. SO_ERROR int Retrieve error status and clear.
  88. SO_KEEPALIVE BOOL Keepalives are being sent.
  89. SO_LINGER struct Returns the current linger
  90. linger options.
  91. FAR *
  92. SO_OOBINLINE BOOL Out-of-band data is being received in the
  93. normal data stream.
  94. SO_RCVBUF int Buffer size for receives
  95. SO_REUSEADDR BOOL The socket may be bound to an address which
  96. is already in use.
  97. SO_SNDBUF int Buffer size for sends
  98. SO_TYPE int The type of the socket (e.g. SOCK_STREAM).
  99. Arguments:
  100. s - A descriptor identifying a socket.
  101. level - The level at which the option is defined; the only supported
  102. level is SOL_SOCKET.
  103. optname - The socket option for which the value is to be retrieved.
  104. optval - A pointer to the buffer in which the value for the
  105. requested option is to be returned.
  106. optlen - A pointer to the size of the optval buffer.
  107. Return Value:
  108. If no error occurs, getsockopt() returns 0. Otherwise, a value of
  109. SOCKET_ERROR is returned, and a specific error code may be retrieved
  110. by calling WSAGetLastError().
  111. --*/
  112. {
  113. ULONG error;
  114. #undef getsockopt
  115. extern int WSAAPI getsockopt( SOCKET s, int level, int optname,
  116. char FAR * optval, int FAR * optlen );
  117. //
  118. // Set up locals so that we know how to clean up on exit.
  119. //
  120. error = NO_ERROR;
  121. //
  122. // Map the old IP multicast values to their BSD equivilants.
  123. //
  124. if( Level == IPPROTO_IP ) {
  125. OptionName = MapOldIpMulticastOptionToBsdValue( OptionName );
  126. }
  127. //
  128. // Handle TCP_BSDURGENT specially.
  129. //
  130. if( Level == IPPROTO_TCP && OptionName == TCP_BSDURGENT ) {
  131. if( getsockopt(
  132. Handle,
  133. Level,
  134. TCP_EXPEDITED_1122,
  135. OptionValue,
  136. OptionLength
  137. ) == SOCKET_ERROR ) {
  138. return SOCKET_ERROR;
  139. }
  140. //
  141. // TCP_BSDURGENT is the inverse of TCP_EXPEDITED_1122.
  142. //
  143. *OptionValue = !(*OptionValue);
  144. goto exit;
  145. }
  146. //
  147. // Forward it to the "real" WS2_32.DLL.
  148. //
  149. if( getsockopt(
  150. Handle,
  151. Level,
  152. OptionName,
  153. OptionValue,
  154. OptionLength
  155. ) == SOCKET_ERROR ) {
  156. return SOCKET_ERROR;
  157. }
  158. exit:
  159. if ( error != NO_ERROR ) {
  160. SetLastError( error );
  161. return SOCKET_ERROR;
  162. }
  163. return NO_ERROR;
  164. } // getsockopt
  165. int PASCAL
  166. setsockopt(
  167. IN SOCKET Handle,
  168. IN int Level,
  169. IN int OptionName,
  170. IN const char *OptionValue,
  171. IN int OptionLength
  172. )
  173. /*++
  174. Routine Description:
  175. setsockopt() sets the current value for a socket option associated
  176. with a socket of any type, in any state. Although options may exist
  177. at multiple protocol levels, this specification only defines options
  178. that exist at the uppermost "socket'' level. Options affect socket
  179. operations, such as whether expedited data is received in the normal
  180. data stream, whether broadcast messages may be sent on the socket,
  181. etc.
  182. There are two types of socket options: Boolean options that enable
  183. or disable a feature or behavior, and options which require an
  184. integer value or structure. To enable a Boolean option, optval
  185. points to a nonzero integer. To disable the option optval points to
  186. an integer equal to zero. optlen should be equal to sizeof(int) for
  187. Boolean options. For other options, optval points to the an integer
  188. or structure that contains the desired value for the option, and
  189. optlen is the length of the integer or structure.
  190. SO_LINGER controls the action taken when unsent data is queued on a
  191. socket and a closesocket() is performed. See closesocket() for a
  192. description of the way in which the SO_LINGER settings affect the
  193. semantics of closesocket(). The application sets the desired
  194. behavior by creating a struct linger (pointed to by the optval
  195. argument) with the following elements:
  196. struct linger {
  197. int l_onoff;
  198. int l_linger;
  199. }
  200. To enable SO_LINGER, the application should set l_onoff to a
  201. non-zero value, set l_linger to 0 or the desired timeout (in
  202. seconds), and call setsockopt(). To enable SO_DONTLINGER (i.e.
  203. disable SO_LINGER) l_onoff should be set to zero and setsockopt()
  204. should be called.
  205. By default, a socket may not be bound (see bind()) to a local
  206. address which is already in use. On occasions, however, it may be
  207. desirable to "re- use" an address in this way. Since every
  208. connection is uniquely identified by the combination of local and
  209. remote addresses, there is no problem with having two sockets bound
  210. to the same local address as long as the remote addresses are
  211. different. To inform the Windows Sockets implementation that a
  212. bind() on a socket should not be disallowed because of address
  213. re-use, the application should set the SO_REUSEADDR socket option
  214. for the socket before issuing the bind(). Note that the option is
  215. interpreted only at the time of the bind(): it is therefore
  216. unnecessary (but harmless) to set the option on a socket which is
  217. not to be bound to an existing address, and setting or resetting the
  218. option after the bind() has no effect on this or any other socket..
  219. An application may request that the Windows Sockets implementation
  220. enable the use of "keep- alive" packets on TCP connections by
  221. turning on the SO_KEEPALIVE socket option. A Windows Sockets
  222. implementation need not support the use of keep- alives: if it does,
  223. the precise semantics are implementation-specific but should conform
  224. to section 4.2.3.6 of RFC 1122: Requirements for Internet Hosts --
  225. Communication Layers. If a connection is dropped as the result of
  226. "keep- alives" the error code WSAENETRESET is returned to any calls
  227. in progress on the socket, and any subsequent calls will fail with
  228. WSAENOTCONN.
  229. The following options are supported for setsockopt(). The Type
  230. identifies the type of data addressed by optval.
  231. Value Type Meaning
  232. SO_ACCEPTCONN BOOL Socket is listen()ing.
  233. SO_BROADCAST BOOL Socket is configured for the transmission
  234. of broadcast messages.
  235. SO_DEBUG BOOL Debugging is enabled.
  236. SO_DONTLINGER BOOL If true, the SO_LINGER option is disabled.
  237. SO_DONTROUTE BOOL Routing is disabled.
  238. SO_ERROR int Retrieve error status and clear.
  239. SO_KEEPALIVE BOOL Keepalives are being sent.
  240. SO_LINGER struct Returns the current linger
  241. linger options.
  242. FAR *
  243. SO_OOBINLINE BOOL Out-of-band data is being received in the
  244. normal data stream.
  245. SO_RCVBUF int Buffer size for receives
  246. SO_REUSEADDR BOOL The socket may be bound to an address which
  247. is already in use.
  248. SO_SNDBUF int Buffer size for sends
  249. SO_TYPE int The type of the socket (e.g. SOCK_STREAM).
  250. Arguments:
  251. Return Value:
  252. If no error occurs, setsockopt() returns 0. Otherwise, a value of
  253. SOCKET_ERROR is returned, and a specific error code may be retrieved
  254. by calling WSAGetLastError().
  255. --*/
  256. {
  257. ULONG error;
  258. INT optionValue;
  259. INT invertedValue;
  260. char FAR * valuePointer;
  261. #undef setsockopt
  262. extern int WSAAPI setsockopt( SOCKET s, int level, int optname,
  263. const char FAR * optval, int optlen );
  264. //
  265. // Set up locals so that we know how to clean up on exit.
  266. //
  267. error = NO_ERROR;
  268. //
  269. // Map the old IP multicast values to their BSD equivilants.
  270. //
  271. if( Level == IPPROTO_IP ) {
  272. OptionName = MapOldIpMulticastOptionToBsdValue( OptionName );
  273. }
  274. //
  275. // Handle TCP_BSDURGENT specially.
  276. //
  277. valuePointer = (char FAR *)OptionValue;
  278. if( Level == IPPROTO_TCP && OptionName == TCP_BSDURGENT ) {
  279. OptionName = TCP_EXPEDITED_1122;
  280. if( OptionLength >= sizeof(INT) ) {
  281. invertedValue = !(*OptionValue);
  282. valuePointer = (char FAR *)&invertedValue;
  283. OptionLength = sizeof(invertedValue);
  284. }
  285. }
  286. return setsockopt(
  287. Handle,
  288. Level,
  289. OptionName,
  290. valuePointer,
  291. OptionLength
  292. );
  293. } // setsockopt
  294. INT
  295. MapOldIpMulticastOptionToBsdValue(
  296. INT OptionName
  297. )
  298. {
  299. switch( OptionName ) {
  300. case OLD_IP_MULTICAST_IF :
  301. OptionName = IP_MULTICAST_IF;
  302. break;
  303. case OLD_IP_MULTICAST_TTL :
  304. OptionName = IP_MULTICAST_TTL;
  305. break;
  306. case OLD_IP_MULTICAST_LOOP :
  307. OptionName = IP_MULTICAST_LOOP;
  308. break;
  309. case OLD_IP_ADD_MEMBERSHIP :
  310. OptionName = IP_ADD_MEMBERSHIP;
  311. break;
  312. case OLD_IP_DROP_MEMBERSHIP :
  313. OptionName = IP_DROP_MEMBERSHIP;
  314. break;
  315. case OLD_IP_TTL :
  316. OptionName = IP_TTL;
  317. break;
  318. case OLD_IP_TOS :
  319. OptionName = IP_TOS;
  320. break;
  321. case OLD_IP_DONTFRAGMENT :
  322. OptionName = IP_DONTFRAGMENT;
  323. break;
  324. }
  325. return OptionName;
  326. } // MapOldIpMulticastOptionToBsdValue
  327. int WSAAPI
  328. recv(
  329. IN SOCKET s,
  330. OUT char FAR * buf,
  331. IN int len,
  332. IN int flags
  333. )
  334. /*++
  335. Routine Description:
  336. Receive data from a socket.
  337. Arguments:
  338. s - A descriptor identifying a connected socket.
  339. buf - A buffer for the incoming data.
  340. len - The length of buf.
  341. flags - Specifies the way in which the call is made.
  342. Returns:
  343. The number of bytes received. If the connection has been gracefully
  344. closed, the return value is 0. Otherwise, a value of SOCKET_ERROR is
  345. returned, and a specific error code is stored with SetErrorCode().
  346. --*/
  347. {
  348. INT ReturnValue;
  349. WSABUF Buffers;
  350. DWORD LocalFlags;
  351. INT ErrorCode;
  352. Buffers.len = len;
  353. Buffers.buf = buf;
  354. LocalFlags = (DWORD) flags;
  355. ErrorCode = WSARecv(s,
  356. &Buffers,
  357. 1, // Buffer count
  358. (LPDWORD)&ReturnValue,
  359. &LocalFlags,
  360. NULL,
  361. NULL);
  362. if (SOCKET_ERROR == ErrorCode) {
  363. ReturnValue = SOCKET_ERROR;
  364. } else if (LocalFlags & MSG_PARTIAL) {
  365. // If the receive was a partial message (won't happen on a
  366. // streams transport like TCP) set the last error to
  367. // WSAEMSGSIZE and negate ths number of bytes received.
  368. // This allows the app to know that the receive was partial
  369. // and also how many bytes were received.
  370. //
  371. ReturnValue *= -1;
  372. SetLastError (WSAEMSGSIZE);
  373. }
  374. return(ReturnValue);
  375. }
  376. int WSAAPI
  377. recvfrom(
  378. IN SOCKET s,
  379. OUT char FAR * buf,
  380. IN int len,
  381. IN int flags,
  382. OUT struct sockaddr FAR *from,
  383. IN OUT int FAR * fromlen
  384. )
  385. /*++
  386. Routine Description:
  387. Receive a datagram and store the source address.
  388. Arguments:
  389. s - A descriptor identifying a bound socket.
  390. buf - A buffer for the incoming data.
  391. len - The length of buf.
  392. flags - Specifies the way in which the call is made.
  393. from - An optional pointer to a buffer which will hold the source
  394. address upon return.
  395. fromlen - An optional pointer to the size of the from buffer.
  396. Returns:
  397. The number of bytes received. If the connection has been gracefully
  398. closed, the return value is 0. Otherwise, a value of SOCKET_ERROR is
  399. returned, and a specific error code is stored with SetErrorCode().
  400. --*/
  401. {
  402. INT ReturnValue;
  403. WSABUF Buffers;
  404. DWORD LocalFlags;
  405. INT ErrorCode;
  406. Buffers.len = len;
  407. Buffers.buf = buf;
  408. LocalFlags = (DWORD) flags;
  409. ErrorCode = WSARecvFrom(s,
  410. &Buffers,
  411. 1,
  412. (LPDWORD)&ReturnValue,
  413. &LocalFlags,
  414. from,
  415. fromlen,
  416. NULL,
  417. NULL);
  418. if (SOCKET_ERROR == ErrorCode) {
  419. ReturnValue = SOCKET_ERROR;
  420. } else if (LocalFlags & MSG_PARTIAL) {
  421. // If the receive was a partial message (won't happen on a
  422. // streams transport like TCP) set the last error to
  423. // WSAEMSGSIZE and negate ths number of bytes received.
  424. // This allows the app to know that the receive was partial
  425. // and also how many bytes were received.
  426. //
  427. ReturnValue *= -1;
  428. SetLastError (WSAEMSGSIZE);
  429. }
  430. return ReturnValue;
  431. }