System and method of implementing netware core protocol within a sockets model6711621Abstract A system and method of implementing a NetWare Core Protocol (NCP) module within a sockets model, such as a Berkeley Systems Distribution (BSD) Sockets model, is disclosed wherein the NCP module has a NCP reliability sub-module and a NCP library sub-module. The BSD Sockets model has a sockets interface, one or more applications, an Internetwork Packet eXchange (IPX) network layer and a front plane. The system and method of the present invention is implemented such that the NCP library sub-module is located above the sockets interface and the NCP reliability sub-module is located below the sockets interface. This results in many advantages compared to prior implementations which had the entire NCP module located above the sockets layer, including increased performance due to the elimination of task switched data transfer and other interprocess communication steps, such as pipes and selects that impede performance. Claims What is claimed is: Description The present invention generally relates to computer networking software and more particularly to a system and method for implementing NetWare Core Protocol (NCP) within a sockets model, such as a Berkeley System Distribution (BSD) sockets model.
TABLE 1
Name Function
socket( ) create an NCP socket and register it with
SOCK_NCP
close( ) delete an NCP socket
connect( ) create/remove an NCP service connection
read( ) receive a reply to an NCP request
write( ) send an NCP request
setsockopt( ) specify a retransmission, encryption or
checksum option
ioctl( ) remove an association between a socket
FD and an NCP connection
FIG. 3 illustrates the sequence of socket calls that an application must use to established a connection, send and receive data and tear down the connection. The routines that are used to do so are individually described below. socket( ) An NCP socket is created by invoking the socket( ) routine. The socket( ) routine must be called before using any functions to perform network I/O. The arguments to socket( ) are the domain, the protocol type and the protocol. To create an NCP socket, the values of these arguments must be AF_IPX, SOCK_SEQPACKET and NWPROTO_NCP. socket( ) returns OK if successful, ERROR otherwise. In the unusual event that an internal data structure is corrupted, socket( ) may fail, and the global variable errno is set to EINVAL. connect( ) is used to establish an NCP connection to a server. The arguments to connect( ) include: the socket to be used for the connection, a pointer to a sockaddr_nw structure that contains the server's address and an integer containing the number of bytes in the address. New socket( ) may be associated with an existing connection by using ioctl( ). Connections may be torn down by assigning the value AF_UNSPEC in the address family field of the sockaddr argument. connect( ) is used for destroying a connection rather than close( ) because close( ) destroys the socket descriptor which may be reusable. The connect( ) routine returns OK if successful, ERROR otherwise. In the case of an error, the global variable errno is set accordingly: EINVAL if the length of name is incorrect or if the socket is not connected and the caller has specified AF_UNSPEC as the address family of name EAFNOSUPPORT if the address family of name is not AF_IPX EADDRNOTAVAIL if the port field of name is zero Note that name is cast as a pointer to struct sockaddr, but it actually points to a struct sockaddr_nw. read( ) is used to read data from a socket. The arguments to read( ) include: the socket descriptor, a pointer to a buffer and the number of bytes to read read( ) returns the number of bytes read, 0 if end of file or ERROR if there was an error. write( ) is used to write data from a socket. The arguments to write( ) include: the socket descriptor, a pointer to a buffer and the number of bytes to write. write( ) returns the number of bytes written, or ERROR if there was an error. In the event of an error, the global errno is set to EINVAL if the socket is not associated with an NCP connection or if the state of the connection is NCP_BAD.Error! Reference source not found. close( ) is used to destroy an unconnected socket. An attempt to close a connected socket results in an error. The arguments to close( ) include the file descriptor for the socket. close( ) returns 0 if successful, or ERROR otherwise. If the return value is ERROR, the global errno is set accordingly (e.g. EISCONN if the caller attempts to close a connected socket). setsockopt( ) may be used to specify the retransmission algorithm or to toggle IPX checksumming or NCP encryption for an NCP socket. The arguments to setsockopt( ) are: the socket descriptor, the level--SOCK_NCP, the name of the option to set (SO_RETRANSMIT, SO_CHECKSUM or SO_ENCRYPTION), a pointer to an integer that contains the new value of the option, the number of bytes in the optval variable. If the requested number of retransmission attempts is invalid, or if the name of the option is not SO_RETRANSMIT, SO_CHECKSUM or SO_ENCRYPTION, errno is set to EINVAL. ioctl( ) may be used to associate or disassociate a socket with an existing NCP connection. As previously discussed, connect( ) should be used to associate a socket with a new connection. The arguments to ioctl( ) include: the socket descriptor, an integer that specifies a specific request (FIOASSOCIATE or FIODISASSOCIATE), and a pointer to a sockaddr_nw that contains the address of the remote server. ioctl( ) returns 0 if OK, ERROR otherwise. If the return value is ERROR, the global errno is set accordingly (e.g. EINVAL if the socket does not exist or the address does not refer to a valid NCP connection). ncpLibInit( ) is responsible for creating and initializing a protocol switch table entry for the NCP protocol. The arguments to ncpLibInit( ) include a pointer to an NCP_CFG_PARAMS structure. The return value of ncpLibInit( ) is of type STATUS (OK if successful, ERROR otherwise). In accordance with an important aspect of the present invention, as shown in FIG. 2, the NCP module is implemented both above and below the BSD layer. The portion below the socket layer, is referred to as "SOCK_NCP." SOCK_NCP consists of the MUX/Reliability and Watchdog components. The socket API, allows applications to access services offered by NCP. These include: creating a new NCP connection; (dis)associating a socket with an existing connection; destroying a socket; sending requests and receiving replies; setting socket options that control retransmission of data; and controlling user access to available NCP connections such that there is at most one outstanding request per NCP connection at any time. The information required to support this functionality is maintained by the MUX/Reliability sub-module 30. The sole responsibility of NCP Watchdog module 34 is to respond to Watchdog requests. A NetWare server may send a Watchdog request if the connection has been idle for some period of time; if the connection is still considered valid (connected sockets still exist), it will reply. Watchdog requests for invalid connections are simply ignored. FIG. 4 illustrates the sequence of function calls that handle NCP I/O. ncp_usrreq( ) is the entry point in MUX/Reliability for all of the routines in the NCP socket API. The ioctl( ) routine is handled from ncp_usrreq( ) by ncp_controls. The setsockopt( ) routine calls ncp_ctloutput( ) through a pointer in the protocol switch table. Output data is processed in ncp_output( ), which fills in a portion of the NCP header and prepends the IPX header. Because the IPX header is maintained in the ncpcb, the outgoing packet my be given to nw_output( ) directly, bypassing ipx_output( ). nw_output( ) does any necessary route computation before handing the packet to ipxOutput( ). Incoming NCP packets that are addressed to an IPX port that is in use by an NCP connection are processed by ncp_input( ). This routine is responsible for verifying sequence information, security processing, delivering received data to the application socket and issuing the next pending request. The last step is indicated by the horizontal line between ncp_input( ) and ncp_output( ). All other NCP packets are processed by ncpHandleKeepAlive( ). This function determines whether the packet is a valid watchdog request; if so, a reply is constructed and given to nw_outputs. NCP watchdog requests are addressed to the IPX port number equal to one plus that used by the NCP connection; for example, if the local port is 4100, watchdog requests would be addressed to port 4101. The value of the local IPX port number is the same for all NCP connections (0x4100). This simplifies error checking in ncpHandleKeepAlive( ). NCP packets not destined for a valid port are simply dropped. In accordance with yet another important aspect of the present invention, the functions of the MUX/Reliability layer include: 1. Creating and terminating NCP connections. 2. Creating, maintaining and deleting associations between application sockets and NCP connections. 3. Delivering NCP replies. 4. Transmission of NCP requests. 5. Retransmission of lost data. 6. Handling ioctls and application requests to get or set socket options. 7. Ensuring that there is only one outstanding request per NCP connection. FIG. 5 shows the internal data structures used by the NCP MUX/Reliability sub-module 30. There are three NCP connections and four application sockets are shown; one connection is shared by two sockets, and the others are each used by a single socket. An nwpcb/ncpcb pair is maintained for each NCP connection. The pair is created dynamically in response to a connect request from the Connection Manager. All network layer information about the connection, including local and remote IPX addresses and routing data structures, is contained in the nwpcb. The nwpcbs used for NCP connections are maintained on a separate linked list from those associated with IPX and SPX sockets. Each nwpcb contains a pointer to the transport layer data structure, the ncpcb. The ncpcb is defined in Appendix A:. An ncpcb contains all the information necessary to maintain a single NCP connection, including the connection state, the sequence and connection numbers and possibly the current task number. A flags variable is used to control the checksum and encryption options that are in effect for that connection. In order to support the association between an application socket and the NCP connection, an array of ncpClient_t structures is maintained. Each ncpClient_t contains pointers to the socket and the ncpcb. SOCK_NCP can support a maximum of 64 application sockets. Each NCP connection maintains a send queue of pending socket write( ) operations. Requests are handled on a first come, first served basis and are not prioritized. A socket may issue multiple writes at any time, but each successive write is subject to first come, first served access. Each queue element contains a pointer to an ncpClient_t. Elements are not removed from the queue until after the reply has been delivered, obviating the need to maintain a global pointer to the current requester's socket. The queue is implemented as an array. GET and PUT indices locate the head and tail. With regard to associating sockets and NCP connections, the effect of the socket( ) call is to assign the clientSocket field (type struct socket *) of an ncpClient_t structure to the newly created socket. A connection is not associated with the socket until a user calls connect( ) (to associate the socket with a new connection) or ioctl(sFD, FIOASSOCIATE) (to associate a socket with an existing NCP connection). Internally, the effect of the ioctl( ) call is to assign the connP field of the appropriate ncpClient_t to the desired ncpcb. Similarly, the effect of ioctl(sFD, FIODISASSOCIATE) is to break that assignment. After the nwpcb and ncpcb have been created, SOCK_NCP builds and transmits a connection request. When the reply is received, soisconnected( ) is called, triggering a return from the connect system call in the application. With regard to the manner in which NCP requests and replies are processed, after the NCP connection has been established, it may be used to transmit requests from numerous application sockets subject to the requirement that only one request per NCP connection may be outstanding at any time. This forces the MUX/reliability layer to queue requests when the NCP connection is waiting for a reply to a previous request. Each ncpcb structure contains a transmit queue that is implemented as an array of socket pointers (struct socket *) and a pair of indices that locate the head and tail of the queue. When a reply is received, the data is delivered to the requesting socket, and the next request from the queue is sent. SOCK_NCP implements a simple pipelining mechanism whereby an application may issue multiple writes on a single socket before receiving a reply to the first request: 1. An application calls write( ) when that socket is already on the NCP send queue. SOCK_NCP places the request on the socket send buffer; 2. The socket eventually ends up at the front of the queue and the first request is transmitted; 3. A reply is received. SOCK_NCP places the packet on the socket receive buffer, discards the first request from the send buffer and places the ncpClient_t at the back of the NCP send queue; 4. Steps 1-4 may be repeated several times if the application makes more than one write. The number of requests that may be queued is limited by the size of the socket send buffer. There are options regarding sockets in that an application may use setsockopt( ) to toggle checksumming or encryption or to select one of two retransmission algorithms. The MUX/reliability layer implements ncp_ctloutput( ) to process socket option requests. Supported socket options are listed in the table 2 below. Once a value is set, that value persists until it is set to a new value. The same option settings apply to all sockets that share the NCP connection.
TABLE 2
Level Optname Description Flag Datatype Values
SOCK_NCP SO_CHECKSUM toggles yes INT 0 = OFF,
checksumming default
between on/off !0 = ON
SOCK_NCP SO_ENCRYPTION toggles yes INT 0 = OFF,
encrypting default
between on/off !0 = ON
SOCK_NCP SO_RETRANSMIT specifies the no UINT 6 = 6 retries,
number of default
transmit retries n = n
retries
With regard to NCP retransmission, the number of transmit retries is configurable but the delay interval algorithm is constant. The NCP module will retransmit NCP requests based on the value of the SO_RETRANSMIT socket option. The socket option is configurable for each socket descriptor using the setsockopt( ) call. The setsockopt( ) call executes instantaneously and does not queue the socket request. The socket option is listed in table 3 below.
TABLE 3
Level Optname Description Flag Datatype Value
SOCK_NCP SO_RETRANSMIT specifies the no UINT specifies
the
number of number of
transmit retries.
retries 6 = 6 retries,
default
The value of the socket option is the number of retries. The default value of the SO_RETRANSMIT socket option is six but may be a greater or smaller number. If the socket option is set to six, SOCK_NCP will retransmit a packet a maximum of six times. The delay interval algorithm is 500 ms, 1 s, 2 s, 4 s, and 8 s . . . 8 s is the maximum delay between packet re-transmits. After the 4.sup.th retry, a packet will be retransmitted every 8 seconds. For example, a SO_RETRANSMIT value of 8 will direct SOCK_NCP to re-transmit a packet 8 times at the following intervals: 500 ms, 1 s, 2 s, 4 s, 8 s, 8 s, 8 s and 8 s. If the reply packet is not received after the last packet is retransmitted, the read( ) call made by the requesting task will return ERROR and the ERRNO value will be set to "ETIMEDOUT". For the default option, "ETIMEDOUT" occurs after .about.23.5 seconds. Tasks that may have been using the same connection number on which the "ETIMEDOUT" occurred are not notified of the transmit failure. Subsequent requests will be processed regardless of the state of the connection or the outcome of the last request/reply sequence. The operation of an NCP connection may be described by a finite state machine comprised of the following states: NCP_CREATING_CONNECTION: The default initial state when the connection is created NCP_READY: The connection has no outstanding requests and is ready to transmit NCP_WAITING_REPLY: The connection has one outstanding request; new requests are queued NCP_DESTROYING_CONN: The connection is being torn down NCP_BAD: A transmit error occurred FIG. 6 shows the operation of the NCP FSM. In response to connect( ), an NCP connection is created and the connection request issued. When a connection is successful, the NCP_READY state is reached, and user requests may be sent. If the connection attempt is unsuccessful, NCP_BAD is entered and no further activity may occur unless connect(AF_UNSPEC) is made. From NCP_READY, the connection may enter NCP_WAIT_REPLY after a request is sent in response to a write( ) call, or it may transition to NCP_DESTROYING_CONN after sending a destroy request if a user calls connect(AF_UNSPEC). In NCP_WAIT_REPLY, a packet may be received or a timeout may occur. If the send queue is empty and a reply is received, the packet is delivered and the new state becomes NCP_READY; otherwise, the next pending request is sent and the connection remains in NCP_WAIT_REPLY. When a timeout occurs and the maximum number of retransmissions have already been sent, NCP_BAD is entered; otherwise, the request is retransmitted while remaining in NCP_WAIT_REPLY. A write or ioctl(FIOASSOCIATE) operation on a connection in the NCP_BAD state sets the global errno to ENCPBADCONN. It is not an error to call ioctl(FIODISASSOCIATE) or connect(AF_UNSPEC) on an NCP_BAD connection. All pending requests are cancelled on NCP_BAD connections and SOCK_NCP will flush the send and receive buffers of each associated socket. With regard to checksums and encryption signatures, by default, checksumming and encryption are turned off. Checksumming and encryption are flagged as enabled/disabled through the securityFlags byte of the "Get Big Packet NCP Max Packet Size" NCP service request/reply. The security flag can be set by the client in the NCP service request or accepted from the NetWare server in the NCP service reply. Either way, SOCK_NCP will extract the security information from the "Get Big Packet NCP Max Packet Size" reply and store the information locally on a per connection basis. When the IPX/NCP modules become disabled, the security flags are reset to the default. If the security information specifies that encryption signatures are enabled, SOCK_NCP will calculate and append the encryption key to the NCP request packet and decode the key from NCP service replies. If the security information specifies that checksums are enabled, SOCK_NCP will direct the IPX protocol stack to perform outgoing checksums. For incoming packets, SOCK_NCP will perform the checksums. With regard to the socket interfacing the NCP module, ncp_ctloutput( ) is the pr_ctloutput( ) routine in SOCK_NCP's protocol switch table, the ncp_ctloutput( ) routine is used to set and retrieve various protocol-level control options. It is called from the kernel functions sosetopt( ) and sogetopt( ). The arguments to ncp_ctloutput( ) include: the requested control operation, a pointer to the socket on which the request was issued, the level, the name of the option to retrieve or change, and a value field which may be used to return various types of information. The ncp_ctloutput( ) routine returns 0 if successful or EINVAL if the name is not SO_RETRANSMIT, SO_CHECKSUM or SO_ENCRYPTION or the retransmission algorithm (the number of retransmission attempts) is incorrect. The handling of user requests is done by the ncp_usrreq( ) routine which is NCP's pr_usrreq( ) entry in the protocol switch table. All user requests that originate as socket calls for the SOCK_NCP protocol are handled by ncp_usrreq( ). The arguments to ncp_usrreq( ) include: a pointer to the socket; the request (PRU_ATTACH, PRU_CONNECT etc.); a pointer to an mbuf containing data; a pointer to an mbuf containing an address; and possibly a pointer to an ifnet structure. The ncp_usrreq( ) routine returns 0 if successful, or a system error such as EINVAL or ENOBUFS otherwise. The correspondence between the socket API and the value of the req argument to ncp_usrreq( ) is shown in the table below. Only a subset of the full socket API is supported by the NCP MUX. The ncp_control( ) routine is used to handle ioctl( ) calls from the application layer. SOCK_NCP currently supports the following ioctl( ) requests: FIODISASSOCIATE is used to break the association between a user socket and an existing NCP connection. This does not destroy the socket. FIOASSOCIATE is used to associate a user socket with an existing NCP connection. The socket must have been created by a call to sockets. The arguments to ncp_control( ) include: a pointer to the socket, the request; a pointer to request-specific data; and possibly a pointer to the interface. The ncp_control( ) routine returns 0 if successful, or a system error otherwise. A request to associate a socket with an invalid address returns EINVAL; if the socket is already connected, ncp_control( ) returns EISCONN. An attempt to associate a socket with a connection that is in the NCP_BAD state returns ENCPBADCONN. ncp_control( ) returns EINVAL if a user attempts to disassociate an unassociated socket. An invalid command causes ncp_control( ) to return EOPNOTSUPP. The ipxintr( ) routine has the responsibility of determining the type of all incoming IPX packets. If the nwpcb is found (based on sender's address and destination IPX socket number), ipxintr( ) calls ncp_input( ). If the nwpcb is not found, the incoming packet may be an NCP watchdog request, in which case ncpHandleKeepAlive( ) is called. The arguments to ncp_input( ) include a pointer to the incoming packet (mbuf *) and a pointer to the appropriate IPX control block (nwpcb *). The responsibilities of ncp_input( ) include: 1. Verifying correct packet request type, sequence and connection numbers. 2. Security processing, if required. 3. Routing incoming replies to the sender's socket. 4. Sending the next queued request. NCP requests are transmitted using the ncp_output( ) routine. When there are no outstanding requests, the next pending request may be sent. The responsibilities of ncp_output( ) include: filling in IPX and NCP headers; computing checksums and signatures, as required; appending the packet to the socket's send buffer so that it is available for retransmission, if necessary; copying the packet and handing it off to nw_output( ). The arguments to ncp_output( ) include a pointer to an NCP control block, a pointer to an mbuf containing the NCP header and the payload. It is the responsibility of the user to allocate and partially fill the NCP header. ncp_output( ) returns 0 if successful or a system error otherwise. ncp slowtimo( ) is called by the kernel every 500 ms, but this time period could be increased or decreased. Its responsibility is to decrement the retransmission timer (if set) and to call ncp_usrreq( ) with a command value of PRU_SLOWTIMO if the timer value is zero. There are no arguments to ncp-slowtimo( ) and the return type is void. With regard to the NCP Watchdog 34, this component of the NCP module is responsible for accepting and responding to NetWare Watchdog packets and it runs below the sockets layer. As a part of the netTask and kernel of VxWorks, the Watchdog module runs within the netTask's and kernel's thread of execution. Watchdog packet behavior is configurable on the NetWare Server. The default configuration for Watchdog behavior causes the NetWare server to send Watchdog packets to a client that has had an inactive connection for the last 5 minutes. After the first watchdog packet is sent to the client, the server sends a watchdog packet every minute for nine minutes or until a reply is received by the server from the client. If a watchdog reply is not received, the server invalidates the current connection and recycles the connection number. NetWare defines the number of the port dedicated to listening for watchdog packets as one plus the number of the port that is used for NCP service request responses. For example, if port 4100h is used as the source port for NCP service requests/replies, port 4101h would become the port used to capture Watchdog packets. Upon receiving a watchdog packet this component of netTask will determine if the connection number given in the watchdog packet is still valid. If the given connection number is still valid, a watchdog response packet will be built and sent to the source of the Watchdog packet (a NetWare server) via an IPX procedure call. If the connection number is not valid, no response is transmitted. All incoming NCP packets that are destined for a non-existent IPX port are processed by ncpHandleKeepAlive( ). ncpHandleKeepAlive( ) is responsible for verifying that the destination IPX port number satisfies the criterion above, namely that the watchdog port be equal numerically to one plus the port number of an existing NCP connection. It is not necessary to allocate an nwpcb/ncpcb pair for watchdog ports, since all watchdog processing may be confined to ncpHandleKeepAlive( ). With regard to the ncpHandleKeepAlive( ), it is called from ipxintr( ) to handle incoming NCP packets that are not destined for an existing IPX port. Since most of these are valid NCP watchdog packets, the normal course of action is to verify whether the NCP connection to which the request refers is still valid, and to reply accordingly. All other packets are simply dropped. The arguments to ncpHandleKeepAlive( ) include a pointer to the mbuf that contains the incoming packet. The return type is void. The structure of the NCP service request packet is outlined in table 4 below. The shaded areas represent the portions of the packet that are initialized by NCP library functions. The unshaded areas of the packet are supplied by the NCP Mux/Reliability sub-module of netTask below the sockets layer.
TABLE 4
offset content notes type
0 RequestType 0x1111 = create service connection word
0x2222 = service request
0x5555 = destroy service connection
Request
0x7777 = burst mode transfer
2 SequenceNumber Mux/Reliability places LastSequence + 1 here
byte
3 ConnectionNumber Low Assigned by server at login byte
4 TaskNumber Identity of client task byte
5 ConnectionNumber High Service Connection used by 1000 user NetWare,
byte
otherwise 0
6 Payload Contents of the payload vary with each variable
NCP service request. The payload is initialized
Request
with function parameters.
The structure of the NCP service reply packet is outlined in the table 5 below. Data within the shaded area is returned to the requesting task across the sockets layer.
TABLE 5
offset content notes type
0 ReplyType 0x3333 = service reply word
0x7777 = burst mode transfer
0x9999 = request being processed
Reply
2 SequenceNumber should match sequence number of request byte
3 ConnectionNumber Low byte
4 TaskNumber byte
5 ConnectionNumber High byte
6 CompletionCode 0 = success byte
7 ConnectionStatus connection down if 4.sup.th bit = 1 byte
6 Payload Requested data variable }
Reply Pay
From the foregoing it should be appreciated that a system and method of implementing a NetWare Core Protocol (NCP) module within a Berkeley Systems Distribution (BSD) Sockets model wherein the NCP module has a NCP reliability sub-module and a NCP library sub-module has been shown and described which has many desirable attributes and advantages. The system and method of the present invention is implemented such that the NCP library sub-module is located above the sockets interface and the NCP reliability sub-module is located below the sockets interface. This results in many advantages including increased performance due to the elimination of task switched data transfer and other interprocess communication steps, such as pipes and selects that impede performance. Other advantages include portability of applications, because of the ability to allow an application to make non-blocking sockets calls and thereby be portable to environments that utilize sockets. While various embodiments of the present invention have been shown and described, it should be understood that other modifications, substitutions and alternatives are apparent to one of ordinary skill in the art. Such modifications, substitutions and alternatives can be made without departing from the spirit and scope of the invention, which should be determined from the appended claims. Various features of the invention are set forth in the appended claims.
|
Same subclass Same class Consider this |
||||||||||
