Working With GMD


This section discusses how to configure and use GMD with connections. To learn more about working with the basic features of connections, see Working With Connections. The following example programs show the code used to send messages with GMD between two processes through a connection. The programs also show the inner workings of GMD. There are two parts to the example: a server process and a client process.

The source code files for these examples are located in these directories:

UNIX:
$RTHOME/examples/smrtsock/manual 
OpenVMS:
RTHOME:[EXAMPLES.SMRTSOCK.MANUAL] 
Windows:
%RTHOME%\examples\smrtsock\manual 

The online source files have additional #ifdefs to provide C++ support. These #ifdefs are not shown to simplify the example.

Example 30 Common Header Source Code
 
/* conngmd.h -- common header for connections GMD example */ 
 
#include <rtworks/ipc.h> 
 
#define GMD_CONN_NAME "tcp:_node:5252" 
 
void create_conn_cb(); 
Example 31 Common Callback Source Code
 
/* conngmdu.c -- connections GMD example utilities */ 
 
#include "conngmd.h" 
 
/* =============================================================== */ 
/*..cb_conn_msg -- connection msg callback */ 
void T_ENTRY cb_conn_msg( 
                      T_IPC_CONN conn, 
                      T_IPC_CONN_MSG_CB_DATA data, 
                      T_CB_ARG arg) /* really (T_STR) */ 
{ 
  T_IPC_MT mt; 
  T_STR name; 
  T_INT4 seq_num; 
  T_STR info; 
 
  /* This example callback function is not intended to show any */ 
  /* useful processing, only how GMD works. */ 
  TutOut("%s: ", (T_STR)arg); 
 
  /* print out the name of the type of the message */ 
  if (!TipcMsgGetType(data->msg, &mt)) { 
    TutOut("Could not get message type from message: error 
<%s>.\n", 
           TutErrStrGet()); 
    return; 
  } 
  if (!TipcMtGetName(mt, &name)) { 
    TutOut("Could not get name from message type: error <%s>.\n", 
           TutErrStrGet()); 
    return; 
  } 
  TutOut("type %s, ", name); 
  /* print out the sequence number of the message to show how inner */ 
  /* workings of GMD operate */ 
  if (!TipcMsgGetSeqNum(data->msg, &seq_num)) { 
    TutOut("Could not get sequence number from msg: error <%s>.\n", 
           TutErrStrGet()); 
    return; 
  } 
  TutOut("seq_num %d\n", seq_num); 
 
  /* print the first field of the message (INFO or GMD_ACK) */ 
  if (mt == TipcMtLookupByNum(T_MT_INFO)) { 
    if (!TipcMsgSetCurrent(data->msg, 0) 
        || !TipcMsgNextStr(data->msg, &info)) { 
      TutOut("Could not get field from INFO message: error 
<%s>.\n", 
              TutErrStrGet()); 
      return; 
    } 
    TutOut("  INFO field: %s\n", info); 
  } 
  else if (mt == TipcMtLookupByNum(T_MT_GMD_ACK)) { 
    if (!TipcMsgSetCurrent(data->msg, 0) 
        || !TipcMsgNextInt4(data->msg, &seq_num)) { 
      TutOut("Could not get field from GMD_ACK msg: error <%s>.\n", 
              TutErrStrGet()); 
      return; 
    } 
    TutOut("  GMD_ACK field: %d\n", seq_num); 
  } 
 
} /* cb_conn_msg */ 
 
