程式扎記: [ NP in MS ] Socket Options and Ioctls (Part1 : Socket Options - SOL_SOCKET Option Level )

標籤

2011年5月8日 星期日

[ NP in MS ] Socket Options and Ioctls (Part1 : Socket Options - SOL_SOCKET Option Level )


Preface :
The getsockopt function is most frequently used to get information about the given socket. The prototype for this function is :
  1. int getsockopt (  
  2.     SOCKET s,   
  3.     int level,   
  4.     int optname,   
  5.     char FAR* optval,   
  6.     int FAR* optlen  
  7. );  
The first parameter, s, is the socket on which you want to perform the specified option. This must be a valid socket for the given protocol you are using. A number of options are specific to a particular protocol and socket type, while others pertain to all types of sockets. This ties in with the second parameter,level. An option of level SOL_SOCKET means it is a generic option that isn't necessarily specific to a given protocol. We say “necessarily” because not all protocols implement each socket option of level SOL_SOCKET. For example, SO_BROADCAST puts the socket into broadcast mode, but not all supported protocols support the notion of broadcast sockets. The optname parameter is the actual option you are interested in. These option names are constant values defined in the Winsock header files. The most common and protocol-independent options (such as those with the SOL_SOCKET level) are defined in WINSOCK.H and WINSOCK2.H. Each specific protocol has its own header file that defines options specific to it. Finally, the optval and optlen parameters are the variables returned with the value of the desired option. In most cases—but not all—the option value is an integer.
The setsockopt function is used to set socket options on either a socket level or a protocol-specific level. The function is defined as :
  1. int setsockopt (  
  2.     SOCKET s,   
  3.     int level,   
  4.     int optname,   
  5.     const char FAR * optval,   
  6.     int optlen  
  7. );  
The parameters are the same as in getsockopt except that you pass in a value as the optval and optlen parameters, which are the values to set for the specified option. As with getsockoptoptval is often, but not always, an integer. Consult each option for the specifics on what is passed as the option value.
The most common mistake associated with calling either getsockopt or setsockopt is attempting to obtain socket information for a socket whose underlying protocol doesn't possess that particular characteristic. For example, a socket of type SOCK_STREAM is not capable of broadcasting data; therefore, attempting to set or get the SO_BROADCAST option results in the error WSAENOPROTOOPT.

SOL_SOCKET Option Level :
This section describes the socket options that return information based on the socket's characteristics and are not specific to that socket's protocol.
- SO_ACCEPTCONN

If the socket has been put into listening mode by the listen function, this option returns TRUE. Sockets of type SOCK_DGRAM do not support this option.

- SO_BROADCAST

If the given socket has been configured for sending or receiving broadcast data, querying this socket option returns TRUE. Use setsockopt withSO_BROADCAST to enable broadcast capabilities on the socket. This option is valid for sockets that aren't of type SOCK_STREAM.
Broadcasting is the capability to send data so that every machine on the local subnet receives the data. Of course, there must be some process on each machine that listens for incoming broadcast data. The drawback of broadcasting is that if many processes are all sending broadcast data, the network can become saturated and network performance suffers. To receive a broadcast message, you must enable the broadcast option and then use one of the datagram receive functions, such as recvfrom or WSARecvfrom. You can also connect the socket to the broadcast address by calling connect or WSAConnectand then use recv or WSARecv. For UDP broadcasts, you must specify a port number to send the datagram to; likewise, the receiver must request to receive the broadcast data on that port also. The following code example illustrates how to send a broadcast message with UDP :
  1. SOCKET       s;  
  2. BOOL         bBroadcast;  
  3. char         *sMsg = "This is a test";  
  4. SOCKADDR_IN bcast;  
  5.   
  6. s = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);  
  7. bBroadcast = TRUE;  
  8. setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&bBroadcast,  
  9.     sizeof(BOOL));  
  10. bcast.sin_family = AF_INET;  
  11. bcast.sin_addr.s_addr = inet_addr(INADDR_BROADCAST);  
  12. bcast.sin_port = htons(5150);  
  13. sendto(s, sMsg, strlen(sMsg), 0, (SOCKADDR *)&bcast, sizeof(bcast));  
