CS644 Spring '10 Final Project Network-like IPC Service ============================================ [1]===== EXTERNAL SPECIFICATION: API ====== int dgram_init( void ) - It should be called before using the service, from kernel context. int dgram_receive( short dst_port, short *src_port, char *data ) - a system call, that receives DGRAM_LEN bytes of data at *data, for the local port, dst_port. - the source port, src_port, is also returned. - returns DGRAM_LEN number of bytes or SYSERR. int dgram_send( short dst_port, short src_port, char *data ) - a system call that sends DGRAM_LEN bytes of data at *data from the local system and source port, src_port to the destination port. - Returns OK or SYSERR. [2] ==== INTERNAL DOCUMENTATION ====== GENERAL DISCUSSION The datagram service supports sending and receiving fixed-length datagrams between processes. A client process calls dgram_send to send a buffer of data. The data is copied to a system buffer belonging to the dgram service. This buffer of data is stored in a data structure for the destination port, specifically a Xinu port, since multiple datagrams for the same destination port may be needed to be stored at once. A client process calls dgram_receive to receive a datagram worth of data sent by another process to the destination port specified in the system call. Dgram_receive uses XINU message port preceive to obtain a dgram buffer destined to this port, and copies the data from kernel to receiver memory. The caller blocks on the preceive if there is no data available. DATA STRUCTURES: A datagram needs to be stored for a port in such a way that the receiver can be later told the source port. Thus the minimum information is the data and the source port. We could also put the destination port in here: struct stored_dgram { short src_port; /* datagram source dgram port */ char dgram_data[DGRAM_LEN]; }; Each destination port needs a Xinu message port for storing stored_dgrams. struct port_storage { int in_use; /* this slot is in use */ int dgrams; /* XINU message port identifier */ short dgram_port; /* destination dgram port */ }; We need an array of these, one for each ipc port in use. struct port_storage ipc_ports[MAX_IPC_PORTS]; FUNCTIONS: int dgram_init( void ) Initializes the datagram layer. Marks all the port_storage structs in ipc_ports as not in-use. int dgram_receive( short dst_port, short *src_port, char *data ) dgram_receive looks up dst_port in the ipc_ports array, and if not found, sets up a slot for it, creating a Xinu port via pcreate. Then it calls preceive on the Xinu port found in the ipc_ports entry. This may block, but that's expected. When it returns, it returns a pointer to a struct stored_dgram. The datagram data is copied from the stored_dgram to *data, and the source port to *src_port, and the memory is freed. int dgram_send( int dst_sysid, short dst_port, short src_port, char *data ) dgram_send looks up dst_port in ipc_ports, and if not found, sets up a slot for it, creating a Xinu port via pcreate. Then it getmem's space for a new stored_dgram, and sets its src_port, and copies DGRAM_LEN bytes from *data into the datagram data area. Then it psend's the pointer to the stored_dgram into the Xinu message port in the port_storage. Note that psend might block due to a full Xinu message port, which is not expected for network-like services. It would be better to obtain the pcount under kernel mutex and fail if the Xinu port is full. USER-LEVEL code Note that the client and server are both user-level code, so the main function should do each of these in an appropriate function: --start the first server process --start the second server process --run client code for the first service --run client code for the second service