/* =============================================================== */ 
/*..create_conn_cb -- create example callbacks */ 
void T_ENTRY create_conn_cb(conn) 
T_IPC_CONN conn; 
{ 
  /* create callbacks to be executed when certain operations occur */ 
  TutOut("Create callbacks.\n"); 
 
  /* create read callback to show received messages */ 
  if (TipcConnReadCbCreate(conn, NULL, cb_conn_msg, "read") == 
NULL) { 
    TutOut("Could not create read cb: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  /* create write callback to show sent messages */ 
  if (TipcConnWriteCbCreate(conn, NULL, cb_conn_msg, "write") 
      == NULL) { 
    TutOut("Could not create write cb: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  /* create default callback to show processed messages */ 
  if (TipcConnDefaultCbCreate(conn, cb_conn_msg, "default") == 
NULL) { 
    TutOut("Could not create default cb: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
} /* create_conn_cb */ 
Example 32 Server Source Code
 
/* conngmds.c -- connections GMD example server */ 
/* 
This server process waits for a client to connect to it, creates some callbacks to show how GMD 
works, and then loops receiving and processing messages. 
*/ 
#include "conngmd.h" 
 
/* =============================================================== */ 
/*..accept_client -- accept connection from new client */ 
T_IPC_CONN accept_client(server_conn) 
T_IPC_CONN server_conn; 
{ 
  T_IPC_CONN client_conn; /* connection to client */ 
 
  client_conn = TipcConnAccept(server_conn); 
  if (client_conn == NULL) { 
    TutOut("Could not accept client: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  create_conn_cb(client_conn); /* to show inner workings of GMD */ 
  return client_conn; 
} /* accept_client */ 
 
/* =============================================================== */ 
/*..main -- main program */ 
int main() 
{ 
  T_IPC_CONN server_conn; /* used to accept client */ 
  T_IPC_CONN client_conn; /* connection to client */ 
 
  TutOut("Configuring server to use file-based GMD.\n"); 
  TutCommandParseStr("setopt unique_subject conngmds"); 
 
  TutOut("Creating server connection to accept clients on.\n"); 
  server_conn = TipcConnCreateServer(GMD_CONN_NAME); 
  if (server_conn == NULL) { 
    TutOut("Could not create server connection: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  /* accept one client */ 
  TutOut("Waiting for client to connect.\n"); 
  client_conn = accept_client(server_conn); 
 
  /* destroy server conn: it’s not needed anymore */ 
  TutOut("Destroying server connection.\n"); 
  if (!TipcConnDestroy(server_conn)) { 
    TutOut("Could not destroy server connection: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  TutOut("Delete old GMD files.\n"); 
  if (!TipcConnGmdFileDelete(client_conn)) { 
    TutOut("Could not delete old GMD files: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  TutOut("Read and process messages.\n"); 
  if (!TipcConnMainLoop(client_conn, T_TIMEOUT_FOREVER) 
      && TutErrNumGet() != T_ERR_EOF) { 
    TutOut("Could not read and process messages: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  if (!TipcConnDestroy(client_conn)) { 
    TutOut("Could not destroy client connection: error <%s>.\n", 
           TutErrStrGet()); 
  } 
  TutOut("Server process exiting successfully.\n"); 
  return T_EXIT_SUCCESS; /* all done */ 
} /* main */ 
Example 33 Client Source Code
 
/* conngmdc.c -- connections GMD example client */ 
 
/* 
The client process connects to the server process and sends two 
messages with GMD to the server. 
*/ 
 
#include "conngmd.h" 
 
/* =============================================================== */ 
/*..connect_to_server -- create connection to server process */ 
T_IPC_CONN connect_to_server() 
{ 
  T_IPC_CONN conn; /* connection to server */ 
 
  conn = TipcConnCreateClient(GMD_CONN_NAME); 
  if (conn == NULL) { 
    TutOut("Could not create connection to server: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  create_conn_cb(conn); /* to show inner workings of GMD */ 
 
  return conn; 
} /* connect_to_server */ 
 
/* =============================================================== */ 
/*..main -- main program */ 
int main() 
{ 
  T_IPC_CONN conn; /* connection to server */ 
  T_IPC_MT mt; /* message type for messages */ 
  T_IPC_MSG msg; /* message to send */ 
  T_INT4 num_pending; /* number of messages still pending */ 
 
  TutOut("Configuring client to use file-based GMD.\n"); 
  TutCommandParseStr("setopt unique_subject conngmdc"); 
 
  TutOut("Creating connection to server process.\n"); 
  conn = connect_to_server(); 
 
  if (!TipcConnSetTimeout(conn, T_IPC_TIMEOUT_DELIVERY, 1.5)) { 
    TutOut("Could not set conn delivery timeout: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  TutOut("Delete old GMD files.\n"); 
  if (!TipcConnGmdFileDelete(conn)) { 
    TutOut("Could not delete old GMD files: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  TutOut("Create GMD area.\n"); 
  if (!TipcConnGmdFileCreate(conn)) { 
    TutOut("Could not create GMD area: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  TutOut("Constructing and sending an INFO message.\n"); 
  mt = TipcMtLookupByNum(T_MT_INFO); 
  if (mt == NULL) { 
    TutOut("Could not look up INFO message type: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  msg = TipcMsgCreate(mt); 
  if (msg == NULL) { 
    TutOut("Could not create INFO message: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  if (!TipcMsgSetDeliveryMode(msg, T_IPC_DELIVERY_ALL)) { 
    TutOut("Could not set message delivery mode: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  if (!TipcMsgAppendStr(msg, "GMD test #1")) { 
    TutOut("Could not append field to INFO message: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
 
  if (!TipcConnMsgSend(conn, msg)) { 
    TutOut("Could not send INFO message: error <%s>.\n", 
           TutErrStrGet()); 
  } 
 
  if (!TipcMsgDestroy(msg)) { 
    TutOut("Could not destroy message: error <%s>.\n", 
           TutErrStrGet()); 
  } 
 
  /* use convenience functions this time */ 
  TutOut("Send another INFO message with GMD.\n"); 
  if (!TipcConnMsgWrite(conn, mt, 
                        T_IPC_PROP_DELIVERY_MODE, 
                        T_IPC_DELIVERY_ALL, 
                        T_IPC_FT_STR, "GMD test #2", 
                        NULL)) { 
    TutOut("Could not send 2nd INFO message: error <%s>.\n", 
           TutErrStrGet()); 
    TutExit(T_EXIT_FAILURE); 
  } 
  TutOut("Read data until all acknowledgments come in.\n"); 
  do { 
    if (!TipcConnMainLoop(conn, 1.0)) { 
      TutOut("Could not read from conn: error <%s>.\n", 
             TutErrStrGet()); 
      break; 
    } 
    if (!TipcConnGetGmdNumPending(conn, &num_pending)) { 
      TutOut("Could not get pending message count: error <%s>.\n", 
              TutErrStrGet()); 
      break; 
    } 
  } while (num_pending > 0); 
 
  if (!TipcConnDestroy(conn)) { 
    TutOut("Could not destroy connection: error <%s>.\n", 
           TutErrStrGet()); 
  } 
  TutOut("Client process exiting successfully.\n"); 
  return T_EXIT_SUCCESS; /* all done */ 
} /* main */ 

Compiling, Linking, and Running

To compile, link, and run the example programs, first you must either copy the programs to your own directory or have write permission in these directories:

UNIX:
$RTHOME/examples/smrtsock/manual 
OpenVMS:
RTHOME:[EXAMPLES.SMRTSOCK.MANUAL] 
Windows:
%RTHOME%\examples\smrtsock\manual 

Step 1

Compile and link the programs

UNIX:
$ rtlink -o conngmds.x conngmds.c conngmdu.c 
$ rtlink -o conngmdc.x conngmdc.c conngmdu.c 
OpenVMS:
$ cc conngmds.c, conngmdc.c, conngmdu.c 
$ rtlink /exec=conngmds.exe conngmds.obj, conngmdu.obj 
$ rtlink /exec=conngmdc.exe conngmdc.obj, conngmdu.obj 
Windows:
$ nmake /f cngsw32m.mak 
$ nmake /f cngcw32m.mak 

To run the programs, start the server process first in one terminal emulator window and then the client process in another terminal emulator window or in the background (batch).

Step 2

Start the server program in the first window

UNIX:
$ conngmds.x 
OpenVMS:
$ run conngmds.exe 
Windows:
$ conngmds.exe 

Step 3

Start the client program in the second window

UNIX:
$ conngmdc.x 
OpenVMS:
$ run conngmdc.exe 
Windows:
$ conngmdc.exe 

This is a sample of the output from the server program:

Configuring server to use file-based GMD. 
Creating server connection to accept clients on. 
Waiting for client to connect. 
Create callbacks. 
Destroying server connection. 
Delete old GMD files. 
Read and process messages. 
read: type info, seq_num 1 
  INFO field: GMD test #1 
read: type info, seq_num 2 
  INFO field: GMD test #2 
default: type info, seq_num 1 
  INFO field: GMD test #1 
write: type gmd_ack, seq_num 0 
  GMD_ACK field: 1 
default: type info, seq_num 2 
  INFO field: GMD test #2 
write: type gmd_ack, seq_num 0 
  GMD_ACK field: 2 
Server process exiting successfully. 

This a sample of the output from the client program:

Configuring client to use file-based GMD. 
Creating connection to server process. 
Create callbacks. 
Delete old GMD files. 
Create GMD area. 
Constructing and sending an INFO message. 
write: type info, seq_num 0 
  INFO field: GMD test #1 
Send another INFO message with GMD. 
write: type info, seq_num 0 
  INFO field: GMD test #2 
Read data until all acknowledgments come in. 
read: type gmd_ack, seq_num 0 
  GMD_ACK field: 1 
read: type gmd_ack, seq_num 0 
  GMD_ACK field: 2 
Client process exiting successfully. 

TIBCO SmartSockets™ User’s Guide
Software Release 6.8, July 2006
Copyright © TIBCO Software Inc. All rights reserved
www.tibco.com