For UDP, a special broadcast address exists to which broadcast data should be sent. This address is 255.255.255.255. A #define directive forINADDR_BROADCAST is provided to make things a bit simpler and easier to read.
AppleTalk is another protocol capable of sending broadcast messages. AppleTalk also has a special address used by broadcast data. You learned in Chapter 4 that an AppleTalk address has three parts: network, node, and socket (destination). For broadcasting, set the destination to ATADDR_BROADCAST(0xFF), which causes the datagram to be sent to all endpoints on the given network.
Normally, you need to set only the SO_BROADCAST option when sending broadcast datagrams. To receive a broadcast datagram, you need to be listening only for incoming datagrams on that specified port. However, on Windows 95 when using IPX, the receiving socket must set the SO_BROADCAST option in order to receive broadcast data, as described in Knowledge Base article Q137914, which can be found at http://support.microsoft.com/support/search. This is a bug in Windows 95.

- SO_CONDITIONAL_ACCEPT


This option allows applications to conditionally accept or reject incoming connections at the protocol level. For example, by default, this option is off for TCP and any incoming SYN packet is acknowledged with an ACK+SYN even if the application has not called the acceptWSAAccept, or AcceptEx functions. When this option is enabled, the connection is not acknowledged until the application calls one of the accept functions. In the case of WSAAccept and a conditional accept function, the connection is not acknowledged until the conditional accept function returns CF_ACCEPT. This option must be set before the listen call.
The drawback to enabling this is if the application does not post an accept or return CF_ACCEPT in a timely fashion, the client's connection request will time out with an error (WSAETIMEDOUT). For TCP/IP this option is off by default while for ATM, it is enabled by default. This option is available on Windows 2000 and later versions.

- SO_CONNECT_TIME

SO_CONNECT_TIME is a Microsoft-specific option that returns the number of seconds a connection has been established. The most frequent use of this option is with the AcceptEx function. AcceptEx requires that a valid socket handle be passed for the incoming client connection. This option can be called on the client's SOCKET handle to determine whether the connection has been made and how long it has been established. If the socket is not currently connected, the value returned is 0xFFFFFFFF.
This option is especially relevant in the case of AcceptEx. If an application posts an AcceptEx with a receive buffer, then the AcceptEx will not complete until data is received on the client connection. A malicious application could perform a denial of service attack by making many connections without sending data. To prevent this, the server should cycle through all client sockets outstanding in AcceptEx calls to see if they have been connected but the accept has not completed. Refer to Chapter 6 for more details.

- SO_DEBUG

Winsock service providers are encouraged (but not required) to supply output debug information if the SO_DEBUG option is set by an application. How the debug information is presented depends on the underlying service provider's implementation. To turn debug information on, call setsockopt with SO_DEBUGand a Boolean variable set to TRUE. Calling getsockopt with SO_DEBUG returns TRUE or FALSE if debugging is enabled or disabled, respectively. Unfortunately, no Windows platform currently implements the SO_DEBUG option, as described in Knowledge Base article Q138965. No error is returned when the option is set, but the underlying network provider ignores the option.

- SO_DONTLINGER

For protocols that support graceful socket connection closure, a mechanism is implemented so that if one or both sides close the socket, any data still pending or in transmission will be sent or received by both parties. It is possible, with setsockopt and the SO_LINGER option, to change this behavior so that after a specified period of time, the socket and all its resources will be torn down. Any pending or arriving data associated with that socket is discarded and the peer's connection is reset (WSAECONNRESET). The SO_DONTLINGER option can be checked to ensure that a linger period has not been set. Callinggetsockopt with SO_DONTLINGER will return a Boolean TRUE or FALSE if a linger value is set or not set, respectively. A call to setsockopt withSO_DONTLINGER disables lingering. Sockets of type SOCK_DGRAM do not support this option.

- SO_DONTROUTE

