#ifndef _CLMSG_H_ #define _CLMSG_H_ /* ----------------------- ClMsg.h ----------------------- */ /* Cluster messaging */ /* This file contains the specifications of the low-level messaging functions required by the Cluster Manager's module. Primary input to this is the node#; see the MM module for details. It is assumed that this module is configured (by mechanisms not described here) to know the various paths to the target node (IP address, netbios address, async line, Snet address, ...). It is also assumed that *all* CM->CM communication uses this module. The various CM components must be able to do this without conflict. The model is this: There are a set of apis for sending messages from one CM module to another CM. All messages are sent either to existing cluster members or to a node attempting to join the cluster. A message being sent is directed to one or more nodes, and its characteristics are defined (reliable, unreliable, etc). This module is entirely responsible for finding out the best way to get the message to the target node(s). It chooses the transport; it chooses the protocol; it chooses which of the n possible paths to use. No module outside this one cares about such details. On the receiving side, messages must be delivered to the appropriate CM module. For this, each message is tagged with a type. There is one type per independent module of the CM (to a total of a few, say less than 10). Types are statically assigned by values in this header file. When a message of type t arrives in a destination CM process, a function (msgproc) associated with that type t is called. Calls to msgprocs are single-threaded (by the CM caller). After calling a msgproc, this module no longer cares about the details of the message. Messages of one type must be delivered promptly, without interference from messages of different types; this probably requires there to be a thread per message type. The characteristics of the msgproc (whether it can block, take a long time, etc) are not defined; if a msgproc takes too long, then the effect will be that other messages destined for it will be deferred; if it is important to avoid this, msgprocs can pass work off to further threads. /* ------------ */ /* NOTE: only the important semantics of the messaging api are shown below. This module also needs open/close, handles, error returns and so on. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #include #if defined (TDM_DEBUG) #include #endif // TDM_DEBUG /*------------------------- */ /* the set of messages understood by this module */ typedef enum { MM_MSGTYPE = 1, /* for Membership Mgr */ /* others to be added */ } CLMSGTYPE; #define CLMSGMAXBUFFERLENGTH 1024 /* random number; no reason */ /* the biggest buffer which can be sent/received by the CM */ typedef DWORD (*CLMSGPROC) (LPCSTR buffer, DWORD length); void ClProcRegister (CLMSGTYPE msgtype, CLMSGPROC msgproc); /* registers that function should be called whenever an incoming message of type is seen. The type field is always the first DWORD of the incoming buffer. The length passed to is the length received. The worst-case length of all users of this api is known, so there are never cases where the receive-buffer isn't big enough. This must be called by all CM modules in all nodes on CM startup. The msgproc should be called immediately an incoming msg arrives; such msgs should not be delayed by an long blocking events in the thread which delivers these messages. (This may imply that clMsg have a special thread dedicated to handling incoming msgs). Every msgproc will return quickly to its caller. Errors: none possible. */ DWORD ClMsgSendUnack(DWORD targetnode, LPCSTR buffer, DWORD length); /* Sends an unacknowledged packet to a destination up node. This is used mostly for heartbeats. The target node may not be Up at the time. The paths to that node are unknown to MM. (For safety, all paths should be used periodically). The packet should arrive with low latency (bypassing other traffic, if required; going at high priority if possible), and with a high probability of delivery. Although the message can be lost, the contents must be correct. This function should never fail unless zero connectivity exists. This function should return asap; it is preferred that the buffer simply be queued to some driver for later delivery. [It must be the case that, when this routine is used for heartbeats, it is possible to deliver a packet to all other nodes within the established in the MM. This places constraints on this module to work fast, and/or on the minimum polltime value... tbd] It is undefined whether this function should always send all packets on all available paths, cycle through all available paths, or send on some preferred path till a failure occurs, or whether the choice of the above should be user-configurable. [Note that the decision eventually affects the user settings of polltime]. [ is typically short and can be restricted to be so (eg, 256 bytes) is necessary]. Errors: xxx No path to designated node. xxx Success; message was queued for delivery. */ DWORD ClSend (DWORD targetnode, LPCSTR buffer, DWORD length, DWORD timeout); /* This sends the given message to the designated node, eg to download configuration data to it. The message should be reliable. The function should block until the msg is delivered to the target CM. The target node may not be Up at the time. The function must fail if the target node becomes unreachable or is declared down during the operation. The function should fail if the message cannot be delivered to the target CM within ms. Errors: xxx No path to node; node went down. xxx Timeout */ /* ------------------------------------------------------ */ DWORD ClMsgInit (DWORD mynode); /* Input - my node number Errors : WSAsocket errors. */ #if defined (TDM_DEBUG) /* The following templates are for simulation purposes and temporary */ DWORD ClMsgGet (LPCSTR buffer, DWORD maxlen, LPDWORD actuallen); /* Input - pointer to buffer data. buffer length in bytes. pointer to actual buffer length in bytes. Modifies - buffer data actual byte length Errors : WSAsocket errors. */ DWORD ClWriteRead( IN DWORD targetnode, // node to send to IN OUT LPCSTR buffer, // buffer to send and to receive in IN DWORD writelen, // number of bytes to write IN DWORD readlen, // number of bytes to read OUT LPDWORD actuallen, // number of bytes actually read IN DWORD timeout // timeout value in milliseconds ); DWORD ClReadUpdate( IN LPCSTR buffer, // buffer to receive data into IN DWORD readlen, // number of bytes to read OUT LPDWORD actuallen // number of bytes actually read ); DWORD ClReply( IN LPCSTR buffer, // buffer to send IN DWORD writelen // number of bytes to send ); // // This structure is used for request reply messages so that we know // who sent the message. // #define MAX_REQUEST_REPLY_SIZE 256 typedef struct _request_reply_message { DWORD sending_node; DWORD sending_IPaddr; // only used for CLI (sending_node is -1) CHAR message[MAX_REQUEST_REPLY_SIZE]; DWORD messagelen; } REQUEST_REPLY_MESSAGE, *PREQUEST_REPLY_MESSAGE; typedef struct _reply_message_header { DWORD status; cluster_t UpMask; } REPLY_MESSAGE_HEADER, *PREPLY_MESSAGE_HEADER; typedef struct _reply_message { REPLY_MESSAGE_HEADER reply_hdr; DWORD reply_data_len; CHAR reply_data[]; } REPLY_MESSAGE, *PREPLY_MESSAGE; #else //TDM_DEBUG DWORD ClMsgCreateRpcBinding( IN PNM_NODE Node, OUT RPC_BINDING_HANDLE * BindingHandle, IN DWORD RpcBindingOptions ); DWORD ClMsgVerifyRpcBinding( IN RPC_BINDING_HANDLE BindingHandle ); VOID ClMsgDeleteRpcBinding( IN RPC_BINDING_HANDLE BindingHandle ); DWORD ClMsgCreateDefaultRpcBinding( IN PNM_NODE Node, OUT PDWORD Generation ); VOID ClMsgDeleteDefaultRpcBinding( IN PNM_NODE Node, IN DWORD Generation ); DWORD ClMsgCreateActiveNodeSecurityContext( IN DWORD JoinSequence, IN PNM_NODE Node ); DWORD ClMsgInit( IN DWORD MyNode ); VOID ClMsgCleanup( VOID ); VOID ClMsgBanishNode( IN CL_NODE_ID NodeId ); extern RPC_BINDING_HANDLE * Session; #endif //TDM_DEBUG #ifdef __cplusplus } #endif /* __cplusplus */ /* ------------------------ end ------------------------- */ #endif /* _CLMSG_H_ */