A network service, such as a network protocol, is an implementation of the network and transport layers of the OSI network model. As shown in Figure 10-1, network services communicate with the data link layer through the MUX interface. Everything specific to the network interface is handled in the drivers of the data link layer, which are described in 10. Integrating a New Network Interface Driver.
A network service sublayer allows a network service to send and receive packets through the MUX. It may be written as part of a network service, or as a separate element that the service uses. The minimum requirements of a network service sublayer are an initialization routine and routines that support packet transfer and error reporting. Support for flow control is optional.
When the system constructs the network stack, it activates network interfaces that include a network service and a network driver. The activation routine that you provide in your network service sublayer, by convention, is named fooAttach( ), where foo is replaced by an abbreviation for the network service. This naming convention is a generalization based on the name of ipAttach( ). Your fooAttach( ) function typically allocates and initializes data structures that represent the interface being attached to, determines the network driver paradigm (END or NPT), and binds to the driver interface through the MUX.
To determine a driver's operating paradigm, use the muxTkDrvCheck( ) function (see B.2.17 muxTkDrvCheck( ), p.281). If your network service supports only NPT devices, its fooAttach( ) routine should return an error if muxTkDrvCheck( ) returns FALSE.
The network service must bind to a driver before it can send and receive packets through it. Binding to a network driver is accomplished by calling the muxTkBind( ) function (see B.2.16 muxTkBind( ), p.280).1
The protocol type supplied to the bind function is used by the MUX to prioritize the services, and determines which service sees which packets. A MUX_PROTO_SNARF type service sees all the packets that are processed by any driver to which it is bound. A MUX_PROTO_PROMISC type service sees a packet only after all other services bound to a driver have had a chance to consume it. A MUX_PROTO_OUTPUT type service sees outgoing rather than incoming packets. Any other type value configures the service to see only packets of the specified type.
After the bind operation has complete successfully, the sublayer should determine which (if any) registered service address mapping functions are relevant to the network interface. The sublayer should obtain references to those that apply and retain these references for later use within the interface.
The address resolution function translates a network service address to a network driver (physical layer) address. To find the address resolution function that applies to a specific network service/network driver pair, use the muxAddrResFuncGet( ) function (see B.2.3 muxAddrResFuncGet( ), p.274).
Typically, the network service performs address resolution when it sends a packet to the network driver. The sublayer uses the address resolution function obtained in this step to resolve the address. If an address resolution function does not exist for this combination of service and driver, the network service is not expected to initiate the address resolution. This allows flexibility for those services that prefer to have the address resolution performed by the network driver.
If the address resolution mechanism qualifies as an address resolution protocol (for instance, ARP) or network service in itself, it should bind to the MUX as a distinct service. Typically, it would bind itself to the same interface to which the corresponding network service is bound. The address resolution mechanism could even share the same callback functions of the network service if it knows how to distinguish between the two services.
The network address resolution function also supports multicast mapping, and maps a network service multicast address to a network driver (physical layer) multicast address.
The network service sublayer may allocate buffer pools in the form of mBlk clusters for receiving and sending packets. The network buffer management library netBufLib facilitates the implementation of an effective scheme for this purpose. The sublayer may also make use of the system mBlk pools. See 10.1.5 Managing Memory for Network Drivers and Services, p.186, and A. Using netBufLib for more information on network buffer management.
Other resources commonly used by network services include receive/transmit queues and data structures that represent each active network interface controlled by the sublayer. Data that should be collected and maintained for each interface includes:
Network layer packets are sent down through the MUX by using the muxTkSend( ) routine (see B.2.21 muxTkSend( ), p.284). Data to be sent arrives from an upper layer in the form of an mBlk chain, and is modified by your network service before being sent.
The muxTkSend( ) routine may return an error indicating that the driver is out of resources and cannot transmit the packet. A network service can use this error to establish a flow control mechanism (see Flow Control, p.230).
Sending packets through an END requires that the mBlk chain being sent contains fully formed physical layer frames. If necessary, a protocol must use the address resolution function registered for the interface to determine the destination address, and then use the muxAddressForm( ) routine to add the necessary frame header to the packet.
The MUX forwards incoming packets to the appropriate network service by invoking the stackRcvRtn( ) callback that was installed by the sublayer during the bind phase (see stackRcvRtn( ), p.231).
If a service binds to a network interface using muxTkBind( ), it typically receives packets (not frames) from the MUX. This is true whether the network interface is managed using an END or an NPT driver. If a service needs to receive both packets as well as the physical layer header, it can use the optional "piggy-back" facility provided for in the stackRcvRtn( ) argument list. The only absolute exception to this behavior occurs when the service binds to the MUX as a SNARF protocol. Such a service always receives frames not packets. If the service binds as a PROMISC protocol, it typically sees frames. However, it can see a packet if some other service that registered for packets does not consume its packet. If a service binds to an END using muxBind( ), the service always receives frames not packets.
If your stackRcvRtn( ) returns TRUE (except if your service is of type MUX_PROTO_PROMISC), the packet is consumed and will not be available to lower priority services listening to the same driver. If, on the other hand, your routine returns FALSE (or is of type MUX_PROTO_PROMISC), the packet will remain available to other services.
If your service has been registered as of type MUX_PROTO_OUTPUT, its stackRcvRtn( ) callback routine will be called for all packets going out over the driver to which your service is bound. If the stackRcvRtn( ) of such an output protocol returns TRUE, the packet is consumed by the protocol and will not go out over the driver. If it returns FALSE, the outgoing packet will continue on to the driver. Only one service at a time may bind with type MUX_PROTO_OUTPUT to any given driver.
The MUX initiates a shutdown in response to a muxDevUnload( ) call from the system. Before unloading the network driver, the MUX issues a shutdown message to every network service bound to that driver by calling the stackShutdownRtn( ) callbacks that were registered for those driver/service interfaces at bind time (see stackShutdownRtn( ), p.231).
Within this shutdown routine, the network service must take the necessary steps to close the interface, including a call to muxUnbind( ) to unbind the network service from the device (see B.2.23 muxUnbind( ), p.285).
Your network service may want to be notified of errors encountered in lower layers of the stack. Error conditions encountered by a network driver are passed up to the MUX. The MUX forwards each error to your network service sublayer if a stackErrorRtn( ) callback is registered at bind time (see stackErrorRtn( ), p.232).
The muxTkSend( ) routine may return an error, END_ERR_BLOCK, indicating that the network driver has insufficient resources to transmit data2 . The network service sublayer can use this feedback to establish a flow control mechanism by holding off on making any further calls to muxTkSend( ) until the device is ready to restart transmission. At that time, the MUX calls the stackRestartRtn( ) that you registered for the interface at bind time (see stackRestartRtn( ), p.232).
A driver may be written to respond to specific ioctl commands. These commands can be issued from your network service by calling muxIoctl( ) (see B.2.12 muxIoctl( ), p.278).
When a network service registers with the MUX, it must provide references to functions that the MUX can call to handle the following:
The prototypes of the functions you specify to handle these functions differ depending on whether you use muxTkBind( ) or muxBind( ) to bind the service to a network interface in the MUX. If you are implementing a new network service, you should use the muxTkBind( ) interface. This chapter includes the older muxBind( ) interface solely to assist people maintaining network services that were designed to work with ENDs before the development of the NPT.
This routine is typically called by the MUX when it has received a call to muxDevUnload( ) for a specific network device. Before unloading the driver, every network service bound to that device is issued a shutdown message by calling the stackShutdownRtn( ) function registered for that service.
Within this routine, the network service must call muxUnbind( ) to release itself from the device, and it should bring itself to an orderly halt.
STATUS stackShutdownRtn
(
void * netCallbackId /* the handle/ID installed at bind time */
)
The MUX forwards packets received by the driver to the protocol layer by using the stackRcvRtn( ) callback that was installed with muxTkBind( ). This routine receives:
BOOL stackRcvRtn
(
void * netCallbackId, /* the handle/ID installed at bind time */
long type, /* network service type */
M_BLK_ID pNetBuf, /* network service datagram */
void * pSpareData /* pointer to optional data from driver */
)
If a network protocol accepts the frame by returning TRUE, it must free the given mBlk chain when processing is complete.
Error conditions encountered by an driver are passed to the network service when the MUX calls stackErrorRtn( ). It is up to the network service to take the necessary action upon receiving the error.
This function takes two arguments: the callback identifier supplied to the service at bind-time, and a pointer to an END_ERR structure that describes the error (see B.3.2 END_ERR, p.287).
void stackErrorRtn
(
void * netCallbackId, /* the handle/ID installed at bind time */
END_ERR * pError /* pointer to structure containing error */
)
This routine is called by the MUX to restart network services that had previously stopped, perhaps because muxTkSend( ) had returned an error indicating that the network service should wait before transmitting more packets.
When the device has determined that it has enough resources to resume transmission, it will indicate this to the MUX, which will then call stackRestartRtn( ).
This function takes a single argument: the identifier specific to the service/driver pair that was supplied at bind-time.
STATUS stackRestartRtn
(
void * netCallbackId /* the handle/ID installed at bind time */
)
This routine is typically called by the MUX when it has received a call to muxDevUnload( ) for the specified network interface. Before unloading the END, every network service bound to that END's device is issued a shutdown message by calling the stackENDShutdownRtn( ) function registered for the interface at bind time.
Within this routine, the network service must call muxUnbind( ) to release itself from the device, and it should bring itself to an orderly halt.
STATUS stackENDShutdownRtn
(
void * pEND, /* END_OBJ from the driver's load routine */
void * pSpare /* defined on a per-service basis */
)
The MUX forwards packets received by the END to the protocol layer by using the stackENDRcvRtn( ) callback that is installed with muxBind( ). The pNetBuff contains the entire driver-level frame, and pLinkHdr contains information about offsets to the network payload in the frame.
BOOL stackENDRcvRtn
(
void * pCookie, /* returned by muxBind() */
long type, /* from RFC1700, or user-defined */
M_BLK_ID pNetBuff, /* packet with link-level info */
LL_HDR_INFO * pLinkHdr, /* link-level header info structure */
void * pCallbackId /* registered by the network svc with MUX */
)
If a network protocol accepts the frame by returning TRUE, it must free the given mBlk chain when processing is complete.
Error conditions encountered by an END are passed to the network service when the MUX calls stackENDErrorRtn( ). It is up to the network service to take the necessary action upon receiving the error.
This function takes three arguments: the callback identifier supplied to the service at bind-time, a pointer to an END_ERR structure, and the spare data, if any, defined for the service during the bind phase.
void stackENDErrorRtn
(
void * pEND, /* END_OBJ passed to the MUX by the driver */
END_ERR * pError, /* holds error information */
void * pSpare /* defined on a per-service basis */
)
This routine is called by the MUX to restart network services that had previously stopped, perhaps because muxTkSend( ) had returned an error indicating that the network service should wait before transmitting more packets.
When the device has determined that it has enough resources to resume transmission, it will indicate this to the MUX, which will then call stackENDRestartRtn( ).
This function takes a single argument: the identifier specific to the service/driver pair that was supplied at bind-time.
STATUS stackENDRestartRtn
(
void * pEND, /* END_OBJ passed to the MUX by the driver */
void * pSpare, /* defined on a per-service basis */
)
One way to give applications easy access to your network service is to add socket support to the service. In order to make it easier for you to write a network service that includes sockets support, the VxWorks stack includes a standard socket interface.
With the standard socket interface, you can add new socket back ends to access the network stack through your protocol layer implementation. This allows developers who are already familiar with the standard socket API to more easily use your service.
The standard socket interface is designed so that you can use socket back ends simultaneously for multiple protocol layer implementations. A layered architecture makes this possible. The Wind River standard socket interface is a layer above your back end socket layer, as shown in Figure 11-1.
This chapter introduces the process of implementing a socket back end.
Socket calls made by an application are directed to the correct underlying socket back end based on the domain parameter that is passed to the socket( ) call when the application creates the socket. If this parameter matches the domainMap parameter that you use when you add your new socket back end with the sockLibAdd( ) routine, the socket calls are directed to your back end.
When you register your socket back end, you give the system a table that is filled with references to socket functions that you have created to support your implementation (see The Socket Functional Interface, p.236). The system is then able to support standard socket calls that are made using your back end.
The socket functional interface is the set of implementations of standard socket functions that are supported by a particular socket back end. There are two steps involved in creating a socket functional interface, both of which must be completed before the network is initialized.
The first step in creating a socket functional interface is to create a unique constant identifying the back end (for example, the BSD-specific INET back end is identified by the constant AF_INET_BSD). Add this constant to the list found in /target/h/sys/socket.h.
Then, create an initialization function that returns a reference to a SOCK_FUNC table filled with references to all of the functions that your socket back end will support, and call sockLibAdd( ) to have this function invoked by the system. (For details about this initialization function, see usrSockLibInit( ), p.239).
|
|
|||||||||||||||||||
The SOCK_FUNC table is a structure containing references to 19 implementations of functions common to sockets -- functions such as bind( ), recvfrom( ), and setsockopt( ) (see 11.4.3 Implementing Socket Functions, p.238). A new network service that wants to be socket-accessible should implement service-specific versions of as many of these functions as it intends to support. To support the registration of these functions, the service should set up its usrSockLibInit( ) routine to return a SOCK_FUNC table that is populated with references to these functions.
The sockLibAdd( ) function is used to make available a specific implementation of sockets for a particular domain. This function takes three parameters:
The following is an example of how sockLibAdd( ) might be called to add the BSD sockets back end:
sockLibAdd ((FUNCPTR) bsdSockLibInit, AF_INET_BSD, AF_INET);
STATUS sockLibAdd
(
FUNCPTR sockLibInitRtn, /* back end's initialization routine */
int domainMap, /* AF_FOO_BAR, identifying # of back end */
int domainReal, /* AF_FOO, identifying # of domain */
)
Zbufs (zero-copy buffers) are an enhancement that reduces the overhead involved in copying data between buffers as it passes through the layers of a network stack. A socket back end does not have to support zbufs, but may achieve significant performance gains by doing so.
The Wind River implementation of zbufs relies on the flags parameter in the socket send and receive routines. One of the flags that may be set in this parameter is MSG_MBUF. If this flag is set, this indicates that the data is in zbuf format -- in other words, the buffer is not a true buffer, but a pointer to an mbuf chain.
|
|
|||||||||||||||||||
Your socket back end must implement the function usrSockZbufRtn( ) which indicates whether the back end supports zbufs.
If your socket back end has been written to support zbufs, it should check for the MSG_MBUF flag, and if it is present, it should treat the buffers as mbuf chains. See the zbuf section of 7. Sockets under VxWorks for a more complete description of zero-copy buffers.
If your socket back end has not been written to support zbufs, then applications that try to use zbufs with your socket back end will fail with errno set to ENOTSUP. However, these applications will be able to use the sockets interface without zbufs.
This subsection provides implementation details for the functions you must supply in a SOCK_FUNC structure:
typedef struct sockFunc /* SOCK_FUNC */
{
FUNCPTR libInitRtn; /* sockLibInit() */
FUNCPTR acceptRtn; /* accept() */
FUNCPTR bindRtn; /* bind() */
FUNCPTR connectRtn; /* connect() */
FUNCPTR connectWithTimeoutRtn; /* connectWithTimeout() */
FUNCPTR getpeernameRtn; /* getpeername() */
FUNCPTR getsocknameRtn; /* getsockname() */
FUNCPTR listenRtn; /* listen() */
FUNCPTR recvRtn; /* recv() */
FUNCPTR recvfromRtn; /* recvfrom() */
FUNCPTR recvmsgRtn; /* recvmsg() */
FUNCPTR sendRtn; /* send() */
FUNCPTR sendtoRtn; /* sendto() */
FUNCPTR sendmsgRtn; /* sendmsg() */
FUNCPTR shutdownRtn; /* shutdown() */
FUNCPTR socketRtn; /* socket() */
FUNCPTR getsockoptRtn; /* getsockopt() */
FUNCPTR setsockoptRtn; /* setsockopt() */
FUNCPTR zbufRtn; /* ZBUF support */
} SOCK_FUNC;
The usrSockLibInit( ) function should install the socket back end as a driver within the VxWorks I/O system by calling iosDrvInstall( ), and then should return a pointer to a SOCK_FUNC structure.
The iosDrvInstall( ) routine takes pointers to seven I/O functions, four of which must be supported by a socket back end: usrSockClose( ), usrSockRead( ), usrSockWrite( ) and usrSockIoctl( )3 . This routine returns a driver number, which should be stored by the socket back end.
Your usrSockLibInit( ) routine, which should be declared public, is based on the following skeleton:
SOCK_FUNC * usrSockLibInit (void)
{
/* install driver for socket */
int driverNum = iosDrvInstall( (FUNCPTR) NULL, (FUNCPTR) NULL,
(FUNCPTR) NULL, (FUNCPTR) usrSockClose,
(FUNCPTR) usrSockRead, (FUNCPTR) usrSockWrite),
(FUNCPTR) usrSockIoctl) );
if( driverNum == ERROR ) return( (SOCK_FUNC *) NULL );
/* Store driverNum somewhere convnient for future reference */
/* Initialize SOCK_FUNC table */
SOCK_FUNC * usrSockFuncs = (SOCK_FUNC *) malloc(sizeof(SOCK_FUNC));
if( !usrSockFuncs )
{
errno = ENOMEM;
return( (SOCK_FUNC *) NULL );
}
usrSockFuncs->libInitRtn = (FUNCPTR) usrSockLibInit;
usrSockFuncs->acceptRtn = (FUNCPTR) usrSockAccept;
/* and so forth... */
usrSockFuncs->setsockoptRtn = (FUNCPTR) usrSockSetSockOpt;
usrSockFuncs->zbufRtn = (FUNCPTR) usrSockZbufRtn;
return (usrSockFuncs);
}
When a socket( ) call is issued, the standard socket interface searches for a back end that corresponds to the domain parameter passed to the socket( ) routine. This domain parameter may be the actual domain name, domainReal. Alternatively, it could be a domain name that maps to the actual domain, domainMap. A back end is registered (using sockLibAdd( )) both with its actual domain name (domainReal) and with domainMap.
If a back end is found for the domain, the usrSocket( ) function from the SOCK_FUNC structure that was registered for that domain is called. This function is called with the real socket domain (domainReal) passed as the domain parameter, regardless of whether the domainReal or domainMap parameters was passed to the original socket( ) call. The type and protocol entries are passed unchanged.
The usrSocket( ) routine should create a socket structure and then generate a new file descriptor representing the socket by calling iosFdNew( ) with the address of the new socket structure. Other back end functions will receive this file descriptor as a reference, and will use it to retrieve the associated socket structure by calling iosFdValue( ) with the file descriptor as an argument.
int usrSocket
(
int domain, /* socket domain or address family number */
int type, /* used to further define socket's nature */
int protocol /* the protocol variety of the socket */
)
The domain argument refers to the socket domain or address family the socket belongs to (a particular back end may potentially be invoked for more than one domain). The type argument can be used to further define the nature of the socket (examples of types in the AF_INET domain include SOCK_STREAM, SOCK_RAW and SOCK_DGRAM). The protocol argument refers to the protocol variety of the socket (in the AF_INET_BSD back end, an example of a protocol variety is IPPROTO_TCP).
The usrSocket( ) function returns the file descriptor that was generated for the socket, or ERROR if it was unable to open a socket.
This routine accepts a connection on a socket and returns a file descriptor representing the new socket created for the connection. Typically for this function to succeed, the socket represented by fd must have been previously bound to an address with usrSockBind( ) and enabled for connections by a call to usrSockListen( ). When usrSockAccept( ) is called, addr should be an available buffer, and addrlen should indicate the size of the buffer.
The usrSockAccept( ) function will block the caller until a connection is present, unless the socket has been explicitly marked as non-blocking.
int usrSockAccept
(
int fd, /* file descriptor for socket */
struct sockaddr * addr, /* network address */
int * addrlen /* length of address structure */
)
This function returns a file descriptor representing a new socket with the same properties as the one represented by fd (or ERROR if the accept fails). In addition, on a successful return, addr should be filled with the address of the machine making the connection, and addrlen should be set to the length of that address.
This routine associates a network address (referred to by name) with a specified socket so that other processes can connect or send to it.
STATUS usrSockBind
(
int fd, /* file descriptor representing socket */
struct sockaddr * name, /* network address */
int namelen /* length of network address */
)
This routine initiates a connection between a socket, fd, and another socket which is specified by name.
STATUS usrSockConnect
(
int fd, /* file descriptor representing socket */
struct sockaddr * name, /* network address */
int namelen /* length of network address */
)
This routine attempts to initiate a connection between a socket, fd, and another socket specified by name, for a duration specified by timeout, reporting an error if it cannot do so in the time required. If timeout is NULL, this function should act exactly like usrSockConnect( ).
STATUS usrSockConnectWithTimeout
(
int fd, /* file descriptor representing socket */
struct sockadr * name, /* network address */
int namelen, /* length of address */
struct timeval * timeout /* maximum duration of connect attempt */
)
This routine gets the name of the peer connected to the socket fd, placing this name in the sockaddr structure of length namelen that was passed in.
STATUS usrSockGetpeername
(
int fd, /* file descriptor representing socket */
struct sockaddr * name, /* structure to hold peer name */
int * namelen /* length of returned peer name */
)
This function should place the name of the peer in name and set namelen to the size of this name in bytes, then return OK, or ERROR if a name could not be retrieved for the specified socket.
This routine gets the current name for the socket fd, placing this name in the available sockaddr structure of size namelen that was passed in.
STATUS usrSockGetsockname
(
int fd, /* file descriptor representing socket */
struct sockaddr * name, /* structure to hold socket name */
int * namelen /* length of returned socket name */
)
This function places the name of the socket in name and set namelen to the size of this name in bytes, then returns OK, or ERROR if a name could not be retrieved for the specified socket.
This routine enables connections to a socket. The backlog parameter specifies the maximum number of unaccepted connections that can be pending at any given time. After enabling connections with usrSockListen( ), connections are actually accepted by usrSockAccept( ).
STATUS usrSockListen
(
int fd, /* file descriptor representing the socket */
int backlog /* max number of unaccepted pending connections */
)
This routine receives data from a connection-based (stream) socket. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockRecv
(
int fd, /* file descriptor represents the socket */
char * buf, /* buffer holding the received data */
int bufLen, /* length of the buffer */
int flags, /* flags describe the nature of the data */
)
This routine receives data from a datagram socket, regardless of whether it is connected. When this function is called, from will either be NULL or will be an available buffer of size pFromLen designed to hold the address from which the data is coming. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockRecvFrom
(
int fd, /* file descriptor represents the socket */
char * buf, /* buffer holding the received data */
int bufLen, /* length of the buffer */
int flags, /* flags describe the nature of the data */
struct sockaddr * from, /* address of the sending agent */
int * pFromLen /* length of the from structure */
)
This routine receives a message from a datagram socket. It may be used in place of usrSockRecvFrom( ) to decrease the overhead of breaking down the message-header structure in each message. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockRecvMsg
(
int fd, /* file descriptor for the socket */
struct msghdr * pMsgHdr, /* the message header */
int flags /* flags describing nature of the data */
)
This routine transmits data from the socket fd to a previously-established connection-based (stream) socket. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockSend
(
int fd, /* file descriptor representing the socket */
char * buf, /* buffer containing data to be sent */
int bufLen, /* length of the buffer */
int flags /* flags describing the nature of the data */
)
This routine transmits data from the socket specified by fd to the datagram socket specified by to. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockSendto
(
int fd, /* file descriptor representing the socket */
caddr_t buf, /* buffer containing message to be sent */
int bufLen, /* length of this buffer */
int flags, /* flags describing the nature of the data */
struct sockaddr * to, /* recipient's address */
int tolen /* length of the to structure */
)
This routine transmits a message to a datagram socket specified by fd. It may be used in place of usrSockSendto( ) to decrease the overhead of reconstructing the message header structure for each message. How the flags parameter should be set depends on the nature of the sockets involved and the requirements of the connection. This will differ for different socket and service implementations.
int usrSockSendMsg
(
int fd, /* file descriptor for the socket */
struct msghdr * pMsgHdr, /* message header */
int flags /* flags describing nature of the data */
)
This routine shuts down all, or part, of the connection-based socket fd. The how value allows for some control over how this shutdown takes place if sends and receives are still pending.
STATUS usrSockShutdown
(
int fd, /* file descriptor representing the socket */
int how /* directs how shutdown proceeds when activity is pending */
)
This routine retrieves socket option values4 associated with a specified socket. To find options set at the socket level, level is set to SOL_SOCKET. To find options set for a particular service, level is set to the identifying number of that service. The optval parameter points to an available buffer of size optlen. The buffer itself, although passed in as a char *, is treated as a pointer to whatever data type or structure is appropriate to the option being referenced.
STATUS usrGetSockOpt
(
int fd, /* file descriptor representing the socket */
int level, /* scope of option being retrieved */
int optname, /* name of option being retrieved */
char * optval, /* holds the value of the option */
int * optlen /* indicates the length of optval */
)
This function fills optval with the setting of the specified option, and sets optlen to the actual size of this value. The function returns OK, or ERROR if it was unable to retrieve a value for this option given these parameters.
This routine sets the options associated with a socket5 . To manipulate options at the socket level, level is set to SOL_SOCKET. Otherwise, level is set to the service number of the service for which the option is being set.
STATUS usrSetSockOpt
(
int fd, /* file descriptor representing the socket */
int level, /* scope of option being set */
int optname, /* name of option being set */
char * optval, /* value the option is being set to */
int optlen /* length of the value field */
)
This function returns OK, or ERROR if the request to set the socket option for the specified socket fails.
This routine returns TRUE if the back end supports the zero-copy interface (zbufs), otherwise it returns FALSE. This function is of the form:
STATUS usrSockZbufRtn()
int usrSockClose
(
[socket structure] * so /* socket being closed */
)
The socket structure corresponds to whatever data structure describes the socket object that was returned from iosFdValue( ). This might be a struct socket, or it may be some other structure.
int usrSockRead
(
[socket structure] * so, /* socket being read from */
char * buf, /* buffer to contain incoming data */
int bufLen /* length of this buffer */
)
The socket structure corresponds to whatever data structure describes the socket object that was returned from iosFdValue( ). This might be a struct socket, or it may be some other structure.
This function returns the number of bytes read, or -1 if the read fails.
int usrSockWrite
(
[socket structure] * so, /* socket being written to */
char * buf, /* buffer containing outgoing data */
int bufLen /* length of this buffer */
)
The socket structure corresponds to whatever data structure describes the socket object that was returned from iosFdValue( ). This might be a struct socket, or it may be some other structure.
This function returns the number of bytes written, or -1 if the write fails.
int usrSockIoctl
(
int fd, /* file descriptor representing the socket */
int function, /* the ioctl function being called */
int arg /* the argument to this ioctl function */
)
1: The muxBind( ) function may also be used, but only with ENDs. The muxBind( ) function also requires you to implement a slightly different set of network service sublayer functions than those that are used with muxTkBind( ).
2: Some less-carefully written drivers may simply return ERROR in this case, and it would not be possible for your service to determine whether this was due to a temporary problem such as insufficient resources or a more serious problem.
3: The others may be skipped as NULL pointers. For more information on these essential functions, see Socket Functions Passed to iosDrvInstall( ), p.248.
4: For instance, in TCP, socket options include SO_KEEPALIVE, SO_LINGER and TCP_NODELAY.
5: For instance, in UDP, socket options include SO_BROADCAST, IP_ADD_MEMBERSHIP and IP_MULTICAST_IF.