The SO_DONTROUTE option tells the underlying network stack to ignore the routing table and to send the data out on the interface the socket is bound to. For example, if you create a IPv4 UDP socket and bind it to interface A and then send a packet destined for a machine on the network attached to interface B, the packet will in fact be routed so that it is sent on interface B. Using setsockopt with the Boolean value TRUE prevents this because the packet goes out on the bound interface. The getsockopt function can be called to determine if routing is enabled (which it is by default).
Calling this option on a Windows platform will succeed; however, the Microsoft provider silently ignores the request and always uses the routing table to determine the appropriate interface for outgoing data.

- SO_ERROR

The SO_ERROR option returns and resets the per-socket–based error code, which is different from the per-thread–based error code that is handled using the WSAGetLastError and WSASetLastError function calls. A successful call using the socket does not reset the per-socket–based error code returned by theSO_ERROR option. Calling this option will not fail; however, the error value is not always updated immediately, so there is a possibility of this option returning 0 (indicating no error). It is best to use WSAGetLastError.

- SO_ EXCLUSIVEADDRUSE

This option is the complement of SO_REUSEADDR, which we will describe shortly. This option exists to prevent other processes from using theSO_REUSEADDR on a local address that your application is using. If two separate processes are bound to the same local address (assuming thatSO_REUSEADDR is set earlier), which of the two sockets receives notifications for incoming connections is not defined. The SO_EXCLUSIVEADDRUSE option locks down the local address to which the socket is bound, so if any other process tries to use SO_REUSEADDR with the same local address, that process fails. Administrator rights are required to set this option. It is available on only Windows 2000 or later versions.

- SO_KEEPALIVE

For a TCP-based socket, an application can request that the underlying service provider enable the use of keepalive packets on TCP connections by turning on the SO_KEEPALIVE socket option. On Windows platforms, keep-alives are implemented in accordance with section 4.2.3.6 of RFC 1122. If a connection is dropped as the result of keepalives, the error code WSAENETRESET is returned to any calls in progress on the socket, and any subsequent calls will fail withWSAENOTCONN. For the exact implementation details, consult the RFC. The important point is that keepalives are sent at intervals no less than two hours apart. The two-hour keepalive time is configurable via the Registry; however, changing the default value changes the keepalive behavior for all TCP connections on the system, which is generally discouraged. Another solution is to implement your own keepalive strategy. Sockets of type SOCK_DGRAM do not support this option.
The Registry keys for keepalives are KeepAliveInterval and KeepAliveTime. Both keys store values of type REG_DWORD in milliseconds. The former key is the interval separating keepalive retransmissions until a response is received; the latter entry controls how often TCP sends a keepalive packet in an attempt to verify that an ideal connection is still valid. In Windows 95, Windows 98, and Windows Me, these keys are located under the following Registry path :
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP

In Windows NT, store the keys under :
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

In Windows 2000, a new socket ioctl command—SIO_KEEPALIVE_VALS —allows you to change the keepalive value and interval on a per-socket basis, as opposed to a system-wide basis. This ioctl command is described later in this chapter.

- SO_LINGER

SO_LINGER controls the action taken when unsent data is queued on a socket and a closesocket is performed. A call to getsockopt with this socket option returns the current linger times in a linger structure, which is defined as :
  1. struct linger {   
  2.     u_short l_onoff;   
  3.     u_short l_linger;  
  4. }  
A nonzero value for l_onoff means that lingering is enabled, and l_linger is the timeout in seconds, at which point any pending data to be sent or received is discarded and the connection with the peer is reset. Conversely, you can call setsockopt to turn lingering on and specify the length of time before discarding any queued data. This is accomplished by setting the desired values in a variable of type struct linger. When setting a linger value with setsockopt, you must set the l_onoff field of the structure to a nonzero value. To turn lingering off once it has been enabled, you can call setsockopt with the SO_LINGER option and the l_onoff field of the linger structure set to 0, or call setsockopt with the SO_DONTLINGER option, passing the value TRUE for the optval parameter. Sockets of type SOCK_DGRAM do not support this option.
Setting the linger option directly affects how a connection behaves when the closesocket function is called. Table 7-1 lists these behaviors :

