Mark Beddow is a freelance systems design engineer involved in PC-based projects for security, surveillance, and building management applications. He may be reached at The Old Cottage, Cat Street, East Hendred, Oxon, OX12 8JT, United Kingdom.
Introduction
The remote procedure calls (RPC) described here were developed to augment the file sharing network services available for applications running under MS-DOS with a network operating system (NOS) such as Lantastic. A NOS allows co-operating computers to share database information, but provides little support for direct message transaction between the computers. One is reduced to polling database structures to determine if a message has been posted, which is inefficient for the network operation.The functions presented here use NetBios-level services below the NOS to provide remote procedure call services between any computer on the network quickly, with low overhead and without affecting the NOS. They are best implemented in a multi-threaded application, but the code examples do not include multi-threading procedures for simplicity.
NetBios Datagrams
NetBios is the software interface between computer programs and the Local Area Network Adaptor (LANA). If you are using a network operating system which uses NetBios to implement file sharing, then the NetBios is available and may be accessed without interfering with the NOS services, provided your application behaves sensibly and cleans up properly on exit.The NetBios interface provides services for two types of data transfer services session-level data transfer and datagram transfer. Session-level data transfer allows reliable communication of large messages between computers on a one-to-one basis. Before session communication can commence, the computers must establish a virtual link by means of the call and listen commands. Session level transfers can send large blocks of data, and the NetBios ensures the data is received.
Datagram transfers operate at a lower level in the NetBios. They can transfer up to 512 bytes of data between any computers on a LAN, without the need to establish a session prior to data transfer, and disconnection afterwards. Providing that a computer has set up the NetBios to receive a datagram, any computer on the network can send a datagram to that computer. The datagram transfer does not guarantee that the data is received; the sender cannot know that the datagram has been received without arranging for a handshake datagram to be returned. However, when implementing remote procedure calls this handshake is a necessary feature. 512 bytes is generally adequate for transferring data to, and returning data from, the remote procedure, and there is no session overhead. Thus, the NetBios datagram transfer provides the best general way of implementing an efficient RPC service between a number of computers on the network.
The data transfer services of NetBios communicate to and from local network names that are registered with the NetBios application programs. A computer may have a number of names registered for its adapter card. NetBios ensures that the local names are unique across the network. The use of names means that an application only needs to know the target name to communicate, the name may be anywhere on the network or in the same LANA. Note that these names are not null terminated like C strings but are fixed length and padded with spaces to give the required 16 characters.
All NetBios calls are interfaced by a network control block (NCB) which is passed by pointer as part of the 0x5c interrupt call to the NetBios. The structure of the NCB is set out in Listing 1. The command field holds the identity code for the command to issue. For sending and receiving datagrams, callname contains the network name to communicate with, num the identity for the local name, buffer a pointer to the send or receive message buffer, and buflen the size of the message.
NetBios calls may be issued with a wait or no-wait option. Wait calls return when the command completes, no-wait calls return immediately. For no-wait calls the application may either poll the command-complete field of the NCB to determine when the command has completed (field != -1), or pass a post-function pointer to be called by NetBios at interrupt level when the command completes. The post-function pointer must be set to null if a post-function call is not required in the no-wait mode.
The NCB also contains the parameters returned by the NetBios when the command completes. Most useful for implementing remote procedure calls is that after a datagram receive, the callname field, of the receive NCB contains the network name that sent the message and to which the reply must be sent.
Remote Procedure Call Model
The model used here to implement the RPC is a client/server transaction. Each computer on the network may have a number of RPC servers and one RPC client. Each RPC server and the RPC client are assigned a network name. The RPC client and the RPC servers are usually set up at initialization to be called in the program body as required. To implement the transaction, the RPC client sends a structure in a datagram to the RPC server name. On receiving the datagram the RPC server calls its remote procedure with a pointer to the structure passed in the datagram. On completion the remote procedure returns a static structure which is passed back by the RPC server to the RPC client name which sent the datagram. A successful datagram receive by the RPC client completes the transaction handshake.This implementation does not use the post-routine services of the NetBios to implement the remote procedure call on the server. The remote procedures of the server are called by a dispatcher routine which polls the command-complete field in the NCB block of each server and calls the remote procedure when a datagram has been received for that RPC name. If the datagram post-routine services are used, then the remote procedures are subject to the usual problems of preventing re-entrance into MS-DOS, but latency is reduced.
Ensuring Synchronization
With a datagram transaction on NetBios, it is important to to ensure that a burst of transactions with the server computer does not lose synchronization and cause a transaction failure. My initial experimental applications had a problem here. For NetBios, call execution time depends on processor performance. A slow client computer may not be quick enough to set up the receive datagram command for the reply from a fast server, causing the reply to be lost.The solution is for the client and server to make the receive datagram command call with the no-wait option set before making the send datagram command call and then to poll for the receive datagram command completion. This ensures that the handshake reply cannot be lost even with a wide disparity in performance between the networked computers. NetBios allows us to cancel the pending receive datagram command should the client timeout the server or when the server closes down. Do not forget to cancel any pending commands before exiting, otherwise the system will probably hang at the next program execution.
Implementation
Listing 1 contains the structure definition for the NetBios network control block (NCB) and the linked control structure for each RPC server. Also included are the full range of NetBios command codes. The macros are included to simplify some of the function related to names and the net_transaction call itself.Listing 2 contains the global data for the netrpcserver list, the client network name and client network id. This holds the client network id issued by the NetBios when the name is registered. Also included are the error messages for the RPC call functions and NetBios.
Listing 3 contains the NetBios API call functions and utilities, including a check to ensure NetBios is actually present. Listing 4 contains the heavier functions for transaction management which forms the interface used in the example application code in Listing 5.
The procedure I adopted for the client interface is similar to a file access. In order for an application to make a remote procedure call (net transaction) it must first open the net client name. If successful, a status value of zero will be returned. Otherwise, the NetBios error code indicates the nature of the failure. Note that only one net client can be opened for each computer. Once opened the application can make NetTransact calls to other machines on the network.
The NetTransact macro call takes as parameters the network name of the remote procedure to be called, a pointer to the reply buffer to which the reply structure will be returned, and a pointer to the structure to be sent. If a NetTransact call succeeds then a status of zero is returned, otherwise the error code, which will be a timeout error if the remote computer does not respond. The net client close procedure simply deletes the client network name and sets the identity value to -1 to allow a new client to be opened if required.
The server interface is similar to an interrupt handler, but the need to use interrupts is avoided by scheduling a periodic call to the RPC call dispatcher, net_comms. Each RPC server is installed with install_rpcserver. This takes as parameters the network name to install, a pointer to the remote procedure call, and the size of the reply structure. install_rpcserver if successflinks a control structure for the RPC service into a linked list, allocates storage for the send and receive NCBs and an input buffer, then sets up a pending datagram receive for the RPC service.
The server function is implemented by the RPC call dispatcher net_comms which must be called regularly. If multi-threading is used this is easily achieved. net_comms checks all pending datagram receives in the server linked list every time it is called. If it finds an NCB for datagram receive for which the command-complete field is not -1, then a datagram has been received for that RPC. The function then calls the remote procedure for that server, passing a pointer to the datagram received to the procedure.
The structure returned by the remote procedure is sent to the client's call name after the next pending receive has been set up. Note the pending receives are set up with the NCBNO_WAIT attribute to allow immediate return from the NetBios API. The servers are removed with the single call remove_all_rpcservers which tracks the linked list and cancels the pending receives, deletes the network names, and frees the storage areas. This is best done incorporating remove_all_dgservers in an atexit call at initialization. When remove_all_dgservers removes a server, it prints the number of network errors that have occurred, if any, and the last error for that server.
Each computer on the network can both have installed RPC servers and an RPC client as part of its application program. An application can, if required, transact with its own server.
Example application
The two short programs transact.c and rpcserver.c of Listing 5 are simple example applications. Compile each of these programs and link with the network functions of Listing 2, Listing 3, and Listing 4. Run rpcserve on one computer first, then transact on the second. transact sends a message for rpcserve to print in its remote procedure. The body of rpcserve is simply a loop that calls net_comms. When transact receives the reply message from the remote procedure, it prints the reply and then sends a second message to cause rpcserve to exit. When the second message completes it exits too.NetBios also allows a single datagram to be simultaneously broadcast to any group names with the same name. If the NCDADDNAME command in install_rpcserver is changed to NCBADDGROUPNAME, remote procedures with the same group name may be installed. If a client computer sends to the group name, then all the remote procedures of the group name will be called but the client will only receive the first reply, the other replies will be lost. Providing the client does not make a burst of transaction calls this is a useful mechanism for making a number of computers do the same thing simultaneously.
Acknowledgements
Thanks to Tom Thompson for the Net Bios programmer's reference and to Rob Boardley for locating it for me on CIX. Now if someone knows where I can obtain a programmers reference for IPX I can make this work with Netware.
References
[1] Tom Thompson, CBIS Net Bios Programmer's Reference, CBIS Inc, 5875 Peachtree Industrial Blvd. Bldg. 100, Suite 170 Norcross, GA 30092, 1988.