$title('nservr - name server routines') $compact /************************************************************************** * * MODULE NAME: nservr * * DESCRIPTION: This module implements the server tasks of the nameserver. * * The nameserver consists of two tasks, rem_server and * loc_server. These two tasks manage a table of name-socket * bindings and service local and remote requests for * nameserver operations. Access to the table is synchronized * via the semaphore, table_sem. * * Requests may be either remote or local. Local requests are * serviced by loc_server and remote requests are serviced by * rem_server. Rem_server communicates with client tasks through * the nucleus communication service while loc_server * communicates via data mailboxes. The distinction between * local and remote requests is necessary because the nucleus * communication service cannot be used for local communication. * * The remote server uses the first byte of the control message * as the request byte on an incoming request. This byte tells * the server the type of request being made. The data message * portion of the request contains the data necessary to * complete the request. Rem_server returns a result byte to * the client in the first byte of the control message. Any * other data required for the response is in the data message * part of the response. * * The local server uses the first byte of a request message as * the request byte. Data following the request byte is used to * complete the request. Similarly, the first byte of the * response message is the result byte and the data following * completes the response. * ****************************************************************************/ nservr: DO; $include(:rmx:inc/rmxplm.ext) $include(nstabl.ext) $include(dcom.ext) $include(nservr.lit) $include(dcom.lit) $include(nstabl.lit) $include(:rmx:inc/error.lit) DECLARE /* literals */ ROOTJOB LITERALLY '3', /* indicates root job */ DATAMBFLAG LITERALLY '20H', /* create data mailbox flag */ SERVRBUFSIZE LITERALLY '127', /* num bytes in receive buffer */ TRUE LITERALLY '1'; DECLARE /* globals */ gl_status WORD, host_id WORD, /* nameserver host id */ table_sem TOKEN; /* semaphore governing access to name table */ $subtitle('init_server') /******************************************************************** * * PROC NAME: init_server * * DESCRIPTION: Create semaphore governing access to server name table, create * local and remote server tasks * * CALL: CALL init_server; * * GLOBALS: * *********************************************************************/ init_server: PROCEDURE; DECLARE /* literals */ TASKPRI LITERALLY '0', /* priority of server tasks */ STACKSIZE LITERALLY '512'; /* server task stack size */ DECLARE /* locals */ status WORD, table_sem_s SELECTOR, loc_task TOKEN, /* local server task */ rem_task TOKEN; /* remote server task */ /* begin init_server */ /* get host id and save it for nameserver host id requests */ host_id = rq$get$host$id(@status); CALL cr_tab; table_sem = rq$create$semaphore(1,1,0,@status); table_sem_s = selector$of(@table_sem); rem_task = rq$create$task(TASKPRI, @rem_server, table_sem_s, NIL, STACKSIZE, 0, @status); loc_task = rq$create$task(TASKPRI, @local_server, table_sem_s, NIL, STACKSIZE, 0, @status); END init_server; $eject $subtitle('srv_get_host_id') /******************************************************************** * * PROC NAME: srv_get_host_id * * DESCRIPTION: Create a segment that will contain the host id. Create a * pointer to the segment at offset 0, insert the host id in * the segment and return indication of success of operation. * * CALL: result = srv_get_host_id(hid_ptr_ptr, idsize_ptr) * * RETURNS: result - indicates result of operation * OUTPUT: hid_ptr_ptr - points to host id pointer * idsize_ptr - number of bytes in host id * * GLOBALS: host_id * *********************************************************************/ srv_get_host_id:PROCEDURE(hid_ptr_ptr, idsize_ptr) BYTE REENTRANT; DECLARE /* params */ hid_ptr_ptr POINTER, idsize_ptr POINTER; DECLARE /* locals */ hid_ptr BASED hid_ptr_ptr POINTER, /* host id pointer */ id_ptr POINTER, /* pointer to start of hostid seg */ hid BASED id_ptr WORD, /* host id */ hid_t TOKEN, /* segment token containing host id */ status WORD, idsize BASED idsize_ptr WORD; /* size of host id */ hid_t = rq$create$segment(size(hid), @status); id_ptr = build$ptr(hid_t, 0); hid = host_id; hid_ptr = id_ptr; idsize = size(hid); RETURN REQCOMPLETED; END srv_get_host_id; $subtitle('rem_server') /******************************************************************** * * PROC NAME: rem_server * * DESCRIPTION: Remote server task of the nameserver. Create a port * to receive request messages. Receive a request message, * process the request and send a response message to the * requestor. * * GLOBALS: table_sem * *********************************************************************/ rem_server: PROCEDURE; DECLARE /* locals */ status WORD, trans_id WORD, /* transaction id */ info rec_info, /* info block on message received */ buf_pool TOKEN, /* buffer pool attached to port */ port_t TOKEN, /* token for server port */ tab_info_ptr POINTER, /* points to name table data from client */ client_req BYTE, /* client request */ rsp_ptr POINTER, /* points to server response data */ rsp_data_size DWORD, /* number of bytes in response data */ rsp_result WORD, /* indicates result of response to client request */ except_info STRUCTURE ( /* contains exception handling info */ handlr_ptr POINTER, mode BYTE); except_info.mode = 0; CALL rq$set$exception$handler(@except_info, @status); port_t = get$dport(SERVERPORT, @buf_pool, CHAIN, @status); IF status <> E$OK THEN CALL rq$exit$io$job(0,NIL,@status); DO WHILE TRUE; tab_info_ptr = rq$receive(port_t, WAITFOREVER, @info, @status); client_req = info.con$msg(REQRSP); rsp_result = process_request(client_req, tab_info_ptr, @rsp_ptr, @rsp_data_size); CALL send_response(port_t, @info, rsp_ptr, rsp_data_size, rsp_result); IF tab_info_ptr <> NIL THEN CALL rq$release$buffer(buf_pool, selector$of(tab_info_ptr), 0, @status); END; END rem_server; $subtitle('local_server') /******************************************************************** * * PROC NAME: local_server * * DESCRIPTION: local server task - Set up in-line exception handling, * create a request mailbox and catalog the token for it in * the root job. Wait for a request, service requests as * they occur and mail a response message back to the * requestor. * * GLOBALS: table_sem * *********************************************************************/ local_server: PROCEDURE; DECLARE /* locals */ status WORD, servr_mbx TOKEN, /* request mailbox for local nameserver */ root_job TOKEN, /* token for root job */ req_size WORD, /* size of incoming request */ req_buffer(SERVRBUFSIZE) BYTE, /* receive buffer for requests */ new_req STRUCTURE( req_type BYTE, /* request type */ client_mbx TOKEN, /* mailbox receiving response */ tab_info(1)BYTE) /* data part of request */ AT (@req_buffer), tab_info_ptr POINTER,/* points to name table data from client */ client_req BYTE, /* client request */ rsp_ptr POINTER,/* points to server response data */ rsp_data_size DWORD, /* number of bytes in response data */ rsp_result WORD, /* indicates result of response to client request */ except_info STRUCTURE ( handlr_ptr POINTER, mode BYTE); except_info.mode = 0; CALL rq$set$exception$handler(@except_info, @status); servr_mbx = rq$create$mailbox(DATAMBFLAG, @status); IF status <> E$OK THEN CALL rq$exit$io$job(0,NIL,@status); root_job = rq$get$task$tokens(ROOTJOB, @status); IF status <> E$OK THEN CALL rq$exit$io$job(0,NIL,@status); CALL rq$uncatalog$object(root_job, @(10,'nameserver'), @status); CALL rq$catalog$object(root_job, servr_mbx, @(10,'nameserver'), @status); IF status <> E$OK THEN CALL rq$exit$io$job(0,NIL,@status); DO WHILE TRUE; req_size = rq$receive$data(servr_mbx, @req_buffer, WAITFOREVER, @status); rsp_result = process_request(new_req.req_type, @new_req.tab_info, @rsp_ptr, @rsp_data_size); CALL mail_response(new_req.client_mbx, new_req.req_type, rsp_ptr, rsp_data_size, rsp_result); END; END local_server; $eject $subtitle('process_request') /******************************************************************** * * PROC NAME: process_request * * DESCRIPTION: Perform requested operation on nameserver table and return * result of operation and associated data. * * CALL: rsp_result = process_request(client_req, req_data_ptr, * rsp_ptr_ptr, rsp_size_ptr) * * INPUTS: client_req - request * req_data_ptr - points to data accompanying request * rsp_ptr_ptr - pointer to the response data pointer * rsp_size_ptr - pointer to number of bytes in response data * * RETURNS: rsp_result - indicates outcome of request processing * * GLOBALS: table_sem * *********************************************************************/ process_request: PROCEDURE(client_req, req_data_ptr, rsp_ptr_ptr, rsp_size_ptr) WORD REENTRANT; DECLARE /* params */ client_req BYTE, req_data_ptr POINTER, rsp_ptr_ptr POINTER, rsp_size_ptr POINTER; DECLARE /* locals */ req_data BASED req_data_ptr ns_ent, result BYTE, /* result of table operation */ units_left WORD, /* number of units left in table semaphore */ status WORD, rsp_size BASED rsp_size_ptr DWORD; units_left = rq$receive$units(table_sem, 1, WAITFOREVER, @status); IF client_req = INSERTREQ THEN DO; result = insert_name(req_data.sock, @req_data.name, @status); rsp_size = 0; END; ELSE IF client_req = DELETEREQ THEN DO; result = delete_name(@req_data.name); rsp_size = 0; END; ELSE IF client_req = LOOKUPREQ THEN DO; result = get_sock(@req_data.name, rsp_ptr_ptr); rsp_size = SOCKETSIZE; END; ELSE IF client_req = CHANGEREQ THEN DO; result = change_sock(@req_data.name, req_data.sock, @status); rsp_size = 0; END; ELSE IF client_req = HOSTREQ THEN result = srv_get_host_id(rsp_ptr_ptr, @rsp_size); ELSE IF client_req = TABLEREQ THEN result = get_table(rsp_ptr_ptr, rsp_size_ptr); ELSE DO; result = ILLEGALOP; rsp_size = 0; END; CALL rq$send$units(table_sem,1,@status); RETURN result; END process_request; $eject $subtitle('send_response') /******************************************************************** * * PROC NAME: send_response * * DESCRIPTION: Send a response to a remote client * * CALL: CALL send_response(port_t, info_ptr, rsp_ptr, rsp_size * rsp_result) * * INPUTS: port_t - token for server port * info_ptr - points to receive info structure * rsp_ptr - points to response data * rsp_size - response data size * rsp_result - result of requested operation * *********************************************************************/ send_response:PROCEDURE(port_t, info_ptr, rsp_ptr, rsp_size, rsp_result); DECLARE /* params */ port_t TOKEN, info_ptr POINTER, rsp_ptr POINTER, rsp_size DWORD, rsp_result BYTE; DECLARE /* literals */ RECTYPEMASK LITERALLY '011110000B', /* gets receive type from info */ CONSIZE LITERALLY '20'; /* size of control message */ DECLARE /* locals */ status WORD, con_msg(CONSIZE) BYTE, /* control message buffer */ trans_id WORD, /* transaction id */ rec_type BYTE, /* type of request message received */ info BASED info_ptr rec_info; /* info block on message received */ con_msg(0) = rsp_result; rec_type = info.flags AND RECTYPEMASK; IF rec_type = TREQUEST THEN trans_id = rq$send$reply(port_t, info.rem$socket, info.trans$id, @con_msg,rsp_ptr, rsp_size, 0, @status); ELSE IF rec_type = NOTRAN THEN trans_id = rq$send(port_t, info.rem$socket, @con_msg, rsp_ptr, rsp_size, 0, @status); END send_response; $eject $subtitle('mail_response') /******************************************************************** * * PROC NAME: mail_response * * DESCRIPTION: Mail a response to a local client * * CALL: CALL mail_response(client_mbx, req_type, rsp_ptr, rsp_size * rsp_result) * * INPUTS: client_mbx - clients mailbox receiving response * req_type - type of request serviced * rsp_ptr - points to response data * rsp_size - response data size * rsp_result - result of requested operation * *********************************************************************/ mail_response:PROCEDURE(client_mbx, req_type, rsp_ptr, rsp_size, rsp_result); DECLARE /* params */ client_mbx TOKEN, req_type BYTE, rsp_ptr POINTER, rsp_size DWORD, rsp_result BYTE; DECLARE /* locals */ status WORD, rsp STRUCTURE( result BYTE, /* result of request */ rsp_data(SERVRBUFSIZE) BYTE), /* response data */ table_info_ptr POINTER, /* points to table pointer */ table_info BASED table_info_ptr STRUCTURE (table_size DWORD, /* number of bytes in table */ table_ptr POINTER); /* points to name table */ rsp.result = rsp_result; IF req_type = TABLEREQ THEN DO; table_info_ptr = @rsp.rsp_data; table_info.table_size = rsp_size; table_info.table_ptr = rsp_ptr; CALL rq$send$data(client_mbx, @rsp, size(table_info) +1, @status); END; ELSE DO; CALL movb(rsp_ptr, @rsp.rsp_data, rsp_size); CALL rq$send$data(client_mbx, @rsp, rsp_size +1, @status); END; END mail_response; CALL init_server; CALL rq$delete$task(selector$of(NIL), @gl_status); END nservr;