If SO_LINGER is set with a zero timeout interval (that is, the linger structure member l_onoff is not 0 and l_linger is 0), closesocket is not blocked, even if queued data has not yet been sent or acknowledged. This is called a hard, or abortive, close because the socket's virtual circuit is reset immediately and any unsent data is lost. Any receive call on the remote side of the circuit fails with WSAECONNRESET.
If SO_LINGER is set with a nonzero timeout interval on a blocking socket, the closesocket call blocks on a blocking socket until the remaining data has been sent or until the timeout expires. This is called a graceful disconnect. If the timeout expires before all data has been sent, the Windows Sockets implementation terminates the connection before closesocket returns.

- SO_MAX_MSG_SIZE

This is a get-only socket option that indicates the maximum outbound (send) size of a message for message-oriented socket types as implemented by a particular service provider. It has no meaning for byte-stream–oriented sockets.

- SO_OOBINLINE

By default, OOB data is not inlined, so a call to a receive function (with the appropriate MSG_OOB flag set) returns the OOB data in a single call. If this option is set, the OOB data appears within the data stream returned from a receive call, and a call to ioctlsocket with the SIOCATMARK option is required to determine which byte is the OOB data. Sockets of type SOCK_DGRAM do not support this option. See Chapter 1 for more details on OOB data.

- SO_OPENTYPE

The socket API returns handles that are overlapped capable by default. However, if the socket is to be used in the C runtime routines, the socket must have been created without the overlapped flag. With Winsock 2, the WSASocket function can be called without specifying the WSA_FLAG_OVERLAPPED flag. Otherwise, this socket option may be set, which affects all subsequent calls to socket from the current thread so that non-overlapped handles are returned. To set this option, INVALID_SOCKET is passed for the SOCKET parameter to setsockopt with a non-zero optval. To change it back, specify a zero optval. A socket created non-overlapped cannot be used with an overlapped fashion (such as completion routines or completion ports)—the operation will fail.

- SO_PROTOCOL_INFO

This is another get-only option that fills in the supplied WSAPROTOCOL_ INFO structure with the characteristics of the protocol associated with the socket. SeeChapter 2 for a description of the WSAPROTOCOL_INFO structure and its member fields.

- SO_RCVBUF

This is a simple option that either returns the size or sets the size of the buffer allocated to this socket for receiving data. When a socket is created, a send buffer and a receive buffer are assigned to the socket for sending and receiving data. When requesting to set the receive buffer size to a value, the call tosetsockopt can succeed even when the implementation does not provide the entire amount requested. To ensure that the requested buffer size is allocated, call getsockopt to get the actual size allocated. All Windows platforms can get or set the receive buffer size except Windows CE, which does not allow you to change the value—you can get only the receive buffer size.
One possible reason for changing the buffer size is to tailor buffer sizes according to your application's behavior. For example, when writing code to receive UDP datagrams, you should generally make the receive buffer size an even multiple of the datagram size. For overlapped I/O, setting the buffer sizes to 0 can increase performance in certain situations; when the buffers are non-zero, an extra memory copy is involved in moving data from the system buffer to the user-supplied buffer. If there is no intermediate buffer, data is immediately copied to the user-supplied buffer. The one caveat is that this is efficient only with multiple outstanding receive calls. Posting only a single receive can hurt performance because the local system cannot accept any incoming data unless you have a buffer posted and ready to receive the data. Performance considerations are covered in Chapter 6.

- SO_RCVTIMEO

The SO_RCVTIMEO option sets the receive timeout value on a blocking socket. The timeout value is an integer in milliseconds that indicates how long a Winsock receive function should block when attempting to receive data. If you need to use the SO_RCVTIMEO option and you use the WSASocket function to create the socket, you must specify WSA_FLAG_OVERLAPPED as part of WSASocket's dwFlags parameter. Subsequent calls to any Winsock receive function (such as recvrecvfromWSARecv, or WSARecvFrom) block only for the amount of time specified. If no data arrives within that time, the call fails with the error 10060 (WSAETIMEDOUT). If the receiver operation does time out the socket is in an indeterminate state and should not be used.
For performance reasons, this option was disabled in Windows CE 2.1. If you attempt to set this option, it is silently ignored and no failure returns. Previous versions of Windows CE do implement this option.

