Message Sender/Receiver
Message Input/Output

This file contains the definition of a GWEN_MSG_ENDPOINT, an object which can send and receive messages (base class).

This file contains the definition of a GWEN_MSG_ENDPOINT, an object which can send and receive messages (base class).

# GWEN_MSG_ENDPOINT

There are a few central structures/objects:

- a socket (or file descriptor for files and/or unix devices)
- list of packets/messages to send (see GWEN_MSG)
- list of packets/messages received

This class was developed around the system call select() which takes 3 sets of sockets to be checked:

- set of sockets to be checked for readability
- set of sockets to be checked for writability
- set of sockets to be checked for "exceptional conditions" (rarely used). Most derived classes will only populate the first two sets.

## Virtual Functions

GWEN_MSG_ENDPOINT has two virtual functions which must be implemented for this class to be usefull:

- GWEN_MSG_ENDPOINT_ADDSOCKETS_FN
- GWEN_MSG_ENDPOINT_CHECKSOCKETS_FN

### GWEN_MSG_ENDPOINT_ADDSOCKETS_FN

This function lets the implementation add sockets to the given socket sets which are then presented to the select() system call. If the given GWEN_MSG_ENDPOINT object is waiting for incoming data it adds its own socket to the read set. if it has data to write it adds its socket to the write set.

### GWEN_MSG_ENDPOINT_CHECKSOCKETS_FN

This function is called after return from the select() system call with the socket sets returned by that function. It lets the implementation check whether its socket(s) has/have become readable or writable and act accordingly (e.g. read data if socket is in the given read set or write if the socket is in the given write set).

## Sending and Receiving Messages

As seen above the main functionality is implemented in the virtual function GWEN_MSG_ENDPOINT_CHECKSOCKETS_FN. To make it easier to use the MSGIO API there is another class called GWEN_MsgIoEndpoint (see GWEN_MsgIoEndpoint_Extend) which simplifies reading and writing messages. It implements GWEN_MSG_ENDPOINT_ADDSOCKETS_FN and GWEN_MSG_ENDPOINT_CHECKSOCKETS_FN. However, it has to know the format of the received messages in order to correctly read them. Therefore that class has another virtual function called GWEN_ENDPOINT_MSGIO_GETBYTESNEEDED_FN. This function is called when data has been read from the endpoints socket to determine how many of those bytes belong to a given message.

### Example Implementation

A first complete example sending an receiving messages is in the GWEN_IpcEndpoint class (see GWEN_IpcEndpoint_CreateIpcTcpClient). This class implements a basic protocol for inter-process-communication. When creating an object of that class the following functions are called:

- GWEN_TcpcEndpoint_new() to instantiate an object using TCP sockets as a client
- GWEN_MsgIoEndpoint_Extend() to add functionality to send/receive messages, implementing virtual functions GWEN_MSG_ENDPOINT_ADDSOCKETS_FN and GWEN_MSG_ENDPOINT_CHECKSOCKETS_FN but adding virtual function GWEN_ENDPOINT_MSGIO_GETBYTESNEEDED_FN
- GWEN_IpcEndpoint_Extend() implementing GWEN_ENDPOINT_MSGIO_GETBYTESNEEDED_FN

### Example Usage Code

`GWEN_MSG_ENDPOINT *epClient; int loop; GWEN_MSG *msg;`

`epClient=GWEN_IpcEndpoint_CreateIpcTcpClient("127.0.0.1", 55555, NULL, 1); msg=GWEN_IpcMsg_new(1, 2, 3, 0, NULL); GWEN_MsgEndpoint_AddSendMessage(epClient, msg);`

`for (loop=0;; loop++) { GWEN_MsgEndpoint_IoLoop(epClient, 2000);`

`while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epClient)) ) { DBG_INFO(GWEN_LOGDOMAIN, " - received msg: protoId=%d, protoVer=%d, code=%d", GWEN_IpcMsg_GetProtoId(msg), GWEN_IpcMsg_GetProtoVersion(msg), GWEN_IpcMsg_GetCode(msg)); GWEN_Msg_free(msg); } } return 0;`

As seen above the application only needs to setup the endpoints according to the type of messages and connections (in this case IPC messages over TCP) and then periodically call a combination of the following functions:

- GWEN_MsgEndpoint_IoLoop() which internally calls the addSockets function, the select() systemcall and the checkSockets function
- GWEN_MsgEndpoint_TakeFirstReceivedMessage() which takes the first received message from the recv msg queue
- GWEN_MsgEndpoint_AddSendMessage() which adds a message to be sent

If the application needs to manage multiple connections at the same time it can take advantage of the TREE2 functions for message endpoints to create a tree of endpoints:

`GWEN_MSG_ENDPOINT *epRoot; GWEN_MSG_ENDPOINT *epClient;`

`epRoot=GWEN_MsgEndpoint_new(NAME, 0); epClient=GWEN_IpcEndpoint_CreateIpcTcpClient("127.0.0.1", 55555, NULL, 1); GWEN_MsgEndpoint_Tree2_AddChild(epRoot, epClient); GWEN_MsgEndpoint_AddSendMessage(epClient, msg);`

`for (loop=0;; loop++) { GWEN_MsgEndpoint_ChildrenIoLoop(epRoot, 2000);`

`while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epClient)) ) { DBG_INFO(GWEN_LOGDOMAIN, " - received msg: protoId=%d, protoVer=%d, code=%d", GWEN_IpcMsg_GetProtoId(msg), GWEN_IpcMsg_GetProtoVersion(msg), GWEN_IpcMsg_GetCode(msg)); GWEN_Msg_free(msg); } } return 0;`

When working with a tree of endpoints (i.e. in this case it rather is a list) the function GWEN_MsgEndpoint_ChildrenIoLoop() needs to be called with the root endpoint as argument instead of GWEN_MsgEndpoint_IoLoop.