INTRA-CLUSTER COMMUNICATIONS (ICC) SYSTEM SERVICES DESIGN 08/23/96 Authors: Niccole Luce, Steve Pitcher, John Covert, Doug Gordon Internal Reviewers: John Covert, Doug Gordon, Greg Jordan, Niccole Luce, Steve Pitcher, Babitha Prasad V 0.9 ICC CODE GENERAL - Due to questions regarding the availability of Jacket routines and other exec support on VAX for system level "C" programming, the new ICC code will be developed in BLISS-64 on Alpha and BLISS-32 on VAX. - We will be calling into IPC at the Kernel-Mode Interface level. - Other than possibly for future modifications for 64-bit support, no modifications are required to the currently existing IPC code. - Alpha and VAX will use a common code base. 64-BIT SUPPORT - For the initial internal release, the underlying IPC does not support 64-bit buffer addresses. Until this is corrected, planned for early in 1997, the ICC System Services will check this and reject buffer addresses located in P2 space. This temporary restriction does not exist for handles or linkage addresses located in P2/S2 space. - When 64-bit support is added, it will be supported only through the ICC System Service. Existing users of either IPC kernel mode interface or the IPC user defined system services will neither be affected by the changes nor able to use 64-bit support. - On Alpha - All address arguments are treated as 64-bits. - All address arguments supplied by the user are treated as quadword 64-bit addresses, and any descriptors may be 64-bit descriptors. This includes the linkage address provided as procedure values when specifying routine addresses as well as any buffer provided to ICC by the user or to the user by ICC. In the case of P1 addresses provided to the user, which cannot currently be larger than a longword, the quadword interface will still be used for consistency, and the high order longword will be guaranteed to be zero. - On VAX - All addresses are 32-bits. - Only 32-bit descriptors are defined and supported. ICC CODE OPEN ASSOCIATION ROUTINE SYS$ICC_OPEN_ASSOC() SYS$ICC_OPEN_ASSOC assoc_handle, [assoc_name], [logical_name], [logical_table], [event_rtn], [recv_rtn], [maxflowbufcnt], [maxrecbufsiz], [maxxmtbufsiz] The Open Association service declares an application association with IPC. Servers must make this call in order to declare/register their name and indicate their readiness to receive incoming connections. Although a client is permitted to call this routine, it is not necessary for simple applications not needing to handle incoming connections or disconnect and unsolicited data event ASTs. A client may open a connection without specifying an open association; this will automatically create a default association of ICC$PID_nnnnnnnn (where nnnnnnnn is the character representation of their Process ID). NETMBX privilege is required to open any association. The Association Namespace is a controlled resource. An attempt to open an association with a name not authorized will fail with the error SS$_NOSYSNAM returned to the caller. In addition to making entries in the system's local association namespace, a call to SYS$ICC_OPEN_ASSOC may also make an entry in a simple clusterwide registry of active assocations. An association opened in an inner mode is not visible to any outer mode. Inner modes are prevented from using the default association. An application may open any number of associations subject to available process BYTLM quota. Currently, there is a systemwide limit of 512 open associations. There is no limit imposed clusterwide. FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_OPEN_ASSOC User 0 Process IPC$START Kernel ASTDEL Process IPC$START takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPST = IPC start packet structure DESIGN: - Using $HAS_PRIV, check for NETMBX privilege. - If the process does not have NETMBX privilege - FAIL the request, returning the error SS$_NONETMBX to the user. - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the required argument: assoc_handle - Return SS$_INSFARG - If we received too many arguments (more than 9) - Return SS$_TOO_MANY_ARGS - Probe required arguments: assoc_handle (write). - Probe optional arguments (if supplied): assoc_name (via calling probe_str_descr_read) and logical_name and logical_table (both via calling probe_str_descr_read) - Copy the arguments we got into local storage, storing a zero for any optional argument(s) (i.e., 2 - 9) we were not passed. - Determine the caller's previous access mode. - Determine if the process is authorized to open this association - Set the local flag SYSNAM_PRIV_USED to zero. - Using $HAS_PRIV, check for SYSNAM privilege. - If the process does NOT have SYSNAM privilege - Call ICC_Chk_Creation_Rights - If the call to ICC_Chk_Creation_Rights fails - Audit the open attempt as the request required SYSNAM privilege (which the process didn't have). - FAIL the request, returning the error SS$_NOSYSNAM to the user. - Otherwise (process DOES have SYSNAM privilege) - Set the local flag SYSNAM_PRIV_USED to one. - Determine if the specified assoc_name may be opened by this process: - Call Dflt_Assoc_Chk_and_Setup to check if this is the default association and to copy the incoming association name (or the default association name string) to ICCPAB$T_assoc_name. DFLT_ASC_RQSTD = Dflt_Assoc_Chk_and_Setup (assoc_name; ICCPAB$T_assoc_name); - If Dflt_Assoc_Chk_and_Setup returns TRUE (i.e., this is the default association) - If the caller's previous access mode is not USER (i.e., attempting to open the default assoc from an inner mode) - FAIL the request, returning the error SS$_IVMODE to the user. - If the local variable DFLT_ASC_RQSTD is set AND the dflt_asc_open bit in ICCPDB$L_flags is set (i.e., they want to open the default association -- local variable DFLT_ASC_RQSTD is TRUE -- but it's already open) - FAIL the request, returning the error SS$_DUPLNAM to the user. - Otherwise - Set status to SS$_NORMAL. - Raise IPL to ASTDEL and save old IPL. - Allocate ICC data structures. - If this is the 1st time this process has invoked the ICC services (its slot in the ICCPDB_VEC$L_PROC_PTRS vector is zero) allocate an ICCPDB and store its address in the slot. - Initialize the new ICCPDB as follows: - ICCPDB$L_PAB_flink and ICCPDB$L_PAB_blink = the address of the ICCPDB$L_PAB_flink. - ICCPDB$L_PCB_flink and ICCPDB$L_PCB_blink = the address of the ICCPDB$L_PCB_flink. - The rest (past the header fields) to zero. - Determine the total size of the ICCPAB/IPST structure. - Call EXE$DEBIT_BYTCNT_BYTLM_ALO to both allocate the ICCPAB/IPST structure and charge the users' BYTCNT and BYTLM quotas for it. - If EXE$DEBIT_BYTCNT_BYTLM_ALO returned a FAILURE status in R0 - FAIL the request, and return the error status to the user. - Otherwise - The actual amount of memory allocated for the combined structure is stored in ICCPAB$W_size. - Initialize the ICCPAB$L_PDB to the address of the ICCPDB, ICCPAB$L_flink and ICCPAB$L_blink to ICCPDB$L_PAB_flink, and the rest (past the header fields) to zero. - Set ICCPAB$L_state to OPENING. - Store the caller's previous access mode in ICCPAB$L_open_mode. - Save the local copy of the following arguments in their ICCPAB fields: event_rtn, recv_rtn - Fill in the IPST as follows: - IPST$L_MAXIN = maxrecbufsiz - IPST$L_MAXOUT = maxxmtbufsiz - IPST$W_MAXBUF = maxflowbufcnt - IPST$W_FLAGS = Clear the IPST$M_KAST flag bit. Set the IPST$M_TX_COMP, IPST$M_FCONT and IPST$M_REPLYCOMP flag bits. Also set the flag bit IPST$M_EVENTRCV if the user has provided a recv_rtn. - IPST$L_PID = the PID of the requestor/caller from the PCB (or KTB on Alpha) - IPST$A_NAMES = ICCPAB$T_assoc_name (Byte counted ASCIC string) - IPST$A_EVENT = the address of our ICC kernel mode event handling routine (called by IPC in kernel mode, and must be part of this execlet) which dispatches to the user's event routine. - Call Link_AB to assign/store the association handle, link the ICCPAB into the ICCPAB queue in the ICCPDB and update the association count. ICCPAB$L_assoc_handle = Link_AB (ICCPAB, DFLT_ASC_RQSTD); - Call IPC$START at IPL = ASTDEL with the address of the IPST within our ICCPAB. status = IPC$START (.IPST); - Upon return from IPC$START - On a SUCCESSFUL completion: - IPC$START will have stored the IPCID value in the IPST which is part of the ICCPAB. - If SYSNAM_PRIV_USED = 1 (i.e., they have SYSNAM privilege AND it was required to open the association ICCPAB$T_assoc_name): - If they're in USER mode, audit the use of the SYSNAM privilege. - If the logical_name argument was specified - Call Simple_Registry_Add to make an entry in the simple clusterwide registry for this assocation. status = Simple_Registry_Add (logical_name, logical_table, ICCPAB); - If the call to Simple_Registry_Add fails - Call EXE$ICC_CLOSE_ASSOC with ICCPAB$L_assoc_handle. - FAIL the request, returning the error status from Simple_Registry_Add to the user. - Set ICCPAB$L_state to OPEN. - Store ICCPAB$L_assoc_handle in the assoc_handle argument. - On a FAILURE completion: - Call Cleanup_ICCPAB to credit/unlink/deallocate the ICCPAB/IPST. Cleanup_ICCPAB (ICCPAB); - Restore IPL. - Return to user with status (and information). - Return SS$_NORMAL instead of SS$_SYNCH as this service always completes synchronously. ICC CODE CLOSE ASSOCIATION ROUTINE SYS$ICC_CLOSE_ASSOC() SYS$ICC_CLOSE_ASSOC assoc_handle The Close Association System Service closes the application's association with IPC. If multiple associations are open, only the specified association is closed. When an association is closed, any active connections on that association are disconnected. All associations opened in user mode will be closed at image exit; associations opened in inner modes will be closed at process termination. When an association is closed, the entry (if any) in the simple clusterwide association registry is removed. FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_CLOSE_ASSOC User 0 Process IPC$STOP Kernel ASTDEL Process IPC$STOP takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPST = IPC start packet structure - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the required argument: assoc_handle - Return SS$_INSFARG - If we received too many arguments (more than 1) - Return SS$_TOO_MANY_ARGS - Call AssocHndl_to_ICCPAB to look up the ICCPAB associated with the specified assoc_handle. - If AssocHndl_to_ICCPAB returns a 0 (i.e., none found) - FAIL the request, returning the error SS$_IVCHAN to the user. - Determine the caller's previous access mode. - If the caller's previous access mode is not equal to ICCPAB$L_open_mode (the user is attempting to open this connection from a mode other than the one the association was opened in) - If caller's previous access mode is less than ICCPAB$L_open_mode - FAIL the request, returning the error SS$_IVMODE to the user. - Otherwise (i.e., caller's prev access mode is greater than ICCPAB$L_open_mode) - FAIL the request, returning the error SS$_IVCHAN to the user. - Raise IPL to ASTDEL and save old IPL. - Set ICCPAB$L_state to CLOSING. - For all the ICCPCB's associated with this ICCPAB: - Get the (now) 1st ICCPCB on the ICCPAB's ICCPCB list. - Call SYS$ICC_DISCONNECTW (the synchronous form of the SYS$ICC_DISCONNECT call) with the following arguments: - conn_handle = ICCPCB$L_conn_handle - IOSB = a local IOSB - astadr, astprm, disc_buf_len and disc_buf = 0 - If ICCPAB$L_lgcl_name_addr is not 0 (i.e., we have a logical name string) - Call Simple_Registry_Remove to remove the entry for this association from the simple clusterwide registry and save the return status. Simple_Registry_Remove (ICCPAB); - Call IPC$STOP (at IPL = ASTDEL) with the address of the IPST within our ICCPAB where - IPST$L_IPCID = Value returned to us from IPC on the SYS$ICC_OPEN_ASSOC call. status = IPC$STOP (.IPST); - Upon return from IPC$STOP - Call Cleanup_ICCPAB to credit/unlink/deallocate the ICCPAB/IPST. Cleanup_ICCPAB (ICCPAB); - If this was the last ICCPAB for this process, deallocate the ICCPDB and zero the process's slot in the ICCPDB_VECTOR. - Restore IPL. - Return to caller with status. - If status is successful - Return SS$_NORMAL (no need to return SS$_SYNCH as this service always completes synchronously) - Otherwise Return the error status to the user. ICC CODE INITIATE CONNECTION ROUTINE SYS$ICC_CONNECT(), SYS$ICC_CONNECTW() SYS$ICC_CONNECT IOSB, [astadr], [astprm], assoc_handle, conn_handle, remote_assoc, [remote_node], [user_context], [conn_buf], [conn_buf_len], [return_buf], [return_buf_len], [retlen_addr], [flags] The Connect System Service establishes a connection to a remote application over an open association. Connections must be opened in the same mode as their association. If the user provides the default association constant ICC$C_DFLT_ASSOC_HANDLE as its association handle, the default association will be used; it will be opened if it is not already open. Any number of connections are possible over a single association, up to a limit of 262,144 total connections on any system and subject to process BYTLM quota. At image exit, as a result of closing any open user mode associations, all user mode connections will be disconnected. Inner mode connections are the responsibility of the inner mode code, but will be disconnected at process termination when inner mode associations are closed. Connections opened in an inner mode are not visible to outer modes. A client opens connections with the Connect service; a server opens connections with the Accept service. ICC CODE FLOW: This operation is not actually complete until the ACCEPT or REJECT message is received from the remote target. The following diagram will hopefully help to visualize the flow of this operation and the ICCPCB state stages. Requestor Target --------- ------ Calls SYS$ICC_CONNECT ICCPCB$L_state = CONNECTING msg type = IPC$_EV_LINK msg sent to target ----------> Target receives IPC$_EV_LINK msg no ICCPCB exists as of yet ... +------ Target may reject due to lack | of resources, etc. which sends | an IPC$_EV_REJECT type msg back | to the requestor | ... | Allocate and set up an ICCPCB | Set ICCPCB$L_state to | ICCPCB$C_CONN_RCVD | ... | Schedule AST to user (target assoc) | ... | The target user then: | Calls SYS$ICC_ACCEPT | Set ICCPCB$L_state to OPEN | msg type = IPC$_EV_ACCEPT | or SYS$ICC_REJECT | deallocate ICCPCB V msg type = IPC$_EV_REJECT Requestor receives msg <---------- which sends msg back to requestor if ACCEPTED Set ICCPCB$L_state to OPEN if REJECTED or FAILED Deallocate ICCPCB Connect operation complete Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_CONNECT User 0 Process IPC$LINK Kernel ASTDEL Process IPC$LINK takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPLK = link_ipcrp structure ICC CODE DESIGN: - If we were not passed an IOSB address - FAIL the request, returning the error SS$_INSFARG to the user. - Determine the caller's previous access mode. - Call ICC_IOS_ICC_INIT to probe/clear an IOSB of type ICC$C_TYP_IOSB. - If ICC_IOS_ICC_INIT returned an error status - FAIL the request with the error status being returned to the user. - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the other required arguments: assoc_handle, conn_handle and remote_assoc - Return SS$_INSFARG - If we received too many arguments (more than 14) - Return SS$_TOO_MANY_ARGS - Copy the arguments we got into local storage, storing a zero for any optional argument(s) (i.e., 2-3, 7-14) we were not passed. - Probe required arguments: conn_handle (write), remote_assoc (via probe_str_descr_read) and retlen_addr (write). - Probe optional arguments (if supplied): remote_node (via probe_str_descr_read), conn_buf (via probe_buffer for read) and return_buf (via probe_buffer for read). - Set up a mask of length bits to be saved later in ICCPCB$L_arg_lens. - Validate the association handle and get the associated ICCPAB. - If assoc_handle = ICC$C_DFLT_ASSOC_HANDLE - If the dflt_asc_open bit in ICCPDB$L_flags is clear (i.e., the default association for this process is NOT open) - Set up and call SYS$ICC_OPEN_ASSOC - If the open attempt fails - FAIL the request, passing through the error status returned from the SYS$ICC_OPEN_ASSOC call to the user. - Otherwise (i.e., the default association for this process should already be open so just get and use it) - Call AssocHndl_to_ICCPAB to get the ICCPAB associated with the default association. - If AssocHndl_to_ICCPAB returns a 0 (i.e., NO ICCPAB was found for the default association) - Set up and call SYS$ICC_OPEN_ASSOC - If the open attempt fails - FAIL the request, passing through the error status returned from the SYS$ICC_OPEN_ASSOC call to the user. - Otherwise (ICCPAB found for default association) - If the caller's previous access mode is not equal to ICCPAB$L_open_mode (i.e., the user is attempting to open this connection from a mode other than the one the association was opened in). Note that this can't be done before now as we don't have an ICCPAB before the call to AssocHndl_to_ICCPAB. - If caller's prev access mode is less than ICCPAB$L_open_mode - FAIL the request, returning SS$_IVMODE to the user. - Otherwise (i.e., caller's prev mode is greater than ICCPAB$L_open_mode) - FAIL the request, returning SS$_IVCHAN to the user. - Otherwise (this is NOT the default association handle) - Call AssocHndl_to_ICCPAB to look up the ICCPAB associated with the specified assoc_handle. - If AssocHndl_to_ICCPAB returns a 0 (i.e., NO association with that handle exists for this process) - FAIL the request, returning the error status SS$_IVCHAN to the user. - Otherwise (an association exists for the specified handle) - If the caller's previous access mode is not equal to ICCPAB$L_open_mode (i.e., the user is attempting to open this connection from a mode other than the one the association was opened in). Note that this can't be done before now as we don't have an ICCPAB before the call to AssocHndl_to_ICCPAB. - If caller's prev access mode is less than ICCPAB$L_open_mode - FAIL the request, returning the error SS$_IVMODE to the user. - Otherwise (i.e., caller's prev mode is greater than ICCPAB$L_open_mode) - FAIL the request, returning the error SS$_IVCHAN to the user. - If its ICCPAB$L_state is NOT OPEN - FAIL the request, returning the error status SS$_WRONGSTATE to the user. - Determine/Obtain the remote association name and node to connect to. - If the remote_node argument is zero (i.e., not specified) Note: REM_NODE_NAME is declared to be 6 bytes in length and REM_ASC_NAME is declared to be 32 bytes in length. - Call Simple_Registry_Lookup status = Simple_Registry_Lookup (remote_assoc; REM_NODE_NAME; REM_ASC_NAME); - If the call to Simple_Registry_Lookup is UNsuccessful - FAIL the request, returning SS$_ITEMNOTFOUND to the user. - Otherwise (a descriptor was passed to us) (but the nodename string portion could be blank/empty, specify 1 node name, or specify a list of node names) - If the buffer pointed to by remote_node is null or all blanks - Copy the local SCS nodename to REM_NODE_NAME. - Otherwise - If remote_node has a list of nodes (i.e., it contains a comma) - Call Random_Pick with an integer representing the number of nodenames in the list to randomly choose a member (i.e., no state is maintained by the random number algorithm). - Copy the nodename in the list that corresponds to the value returned by Random_Pick to REM_NODE_NAME. - Otherwise (just 1 name specified) - Copy the buffer pointed to by remote_node to REM_NODE_NAME. - Copy the buffer pointed to by remote_assoc to REM_ASC_NAME. - Determine if the process is authorized to make this connection. - Call ICC_Chk_Connect - If the call to ICC_Chk_Connect fails - FAIL the request, returning the error SS$_NOPRIV to the user. - Raise IPL to ASTDEL and save old IPL. - Allocate ICC data structures. - Determine the total size of the ICCPCB/IPLK structure. - Call EXE$DEBIT_BYTCNT_BYTLM_ALO to both allocate the ICCPCB/IPLK structure and charge the users' BYTCNT and BYTLM quotas for it. - If EXE$DEBIT_BYTCNT_BYTLM_ALO returned a FAILURE status in R0 - FAIL the request and return the error status to the user. - Otherwise - The actual amount of memory allocated for the combined structure is stored in ICCPCB$W_size. - Initialize the ICCPCB as follows: - ICCPCB$L_PDB to the address of the ICCPDB. - ICCPCB$L_PAB to the address of the ICCPAB. - Initialize queues maintained in the ICCPCB - ICCPCB$L_PSB_flink and ICCPCB$L_PSB_blink to the address of the ICCPCB$L_PSB_flink. - ICCPCB$L_PRB_flink and ICCPCB$L_PRB_blink to the address of the ICCPCB$L_PRB_flink. - ICCPCB$L_IPB_flink and ICCPCB$L_IPB_blink to the address of the ICCPCB$L_IPB_flink. - ICCPCB$l_open_mode = caller's previous mode - If the SYNCH_MODE bit is set in the flags argument - Set the synch_mode bit in ICCPCB$L_flags. - Setup byte counted ASCIC remote nodename string. - Byte 0 of ICCPCB$T_rem_node_name = length of REM_NODE_NAME. - Copy REM_NODE_NAME to ICCPCB$T_rem_node_name starting at byte offset 1. - Setup byte counted ASCIC remote association name string. - Byte 0 of ICCPCB$T_rem_asc_name = length of REM_ASC_NAME. - Copy REM_ASC_NAME to ICCPCB$T_rem_asc_name starting at byte offset 1. - The rest (past the header fields) to zero. - Call P1C_IPB_setup with the ICCPCB and ICCPAB addresses. status = P1C_IPB_setup (ICCPCB, ICCPAB) - If the call failed - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=FALSE); - FAIL the request, returning the error status SS$_INSFP1POOL to the user. - Allocate an ACB from NonPaged Pool for the connect. - If the allocation attempt failed - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=FALSE); - FAIL the request, returning SS$_INSFMEM to the user. - Otherwise - Store the ACB's address in ICCPCB$A_Conn_ACB. - If a conn_buf or return_buf was specified: - Allocate a buffer of length max(conn_buf_len,return_buf_len) from NonPaged Pool and store its address in ICCPCB$A_pool_bfr and its length in ICCPCB$L_pool_bfr_alo. - If the allocation attempt failed - Deallocate the ACB pointed to by ICCPCB$A_Conn_ACB. - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=FALSE); - FAIL the request and return the error status to the user. - If connect data was specified (i.e., conn_buf is not zero): - Copy the user's connect data into our NonPaged Pool data buffer. - Call EXE$DEBIT_BYTCNT with ICCPCB$L_pool_bfr_alo to charge the user for allocating the buffer. - Call Link_CB to link the ICCPCB onto the ICCPCB queue in the ICCPDB, assign/store the connection handle and update the connection count. - Store the following ICCPAB information in the ICCPCB: Association handle and ICCPAB address. - Save the local copy of the following arguments in the ICCPCB: ICCPCB$A_IOSB = IOSB ICCPCB$L_retbfr_max = return_buf_len ICCPCB$A_ret_buf = return_buf ICCPCB$Q_compl_prm = astprm ICCPCB$A_compl_rtn = astadr ICCPCB$A_actual_retlen = retlen_addr - Set ICCPCB$L_state to CONNECTING. - Set up the IPLK fields as follows: - IPLK$L_IPCID = the value in the requested association's ICCPAB. - IPLK$L_NODEID = zero - IPLK$W_NODEIDH = zero - IPLK$A_NAMES = the address of ICCPCB$T_rem_asc_name. - IPLK$A_NODENAMES = the address of ICCPCB$T_rem_node_name. - If conn_buf is not equal to zero (i.e., connection data was specified) - IPLK$L_SEND_LEN = conn_buf_len - IPLK$A_SEND_BUFFER = ICCPCB$A_pool_bfr (the address of our allocated buffer in pool) - Otherwise - IPLK$L_SEND_LEN = 0 - IPLK$A_SEND_BUFFER = 0 - If return_buf is not equal to zero (i.e., return data was requested) - IPLK$L_REPLY_LEN = return_buf_len - IPLK$A_REPLY_BUFFER = ICCPCB$A_pool_bfr (the address of our allocated buffer in pool) - Otherwise - IPLK$L_REPLY_LEN = 0 - IPLK$A_REPLY_BUFFER = 0 - IPLK$Q_CONTEXT = the address of the ICCPCB. - IPLK$L_ALIAS = user_context - IPLK$L_TSELECT_MASK = Set the following flag bits: IPLK$M_LOCAL (= net$m_tselect_local) IPLK$M_SCS (= net$m_tselect_scs) - IPLK$L_FLAGS = the flag IPLK$M_TSELECT is set. - Call IPC$LINK with the IPLK address status = IPC$LINK (.IPLK); - Upon return from IPC$LINK: - Restore IPL. - Return to user (or SYS$ICC_CONNECTW) with status in R0. - Upon receipt of an IPC$_EV_ACCEPT event by our event handler, where we will get back as an argument our IPLK: - Get the ICCPCB address from IPLK$Q_CONTEXT. - From that ICCPCB, retrieve the IPLK address (ICCPCB$R_iplk). - If the ICCPCB's IPLK address DOES NOT match the address of the IPLK we were handed - Bugcheck - Set ICCPCB$L_state to OPEN. - If IPLK$L_REPLY_LEN is not zero - Re-Probe return_buf and the user's return buffer for write access. - If the probes are successful - Copy the data to the user's buffer. - If the retlen_addr argument was specified - Re-probe it for write access. - If the probe is successful - Store IPLK$L_REPLY_LEN in the the retlen_addr argument. - If ICCPCB$A_pool_bfr is not zero (i.e., we allocated a buffer from pool) - Call Return_ICCPCB_Pool_Bfr to credit/deallocate it. Return_ICCPCB_Pool_Bfr (ICCPCB); - If IPLK$A_SEND_BUFFER does not contain a zero (i.e., connection data was specified) - Set IPLK$L_SEND_LEN and IPLK$A_SEND_BUFFER to zero. - If IPLK$A_REPLY_BUFFER does not contain a zero (i.e., return data was requested) - Set IPLK$L_REPLY_LEN and IPLK$A_REPLY_BUFFER to zero. - Re-probe the conn_handle argument for write access. - If the probe is successful - Store ICCPCB$L_conn_handle in the conn_handle argument. - Call probe_IOS_ICC to re-probe the IOSB for write access. - If the probe is successful - Fill in the IOSB. - If ICCPCB$A_compl_rtn does not contain a zero (i.e., an AST completion routine was provided) - Retrieve the ICCPAB from ICCPCB$L_PAB. - Call ICC_Sched_AST to set up the ACB and schedule the AST. ICC_Sched_AST (ICCPAB, ICCPCB$A_Conn_ACB, ICCPCB$A_compl_rtn, ICCPCB$Q_compl_prm, ICCPCB$L_open_mode); - Call SCH_STD$POSTEF with efn=EFN$C_ENF to post the completion. - Upon receipt of an IPC$_EV_REJECT event by our event handler, where we will get back as an argument our IPLK: - Get the ICCPCB address from IPLK$Q_CONTEXT. - From that ICCPCB, retrieve the IPLK address. - If the ICCPCB's IPLK address DOES NOT match the address of the IPLK we were handed: - Bugcheck - If IPLK$L_REPLY_LEN is not zero - Re-Probe return_buf and the user's return buffer for write access. - If the probes are successful - Copy the data to the user's buffer. - If the retlen_addr argument was specified - Re-probe it for write access. - If the probe is successful - Store IPLK$L_REPLY_LEN in the the retlen_addr argument. - If ICCPCB$A_pool_bfr is not zero (i.e., we allocated a buffer from pool) - Call Return_ICCPCB_Pool_Bfr to credit/deallocate it. Return_ICCPCB_Pool_Bfr (ICCPCB); - If IPLK$A_SEND_BUFFER does not contain a zero (i.e., connection data was specified) - Set IPLK$L_SEND_LEN and IPLK$A_SEND_BUFFER to zero. - If IPLK$A_REPLY_BUFFER does not contain a zero (i.e., return data was requested) - Set IPLK$L_REPLY_LEN and IPLK$A_REPLY_BUFFER to zero. - Call probe_IOS_ICC to re-probe the IOSB for write access. - If the probe is successful - Fill in the IOSB - 1st word (the status) = SS$_REJECT - 2nd longword (the reason) = IPLK$L_REMSTAT - If ICCPCB$A_compl_rtn does not contain a zero (i.e., an AST completion routine was provided) - Retrieve the ICCPAB from ICCPCB$L_PAB. - Call ICC_Sched_AST to set up the ACB and schedule the AST. ICC_Sched_AST (ICCPAB, ICCPCB$A_Conn_ACB, ICCPCB$A_compl_rtn, ICCPCB$Q_compl_prm, ICCPCB$L_open_mode); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Call SCH_STD$POSTEF with efn=EFN$C_ENF to post the completion. ICC CODE SYS$ICC_CONNECTW IOSB, [astadr], [astprm], assoc_handle, conn_handle, remote_assoc, [remote_node], [user_context], [conn_buf], [conn_buf_len], [return_buf], [return_buf_len], [retlen_addr], [flags] FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_CONNECTW User 0 Process SYS$ICC_CONNECT User 0 Process IPC$LINK Kernel ASTDEL Process DESIGN: - To call the ICC routine SYS$ICC_CONNECT we need to: - Determine how many arguments we received. - Re-push however many arguments we got. - call SYS$ICC_CONNECT (see the description above for details on this routine) - Upon return from SYS$ICC_CONNECT - If SYS$ICC_CONNECT returned an error status (in R0) - Return to user with status. - Otherwise - Call the internal entry point for the SYS$SYNCH service status = EXE_STD$SYNCH_LOOP (efn=EFN$C_ENF, IOSB); - When EXE_STD$SYNCH_LOOP completes, return its status to the user. NOTE -- Except for the routine being called (SYS$ICC_CONNECT in this case), all the "Wait" forms of the ICC system services will basically follow the same design as described above. ICC CODE ACCEPT CONNECTION ROUTINE SYS$ICC_ACCEPT() SYS$ICC_ACCEPT conn_handle, [accept_buf], [accept_len], [user_context], [flags] The Accept System Service is used by a server to respond to an incoming connection request notified in a connect/disconnect AST. At the completion of the service, the connection is open and data may be exchanged. Once opened, there is no logical distinction between a connection opened by a client with the Connect service or a server with the Accept service. A server may reject a request by calling the Reject service. FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_ACCEPT User 0 Process IPC$ACCEPT Kernel ASTDEL Process IPC$ACCEPT takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPLK = link_ipcrp structure DESIGN: - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the required argument: conn_handle - Return SS$_INSFARG - If we received too many arguments (more than 4) - Return SS$_TOO_MANY_ARGS - Probe optional arguments (if supplied): accept_buf (via probe_buffer for read). - Set up a mask of length bits to be saved later in ICCPCB$L_arg_lens. - Copy the arguments we got into local storage, storing a zero for any optional argument(s) (i.e., 2-5) we were not passed. - Raise IPL to ASTDEL and save old IPL. - Call ConnHndl_to_ICCPCB to look up the ICCPCB. - If ConnHndl_to_ICCPCB returns a 0 (i.e., none found) - FAIL the request, returning the error SS$_IVCHAN to the user. - If ICCPCB$A_P1B does not contain a zero (i.e., we allocated a P1-Space buffer for this connect) - Call Return_ICCP1B to deallocate it. Return_ICCP1B (ICCPCB_addr) - Call P1C_IPB_setup with the ICCPCB and ICCPAB addresses. status = P1C_IPB_setup (ICCPCB, ICCPAB) - If the call failed, reject the request - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_INSFP1POOL); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Return SS$_INSFP1POOL to the user. - If the SYNCH_MODE bit is set in the flags argument - Set the synch_mode bit in ICCPCB$L_flags. - Retrieve the IPLK from the ICCPCB. - Fill in the IPLK fields as follows: - IPLK$L_ALIAS = user_context - IPLK$L_REPLY_LEN = MIN (IPLK$L_REPLY_LEN, accept_len) - IPLK$A_REPLY_BUFFER = IPLK$L_REPLY_LEN bytes of data from accept_buf - Call IPC$ACCEPT with the IPLK address status = IPC$ACCEPT (.IPLK); - Upon return from IPC$ACCEPT: - On a SUCCESSFUL completion - Set ICCPCB$L_state to OPEN. - Return SS$_NORMAL. - On a FAILURE completion - Call IPC$RELBUF to deallocate the IPLK status = IPC$RELBUF (.IPLK); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Return status to user ICC CODE REJECT CONNECTION ROUTINE SYS$ICC_REJECT() SYS$ICC_REJECT conn_handle, [reject_buf], [reject_buf_len], [reason] The Reject System Service is used by a server to refuse an incoming connection request notified in a connect / disconnect AST. After the completion of the service, the client will be notified that the connection has not been opened. FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_REJECT User 0 Process IPC$REJECT Kernel ASTDEL Process IPC$REJECT takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPLK = link_ipcrp structure DESIGN: - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the required argument: conn_handle - Return SS$_INSFARG - If we received too many arguments (more than 4) - Return SS$_TOO_MANY_ARGS - Probe optional arguments (if supplied): reject_buf (via probe_buffer for read). - Set up a mask of length bits to be saved later in ICCPCB$L_arg_lens. - Copy the arguments we got into local storage, storing a zero for any optional argument(s) (i.e., 2-4) we were not passed. - Raise IPL to ASTDEL and save old IPL. - Call ConnHndl_to_ICCPCB to look up the ICCPCB. - If ConnHndl_to_ICCPCB returns a 0 (i.e., none found) - FAIL the request, returning the error SS$_IVCHAN to the user. - If ICCPCB$A_P1B does not contain a zero (i.e., we allocated a P1-Space buffer for this connect) - Call Return_ICCP1B to deallocate it. Return_ICCP1B (ICCPCB_addr) - Store any specified reason code in ICCPCB$L_discon_rsn. - Retrieve the IPLK from the ICCPCB. - Fill in the IPLK fields as follows: - IPLK$L_REMSTAT = reason (or SS$_REJECT if reason = 0) - IPLK$L_REPLY_LEN = MIN (IPLK$L_REPLY_LEN, reject_buf_len) - IPLK$A_REPLY_BUFFER = IPLK$L_REPLY_LEN bytes of data from reject_buf - Call IPC$REJECT with the IPLK address status = IPC$REJECT (.IPLK); - Upon return from IPC$REJECT - On a FAILURE completion - Call IPC$RELBUF to deallocate the IPLK status = IPC$RELBUF (.IPLK); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Return status to user. ICC CODE INITIATE DISCONNECT ROUTINE SYS$ICC_DISCONNECT(), SYS$ICC_DISCONNECTW() SYS$ICC_DISCONNECT conn_handle, IOSB, [astadr], [astprm], [disc_buf], [disc_buf_len] The Disconnect System Service terminates the specified connection. After this service has been called, no further communication is possible over this connection. All outstanding data transmission and reception functions will be terminated with an error before completion is signalled by return to the user in the W form of the service or by calling the AST (if specified). A connection may be disconnected by either party. Proper programming procedure for network communications strongly recommends that the party which last received a message be the one to initiate the disconnection. If the party which last sent a message initiates the disconnection, there is no guarantee that the message was delivered. Similarly, although this interface provides the ability to send disconnect data, only non-critical information should be transmitted with the disconnect data mechanism as there is likewise no guarantee that the data will have been received or acted upon by the other party to the connection. FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_DISCONNECT[W] User 0 Process IPC$UNLINK Kernel ASTDEL Process IPC$UNLINK takes the following arguments: Arg Usage ------ ---------------------------------------------------------- IPLK = link_ipcrp structure DESIGN: - If we were not passed an IOSB address - FAIL the request with SS$_INSFARG being returned to the user. - Determine the caller's previous access mode. - Call ICC_IOS_ICC_INIT to probe/clear an IOSB of type ICC$C_TYP_IOSB. - If ICC_IOS_ICC_INIT returned an error status - FAIL the request with the error status being returned to the user. - Call ACTUALCOUNT to determine the number of incoming arguments. (The common linkage-function ACTUALCOUNT needs to be declared BUILTIN within the body of the routine) nbr_of_args = ACTUALCOUNT(); - If we do not have the other required argument: conn_handle - Return SS$_INSFARG - If we received too many arguments (more than 7) - Return SS$_TOO_MANY_ARGS - Probe optional arguments (if supplied): disc_buf (via probe_buffer for read). - Set up a mask of length bits to be saved later in ICCPCB$L_arg_lens. - Copy the arguments we got into local storage, storing a zero for any optional argument(s) (i.e., 3 - 6) we were not passed. - Raise IPL to ASTDEL and save old IPL. - Call ConnHndl_to_ICCPCB to look up the ICCPCB. - If ConnHndl_to_ICCPCB returns a 0 (i.e., none found) - FAIL the request, returning the error SS$_IVCHAN to the user. - If the caller's previous access mode is not equal to ICCPAB$L_open_mode (the user is attempting to open this connection from a mode other than the one the association was opened in) Note that this can't be done before now as we don't have an ICCPCB (or ICCPAB) before the call to ConnHndl_to_ICCPCB. - If caller's previous access mode is less than ICCPCB$L_open_mode - Restore IPL. - FAIL the request, returning the error SS$_IVMODE to the user. - Otherwise (i.e., caller's prev access mode is greater than ICCPCB$L_open_mode) - Restore IPL. - FAIL the request, returning the error SS$_IVCHAN to the user. - If ICCPCB$L_state = ICCPCB$C_DISC_RCVD - If ICCPCB$A_P1B does not contain a zero (i.e., we allocated a P1-Space buffer for this disconnect) - Call Return_ICCP1B to deallocate it. Return_ICCP1B (ICCPCB_addr) - If ICCPCB$L_state = ICCPCB$C_CONN_RCVD, just reject the connection. - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_DISCONNECT); - If ICCPCB$A_pool_bfr is NOT equal to zero (i.e., a connect/ disconnect buffer was allocated and data still exists) - Call Return_ICCPCB_Pool_Bfr to credit/deallocate it. Return_ICCPCB_Pool_Bfr (ICCPCB); - Set IPLK$L_SEND_LEN and IPLK$A_SEND_BUFFER to zero. - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Restore IPL. - Return to user (or SYS$ICC_DISCONNECTW) with error status SS$_IVCHAN. - If ICCPCB$L_state = ICCPCB$C_DISC_RCVD AND ICCPCB$A_dsc_iplk_addr is NOT equal to zero (i.e., we've been through the ICC_CONN_DISC_FRONT_END routine and have a disconnect IPLK) - Call IPC$RELBUF to deallocate the IPLK IPC$RELBUF (.IPLK); - Allocate an ACB from NonPaged Pool for the disconnect. - If the allocation attempt failed - Restore IPL. - FAIL the request, returning the error SS$_INSFMEM to the user. - Otherwise - Store the ACB's address in ICCPCB$A_Disc_ACB. - Set status to SS$_NORMAL. - If ICCPCB$L_state is not ICCPCB$C_DISC_RCVD (i.e., we have an fully established link) - Using the internal IPLK in the ICCPCB, set up to call the IPC routine IPC$UNLINK. - Set ICCPCB$L_state to DISCONNECTING. - Store the local copy of the astadr and astprm arguments in the ICCPCB fields ICCPCB$A_compl_rtn and ICCPCB$Q_compl_prm respectively (they will contain a zero if not specified). - If disc_buf is not equal to zero (i.e., disconnect data was specified): - Allocate NonPaged Pool for it. - Copy the user's disconnect data into our disconnect data buffer. - Fill in the IPLK fields as follows: - IPLK$L_IPCID was already filled in at connect time. - IPLK$L_LINKID was already filled in at connect time. - IPLK$Q_CONTEXT was already filled in at connect time with the ICCPCB address. - If disc_buf is not equal to zero - IPLK$L_SEND_LEN = disc_buf_len - IPLK$A_SEND_BUFFER = ICCPCB$A_pool_bfr (the address of the NonPaged Pool disconnect data buffer we allocated) - Otherwise - IPLK$L_SEND_LEN = 0 - IPLK$A_SEND_BUFFER = 0 - Call IPC$UNLINK with the IPLK address status = IPC$UNLINK (.IPLK); - Upon completion with a status of SS$_IVCHAN: - Call ICC_Disc_Cleanup with the ICCPCB address to finish the disconnect. - If ICC_Disc_Cleanup completed successfully - Reset the return status to SS$_IVCHAN. - Upon completion with a status of SS$_DISCONNECT: - Call ICC_Disc_Cleanup with the ICCPCB address to finish the disconnect. - If ICC_Disc_Cleanup completed successfully - Reset the return status to SS$_DISCONNECT. - If status = SS$_NORMAL: - Return; we'll finish cleaning things up in the disconnection completion routine. - Restore IPL. - Return to user (or SYS$ICC_DISCONNECTW) with status (and information). ICC CODE SYS$ICC_DISCONNECTW conn_handle, IOSB, [astadr], [astprm], [disc_buf], [disc_buf_len] FLOW: Routine Mode IPL Context --------------------------- ------ ------ ------- SYS$ICC_DISCONNECTW User 0 Process SYS$ICC_DISCONNECT User 0 Process IPC$UNLINK Kernel ASTDEL Process DESIGN: - To call the ICC routine SYS$ICC_DISCONNECT we need to: - Determine how many arguments we received. - Re-push however many arguments we got. - Re-push the arguments. - call SYS$ICC_DISCONNECT (see the description above for details on this routine). - Upon return from SYS$ICC_DISCONNECT - If SYS$ICC_DISCONNECT returned an error status (in R0) - Return to user with status. - Otherwise - Call the internal entry point for the SYS$SYNCH service status = EXE_STD$SYNCH_LOOP (efn=EFN$C_ENF, IOSB); - When EXE_STD$SYNCH_LOOP completes, return its status to the user. NOTE -- Except for the routine being called (SYS$ICC_DISCONNECT in this case), all the "Wait" forms of the ICC system services will basically follow the same design as described above. ICC CODE TRANSMIT DATA ROUTINE SYS$ICC_TRANSMIT(), SYS$ICC_TRANSMITW() SYS$ICC_TRANSMIT[W] conn_handle, iosb, [astadr], [astprm], send_buf, send_len (Does not use the extended IOSB.) The Transmit Data System Service sends a single message over a connection. When completion is signalled by return to the user in the W form of the service or by calling the AST (if supplied), the data has been delivered to the communications system, but not necessarily to the system or application at the other end of the connection. After completion the user may reuse the buffer. DESIGN: Kernel mode, IPL 0... Call ICC_IOS_ICC_INIT with type ICC$C_TYP_IOSB to probe and clear the IOSB. If fail, return status. Probe buffer (read). Raise IPL to 2 and save old IPL. Verify conn_handle. Else Lower IPL Return SS$_IVCHAN. Using the conn_handle argument, look up the ICCPCB (ConnHndl_to_ICCPCB()), and find the IPC connection ID (ICCPCB [ICCPCB$R_iplk][IPLK$L_LINKID]). Verify previous access mode equal to ICCPCB$L_open_mode. If less than Lower IPL Return SS$_IVCHAN. Verify ICCPCB is in the OPEN state: Else Lower IPL Return SS$_WRONGSTATE. Call EXE$DEBIT_BYTCNT_ALO to allocate a block for an ICCPSB (including IPBR). Initialize the ICCPSB with a(ios_icc), ASTADR, ASTPRM, caller's access mode, buffer address and length. And link the ICCPSB off the ICCPCB. If allocation failure due to quota Lower IPL Return SS$_EXBYTLM If allocation failure otherwise Lower IPL Return SS$_INSFMEM IPBR is allocated as part of the ICCPSB. Call EXE$DEBIT_BYTCNT to account for IPB. Note: Its not entirely clear yet exactly what quota we should charge. Need to examine IPC$GETBUF. Do we charge what IPC is going to allocate? Or charge for the user specified buffer size (send_len)??? IPC may allocate both send and reply buffers, even where we're only using one. Resolution: Do whatever feels right. If failure due to quota Dequeue and Deallocate ICCPSB. Lower IPL Return SS$_EXBYTLM Call IPC$GETBUF to get an IPB, with IPBR containing: IPBR$L_LINKID = IPC linkid from ICCPCB$L_IPLK.IPLK$L_LINKID. IPBR$L_SEND_LEN = send_len argument. IPBR$L_REPLY_LEN = 0; If error: EXE$CREDIT_BYTCNT Dequeue and Deallocate ICCPSB. Lower IPL. Return status from IPC$GETBUF. If IPB$L_SEND_LEN is greater than or equal to the send_len argument: Copy user's buffer (the data pointed to by send_buf) to the IPB buffer Else, copy send_buf to IPB$A_SEND_BUFFER. Call IPC$SEND, with IPB containing: IPB$L_LINKID = IPC linkid from ICCPCB$R_iplk.IPLK$L_LINKID IPB$L_SEND_LEN = send_len argument. IPB$A_SEND_BUFFER filled in by IPC$GETBUF or caller's buffer if caller's buffer is bigger than the buffer returned by GETBUF. IPB$L_REPLY_LEN = 0 IPB$A_REPLY_BUFFER = N/A IPB$L_PID = Our PID from PCB (or KTB on Alpha) IPB$L_ACMODE = Previous access mode. IPB$Q_CONTEXT = a(ICCPSB). IPB$L_FLAGS = IPB$M_NOREPLY | (IPB$M_SYNCH_MODE if synch mode requested at connect.) CASE status return from IPC is SS$_NORMAL: (This is the asynchronous return case) Lower IPL. Return the status value returned by IPC$SEND (SS$_NORMAL!) SS$_SYNCH: Copy IPB$L_STATUS to IOSB Fall through to default case Default: (This is an error; the operation is complete.) Call IPC$RELBUF to release the IPB. Call EXE$CREDIT_BYTCNT. Dequeue and free the ICCPSB. Call EXE$CREDIT_BYTCNT. (((Note: We DON'T set the [non]EFN nor deliver the AST!!!))) Lower IPL. Return the status value returned by IPC$SEND. Events If the call to IPC$SEND completed successfully, then it will generate an IPC$_EV_TX_COMP event, when transmission is complete. IPC$_EV_TX_COMP event processing: Special Kernel AST, IPL 2 Pick up ICCPSB from IBP$Q_CONTEXT. Confirm IPB$L_LINKID equals ICCPSB.IPLK$L_LINKID. Maybe one or two other sanity checks. Re-probe the IOSB. Copy IPB$L_STATUS to IOSB Copy the longword, to the first longword of the IOSB, even though only the first WORD of the IOSB is for status. Call SCH$POSTEF (EFN$C_ENF) to post completion. Call IPC$RELBUF (IPB) to deallocate the buffer. Call EXE$CREDIT_BYTCNT. If ASTADR != zero, deliver a caller's mode AST. Dequeue and free the ICCPSB. Call EXE$CREDIT_BYTCNT. Return. ICC CODE RECEIVE DATA ROUTINE SYS$ICC_RECEIVE(), SYS$ICC_RECEIVEW() SYS$ICC_RECEIVE[W] conn_handle, iosb, [astadr], [astprm], recv_buf, recv_buf_len Outputs via extended IOSB: (referred to as IOS_ICC) +2 0 ------------------------------------------------- | undefined | completion status | ------------------------------------------------- | IOS_ICC$L_R1: recvlen | +4 ------------------------------------------------- | IOS_ICC$L_R2: request_handle | +8 ------------------------------------------------- | IOS_ICC$L_R3: reply_len | +12 ------------------------------------------------- The Receive Data System Service receives a single message over a connection. If a Request ID is returned at completion, the partner has used a Transceive System Service and requires data to be returned with a Reply service. For efficiency reasons, the number of parameters for this routine has been limited to six. Three of the parameters are passed through the extended IOSB. DESIGN: Kernel mode, IPL 0. Call ICC_IOS_ICC_INIT with type ICC$C_TYP_IOS_RECEIVE to probe and clear the IOS_ICC. Probe buffer for write. Raise IPL to 2 and save old IPL. Verify conn_handle. Lower IPL & SS$_IVCHAN if bad. Using the conn_handle argument, look up the ICCPCB (ConnHndl_to_ICCPCB()), and find the IPC connection ID (ICCPCB [ICCPCB$R_iplk][IPLK$L_LINKID]) and the ICCPAB (ICCPCB [ICCPCB$L_PAB]). Verify previous access mode equal to ICCPCB$L_open_mode. If less than Lower IPL SS$_IVMODE If greater than Lower IPL SS$_IVCHAN Verify that ICCPCB is in OPEN state. Else Lower IPL SS$_WRONGSTATE Call EXE$DEBIT_BYTCNT_ALO to allocate a block for an ICCPRB. If allocation failure due to quota Lower IPL Return SS$_EXBYTLM If allocation failure otherwise Lower IPL Return SS$_INSFMEM Initialize the ICCPRB with a(ios_icc), ASTADR, ASTPRM, recv_len, recv_buf, a(retlen), a(request_handle), a(reply_len) and caller's access mode. Clear ICCPRB$A_P1C. Check ICCPCB$L_IPB queue. (Actually, REMQUE an IPB.) Not empty: (We've got a request and a data event... real or pending. Thus we may already have data!) IPB Pending (IPB$A_SEND_BUFFER = 0)? No: (We have a message sitting around waiting for us!) Call Complete-The-Request with REPROBE=FALSE. Yes: (A Pending Data Event message has been sent by the other end... but we have to request it from IPC.) (((Note: In this case, the user must have declared a Data Event Routine, although we don't bother checking for it here. IPC never generates Pending Data Events, unless we set IPST$M_EVENTRCV, which we don't, unless the user specifies a data event routine in the open assoc.))) Call IPC$EXP_REC using this IPB and the buffer specified by caller. (This will generate an IPC Data Event.) If error status from IPC$EXP_REC Deallocate ICCPRB. Call EXE$CREDIT_BYTCNT for ICCPRB. Drop IPL. Return status from IPC$EXP_REC. Queue the ICCPRB (ICCPCB$L_PRB_F/BLINK). Set return status = SS$_NORMAL. Empty: (We've got a receive request, but we do NOT have any data.) Is ICC Data Event Routine declared? No: Queue ICCPRB in the ICCPCBs ICCPRB queue. Set return status = SS$_NORMAL. Yes: (User shouldn't call SYS$ICC_RECEIVE with a Data Event routine declared, except after receiving an IPC$_EV_DATA event.) Deallocate ICCPRB. Call EXE$CREDIT_BYTCNT for ICCPRB. Set return status = SS$_WRONGSTATE. Drop IPL. Return. Complete-The-Request (ICCPRB, IPB, REPROBE): (This routine is called with a ICCPRB and an IPB, when everything is done, and we just need to give the caller his data, cleanup and return. Its called both from SYS$ICC_RECEIVE mainline code, and from the handler for the IPC$_EV_DATA event. REPROBE tells us whether we need to reprobe caller supplied arguments. This is necessary if we're in an AST, its wasteful if we're still in mainline. Note that REPROBE can also be used to determine if we're returning synchronously. If !REPROBE and the SYNCH bit is set, we can return SS$_SYNCH.) If IPB buffer is not the same as the ICCPRB buffer: If REPROBE: Re-probe the ICCPRB buffer. (((If the probe is bad, we return ACCVIO. There's nothing else we can do. There's also not much our caller can do. He's an AST routine, and can't exactly return much status... but there are no other options. He'll try to put the ACCVIO in the IOS_ICC, otherwise, drop it!))) Copy the IPB buffer into the ICCPRB buffer If REPROBE: Re-probe the IOS_ICC. Copy transfer size (IPB$L_SEND_LEN) to IOS_ICC$L_R1 (recvlen). Set IOS_ICC status to SS$_NORMAL. If the IPB$V_NOREPLY flag in IPB$L_FLAGS is clear: Call EXE$DEBIT_BYTCNT_ALO to allocate a ICCPSB. If this fails, cry! (Return status.) Calculate request_handle as an index or handle to the ICCPSB. Save request_handle in the ICCPSB, and in the IOS_ICC$L_R2 (request_handle) argument. Copy IPB$L_REPLY_LEN to IOS_ICC$L_R3 (reply_len) Queue the ICCPSB off the ICCPCB (ICCPCB$L_PSB_F/BLINK). Save the IPB in the ICCPSB. else Release the IPB (IPC$RELBUF). Call IPC$CREDIT for the IPB. If (REPROBE or !SYNCH) THEN { SCH$POSTEF (EFN$C_ENF) If ASTRTN is not zero, deliver AST. } If there's an ICCP1C in the ICCPRB (I forget... is this how it works?) Return the ICCP1C to the Ring Buffer in the ICCPCB. Dequeue the ICCPRB. Deallocate the ICCPRB. Call EXE$CREDIT_BYTCNT for the ICCPRB. Return. Events: Special Kernel AST, IPL 2 Asynchronous to a RECEIVE operation, either an IPC$_EV_DATA or an IPC$_EV_PENDING_DATA event may be issued. If the message sent by the sender fits in the IPB buffer, IPC$_EV_DATA is generated. If the message does not fit, then IPC$_EV_PENDING_DATA is generated. In either case, the event routine is called with an IPB. In the case of the IPC$_EV_DATA event, the message has been received, and is contained in the IPB. In the case of IPC$_EV_PENDING_DATA, the sender has issued IPC$SEND (or REPLY), and the receiving end has been notified of the message and its size, but the message can not be received until an appropriately large buffer is provided... and only the user can provide an appropriate buffer. We handle IPC$_EV_PENDING_DATA by calling the user's ICC data event routine, passing him the size given to us by IPC. He's then expected to generate an SYS$ICC_RECEIVE call with an appropriately large buffer. With that buffer, we call IPC$EXP_REC to go retrieve the data. We also call the user's ICC data event routine if we get a IPC$EV_DATA event and the user hasn't yet issued ICC$RECEIVE. He doesn't know whether its a EV_DATA or an EV_PENDING_DATA, except for the size of the buffer being requested. IPC$_EV_DATA: Find ICCPCB from IPB$L_LINKID. If none, drop event on the floor. Check ICCPCB$L_PRB queue. Empty: (We've got data, but no request.) Queue IPB into ICCPCB$L_IPB queue. Check ICC Data Event Routine Declared. Yes: Call Generate_User_Data_Event No: There's nothing we can do but hope the guy gets around to calling SYS$ICC_RECEIVE eventually. Return. Non-Empty: (We've got data, and a request for it!) (((Note: In this case, the user has not declared a Data Event Routine.))) Call Complete-The-Request. If bad status return: Re-Probe IOS_ICC If ok, put status from Complete-The-Request into IOS_ICC. (Note: If Complete-The-Request returns AccVio, and the re-probe of the IOS_ICC also fails, the user is not notified of any problem. He'll just hang! But that's OK. He deserves it!!!) Return. IPC$_EV_PENDING_DATA: Find ICCPCB from IPB$L_LINKID. If none, drop event on the floor. Check ICC Data Event Routine Declared. No: BUGCHECK INCONSTATE Yes: Check ICCPCB$L_PRB_F/BLINK queue. Empty: Queue IPB into ICCPCB$L_IPB_B/FLINK queue. Call Generate_User_Data_Event Return. Non-Empty: BUGCHECK! Return. Routine: Generate_User_Data_Event Allocate an ACB. Mark ACB for deletion on AST delivery. Specify ICC_Data_Event_AST (see below) as the ASTADR. Get an ICCP1C block from the ICCPCB's ring buffer. Specify the address of the ICCP1C as the ASTPRM. Save ICCP1C's address in the ICCPRB. (So we can free it when its done. Specify mode of caller (ICCPCB$L_open_mode) as access mode. Fill the ICCP1C with: Message size from IPB$L_SEND_LEN. Connection Handle from ICCPCB$L_conn_handle. user_context from ICCPAB$R_IPLK.IPLK$L_ALIAS. Call SCH$ASTDEL. Return. Routine: ICC_Data_Event_AST This routine is the ICC AST routine called to call the user's data event routine in the mode of the caller. An intermediary routine is required since real ASTs only take a single argument, but we need to call the user's routine with three arguments. Call user's Data Event routine with three arguments take from the ICCP1C. ICC CODE TRANSCEIVE DATA ROUTINE SYS$ICC_TRANSCEIVE(), SYS$ICC_TRANSCEIVEW() SYS$ICC_TRANSCEIVE[W] conn_handle, iosb, [astadr], [astprm], send_buf, send_len Inputs/Outputs Via extended IOSB: (referred to as IOS_ICC) +2 0 ------------------------------------------------- | undefined | completion status | -------------------------------------------------- | IOS_ICC$L_R1: returned_data_len | +4 ------------------------------------------------- | IOS_ICC$Q_P1: reply_buf | +8 | ...... | +12 ------------------------------------------------- | IOS_ICC$L_P2: reply_buf_len | +16 ------------------------------------------------- Note: on VAX we only use the low order longword of IOS_ICC$Q_P1, and define the symbol IOS_ICC$L_VP1 for convenience. The Transceive Data System Service sends a single message over a connection and then waits for a reply. When completion is signalled by return to the user in the W form of the service or by calling the AST (if supplied), the data has been delivered to the application at the other end of the connection and that application has delivered a reply, now present in the reply buffer. The user may reuse the send and receive buffers after completion. For efficiency reasons, the number of parameters for this routine has been limited to six. One of the parameters is passed and two values returned through the extended IOSB. DESIGN: (((Note: TRANSCEIVE is nearly identical to TRANSMIT, except there's the extra buffer. I can likely use common code, especially if we use a single data block type, instead of the ICCPSB/ICCPRB.))) Kernel mode, IPL 0... Call ICC_IOS_ICC_INIT with type ICC$C_TYP_IOS_TRANCEIVE to probe and clear the IOS_ICC. Probe both buffers (One for read/One for write). Return SS$_ACCVIO if bad. Clear retlen. Raise IPL to 2 and save old IPL. Verify conn_handle. Lower IPL & Return SS$_IVCHAN if bad. Using the conn_handle argument, look up the ICCPCB (ConnHndl_to_ICCPCB()), and find the IPC connection ID (ICCPCB [ICCPCB$R_iplk][IPLK$L_LINKID]). Verify previous access mode equal to ICCPCB$L_open_mode. If less than Lower IPL Return SS$_IVMODE If greater than Lower IPL Return SS$_IVCHAN. Verify the ICCPCB is in OPEN state: Else Lower IPL Return SS$_WRONGSTATE Call EXE$DEBIT_BYTCNT_ALO to allocate a block for an ICCPSB (including IPBR). Initialize the ICCPSB with a(ios_icc), ASTADR, ASTPRM, caller's access mode, send_len, send_buf, reply_len, reply_buf and retlen. And link the ICCPSB off the ICCPCB. If allocation failure due to quota Lower IPL Return SS$_EXBYTLM If allocation failure otherwise Lower IPL Return SS$_INSFMEM Call EXE$DEBIT_BYTCNT for the IPB. If failure: Deallocate ICCPSB. Lower IPL. Return SS$_EXBYTLM if failure due to quota. IPBR is allocated as part of the ICCPSB. Call IPC$GETBUF to get an IPB, with IPBR containing: IPBR$L_LINKID = IPC linkid from ICCPCB$L_IPLK.IPLK$L_LINKID. IPBR$L_SEND_LEN = send_len argument. IPBR$L_REPLY_LEN = reply_buf_len argument. If error return Deallocate ICCPSB. Lower IPL. Return status. If IPB$L_SEND_LEN is greater than or equal to the send_len argument: Copy user's buffer (send_buf) to the IPB buffer. Else, copy the argument, send_buf (an address) to IPB$A_SEND_BUFFER and send_len to IPB$L_SEND_LEN. If IPB$L_REPLY_LEN is less than the reply_buf_len argument, then copy reply_buf_len argument into IPB$L_REPLY_LEN and reply_buf argument into IPB$A_REPLY_BUFFER. {Note: 64 bit support gotcha} Call IPC$SEND, with IPB containing: IPB$L_LINKID = IPC linkid from ICCPCB$R_iplk.IPLK$L_LINKID IPB$L_SEND_LEN = send_len argument. IPB$A_SEND_BUFFER filled in by IPC$GETBUF or caller's buffer if caller's buffer is bigger than the buffer returned by GETBUF. IPB$L_REPLY_LEN = reply_len IPB$A_REPLY_BUFFER = filled in by IPC$GETBUF or caller's buffer if callers buffer is bigger than the buffer returned by GETBUF. IPB$L_PID = Our PID from PCB or KTB IPB$L_ACMODE = Previous access mode. IPB$Q_CONTEXT = a(ICCPSB). IPB$L_FLAGS.IPB$M_NOREPLY = 0; IPB$L_FLAGS.IPB$M_SYNCH_MODE = 0; {Careful here, IPC spec implies that IPC may set other bits so be sure to use bitwise operations.} If status return from IPC is SS$_NORMAL then (This is the asynchronous return case) Lower IPL. Return the status value returned by IPC$SEND (SS$_NORMAL!) else (This is an error; the operation is complete.) Call IPC$RELBUF to release the IPB. Call EXE$CREDIT_BYTCNT, for the IPB. Dequeue and free the ICCPSB. Call EXE$CREDIT_BYTCNT, for the ICCPSB. (((Note: We DON'T set the [non]EFN nor deliver the AST!!!))) Lower IPL. Return the status value returned by IPC$SEND. Events: Upon a successful call to IPC$SEND with NOREPLY clear, IPC will generate an IPC$_EV_REPLY event. This signals that the reply data from the other end of the link has been received, and is sitting in the IPB (which may be pointing at the user's buffer, or may be pointing at the system buffer.) Special Kernel AST, IPL 2 IPC$_EV_REPLY: Find ICCPCB from IPB$L_LINKID. If none, drop event on the floor. If IPB reply buffer is not the same as the ICCPRB reply buffer: Re-probe the ICCPRB buffer. Copy the IPB buffer into the ICCPRB buffer Re-probe the IOS_ICC. Set IOS_ICC status to IPB$L_STATUS. Copy transfer size (IPB$L_REPLY_LEN) to IOS_ICC$L_R1 (returned_data_len). Release the IPB (IPC$RELBUF). Call IPC$CREDIT_BYTCNT for the IPB. Call SCH$POSTEF (EFN$C_ENF) to post completion. If ASTRTN is not zero, deliver AST. Dequeue the ICCPRB. Deallocate the ICCPRB. Call EXE$CREDIT_BYTCNT for the ICCPRB. Return. ICC CODE REPLY ROUTINE SYS$ICC_REPLY(), SYS$ICC_REPLYW() SYS$ICC_REPLY[W] conn_handle, iosb, [astadr], [astprm], reply_buf, reply_len +2 0 ------------------------------------------------- | undefined | completion status | ------------------------------------------------- | IOS_ICC$L_P0: request_handle | +4 ------------------------------------------------- The Reply System service is almost identical to the Transmit Data System Service in that it sends a single message over a connection. The only difference is that it is used in response to the reception of a Request ID in a previous Receive Data System Service. When completion is signalled by return to the user in the W form of the service or by calling the AST (if suppmlied), the data has been delivered to the communications system, but not necessarily to the application at the other end of the connection. The user may reuse the buffer after completion has been signaled. For efficiency reasons, the number of parameters for this routine has been limited to six. One of the parameters is passed through the extended IOSB. DESIGN: Call ICC_IOS_ICC_INIT with type ICC$C_TYP_IOS_REPLY to probe and clear the IOS_ICC. Probe buffer; Return SS$_ACCVIO if bad. Raise IPL to 2 and save old IPL. Verify conn_handle. Return SS$_IVCHAN if bad. Using the conn_handle argument, look up the ICCPCB (ConnHndl_to_ICCPCB()), and find the IPC connection ID (ICCPCB [ICCPCB$R_iplk][IPLK$L_LINKID]). Verify previous access mode equal to ICCPCB$L_open_mode. If less than Lower IPL Return SS$_IVMODE. If greater than Lower IPL Return SS$_IVCHAN. Verify ICCPCB is in OPEN state. Else Lower IPL. return SS$_LINKDISCON. From the request_handle argument, locate the ICCPSB (via ICCPCB$L_PSB queue). If invalid Lower IPL. Return SS$_BADPARAM. Initialize the ICCPSB with a(ios_icc), ASTADR, ASTPRM, the caller's access mode, reply_len, reply_buf. Find the IPB from the ICCPSB (ICCPSB [ICCPCB$L_IPB]. Check if reply_len is greater than IPB$L_REPLY_LEN. Lower IPL. Return SS$_IVBUFLEN. Copy user's buffer (reply_buf) to the IPB reply buffer Call IPC$REPLY with IPB containing: IPB$L_REPLY_LEN = reply_size. IPB$A_REPLY_BUFFER (untouched). IPB$L_FLAGS.IPB$M_SYNCH_MODE = ICCPCB$L_FLAGS.ICCPCB$V_SYNCH_MODE If status return from IPC is SS$_NORMAL then (This is the asynchronous return case) Lower IPL. Return the status value returned by IPC$REPLY (SS$_NORMAL!) else (Error, or synchronous completion) If SS$_SYNCH Copy IPB$L_STATUS to IOSB Call IPC$RELBUF Call EXE$CREDIT_BYTCNT for IPB. Dequeue the ICCPSB. Call EXE$CREDIT_BYTCNT for the ICCPSB. Deallocate the ICCPSB. Lower IPL. Return the status value returned by IPC. Events: If the call to IPC$REPLY completed successfully, returning SS$_NORMAL, then it will generate an IPC$_EV_REPLY_COMP event, when transmission is complete. Special Kernel AST, IPL 2 IPC$_EV_REPLY_COMP event processing: (((Note: This is totally identical to IPC$_EV_TX_COMP processing. We can use a common routine.))) Pick up ICCPSB from IBP$Q_CONTEXT. Confirm IPB$L_LINKID equals ICCPSB.IPLK$L_LINKID. Maybe one or two other sanity checks. Re-probe the IOS_ICC. Copy IPB$L_STATUS to IOS_ICC Copy the longword, to the first longword of the IOS_ICC, even though only the first WORD of the IOS_ICC is for status. Call SCH$POSTEF (EFN$C_ENF) to post completion. Call IPC$RELBUF (IPB) to deallocate the buffer. Call EXE$CREDIT_BYTCNT. If ASTADR != zero, deliver a caller's mode AST. Dequeue and free the ICCPSB. Call EXE$CREDIT_BYTCNT. Data Linkages ICCPAB+------------+ ICCPCB+------------+ ICCPCB+------------+ | | +----->|------------|-------->|------------| | | | |------------|<--------|------------| |------------| | |PSB Q hdr |---+ | | | PCB Q hdr |--+ |------------| | | | |------------| |PRB Q hdr |--+| | | | | |------------| || | | | | |IPB Q hdr |-+|| | | | | |------------| ||| | | | | | | ||| | | | | | | ||| | | +------------+ +------------+ ||| +------------+ ||| +----------------------------------+|| | || | +--------------------+| | | | | | | ICCPSB+-----------+ | | +------>|-----------| | | |-----------| | |ICCPRB+-----------+ | TRANSMIT | | +----->|-----------| | (I/O in | | |-----------| | Progress)| | | RECEIVE | | OR.... | | | (Awaiting | | Awaiting | | | Data | | $REPLY | |IPB+-----------+ | Event) | | | +-->|-----------| +-----------+ +-----------+ |-----------| | Data Event| | IPB | | (Awaiting | | $RECEIVE)| +-----------+ ICC CODE INITIALIZATION ROUTINE This routine is responsible for allocating pool for, and initializing the ICC system service's data structures and setting up the ICC system data cells to point to their allocated memory areas. If the ICC services are part of the IPC execlet, we will need to modify the IPC initialization routine to call this routine. ICC_SS_Init() - Initially set the system data cells to zero in case we run into trouble allocating the necessary memory. - Allocate NonPaged pool for the the ICCPDB_VECTOR, store the starting address in the system data cell ICC$GL_ICC_PDB_VECTOR and initialize each slot with zero. - If the trace area is being used %IF (%VARIANT AND ICC$C_VARIANT_TRACE) NEQU 0 (i.e., the compile-time option ICC$C_VARIANT_TRACE is set) - Allocate NonPaged pool for the trace area and - Store the starting address in the system data cell ICC$GL_ICC_TRACE_INFO - Store 0 in Nxt_Trace_Group - Set Max_Trace_Groups to ICC$C_MAX_TRC_GROUPS - Otherwise - Store a zero in ICC$GL_ICC_TRACE_INFO. - Return SS$_NORMAL or any error from EXE_STD$ALONONPAGED. ICC CODE KERNEL-MODE RUNDOWN HANDLER This routine is responsible for disconnecting connections, closing associations and generally cleaning up any ICC data structures in the event of image or process rundown. The argument "What_Type" is required and its setting represents what is being run down, the image or the process; where TRUE represents Process Rundown and FALSE represents Image Rundown. - For image rundown we need to close any association(s) opened in user- mode and all connection(s) on them. (As connections must be opened in the same mode as the association, this catches all user-mode connections). - For process rundown we need to close all associations opened by this process along with their related connection(s) regardless of the mode they were opened in and deallocate the ICCPDB. (SYS$ICC_CLOSE_ASSOC deallocates the ICCPDB if this was the last ICCPAB for this process) - Hooks to call this routine need to be placed in both the system's image rundown and process rundown routines. ICC_KMODE_RUNDWN (Boolean What_Type) - Determine the ICCPDB by the process's PID. - For each ICCPAB on the ICCPDB$L_PAB queue - Set ICCPAB$L_rndwn_in_prog to 1. - If What_Type = TRUE (i.e., Process Rundown) - Call SYS$ICC_CLOSE_ASSOC with the ICCPAB address. - Otherwise (i.e., Image Rundown) - If the ICCPAB$L_open_mode specifies a user-mode open - Call SYS$ICC_CLOSE_ASSOC with the ICCPAB address. ICC CODE ICC EVENT HANDLER AST Signals incoming events on connections/associations managed by the ICC system service. ICC_EVNT_HNDLR_AST - Entered in Kernel mode at IPL 2 - Called with the address of a data block that will initially be treated as an IPCRP. - From that IPCRP data block, obtain the event type code. - Based on that event type code: - EVENT = IPC$_EV_LINK (Unsolicited event - Incoming Connect request) - Treat the incoming data block as an IPLK. - Only support incoming local or cluster transport connections - If IPLK$W_TRANSPORT is not either IPC$_SCS (cluster transport connection) or IPC$_LCL (local connection) - Reject the request and clean up - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_UNREACHABLE); - Return - Look up our ICCPAB associated with the incoming connect request. - Get the PID (we are in the context of the process). - Determine the ICCPDB by the process's PID. - Walk the chain of ICCPABs in the ICCPDB looking for one whose embedded IPST$L_IPCID matches the incoming IPLK$L_IPCID. - If NO match is found, reject the request. - Call ICC_Reject_Due_To_Error to reject the request ICC_Reject_Due_To_Error (IPLK, SS$_NOSUCHID); - Return - If ICCPAB$L_state is not CLOSING or CLOSED: - Determine the total size of the ICCPCB/IPLK structure. - Call EXE$DEBIT_BYTCNT_BYTLM_ALO to both allocate the ICCPCB/IPLK structure and charge the users' BYTCNT and BYTLM quotas for it. - If EXE$DEBIT_BYTCNT_BYTLM_ALO returned a FAILURE status in R0, reject the request - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, error from EXE$DEBIT_BYTCNT_BYTLM_ALO); - Return - Otherwise - The actual amount of memory allocated for the combined structure is stored in ICCPCB$W_size. - Initialize the ICCPCB as follows: - ICCPCB$L_PDB to the address of the ICCPDB. - ICCPCB$L_PAB to the address of the ICCPAB. - Initialize queues maintained in the ICCPCB - ICCPCB$L_PSB_flink and ICCPCB$L_PSB_blink to the address of the ICCPCB$L_PSB_flink. - ICCPCB$L_PRB_flink and ICCPCB$L_PRB_blink to the address of the ICCPCB$L_PRB_flink. - ICCPCB$L_IPB_flink and ICCPCB$L_IPB_blink to the address of the ICCPCB$L_IPB_flink. - Copy the incoming IPLK into the ICCPCB starting at ICCPCB$R_iplk. - The rest (past the header fields) to zero. - Store the following ICCPAB information in the ICCPCB: Association handle, previous mode of the caller of SYS$ICC_OPEN_ASSOC, and ICCPAB address. - Set ICCPCB$L_state to ICCPCB$C_CONN_RCVD. - Determine the length of the ICCP1B (in bytes) Header (12) + 6 arguments (28) + IPLK$L_SEND_LEN - Call EXE$ALOP1PROC to allocate an ICCP1B (in P1-Space) - If the allocation attempt failed, reject the request - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_INSFP1POOL); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Return - Store the address of the allocated ICCP1B in ICCPCB$A_P1B and the length of the structure in ICCP1B$W_size. - Call Link_CB to link the ICCPCB onto the ICCPCB queue in the ICCPDB, assign/store the connection handle and update the connection count. - Fill in the ICCP1B fields as follows: - ICCP1B$L_ev_type = ICC$C_EV_CONNECT - ICCP1B$L_conn_handle = ICCPCB$L_conn_handle - ICCP1B$L_P5 = IPLK$L_REPLY_LEN - ICCP1B$L_P6 = 0 - If IPLK$A_SEND_BUFFER is not equal to zero (i.e., there is connect data present) - ICCP1B$L_data_len = IPLK$L_SEND_LEN - ICCP1B$Q_data_buf_addr = Address of ICCP1B$T_data_buf - Copy IPLK$L_SEND_LEN bytes of data into ICCP1B$T_data_buf - Otherwise - ICCP1B$L_data_len = 0 - ICCP1B$Q_data_buf_addr = 0 - Allocate an ACB from NonPaged Pool for this side of the connect. - If the allocation attempt was successful - Retrieve the ICCPAB from ICCPCB$L_PAB. - Call ICC_Sched_AST to set up the ACB and schedule the AST. ICC_Sched_AST (ICCPAB, ICCPCB$A_Conn_ACB, ICC_CONN_DISC_FRONT_END routine address, ICCPCB$A_P1B, ICCPCB$L_open_mode); - Otherwise - Reject the request - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_REMRSRC); - Call Return_ICCP1B to deallocate it. Return_ICCP1B (ICCPCB_addr) - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK structure. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Return - Otherwise (ICCPAB$L_state is CLOSING or CLOSED) - Reject the request - Call ICC_Reject_Due_To_Error to reject the request. ICC_Reject_Due_To_Error (IPLK, SS$_REJECT); - Return - EVENT = IPC$_EV_ACCEPT (Solicited event - Accept connection) Described under SYS$ICC_CONNECT. - EVENT = IPC$_EV_DISC_COM (Solicited event - Disconnect complete) Signals that all processing related to the disconnect request is completed. Either this event or IPC$_EV_DISC is guaranteed by IPC to be the last event signaled on a connection. This means that IPC will have completed (or otherwise terminated) all outstanding I/O by the time we would get this event. - Treat the incoming data block as an IPLK. - Retrieve the ICCPCB address from IPLK$Q_CONTEXT. - If ICCPCB$L_state is not DISCONNECTING or DISCONNECTED - Bugcheck - Call ICC_Disc_Cleanup with the ICCPCB address to finish the disconnect. - EVENT = IPC$_EV_DISC (Unsolicited event - Disconnecting) Signals that either the partner on the other end of an active connection has initiated a disconnect operation OR a communications failure has occurred. Either this event or IPC$_EV_DISC_COM is guaranteed by IPC to be the last event signaled on a connection, and IPC$_EV_DISC will be the last event signaled on a connection that is being terminated due to an act other than the user initiating a disconnect. This means that IPC will have completed (or otherwise terminated) all outstanding I/O by the time we would get this event. - Treat the incoming data block as an IPLK. - Call LinkID_to_ICCPCB to look up the ICCPCB based on IPLK$L_LINKID. - Set up and schedule the AST if this assoc is not being run down. - Retrieve the ICCPAB from ICCPCB$L_PAB. - If ICCPAB$L_rndwn_in_prog = 0 - Save the address of the disconnect IPLK in ICCPCB$A_dsc_iplk_addr. - Set ICCPCB$L_state to ICCPCB$C_DISC_RCVD. - Determine the length of the ICCP1B (in bytes) Header (12) + 6 arguments (28) + IPLK$L_SEND_LEN - Call EXE$ALOP1PROC to allocate an ICCP1B (P1-Space structure). - If the allocation attempt failed: - Call SYS$ICC_DISCONNECT. - Return to system. - Store the address of the allocated ICCP1B in ICCPCB$A_P1B and the length of the structure in ICCP1B$W_size. - Fill in the ICCP1B fields as follows: - ICCP1B$L_ev_type = ICC$C_EV_DISCONNECT - ICCP1B$L_conn_handle = ICCPCB$L_conn_handle - ICCP1B$L_P5 = IPLK$L_REMSTAT (or SS$_REJECT if IPLK$L_REMSTAT=0) - ICCP1B$L_P6 = ICCPCB.IPLK$L_ALIAS - If IPLK$A_SEND_BUFFER is not equal to zero (i.e., there is disconnect data present) - ICCP1B$L_data_len = IPLK$L_SEND_LEN - ICCP1B$Q_data_buf_addr = Address of ICCP1B$T_data_buf - Copy IPLK$L_SEND_LEN bytes of data into ICCP1B$T_data_buf - Otherwise - ICCP1B$L_data_len = 0 - ICCP1B$Q_data_buf_addr = 0 - Retrieve the ICCPAB from ICCPCB$L_PAB. - Call ICC_Sched_AST to set up the ACB and schedule the AST. ICC_Sched_AST (ICCPAB, ICCPCB$A_Disc_ACB, ICC_CONN_DISC_FRONT_END routine address, ICCPCB$A_P1B, ICCPCB$L_open_mode); - Return - EVENT = IPC$_EV_REJECT (Solicited event - Reject connection) Described under SYS$ICC_CONNECT. - EVENT = IPC$_EV_DATA (Unsolicited event) Described under SYS$ICC_RECEIVE. - EVENT = IPC$_EV_PENDING_DATA (Unsolicited event) Described under SYS$ICC_RECEIVE. - EVENT = IPC$_EV_TX_COMP (Solicited event) Described under SYS$ICC_TRANSMIT. - EVENT = IPC$_EV_REPLY (Solicited event) Described under SYS$ICC_TRANSCEIVE. - EVENT = IPC$_EV_REPLY_COMP (Solicited event) Described under SYS$ICC_REPLY. - ICC_CONN_DISC_FRONT_END In the case of an incoming Connect Event (IPC$_EV_LINK) or an incoming Disconnect Event (IPC$_EV_DISC or IPC$_EV_DISC_COM), an AST routine is set up to call the user-supplied connect/disconnect routine (from the ICC event handler). In response to receiving an ICC$C_EV_CONNECT event, the user MUST call one of either SYS$ICC_ACCEPT or SYS$ICC_REJECT (which can be called either before or after returning from the AST). In response to receiving the ICC$C_EV_DISCONNECT event, the user MUST do whatever cleanup of their own data structures they want to do and then call either SYS$ICC_DISCONNECT or SYS$ICC_DISCONNECTW (which can be done from within the AST or after returning from it). ICC_CONN_DISC_FRONT_END (ICCP1B address) - Using the previously prepared ICCP1B, call the User's Connect/ Disconnect event routine with the following arguments: Event_Type = ICCP1B$L_ev_type (Which will be ICC$C_EV_CONNECT for a connect or ICC$C_EV_DISCONNECT for a disconnect) conn_handle = ICCP1B$L_conn_handle Data_Len = ICCP1B$L_data_len Data_Bfr = ICCP1B$Q_data_buf_addr P5 = ICCP1B$L_P5 (Which will be the length, in bytes, available for a reply for ICC$C_EV_CONNECT or the user defined disconnect reason/status from the remote partner for ICC$C_EV_DISCONNECT) P6 = ICCP1B$L_P6 (Which will be 0 for ICC$C_EV_CONNECT or the user-specified user_context for ICC$C_EV_DISCONNECT) ICC CODE SIMPLE CLUSTERWIDE REGISTRY ROUTINES There are three registry routines called by ICC Services: 1. Simple_Registry_Add (user_lognam, user_logtable, association_block) (called in $ICC_OPEN_ASSOC) 2. Simple_Registry_Remove (association_block) (called in $ICC_CLOSE_ASSOC) 3. Simple_Registry_Lookup (user_association_name, output_node, output_assoc) (called in $ICC_CONNECT). There is also one routine used by the simple registry and also used by $ICC_CONNECT: Random_Pick (integer_value) Common notes on the registry: The logical name represents the service; the equivalence values are node and association pairs providing this service. This design permits up to 762 servers within a cluster offering the same service. VMS logical names may have up to 128 equivalence values indexed from 0 to 127. In the registry, equivalence value 0 will be a binary word containing the current number of entries (from 1 to 762). For up to 127 servers offering the same service, equivalence values 1 to 127 will contain fixed length 38 byte entries with six bytes of node name and 32 bytes of association name (each zero filled). For more than 127 servers, value 1 will contain the first, the 128th, the 255th, the 382nd, the 519th, etc., entries, each as a fixed length 38 byte entry. This design means that the number of values and the length of each is completely predetermined from the total number of entries indicated in value 0, allowing memory to read in the whole table to be allocated at once and read with a single long itemlist. Any server entry "n" is in the equivalence value with index (n-1) mod 127 + 1 and within that value it is at at offset (n-1) div 127 * 38. When reading in a table we can set nentries to one greater than the current value to leave one memory slot available for the addition of a new entry. We read in MIN(127, nentries) logical name equivalence values. For each indexed logical name value to be read in, we could compute the address offset to be placed in its itemlist entry to be (index-1) * 38 + 38 * ((nentries-1) DIV 127) * IF index LE (nentries-1) mod 127 + 1 THEN ((index-1) mod 127 + 1) ELSE ((nentries-1) mod 127 + 1) relative to the beginning of the table. Fortunately, calculating this offset in a loop initializing the itemlist does not require executing this formula. Instead, the following initialization is done before beginning the loop: offset=0 binc=38; IF nentries LE 127 THEN usea = 0 ELSE (usea = (nentries-1) mod 127 + 1; ainc=38 * ((nentries-1) DIV 127 + 1)) In the loop: For Index <- 1 to Max(nentries, 127) (use the offset; if index gt usea then add ainc else add binc to offset for the next itemlist entry) All registry logical names will be created in exec mode as terminal translations. For lookups, exec mode translation from the table (or exec mode logical name or search list) ICC$NAME_TABLE will be enforced. Registry operations are interlocked by EX mode enqueues on the lock ICC$REGISTRY. - SIMPLE_REGISTRY_ADD Called only from $ICC_OPEN_ASSOC. Called while still at ASTDEL. Simple_Registry_Add (user_lognam, user_logtable, association_block) Inputs: the address of the user descriptor arguments for logical name and logical table. These were already probed during initial argument verification. The address of the ICCPAB. Outputs: The ICCPAB fields ICCPAB$L_lgcl_name_addr ICCPAB$L_lgcl_name_len ICCPAB$L_lgcl_name_alo ICCPAB$L_lgcl_tbl_addr ICCPAB$L_lgcl_tbl_len ICCPAB$L_lgcl_tbl_alo are filled in with pointers to non-paged-pool areas allocated by this routine and deallocated by Simple_Registry_Remove. Return value: status. All returns go through the return path. Allocate pool for the copy of the user's logical name, copy it, and initialize the ICCPAB$L_lgcl_name_* fields. Don't charge the user for this; he only gets one of these, and we've already charged him enough for the PAB and other association structures. Temporarily (hopefully) allocate 256 bytes for the returned lgcl tbl addr. If allocation fails, deallocate anything allocated and then return an insufficient memory error. $ENQ EX mode lock on ICC$REGISTRY. $trnlnm index 0 of the logical name on failure, set nentries to 1 Note: length of index 0 not equal two bytes, value lt 1 or gt 762 is considered an error, but we ignore it and just set nentries to 1. The logical name can be reinitialized. on success, set nentries to 1+translated binary word value If nentries ge 763, return TOOMANY error. Allocate storage for the translation and creation, all in one piece. Compute: Fixed overhead for fixed itemlist entries and any other things needed. Per-entry space for itemlist and 38bytes of data. If nentries > 1, create $TRNLNM itemlist to fill in the space just allocated. $TRNLNM. Search list to see if already registered. If so, this is just fine. Skip the update by going directly to the return path with a successful status. Put local SCSNODE name and the name of the association into entry #nentries (the new entry goes at the end). Create $CRELNM itemlist (in the space previously used by the $TRNLNM itemlist, since the $CRELNM item list will be smaller, not needing a bunch of LNM$INDEX items). Each of the items still points to the same buffer and has the same length, except for the one item containing the new value ((nentries-1) mod 127 + 1), which has its length increased by 38. Call $CRELNM. Return any error to the caller. Return path: $DEQ the lock on ICC$REGISTRY. If there is a success status: Allocate properly sized pool for the resultant table name. On error just use the long one we already have. (won't happen often, since this is pretty small and we just gave a bunch back). On success, copy, switch pointers, and release the long one. If there is an error status: Deallocate the memory referenced by ICCPAB$L_lgcl_* and zero these fields. Deallocate the hunk of memory for the $TRNLNM/$CRELNM operation if we got that far. Return. Any error status will cause $ICC_OPEN_ASSOC to close the association and return the error to the user. - SIMPLE_REGISTRY_REMOVE Called only from $ICC_CLOSE_ASSOC. Called while still at ASTDEL. Simple_Registry_Remove (association_block) Inputs: The input parameter is the address of the ICCPAB. This routine accesses ICCPAB$L_lgcl_* and the association name in the ICCPAB. Outputs: The ICCPAB fields ICCPAB$L_lgcl_* are all zeroed after the storage they represent is deallocated. Return Value: void. $ENQ EX mode lock on ICC$REGISTRY. $trnlnm index 0 of the logical name on failure, just return. No special status. Note: length of index 0 not equal two bytes, value lt 1 or gt 762 is considered an error, and we just return. No special status. 1. The logical name can be reinitialized. on success, set nentries to translated binary word value If nentries is 1, just $DELLNM and return, ignoring errors. Otherwise, allocate storage as above, create an itemlist and $TRNLNM. Locate the entry for local SCSnode/association_name. If not found, release storage and return. Not an error worth reporting. If not the last entry, move the last entry into the vacated position. Decrement nentries, fixup itemlist, and $CRELNM. $DEQ lock on ICC$REGISTRY. Return path: Release storage and return. - SIMPLE_REGISTRY_LOOKUP Called only from $ICC_CONNECT, and only if the user did not specify a node for the connection. Called while at ASTDEL. Simple_Registry_Lookup (user_remote_association_desc, node, association) Input: The descriptor provided by the user specifying his association name. Descriptor and buffer have already been probed. Address of 6-byte nodename buffer for output Address of 32-byte association name buffer. Both of these are private to $ICC_CONNECT. Outputs: On success, node and association buffers are filled in. Return_Value: condition value. $ENQ EX mode lock on ICC$REGISTRY. $trnlnm index 0 of the logical name on failure, return NOTFOUND. Note: length of index 0 not equal two bytes, value lt 1 or gt 762 is considered an error, and we return NOTFOUND. on success, set nentries to translated binary word value Looking loop: Set desired server to random_pick(nentries). Compute index of desired server's equivalence name as described earlier. $TRNLNM. On failure, return NOTFOUND. Compute offset, and retrieve Nodename and Association Name. Verify that node is still in cluster. If not, begin cleanup: Allocate storage for translation as described above. If we come through this path a second time (unlikely but possible) we can use the storage we had before. Create Itemlist. $TRNLMN. Process each table entry by making sure that it's node is still in the cluster. If not, move the last entry into vacated position, decrement nentries, and continue (rechecking current position). If we were at last position, we were done. If nentries still > 0, $CRELNM to write table back, else $DELLNM. If nentries still > 0, go back to the looking loop. Otherwise, return NOTFOUND. Return path: If we had to allocate storage for cleanup, return it. $DEQ lock on ICC$REGISTRY. Return. ICC CODE MISCELLANEOUS SUPPORT ROUTINES These are generally useful subroutines. This list may not yet be all inclusive. Some of the following routines may be implemented as BLISS MACROS. Likewise, linkage types (JSB or CALL) have not been finalized yet. - PROBE_STR_DESCR_READ Determines the type of string descriptor that was passed to us (32- or 64-bit). Probes the descriptor itself for read access at the specified access mode (acmode), and then probes the buffer pointed to for read access at the specified access mode (acmode). **Note -- for the pre-release, checks first if the descriptor has a 64-bit address and if does, or if the descriptor is a 64-bit descriptor, returns the error SS$_IVADDR. status = probe_str_descr_read (dsc_addr, acmode) - Pre-release, if the descriptor has a 64-bit address (i.e., if .dsc_addr <0, 32, 0> NEQ 0) - Return SS$_IVADDR. - If this is a 64-bit descriptor - Set status to ICC$C_TYP_64. - Probe descriptor for READ access at the specified mode and if it fails return SS$_ACCVIO. - Probe the buffer pointed to by the descriptor for READ access at the specified mode and if it fails return SS$_ACCVIO. - If this is running on an Alpha platform - If the buffer is not quadword aligned - Return SS$_ALIGN. - otherwise - Set status to ICC$C_TYP_32. - Probe descriptor for READ access at the specified mode and if it fails return SS$_ACCVIO. - Probe the buffer pointed to by the descriptor for READ access at the specified mode and if it fails return SS$_ACCVIO. - If this is running on an Alpha platform - If the buffer is not quadword aligned - Return SS$_ALIGN. - PROBE_IOS_ICC Probes the specified number of bytes representing an ICC IOSB/IOS_ICC structure for write access. status = probe_IOS_ICC (IOS_ICC_addr, length, acmode) - Probe the quadword for write access - IF (NOT ($PROBE (.IOS_ICC_addr, length, W, .acmode))) - Return SS$_ACCVIO - PROBE_BUFFER Routine to probe a given number of bytes (bfr_len) of the specified buffer (bfr_addr) for access of the specified type (actyp) at the specified access mode (acmode). **Note -- For the pre-release, checks first to see if the buffer has a 64-bit address and if it does, returns the error status SS$_IVADDR. status = probe_buffer (bfr_addr, bfr_len, actyp, acmode) - Pre-release, if the buffer has a 64-bit address (i.e., if .bfr_addr <0, 32, 0> NEQ 0) - Return SS$_IVADDR - Probe it - If actyp was passed in as ICC$C_READ_ACCESS or ICC$C_MODIFY_ACCESS - IF (NOT ($PROBE (.bfr_addr, .bfr_len, R, .acmode))) - Return SS$_ACCVIO - If actyp was passed in as ICC$C_WRITE_ACCESS or ICC$C_MODIFY_ACCESS - IF (NOT ($PROBE (.bfr_addr, .bfr_len, W, .acmode))) - Return SS$_ACCVIO - If this is running on an Alpha platform - Verify that the buffer is quadword aligned (i.e., if ((.bfr_addr AND 7) NEQ 0) - Return SS$_ALIGN - ICC_IOS_ICC_INIT Routine to probe and clear the IOSB/IOS_ICC. status = ICC_IOS_ICC_INIT (IOS_ICC_addr, IOSB_type, acmode) - Determine the length of the IOSB/IOS_ICC based on the IOSB_type passed to us. - Call probe_IOS_ICC to probe the IOS_ICC for write at the specified access mode. status = probe_IOSIOS_ICC (IOS_ICC_addr, length, acmode) - If the probe is successful - Clear the 1st longword of the IOSB/IOS_ICC (i.e., the status). - Clear the following return fields based on the specified IOSB_type: - ICC$C_TYP_IOSB: 2nd longword - ICC$C_TYP_IOS_RECEIVE: IOS_ICC$L_R1, IOS_ICC$L_R2, IOS_ICC$L_R3 - ICC$C_TYP_IOS_TRANCEIVE: IOS_ICC$L_R1 - Return status. - GENERATE_HANDLE Routine to generate a handle value for a given entity (association, connection or request) update the ICCPDB sequence number and any ICCPDB counts. The handle value is unique within a process and is made up two word-length fields: an original position number (high word) and a sequence number (low word). The sequence number is incremented for every new association, connection or request made by this process (wrapping around to 1) and the original position number is the count of entries preceding where this entry will be linked into its respective queue at, plus 1 (i.e., its original position number within its queue). This longword handle value (ret_hndl) is returned in R0 along with the address of the previous entry on the specified queue (prev_entry_addr) in the argument list. Note that for all the data block types that contain a handle value (the ICCPAB, ICCPCB and ICCPSB), it immediately follows the VMS header fields. ret_hndl = generate_handle (counter_addr, ICCPDB_addr, Q_Hdr_addr; prev_entry_addr); - If queue specified by Q_Hdr_addr is empty - Set prev_entry_addr to the flink associated with Q_Hdr_addr. - Set the high word (i.e. position # portion) of ret_hndl to 1. - If counter_addr is not equal to zero (i.e., this is for an association or a connection) - Set the count pointed to by counter_addr to 0. - Otherwise (specified queue NOT empty) - Walk the queue specified by Q_Hdr_addr looking for the 1st empty/skipped position or the end. - When an empty position (or the end) is located - Set the high word of ret_hndl to the previous position number plus 1). - Assign the address of the "previous" entry to prev_entry_addr. - If this is a new association or connection, increment the appropriate counter in the ICCPDB. - If counter_addr not equal to zero (i.e., this is for an association or a connection) - Add 1 to the count pointed to by counter_addr. - Update the sequence number stored in the ICCPDB. - If ICCPDB$W_seq_nbr is about to overflow a word - Set ICCPDB$W_seq_nbr to 1 (i.e., wrap it around). - Otherwise - Add 1 to ICCPDB$W_seq_nbr. - Assign ICCPDB$W_seq_nbr to the low word of ret_hndl. - Return ret_hndl. - LINK_AB Routine to link the specified ICCPAB onto the ICCPAB queue in the ICCPDB in the first open position (or at the end), obtain and return a handle value for this new association, and increment the association counter. Assoc_Handle = Link_AB (ICCPAB, dflt_asc_flag) - Retrieve the ICCPDB address from the ICCPAB. - If dflt_asc_flag is TRUE (i.e., this is the default association for this process) - If the ICCPDB$L_PAB queue is empty - Set ICCPDB$W_assoc_cnt to 0. - Assign the constant ICC$C_DFLT_ASSOC_HANDLE to assoc_handle. - Set the dflt_asc_open bit in ICCPDB$L_flags. - Link this ICCPAB onto the head of the ICCPDB's ICCPAB queue. - Otherwise - Call generate_handle to get the assoc_handle and where to link the ICCPAB into the queue at. Assoc_Handle = generate_handle (ICCPDB$W_assoc_cnt, ICCPDB, ICCPDB$Q_PAB_Q_Hdr; prev_ICCPAB); - Using the prev_ICCPAB address returned to us by generate_handle, link the ICCPAB into the ICCPDB's ICCPAB queue. - return (Assoc_Handle) - LINK_CB Routine to link the specified ICCPCB onto the ICCPCB queue in the ICCPDB in the first open position (or at the end), obtain and return a handle value for this new connection, and increment the connecttion counter. Conn_Handle = Link_CB (ICCPCB) - Retrieve the ICCPDB address from the ICCPCB. - Call generate_handle to get the conn_handle and where to link the ICCPCB into the queue at. Conn_Handle = generate_handle (ICCPDB$W_conn_cnt, ICCPDB, ICCPDB$Q_PCB_Q_Hdr; prev_ICCPCB); - Set ICCPCB$L_conn_handle to Conn_Handle. - Using the prev_ICCPCB address returned to us by generate_handle, link the ICCPCB into the ICCPDB's ICCPCB queue. - Return (Conn_Handle) - UNLINK_AB Routine to remove an ICCPAB from the ICCPDB queue and update the association count (ICCPDB$W_assoc_cnt). Unlink_AB (ICCPAB address) - Retrieve the ICCPDB address from the ICCPAB. - Find and unlink the specified ICCPAB from the queue in the ICCPDB. - If ICCPAB$L_assoc_handle = ICC$C_DFLT_ASSOC_HANDLE (i.e., we're closing the default association) - Retrieve the ICCPDB address from ICCPAB$L_PDB. - Clear the dflt_asc_open bit in ICCPDB$L_flags. - Subtract 1 from ICCPDB$W_assoc_cnt. - UNLINK_CB Routine to remove an ICCPCB from the ICCPDB queue and update the connection count (ICCPDB$W_conn_cnt). Unlink_CB (ICCPCB address) - Retrieve the ICCPDB address from the ICCPCB. - Find and unlink the specified ICCPCB from the queue in the ICCPDB. - Subtract 1 from ICCPDB$W_conn_cnt. - P1C_IPB_SETUP Routine to allocate an ICCP1C ring buffer in P1-space and charge the user for the maximum number of possible receive IPBs that IPC could allocate on behalf of this connection. status = P1C_IPB_setup (ICCPCB, ICCPAB) - Charge the user for the maximum number of receive IPBs that could be allocated by IPC on behalf of this connection. - Set ICCPCB$L_IPB_charge to 0 (in case the debit call fails). - Determine the number of bytes to charge and store it currently in a local variable (in case the debit call fails). (IPB$K_LENGTH + ICCPAB.IPST$L_MAXIN) * ICCPAB.IPST$W_MAXBUF (i.e., the length of the IPB structure plus the default receive buffer length multiplied by the maximum number of possible outstanding receive operations) - Call EXE$DEBIT_BYTCNT_BYTLM with the number of bytes to charge. - If the call to EXE$DEBIT_BYTCNT_BYTLM fails - Return the error status to the caller. - Otherwise - Store the number of bytes charged in ICCPCB$L_IPB_charge. - Allocate P1-space for a ring buffer for ICCP1Cs - Determine the length for the ICCP1C ring buffer (in bytes). ((1 + #args) * 4) * ICCPAB.IPST$W_MAXBUF Where #args is currently 3, we're adding 1 for the #args field itself, multiplying by 4 as the fields are all longwords, and then multiplying by IPST$W_MAXBUF to account for the maximum number of possible outstanding receive operations. - Call EXE$ALOP1PROC to allocate the memory. - If the allocation attempt failed - Call P1C_IPB_cleanup with the ICCPCB address. - Return the error status to the caller. - Otherwise - Store the starting address of the ICCP1C ring buffer in ICCPCB$L_P1C_start, ICCPCB$L_P1C_in and ICCPCB$L_P1C_out. - Store the ending address of the ICCP1C ring buffer (starting address + length) in ICCPCB$L_P1C_end. - Return status to caller. - P1C_IPB_CLEANUP Routine to deallocate ICCP1C ring buffer we allocated on behalf of this connection and credit the user for the IPC-allocated receive IPBs we charged them for. P1C_IPB_cleanup (ICCPCB) - Cleanup the ICCP1C ring buffer - If ICCPCB$L_P1C_start is not equal to zero (i.e., we allocated P1-Space for an ICCP1C ring buffer) - Call EXE$DEAP1 with ICCPCB$L_P1C_start and the length of the ICCP1C ring buffer (i.e., ICCPCB$L_P1C_end - ICCPCB$L_P1C_start) to deallocate the ICCP1C ring buffer. - Store zero in ICCPCB$L_P1C_start, ICCPCB$L_P1C_end, ICCPCB$L_P1C_in and ICCPCB$L_P1C_out. - Credit the user for returning the receive IPBs - If ICCPCB$L_IPB_charge is not equal to zero (i.e., we charged the user for receive IPBs) - Call EXE$CREDIT_BYTCNT_BYTLM with ICCPCB$L_IPB_charge. - Set ICCPCB$L_IPB_charge to 0. - ASSOCHNDL_TO_ICCPAB Routine to look up the ICCPAB that corresponds to a specified association handle and return the address of the ICCPAB (or zero if no match is found). ICCPAB = AssocHndl_to_ICCPAB (assoc_handle) - Determine the ICCPDB by the process's PID. - Set the return value to 0 (in case no matching ICCPAB is found) - Walk through the ICCPAB queue in the ICCPDB - If an ICCPAB is found whose ICCPAB$L_assoc_handle = assoc_handle Return the address of that ICCPAB - CONNHNDL_TO_ICCPCB Routine to look up the ICCPCB that corresponds to a specified connection handle and return the address of the ICCPCB (or zero if no match is found). ICCPCB = ConnHndl_to_ICCPCB (Conn_Handle) - Determine the ICCPDB by the process's PID. - Set the return value to 0 (in case no matching ICCPCB is found) - Walk through the ICCPCB queue in the ICCPDB - If an ICCPCB is found whose ICCPCB$L_conn_handle = conn_handle - Return the address of that ICCPCB - LINKID_TO_ICCPCB Routine to look up the ICCPCB that corresponds to a given IPLK$L_LINKID. and return the address of the ICCPCB (or zero if no match is found). ICCPCB = LinkID_to_ICCPCB (linkid) - Determine the ICCPDB by the process's PID. - Set the return value to 0 (in case no matching ICCPCB is found) - Walk through the ICCPCB queue in the ICCPDB - If an ICCPCB is found whose IPLK$L_LINKID in the embedded IPLK matches the specified linkid - return the address of that ICCPCB. - ICC_REJECT_DUE_TO_ERROR Routine to call IPC$REJECT to reject a connection due to an error condition. ICC_Reject_Due_To_Error (IPLK_addr, rej_reason); - Fill in the following IPLK fields: - IPLK$L_REMSTAT = rej_reason - IPLK$L_REPLY_LEN = 0 - IPLK$A_REPLY_BUFFER = 0 - Call IPC$REJECT with the IPLK address status = IPC$REJECT (.IPLK_addr); - On a FAILURE completion - Call IPC$RELBUF to deallocate the IPLK status = IPC$RELBUF (.IPLK_addr); - Return to caller - ICC_DISC_CLEANUP Routine to handle the final cleanup of a disconnecting connection. Deallocates associated data structures, fills in the IOSB, posts the "non-existant" event flag and schedules the users' AST (if one was specified and the association is not in the process of being run down). status = ICC_Disc_Cleanup (ICCPCB address) - Clean up any outstanding send and receive resources (ICCPSBs, ICCPRBs, IPBs, and related buffers) by calling the routine Cleanup_Data_Transfers. - If ICCPCB$A_pool_bfr is NOT equal to zero (i.e., a connect/ disconnect buffer was allocated and data still exists) - Call Return_ICCPCB_Pool_Bfr to credit/deallocate it. Return_ICCPCB_Pool_Bfr (ICCPCB); - Set IPLK$L_SEND_LEN and IPLK$A_SEND_BUFFER to zero. - Call probe_IOS_ICC to re-probe the IOSB for write access. - If the probe is successful - Fill in the IOSB. - If ICCPCB$A_compl_rtn does not contain a zero (i.e., an AST completion routine was provided) - Retrieve the ICCPAB from ICCPCB$L_PAB. - Call ICC_Sched_AST to set up the ACB and schedule the AST. ICC_Sched_AST (ICCPAB, ICCPCB$A_Disc_ACB, ICCPCB$A_compl_rtn, ICCPCB$Q_compl_prm, ICCPCB$L_open_mode); - Call Cleanup_ICCPCB to credit/unlink/deallocate the ICCPCB/IPLK. Cleanup_ICCPCB (ICCPCB, Was_Linked_In=TRUE); - Call SCH_STD$POSTEF with efn=EFN$C_ENF to post the completion. - ICC_CHK_CREATION_RIGHTS Ultimately, this routine will determine if a process is authorized to open a specified association. For now, it just returns FALSE as it is being called after a privilege check for SYSNAM has failed. status = ICC_Chk_Creation_Rights () - Return FALSE - ICC_CHK_CONNECT Ultimately, this routine will determine if a process is authorized to make the specified connection. It will take the arguments: the address of the remote association name string (32 characters) and the address of the remote node name (6 characters), but for now it just returns TRUE as both processes will have SYSNAM privilege. status = ICC_Chk_Connect () - Return TRUE - RANDOM_PICK This routine returns a number between 1 and integer_value. It is used within Simple_Registry_Lookup and also within $ICC_CONNECT if the user supplied a list of nodes. Random_pick (integer_value) We need a fairly good random number with a uniform distribution. The design of this routine is TBD. Since this is an execlet, we can't call an RTL routine unless we link in a private copy. We don't plan to keep state, but we could keep state in the ICC vector if the design calls for it. - ICC_SCHED_AST Routine to fill in the ACB with the specified parameters and queue an AST. ICC_Sched_AST (ICCPAB_addr, ptr_to_ACB_addr, astrtn, astprm, acmode); - If (ICCPAB$L_rndwn_in_prog = 1) (i.e., this association is being rundown) - Return with status = SS$_NORMAL. - Otherwise - Build the ACB for the AST with ACB$L_AST = contents of astrtn (by value) ACB$L_ASTPRM = contents of astprm (by value) ACB$B_RMOD = ACB$V_MODE (bits 0-1) = acmode ACB$V_NODELETE (bit 5) = clear (so the ACB will be deallocated after the AST is delivered) - Schedule the AST by queuing the ACB. - If the ACB was successfully queued - Zero out the address of the ACB (pointed to by ptr_to_ACB_addr) as the ACB will be deallocated after its delivery. - Otherwise - Deallocate the ACB pointed to by ptr_to_ACB_addr. - Zero out the address of the ACB (pointed to by ptr_to_ACB_addr). - Return - DFLT_ASSOC_CHK_AND_SETUP Routine to determine if the association attempting to be opened is the default association for this process and to setup the byte counted ASCIC string name_out with the incoming association name (or the default association name string ICC$PID_nnnnnnnn, where nnnnnnnn is the character representation of the Process ID) and its length. dflt_flag = Dflt_Assoc_Chk_and_Setup (name_in; name_out) - Set dflt_flag to FALSE. - If name_in = 0 (i.e., no name string was specified so the default association is wanted and we need to build the default association name string) - Set the string length byte (i.e., name_out[0]) to 16. - Copy the string "ICC$PID_" to name_out (starting at name_out[1]). - Get the PID. - Convert it to a string of hex characters. - Append the string of hex characters to name_out. - Set dflt_flag to TRUE. - Otherwise (we have a name string to check against) - Store the length of name_in in the length byte (i.e., name_out[0]). - Copy name_in to name_out (starting at name_out[1]). - If the length of name_out is 16 (i.e., the string is the right length) - If name_out starts with "ICC$PID_" (i.e., it could be the default association) - Get the PID. - Convert it to a string of hex characters. - If the last 8 characters of name_out match the hex representation of the PID (i.e., we were handed the default association name string) - Set dflt_flag to TRUE. - Return dflt_flag (in R0) and name_out (in the argument list) to the caller. - CLEANUP_ICCPAB Routine to credit the user for returning the ICCPAB/IPST, unlink the specified ICCPAB from the queue and deallocate it. Cleanup_ICCPAB (ICCPAB) - Call EXE$CREDIT_BYTCNT_BYTLM with ICCPAB$W_size to credit the user for returning the ICCPAB/IPST. - Call Unlink_AB to remove the ICCPAB from the queue in the ICCPDB, update the association count (ICCPDB$W_assoc_cnt), and clear the dflt_asc_open bit in ICCPDB$L_flags if this is the default association. - Deallocate the ICCPAB/IPST structure. - CLEANUP_ICCPCB Routine to finish the clean up of the ICCPCB; credit the user for returning the ICCPCB/IPLK structure, unlink the specified ICCPCB from the queue (if it had been linked in) and finally deallocate it. Note that the user will always have been charged for the structure if it was successfully allocated, as EXE$DEBIT_BYTCNT_BYTLM_ALO is used. Cleanup_ICCPCB (ICCPCB, Was_Linked_In) - Call P1C_IPB_cleanup with the ICCPCB address. - Call EXE$CREDIT_BYTCNT_BYTLM with ICCPCB$W_size to credit the user for returning the ICCPCB/IPLK structure. - If Was_Linked_In = TRUE (i.e., Link_CB was called for this ICCPCB) - Call Unlink_CB to remove the ICCPCB from the ICCPDB queue and update the connection count (ICCPDB$W_conn_cnt). - Deallocate the ICCPCB/IPLK structure. - RETURN_ICCPCB_POOL_BFR Routine to credit the user for returning the NonPaged pool buffer allocated on their behalf during connect/disconnect, deallocate it, and set the relevant ICCPCB address and length fields to zero. Return_ICCPCB_Pool_Bfr (ICCPCB_addr) - Call EXE$CREDIT_BYTCNT with ICCPCB$L_pool_bfr_alo to credit the user for returning the buffer. - Deallocate ICCPCB$A_pool_bfr. - Set ICCPCB$A_pool_bfr and ICCPCB$L_pool_bfr_alo to zero. - RETURN_ICCP1B Routine to deallocate ICCP1B structure (allocated in P1-space for a connect/disconnect) and set the relevant ICCPCB address field to zero. Return_ICCP1B (ICCPCB_addr) - Call EXE$DEAP1 with ICCPCB$A_P1B and ICCP1B$W_size to deallocate the ICCP1B. - Store zero in ICCPCB$A_P1B. - ADD_TRACE_ENTRY Routine to add an entry to the ICC trace area and update the necessary counters, etc. Add_Trace_Entry (code, func, data_blk_addr, info1, info2) - If tracing is OFF (ICC$GL_ICC_TRACE_INFO = 0) - Return - Add the information to the group specified by Nxt_Trace_Group. - Increment Nxt_Trace_Group. - if Nxt_Trace_Group = Max_Trace_Groups - Set Nxt_Trace_Group to 0. NEW ICC MODULES DATA DEFINITIONS - ICCDEF.SDL (Externally visable data definitions) - IOS_ICC - Routine prototype interfaces - Externally visable constants - ICC_IDEF.SDL (Internally visable data definitions) - ICCP1B - ICCP1C - ICCPDB - ICCPAB - ICCPCB - ICCPSB - ICCPRB - Internally visable constants - ICCPDB_VECTOR This array of MAXPROCESSCNT longwords (technically 0 to MAXPROCESSCNT-1), one for each allowable process on the system, keeps track of which process(es) are using the $ICC system services. A zero in a slot indicates non-use; otherwise it will contain the address of the ICCPDB associated with that process. It is indexed into by the process's process index (determinable by the PID). - ICC_TRACE_INFO The trace area contains some counter and control/header fields and a "circular" array of 0 to Max_Trace_Groups-1 4-longword groups. The array will wrap back around to the 1st group after using the last group. Trace Header/Control information Longword 1: Max_Trace_Groups Longword 2: Nxt_Trace_Group Longword 3: Longword 4: Groups 1... : Trace group/entry Longword 1: Hi word : Unique trace code Low word: Function code (See the "ICC CODES RELATED TO TRACING" portion of the "EVENT CODES AND OTHER CONSTANTS" section later in this document for function code names/values) Longword 2: Address of most relevant ICC data block (i.e., ICCPAB, ICCPCB, ICCPSB, ICCPRB) Longword 3: Additional information as necessary (or zero) Longword 4: Additional information as necessary (or zero) - Definitions related to Argument/Descriptor probing - ICC$C_TYP_64 1 - 64-bit descriptor - ICC$C_TYP_32 3 - 32-bit descriptor - ICC$C_READ_ACCESS 0 - Check for READ access at specified mode - ICC$C_WRITE_ACCESS 1 - Check for WRITE access at specified mode - ICC$C_MODIFY_ACCESS 2 - Chk for RD/WRT access at specified mode - Definitions related to tracing - ICC$C_MAX_TRC_GROUPS 25 - The maximum number of trace group entries to size the trace array to. ROUTINES RELATING TO OPENING/CLOSING AN ASSOCIATION - ICC_ASC.BLI - EXE$ICC_OPEN_ASSOC - Open an association - EXE$ICC_CLOSE_ASSOC - Close an association ROUTINES RELATING TO CONNECTION INITIATION AND DISCONNECTION - ICC_CONN.BLI - EXE$ICC_CONNECT - Initiate a connection - EXE$ICC_CONNECTW - Initiate a connection and wait - EXE$ICC_ACCEPT - Accept a requested connection - EXE$ICC_REJECT - Reject a requested connection - EXE$ICC_DISCONNECT - Initiate a disconnection - EXE$ICC_DISCONNECTW - Initiate a disconnection and wait ROUTINES RELATING TO DATA TRANSFER - ICC_XFER.BLI - exe$icc_transmit - Send a single shot message - exe$icc_transmitw - Send a single shot message and wait - exe$icc_reply - Send a response message - exe$icc_replyw - Send a response message and wait - exe$icc_receive - Receive a message - exe$icc_receivew - Receive a message and wait - exe$icc_transceive - Send a request/response message - exe$icc_transceivew - Send a request/response message and wait ROUTINES RELATING TO THE SIMPLE CLUSTERWIDE REGISTRY - ICC_SIMPLE_REGISTRY.BLI - Simple_Registry_Add - Simple_Registry_Remove - Simple_Registry_Lookup ROUTINES RELATING TO THE SIMPLE CLUSTERWIDE REGISTRY - ICC_SECURITY.BLI - ICC_Chk_Creation_Rights - ICC_Chk_Connect MISCELLANEOUS ROUTINES - ICC_SUBS.BLI - ICC_SS_Init - initialization routine - ICC_EVNT_HNDLR_AST - ICC event handler AST - ICC_KMODE_RUNDWN - Kernel-mode rundown handler - Other subroutines general to ICC EVENT CODES AND OTHER CONSTANTS ICC DEFAULT ASSOCIATION HANDLE Name Value Visability ----------------------- ----- ---------- ICC$C_DFLT_ASSOC_HANDLE 1 External The value 1 represents an original position number (high word) of 0 and a sequence number (low word) of 1. ICC EVENT CODES Name Value Visability ----------------- ----- ---------- ICC$C_EV_CONNECT 1 External ICC$C_EV_DISCONNECT 2 External ICC CODES RELATED TO ARGUMENT/DESCRIPTOR/IOSB/IOS_ICC PROBING Name Value Visability ----------------- ----- ---------- ICC$C_TYP_64 1 Internal ICC$C_TYP_32 3 Internal ICC$C_READ_ACCESS 0 Internal ICC$C_WRITE_ACCESS 1 Internal ICC$C_MODIFY_ACCESS 2 Internal ICC$C_TYP_IOSB 0 Internal ICC$C_TYP_IOS_RECEIVE 1 Internal ICC$C_TYP_IOS_REPLY 2 Internal ICC$C_TYP_IOS_TRANCEIVE 3 Internal ICC CODES RELATED TO TRACING Name Value Visability Description ----------------- ------- ---------- ---------------------------- ICC$C_MAX_TRC_GROUPS 25 (19) Internal Max # of traces stored at any one time ICC$C_FC_OPEN 1 Internal Func cd for $ICC_OPEN_ASSOC ICC$C_FC_CLOSE 2 Internal Func cd for $ICC_CLOSE_ASSOC ICC$C_FC_CONNECT 3 Internal Func cd for $ICC_CONNECT ICC$C_FC_CONNECTW 4 Internal Func cd for $ICC_CONNECTW ICC$C_FC_ACCEPT 5 Internal Func cd for $ICC_ACCEPT ICC$C_FC_REJECT 6 Internal Func cd for $ICC_REJECT ICC$C_FC_DISCONNECT 7 Internal Func cd for $ICC_DISCONNECT ICC$C_FC_DISCONNECTW 8 Internal Func cd for $ICC_DISCONNECTW ICC$C_FC_TRANSMIT 9 Internal Func cd for $ICC_TRANSMIT ICC$C_FC_TRANSMITW 10 (A) Internal Func cd for $ICC_TRANSMITW ICC$C_FC_REPLY 11 (B) Internal Func cd for $ICC_REPLY ICC$C_FC_REPLYW 12 (C) Internal Func cd for $ICC_REPLYW ICC$C_FC_RECEIVE 13 (D) Internal Func cd for $ICC_RECEIVE ICC$C_FC_RECEIVEW 14 (E) Internal Func cd for $ICC_RECEIVEW ICC$C_FC_TRANSCEIVE 15 (F) Internal Func cd for $ICC_TRANSCEIVE ICC$C_FC_TRANSCEIVEW 16 (10) Internal Func cd for $ICC_TRANSCEIVEW ICC DYNDEF DEFINITIONS DYN$C_ICC = ICC data type DYN$C_ICCP1B = subtype - ICCP1B structure for P1-space data DYN$C_ICCPDB = subtype - ICC Process Data Block DYN$C_ICCPAB = subtype - Association Data Block DYN$C_ICCPCB = subtype - Connection Data Block DYN$C_ICCPSB = subtype - Send Data Block DYN$C_ICCPRB = subtype - Receive Data Block ICC "VARIANT" COMPILATION CONSTANTS ICC$C_VARIANT_DEBUG = 1 ICC$C_VARIANT_TRACE = 2 IPC EVENT CODES -- Defined in IPC_DEF.SDL, module $IPCDEF IPC$_EV_LINK = 0 IPC$_EV_ACCEPT = 1 IPC$_EV_REJECT = 2 IPC$_EV_DATA = 3 IPC$_EV_REPLY = 4 IPC$_EV_DISC = 5 IPC$_EV_TRANS = 6 IPC$_EV_DISC_COM = 7 IPC$_EV_TX_COMP = 8 IPC$_EV_REPLY_COMP = 9 IPC$_EV_PENDING_DATA = 10 IPC TRANSPORT TYPE CODES -- Defined in IPC_DEF.SDL, module $IPCDEF IPC$_LCL = 0 IPC$_NSP = 1 IPC$_SCS = 2 IPC$_OSI = 3 IPC$_TCP = 4 IPC ROUTINE LINKAGES All the IPC routines use JSB linkages rather than standard call interfaces. Linkage definitions can be found in the modules: SYSIPC$LINKAGES.R32, IPC_DEFINITIONS.R32 and SCATPREQ.R32. Routine Name Linkage Name Linkage Type -------------- --------------------- ------------------ IPC$START ipc$start_linkage JSB (REGISTER = 7) IPC$LINK ipc$link_linkage JSB (REGISTER = 7) IPC$ACCEPT ipc$accept_linkage JSB (REGISTER = 7) IPC$REJECT ipc$reject_linkage JSB (REGISTER = 7) IPC$GETBUF ipc$getbuf_linkage JSB (REGISTER = 7) IPC$RELBUF ipc$relbuf_linkage JSB (REGISTER = 7) IPC$CREDIT ipc$credit_linkage JSB (REGISTER = 7) IPC$SEND ipc$send_linkage JSB (REGISTER = 7) IPC$REPLY ipc$reply_linkage JSB (REGISTER = 7) IPC$EXP_REC ipc$exp_rec_linkage JSB (REGISTER = 7) IPC$UNLINK ipc$unlink_linkage JSB (REGISTER = 7) IPC$STOP ipc$stop_linkage JSB (REGISTER = 7) ICC DATA STRUCTURES ICC DATA STRUCTURE RELATIONSHIPS ICC$GL_ICC_PDB_VECTOR ICC$GL_ICC_TRACE_AREA ( System data cell ) ( System data cell ) | | V V +-------------+ +-------------+ |ICCPDB_VECTOR| | ICC Trace | | ... | | area | | One to | +-------------+ |MAXPROCESSCNT| | Longwords | | | |(Init to 0 by| | the ICC SS | | init rtn) | | | | Each cell | | points to |--+ | | | +-------------+ | | _________| | V +--------+ | ICCPDB | | ... | | | +-------------+ +-------------+ | ICCPAB |->| ICCPAB/IPST |---->| ICCPAB/IPST |... | | +-------------+ +-------------+ | | +-------------+ +-------------+ | ICCPCB |->| ICCPCB/IPLK |---->| ICCPCB/IPLK |... +--------+ +-------------+ +-------------+ ^ ^ ^ | | | | ^ ^ ^ +--------------+ | | | | | | | | +---------------+ | +--------+ | | | | | | +----------+ | V | +----+ | | | | +------+ | V +------+ | V | | | | V | +------+ |ICCPSB| | +---+ +--+ | | +---+ +---+ | |ICCPSB| +------+ V |IPB| | | | | |IPB| V +------+ | +------+ +---+ | | | | +---+ +------+ | | |ICCPRB| | V | | V | |ICCPRB| | V +------+ | +------+ | | +------+ | +------+ V +------+ | | |ICCP1B| | | |ICCP1B| | | +------+ |ICCPSB| | | +------+ | | +------+ | | |ICCPSB| +------+ V V V V V V +------+ +------+ +---+ +------+ +------+ +---+ +------+ |ICCPRB| |IPB| |ICCP1C| |ICCP1C| |IPB| |ICCPRB| +------+ +---+ +------+ +------+ +---+ +------+ ICC DATA STRUCTURES SYSTEM DATA CELLS - ICC$GL_ICC_PDB_VECTOR - ICC$GL_ICC_TRACE_AREA ICC EXTENDED IOSB DATA STRUCTURE FOR DATA TRANSFER ROUTINES Visability: External IOS_ICC - IOS_ICC$W_STATUS - Return status code (returned) - IOS_ICC$W_RESERVED - Unused UNION - RECEIVE STRUCTURE - IOS_ICC$L_R1 - retlen (returned) - IOS_ICC$L_R2 - request_handle (returned) - IOS_ICC$L_R3 - reply_len (returned) - IOS_ICC$L_FILL1 - Unused - REPLY STRUCTURE - IOS_ICC$L_P0 - request_handle (input) - IOS_ICC$L_FILL2 DIMENSION 3 - Unused - TRANCEIVE STRUCTURE - IOS_ICC$L_R1 - retlen (returned) UNION - reply_buf (input) - IOS_ICC$Q_P1 - 64-bit buffer addresses (Alpha) - IOS_ICC$L_VP1 - 32-bit buffer addresses (VAX) END UNION - IOS_ICC$L_P2 - reply_len (input) END UNION PROCESS DATA STRUCTURES The following data structures are all specific to a process and will only be manipulated in the context of that owning process. Since kernel threads (Alpha) permit only one thread to operate at a time on a system, and likewise only one process will execute at a time in a VAX environment, being in kernel mode should provide sufficient synchronization. P1-SPACE RING BUFFER FOR PASSING ARGUMENTS Visability: Internal ICCP1C - ICCP1C$L_max_P1Cs dimension "ICCPAB.IPST$L_MAXIN" - ICCP1C$L_nargs - Number of arguments (currently 3) - ICCP1C$L_arg_array dimension "ICCP1C$L_nargs" - An array for "Narg" arguments P1-SPACE DATA STRUCTURE FOR PASSING DATA AND ARGUMENTS Visability: Internal ICCP1B - ICCP1B$L_flink - Forward link - ICCP1B$L_blink - Backward link - ICCP1B$W_size - Structure size - ICCP1B$B_type - DYN$C_ICC - ICCP1B$B_subtype - DYN$C_ICCP1B - ICCP1B$L_ev_type - Event type code ICC$C_EV_CONNECT ICC$C_EV_DISCONNECT - ICCP1B$L_conn_handle - Handle # of this ICC connection - ICCP1B$L_data_len - Length of the incoming data (Max = 1024) - ICCP1B$Q_data_buf_addr - Address of ICCP1B$T_data_buf (the data buffer below) - ICCP1B$L_P5 - On CONNECT : the Length in bytes of the buffer available for a reply (Max = 1024) On DISCONNECT: the user defined disconnect reason/status from the remote partner - ICCP1B$L_P6 - On CONNECT : zero On DISCONNECT: user-specified user_context value (or 0 if none) quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; - ICCP1B$T_data_buf - Starting address (quad aligned) of the actual data (Max 1024 bytes) PROCESS DATA BLOCK Visability: Internal ICCPDB - ICCPDB$L_flink - Forward link - ICCPDB$L_blink - Backward link - ICCPDB$W_size - Structure size - ICCPDB$B_type - DYN$C_ICC - ICCPDB$B_subtype - DYN$C_ICCPDB - ICCPDB$L_flags - Flag bit mask dflt_asc_open - Set to 1 if the default assoc for this process is open/assigned - ICCPDB$Q_PAB_Q_Hdr - ICCPAB Queue header. Comprised of: - ICCPDB$L_PAB_flink - Assoc Data Block Q header (forward link) - ICCPDB$L_PAB_blink - Assoc Data Block Q header (backward link) - ICCPDB$Q_PCB_Q_Hdr - ICCPCB Queue header. Comprised of: - ICCPDB$L_PCB_flink - Conn Data Block queue header (forward link) - ICCPDB$L_PCB_blink - Conn Data Block queue header (backward link) - ICCPDB$W_assoc_cnt - The nbr of associations in the ICCPAB queue - ICCPDB$W_conn_cnt - The nbr of connections in the ICCPCB queue - ICCPDB$W_seq_nbr - Sequence number (incremented for each association and connection opened by this process. Wraps around to 1. ASSOCIATION DATA BLOCK Visability: Internal Note that the embedded IPST contains fields for the following: PID (IPST$L_PID), MAXRECBUFSIZ (IPST$L_MAXIN), MAXXMTBUFSIZ (IPST$L_MAXOUT) and MAXFLOWBUFCNT (IPST$W_MAXBUF). ICCPAB - ICCPAB$L_flink - Forward link - ICCPAB$L_blink - Backward link - ICCPAB$W_size - Structure size - ICCPAB$B_type - DYN$C_ICC - ICCPAB$B_subtype - DYN$C_ICCPAB - ICCPAB$L_assoc_handle - The following 2 fields comprise the association handle - ICCPAB$W_seq_nbr - Sequence # assigned to the association - ICCPAB$W_assoc_idx - Original position # assigned to the ICCPAB - ICCPAB$L_PDB - Pointer to the parent process data block - ICCPAB$L_open_mode - Mode the association was opened from - ICCPAB$L_state - State of the association Note that the only odd state (i.e., LBS) is open. ICCPAB$C_CLOSED = 0 ICCPAB$C_OPENING = 2 ICCPAB$C_OPEN = 1 ICCPAB$C_CLOSING = 4 - ICCPAB$L_rndwn_in_prog - Set to 1 to indicate that this association is in the process of being run down - ICCPAB$A_event_rtn - Pointer to User's event routine (AST) - ICCPAB$A_recv_rtn - Pointer to User's "Get lg bfr" AST routine - ICCPAB$T_assoc_name - Name specified for this association (ASCIC) (36 characters -- Up to 32 for the name, 1 for the length and 3 to longword align) - ICCPAB$L_lgcl_name_addr - Address of a piece of pool containing the logical name associated with this association - ICCPAB$L_lgcl_name_len - Actual length of ICCPAB$L_lgcl_name_addr - ICCPAB$L_lgcl_name_alo - Allocated length of ICCPAB$L_lgcl_name_addr - ICCPAB$L_lgcl_tbl_addr - Address of a piece of pool containing the logical name table for the logical name pointed to by ICCPAB$A_lgcl_name_addr - ICCPAB$L_lgcl_tbl_len - Actual length of ICCPAB$L_lgcl_tbl_addr - ICCPAB$L_lgcl_tbl_alo - Allocated length of ICCPAB$L_lgcl_tbl_addr quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; - ICCPAB$R_ipst - Starting address (quad aligned) of an embedded IPST structure (see IPST field descriptions below) CONNECTION DATA BLOCK Visability: Internal Note that the embedded IPLK contains fields for the following: PID (IPLK$L_PID) and USER_CONTEXT (IPLK$L_ALIAS). ICCPCB - ICCPCB$L_flink - Forward link - ICCPCB$L_blink - Backward link - ICCPCB$W_size - Structure size - ICCPCB$B_type - DYN$C_ICC - ICCPCB$B_subtype - DYN$C_ICCPCB - ICCPCB$L_conn_handle - The following 2 fields comprise the connection's handle - ICCPCB$W_seq_nbr - Sequence # assigned to the connection - ICCPCB$W_conn_idx - Original position # assigned to the ICCPCB - ICCPCB$L_assoc_handle - Handle # of the owner ICC Association - ICCPCB$L_PDB - Pointer to the ICCPDB for this process - ICCPCB$L_PAB - Ptr to the owner ICC Assoc Data Blk (ICCPAB) - ICCPCB$Q_PSB_Q_Hdr - ICCPSB Queue header. Comprised of: - ICCPCB$L_PSB_flink - Conn.'s Send Data Block queue (Forward ptr) - ICCPCB$L_PSB_blink - Conn.'s Send Data Block queue (Backward ptr) - ICCPCB$Q_PRB_Q_Hdr - ICCPRB Queue header. Comprised of: - ICCPCB$L_PRB_flink - Conn.'s Recv Data Block queue (Forward ptr) - ICCPCB$L_PRB_blink - Conn.'s Recv Data Block queue (Backward ptr) - ICCPCB$Q_IPB_Q_Hdr - IPB Queue header. Comprised of: - ICCPCB$L_IPB_flink - Connection's IPB queue (Forward pointer) - ICCPCB$L_IPB_blink - Connection's IPB queue (Backward pointer) - ICCPCB$A_Conn_ACB - Address of an ACB used by connect - ICCPCB$A_Disc_ACB - Address of an ACB used by disconnect - ICCPCB$L_state - State of the connection Note that the only odd state (i.e., LBS) is open. ICCPCB$C_DISCONNECTED = 0 ICCPCB$C_CONN_RCVD = 2 ICCPCB$C_CONNECTING = 4 ICCPCB$C_OPEN = 1 ICCPCB$C_DISC_RQSTD = 6 ICCPCB$C_DISC_RCVD = 8 ICCPCB$C_DISCONNECTING = 10 - ICCPCB$L_arg_lens - Argument length mask Bit notes bit len for assoc arg (0=32, 1=64) - ICCPCB$L_open_mode - Mode the connection was opened from - ICCPCB$L_flags - Flag bit mask synch_mode - Data transfer routines are allowed to return a status of SS$_SYNCH to the user - ICCPCB$A_IOSB - Address of the Connect/Disconnect IOSB - ICCPCB$L_retbfr_max - Maximum length of accept/reject data buffer - ICCPCB$L_retbfr_len - Amount of data in accept/reject buffer - ICCPCB$A_ret_buf - Address of accept/reject data buffer - ICCPCB$A_actual_retlen - Address of where to store the actual number of bytes of accept/reject data returned - ICCPCB$Q_compl_prm - Parameter to pass to the completion routine - ICCPCB$A_compl_rtn - User's connect complete AST routine - ICCPCB$L_discon_rsn - Disconnect reason code - ICCPCB$A_pool_bfr - Address of the buffer we allocated from pool for connect data - ICCPCB$L_pool_bfr_alo - Allocated length of ICCPCB$A_pool_bfr - ICCPCB$A_P1B - Address of the ICCP1B (the P1-space data structure we allocated to copy the arguments and connect/disconnect data into for the ICC_CONN_DISC_FRONT_END routine. - ICCPCB$A_dsc_iplk_addr - Address of the disconnect IPLK - ICCPCB$L_P1C_start - The starting address of our allocated ICCP1C P1-space ring buffer - ICCPCB$L_P1C_end - The ending address of our allocated ICCP1C P1-space ring buffer - ICCPCB$L_P1C_in - Address to insert the next ICCP1C entry at - ICCPCB$L_P1C_out - Address to remove the next ICCP1C entry from - ICCPCB$L_IPB_charge - Number of bytes charged for receive IPBs - ICCPCB$T_rem_node_name - Name specified for the remote node (ASCIC) (8 characters -- Up to 6 for the nodename, 1 for the length and 1 to quadword align) - ICCPCB$T_rem_asc_name - Name specified for the remote partner (ASCIC) (36 characters -- Up to 32 for the name, 1 for the length and 3 to longword align) quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; - ICCPCB$R_iplk - Starting address (quad aligned) of an embedded IPLK structure (see IPLK field descriptions below) SEND/REPLY DATA BLOCK Visability: Internal ICCPSB - ICCPSB$L_flink - Forward link - ICCPSB$L_blink - Backward link - ICCPSB$W_size - Structure size - ICCPSB$B_type - DYN$C_ICC - ICCPSB$B_subtype - DYN$C_ICCPSB - ICCPSB$L_request_handle - Handle assigned to the Request/Response ID. Made up of the following 2 fields: - ICCPSB$W_seq_nbr - Sequence # - ICCPSB$W_request_idx - Original position # assigned to the ICCPSB - ICCPSB$L_pid - Process ID (PID) of User Process - ICCPSB$L_PCB - Ptr to this send requests' Conn Data Block - ICCPSB$L_conn_handle - Handle # of this ICC connection - ICCPSB$L_arg_lens - Argument length mask Bit notes bit len for assoc arg (0=32, 1=64) - ICCPSB$A_IOS_ICC - Address of request's extended IOSB - ICCPSB$L_send_len - Length of send data - ICCPSB$A_send_buf - Address of the send data buffer - ICCPSB$Q_compl_prm - Parameter to pass to the completion routine - ICCPSB$A_compl_rtn - User's completion AST routine - ICCPSB$A_ACB - Address of an ACB (??here or in the ICCPCB??) - ICCPSB$A_IPB - Address of an associated IPB (Only used for Replies) quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; - ICCPSB$R_ipbr - Starting address (quad aligned) of an embedded IPBR structure. Used to allocate an IPB. Only one of the IPB or IPBR fields will be used per request. RECEIVE/TRANSCEIVE DATA BLOCK Visability: Internal ICCPRB - ICCPRB$L_flink - Forward link - ICCPRB$L_blink - Backward link - ICCPRB$W_size - Structure size - ICCPRB$B_type - DYN$C_ICC - ICCPRB$B_subtype - DYN$C_ICCPRB - ICCPRB$L_pid - Process ID (PID) of User Process - ICCPRB$L_PCB - Ptr to this receive requests' Conn Data Block - ICCPRB$L_arg_lens - Argument length mask Bit notes bit len for assoc arg (0=32, 1=64) - ICCPRB$A_IOS_ICC - Address of request's extended IOSB - ICCPRB$L_conn_handle - Handle # of this ICC connection - ICCPRB$A_recv_buf - Address of the receiving data buffer - ICCPRB$A_reply_buf - Address of the reply data buffer - ICCPRB$L_recv_max - Len of the buffer available to recv the data - ICCPRB$L_recv_len - Actual length of the data received - ICCPRB$L_reply_max - Maximum length for reply message - ICCPRB$L_reply_len - Actual length of the reply message - ICCPRB$Q_compl_prm - Parameter to pass to the completion routine - ICCPRB$A_compl_rtn - User's receive completion AST routine - ICCPRB$A_ACB - Address of an ACB (??here or in the ICCPCB??) RELATED IPC DATA STRUCTURES IPC IPST DATA STRUCTURE LAYOUT IPST$L_FLINK - Forward link IPST$L_BLINK - Backward link IPST$W_SIZE - Structure size IPST$B_TYPE - DYN$C_IPC IPST$B_SUBTYPE - DYN$C_IPC_IPST IPST$L_IPCID - IPC ID IPST$L_MAXIN - Max inbound msg size IPST$L_MAXOUT - Max outbound msg size IPST$W_MAXBUF - Max buffers per link IPST$W_FLAGS - Currently defined flag bits include: kast - Kernel AST delivery txcomp - Tx complete (for single shot) nomux - Non muxed links (not implemented yet) fcont - Flow control enable eventrc - Explicit receive mode replycomp - Need reply completion IPST$L_PID - Process ID of application IPST$A_NAMES - Address of name string IPST$A_EVENT - Address of inbound event handler quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; IPST$K_LENGTH - IPST structure length (constant) IPC IPLK DATA STRUCTURE LAYOUT IPLK$L_FLINK - Forward link IPLK$L_BLINK - Backward link IPLK$W_SIZE - Structure size IPLK$B_TYPE - DYN$C_IPC IPLK$B_SUBTYPE - DYN$C_IPC_IPLK IPLK$B_EVENT - Event type of IPCRP IPLK$B_UNUSED - Unused byte IPLK$W_UNUSED1 - Unused word IPLK$L_LINKID - IPC Link ID IPLK$L_ALIAS - Link alias (user_context) field IPLK$L_SEND_LEN - Size of link message IPLK$L_REPLY_LEN - Size of link reply IPLK$A_SEND_BUFFER - Send buffer address IPLK$A_REPLY_BUFFER - Reply buffer address IPLK$L_PID - PID of User Process IPLK$L_ACMODE - Buffer owners access mode IPLK$L_SEND_SVAPTE - SVAPTE for send buffer IPLK$L_REPLY_SVAPTE - SVAPTE for reply buffer IPLK$L_SEND_BOFF - BOFF for send buffer IPLK$L_REPLY_BOFF - BOFF for reply buffer IPLK$L_FLAGS - Currently defined flag bits include: inuse - Buffer in use noreply - Send-only buffer synch - Synch send reque delete variable - Variable buffer txcomp - Signaled txcom disccom - Signal dc complete replycomp - Signaled reply complete nocheck - Don't check for cached buffer cancel - Allow cancel of this IPB queued - IPLK queued on PHL/LCB log_client - Log client connection flag tselect - Transport selection requested ipb_dummy1 - Pending_data condition found IPLK$L_REMSTAT - Status supplied by target IPLK$A_ACB - Address of ACB IPLK$Q_CONTEXT - User context area IPLK$L_STACK dimension 14 - Scratch area (14 longwords) IPLK$A_QUEUED_HERE - IPLK queued on IPLK$L_QUEUED_PC - IPLK queued by IPLK$L_VERSION - Buff version IPLK$A_XBUF IPLK$Q_PRIVATE - IPC private area IPLK$L_RECEIVE_IPB - Address of cross linked IPB IPLK$L_NODEID - First 32 bits of node id IPLK$W_NODEIDH - High order word of node id IPLK$W_TRANSPORT - Transport type IPLK$A_NODENAMES - Address of target node name string IPLK$A_NAMES - Address of target IPC name string IPLK$L_IPCID - IPC ID IPLK$L_TSELECT_MASK - Transport preference mask local - Local transport scs - Cluster transport nsp - DECnet transport quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; IPLK$K_LENGTH - IPLK structure length (constant) IPC IPBR DATA STRUCTURE LAYOUT IPBR$L_FLINK - Forward link IPBR$L_BLINK - Backward link IPBR$W_SIZE - Structure size IPBR$B_TYPE - DYN$C_IPC IPBR$B_SUBTYPE IPBR$L_LINKID - Link ID IPBR$L_SEND_LEN - Transmit length IPBR$L_REPLY_LEN - Reply length IPBR$A_IPB - Returned IPB address quadword_align CHARACTER LENGTH (8-(.&7))&7 FILL; IPBR$K_LENGTH - IPBR structure length (constant)