- SO_REUSEADDR

By default, a socket cannot be bound to a local address that is already in use; however, occasionally it is necessary to reuse an address this way. A connection is uniquely identified by the combination of its local and remote addresses. As long as the address you are connecting to is unique in the slightest respect (such as a different port number in TCP/IP), the binding will be allowed.
The only exception is for a listening socket. Two separate sockets cannot bind to the same local interface (and port, in the case of TCP/IP) to await incoming connections. If two sockets are actively listening on the same port, the behavior is undefined as to which socket will receive notification of an incoming connection. The SO_REUSEADDR option is most useful in TCP when a server shuts down or exits abnormally so that the local address and port are in theTIME_WAIT state, which prevents any other sockets from binding to that port. By setting this option, the server can listen on the same local interface and port when it is restarted.

- SO_SNDBUF

This is a simple option that either returns the size or sets the size of the buffer allocated to this socket for sending data. When a socket is created, a send buffer and a receive buffer are assigned to the socket for sending and receiving data. When requesting to set the size of the send buffer, the call tosetsockopt can succeed even when the implementation does not provide the entire amount requested. To ensure that the requested buffer size is allocated, call getsockopt to get the actual size allocated. All Windows platforms can get or set the send buffer size except Windows CE, which does not allow you to change the value—you can get only the receive buffer size.
As with SO_RCVBUF, you can use the SO_SNDBUF option to set the size of the send buffer to 0. The advantage of the buffer size being 0 for blocking send calls is that when the call completes you know that your data is on the wire. Also, as in the case of a receive operation with a zero-length buffer, there is no extra memory copy of your data to system buffers. The drawback is that you lose the pipelining gained by the default stack buffering when the send buffers are zero in size. In other words, if you have a loop performing sends, the local network stack can copy your data to a system buffer to be sent when possible (depending on the I/O model being used). On the other hand, if your application is concerned with other logistics, disabling the send buffers can save you a few machine instructions in the memory copy. See Chapter 6 for more information.

- SO_SNDTIMEO

The SO_SNDTIMEO option sets the timeout value on a blocking socket when calling a Winsock send function. The timeout value is an integer in milliseconds that indicates how long the send function should block when attempting to send data. If you need to use this option and you use the WSASocket function to create the socket, you must specify WSA_FLAG_OVERLAPPED as part of WSASocket's dwFlags parameter. Subsequent calls to any Winsock send function (such as sendsendtoWSASend, or WSASendTo) block for only the amount of time specified. If the send operation cannot complete within that time, the call fails with error 10060 (WSAETIMEDOUT). If the send operation times out the socket is in an indeterminate state and should not be used.
For performance reasons, this option was disabled in Windows CE 2.1. If you attempt to set this option, the option is silently ignored and no failure is returned. Previous versions of Windows CE do implement this option.

- SO_TYPE

This option is a get-only option that simply returns the socket type of the given socket. The possible socket types are SOCK_DGRAMSOCK_STREAM,SOCK_SEQPACKETSOCK_RDM, and SOCK_RAW.

- SO_UPDATE_ACCEPT_CONTEXT

This option is a Microsoft-specific extension used in conjunction with the AcceptEx function. The unique characteristic of this function is that it is part of the Winsock 1 specification and allows the use of overlapped I/O for an accept call. The function takes the listening socket as a parameter as well as a socket handle that becomes the accepted client. This socket option must be set for the characteristics of the listening socket to be carried over to the client socket. This is particularly important for QOS–enabled listening sockets. For the client socket to be QOS-enabled, this option must be set. To set this option on a socket, use the listening socket as the SOCKET parameter to setsockopt and pass the accepting socket handle (for example, the client handle) as optval. This option is specific to Windows. 
This message was edited 20 times. Last update was at 20/04/2011 09:46:57

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!