Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

nml.cc

Go to the documentation of this file.
00001 /*************************************************************************
00002 * File: nml.cc                                                           *
00003 * Authors: Fred Proctor, Will Shackleford                                *
00004 * Purpose: C++ file for the  Neutral Manufacturing Language (NML).       *
00005 *          Includes:                                                     *
00006 *                    1. Member functions for class NML.                  *
00007 *************************************************************************/
00008 
00009 /* Include Files */
00010 #include "rcs_defs.hh"          /* _Windows, RCS_FAR, EXTERN_C_STD_HEADERS */
00011 
00012 #include "rcsvers.hh"           // rcs_version_printed, print_rcs_version()
00013 
00014 #ifdef _Windows
00015 #if defined(WIN32) && !defined(USE_OLD_WINSOCK)
00016 /* Lame problem if windows.h is included before winsock2.h many redefined
00017  compiler errors result. */
00018 #include <winsock2.h>
00019 #endif
00020 #include <windows.h>            /* GetCurrentTask() */
00021 #ifndef UNDER_CE
00022 #include <direct.h>             // _getcwd()
00023 #endif
00024 #endif
00025 
00026 #ifdef EXTERN_C_STD_HEADERS
00027 extern "C"
00028 {
00029 #endif
00030 
00031 #include <string.h>             /* memcpy() */
00032 #include <stdlib.h>             /* atexit() */
00033 #ifdef VXWORKS
00034 #include <taskLib.h>            /* taskIdSelf() */
00035 #endif
00036 
00037 #if defined(sunos5) || defined(SGI) || defined(linux)
00038 #include <sys/param.h>          // MAXHOSTNAMELEN
00039 #endif
00040 
00041 #ifdef UNDER_CE
00042 #include "rcs_ce.h"
00043 #endif
00044 
00045 
00046 #ifdef EXTERN_C_STD_HEADERS
00047 }
00048 #endif
00049 
00050 #include "nml.hh"               /* class NML */
00051 #include "nmlmsg.hh"            /* class NMLmsg */
00052 #include "cms.hh"               /* class CMS */
00053 #include "timer.hh"             // esleep()
00054 #if !defined(DOS_WINDOWS) || defined(WIN32)
00055 #include "nml_srv.hh"           /* NML_Default_Super_Server */
00056 #endif
00057 #include "cms_cfg.hh"           /* cms_config(), cms_copy() */
00058 #include "linklist.hh"          /* class RCS_LINKED_LIST */
00059 #include "rcs_prnt.hh"          /* rcs_print_error() */
00060 
00061 #ifndef MAXHOSTNAMELEN
00062 #define MAXHOSTNAMELEN 64
00063 #endif
00064 
00065 #include "dbg_mem.h"            /* DEBUG_FREE,DEBUG_MALLOC,DEBUG_CALLOC */
00066 #include "nmldiag.hh"           // NML_DIAGNOSTICS_INFO
00067 
00068 /* Pointer to a global list of NML channels. */
00069 RCS_LINKED_LIST RCS_FAR *NML_Main_Channel_List =
00070   (RCS_LINKED_LIST RCS_FAR *) NULL;
00071 RCS_LINKED_LIST RCS_FAR *Dynamically_Allocated_NML_Objects =
00072   (RCS_LINKED_LIST RCS_FAR *) NULL;
00073 
00074 #if !defined(linux) && !defined(WINDOWS)
00075 int nml_print_hostname_on_error = 1;
00076 #else
00077 int nml_print_hostname_on_error = 0;
00078 #endif
00079 
00080 int verbose_nml_error_messages = 1;
00081 
00082 
00083 char NML_ERROR_TYPE_STRINGS[8][80] = {
00084   "NML_NO_ERROR",
00085   "NML_BUFFER_NOT_READ",
00086   "NML_TIMED_OUT",
00087   "NML_INVALID_CONFIGURATION",
00088   "NML_FORMAT_ERROR",
00089   "NML_INTERNAL_CMS_ERROR",
00090   "NML_NO_MASTER_ERROR",
00091   "NML_INVALID_MESSAGE_ERROR",
00092 };
00093 
00094 static char *default_nml_config_file = NULL;
00095 int nml_reset_errors_printed = 1;
00096 
00097 void RCS_EXPORT
00098 set_default_nml_config_file (const char RCS_FAR * cfg_file)
00099 {
00100   if (cfg_file == NULL)
00101     {
00102       default_nml_config_file = NULL;
00103     }
00104   default_nml_config_file = (char *) DEBUG_MALLOC (strlen (cfg_file) + 1);
00105   strcpy (default_nml_config_file, cfg_file);
00106 }
00107 
00108 const char *
00109 get_default_nml_config_file ()
00110 {
00111   return default_nml_config_file;
00112 }
00113 
00114 /*
00115 * NML Member Functions
00116 */
00117 
00118 /* Special new operator to allow the nml_cleanup function to
00119 distinguish between dynamically and statically allocated NML
00120 objects. */
00121 void *
00122 NML::operator new (size_t size)
00123 {
00124   if (size < sizeof (NML))
00125     {
00126       rcs_print_error
00127         ("void *NML::operator new() called with size (%d) < sizeof(NML) (%d) the code calling NML was probably not compiled with the correct header file version.\n",
00128          size, sizeof (NML));
00129       size = sizeof (NML);
00130     }
00131   void *nml_space = NULL;
00132   char *cptr = (char *) NULL;
00133   int dynamic_list_id = 0;
00134   nml_space = DEBUG_MALLOC (size + sizeof (int) * 2);
00135   if (NULL != nml_space)
00136     {
00137       memset (nml_space, 0, size);
00138     }
00139   if (NULL == Dynamically_Allocated_NML_Objects)
00140     {
00141       Dynamically_Allocated_NML_Objects = new RCS_LINKED_LIST ();
00142     }
00143   if (NULL != Dynamically_Allocated_NML_Objects)
00144     {
00145       dynamic_list_id =
00146         Dynamically_Allocated_NML_Objects->store_at_tail (nml_space,
00147                                                           sizeof (NML), 0);
00148       cptr = ((char *) nml_space) + sizeof (NML);
00149       // guarantee alignment
00150       cptr += sizeof (int) - (((int) cptr) % sizeof (int));
00151       *((int *) cptr) = dynamic_list_id;
00152     }
00153   rcs_print_debug (PRINT_NML_CONSTRUCTORS, "%X = NML::operater new(%d)\n",
00154                    nml_space, size);
00155   return nml_space;
00156 }
00157 
00158 void
00159 NML::operator delete (void *nml_space)
00160 {
00161   int dynamic_list_id = 0;
00162   char *cptr = (char *) NULL;
00163 
00164   rcs_print_debug (PRINT_NML_DESTRUCTORS, "NML::operater delete(%X)\n",
00165                    nml_space);
00166 
00167   if (NULL == nml_space)
00168     {
00169       return;
00170     }
00171 
00172   if (NULL != Dynamically_Allocated_NML_Objects)
00173     {
00174       cptr = ((char *) nml_space) + sizeof (NML);
00175       cptr += sizeof (int) - (((int) cptr) % sizeof (int));
00176       dynamic_list_id = *((int *) cptr);
00177       Dynamically_Allocated_NML_Objects->delete_node (dynamic_list_id);
00178       if (Dynamically_Allocated_NML_Objects->list_size == 0)
00179         {
00180           delete Dynamically_Allocated_NML_Objects;
00181           Dynamically_Allocated_NML_Objects = (RCS_LINKED_LIST *) NULL;
00182         }
00183     }
00184   DEBUG_FREE (nml_space);
00185 }
00186 
00187 
00188 /******************************************************************
00189 * Constructor for NML:
00190 * Parameters:
00191 * NML_FORMAT_PTR f_ptr - address of the function to be used to format messages.
00192 * char *buf - Name of the buffer to connect to as written in the config file.
00193 * char *proc - Name of the calling process as expected in the config file.
00194 * char *file - Name of the configuration file.
00195 * int set_to_server - If 1 this NML will consider its calling process to
00196 *   be an NML_SERVER, which effects how and when messages are encoded and
00197 *   decoded.
00198 * int set_to_master - Passed to the CMS constructor - how this is used
00199 *   depends on the type of CMS buffer. In general the master is responsible
00200 *   for creating/initializing the buffer. If set_to_master == 1 then this
00201 *   process will be considered the master, if set_to_master == 0 then
00202 *   the the configuration file determines if this is the master, and it
00203 *   set_to_master == -1 then this will not be the master.
00204 * NOTES:
00205 *  1. Borland C++(for DOS and Windows) does not allow default
00206 *   parameters to be specified both here and in the header file.
00207 *  2. All pointers are first initialized to NULL so that it can be determined
00208 *  later if the constructor returned before creating the objects
00209 *  the pointers are intended to point at.
00210 ******************************************************************/
00211 NML::NML (NML_FORMAT_PTR f_ptr,
00212           char *buf, char *proc,
00213           char *file, int set_to_server, int set_to_master)
00214 {
00215   cms_for_msg_string_conversions = 0;
00216   info_printed = 0;
00217   blocking_read_poll_interval = -1.0;
00218   forced_type = 0;
00219   strncpy (bufname, buf, 40);
00220   strncpy (procname, proc, 40);
00221   if (NULL == file)
00222     {
00223       file = default_nml_config_file;
00224     }
00225   strncpy (cfgfilename, file, 160);
00226 
00227   if (rcs_errors_printed >= max_rcs_errors_to_print
00228       && max_rcs_errors_to_print > 0 && nml_reset_errors_printed)
00229     {
00230       rcs_errors_printed = 0;
00231       rcs_print
00232         ("\nResetting rcs_errors_printed because a new NML channel is being created.\n");
00233     }
00234 
00235 
00236   already_deleted = 0;
00237   channel_type = NML_GENERIC_CHANNEL_TYPE;
00238   sizeof_message_header = sizeof (NMLmsg);
00239 
00240   reconstruct (f_ptr, buf, proc, file, set_to_server, set_to_master);
00241 
00242   if (NULL != cms)
00243     {
00244       cms->sizeof_message_header = sizeof_message_header;
00245       char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00246       if (forced_type_eq != NULL)
00247         {
00248 #ifndef UNDER_CE
00249           long temp = strtol (forced_type_eq + 11, NULL, 0);
00250 #else
00251           long temp = atol (forced_type_eq + 11);
00252 #endif
00253           if (temp > 0)
00254             {
00255               forced_type = temp;
00256               fast_mode = 0;
00257             }
00258         }
00259     }
00260 }
00261 
00262 int RCS_EXPORT
00263 create_NML (NML ** nml, NML_FORMAT_PTR f_ptr,
00264             char *buf, char *proc, char *file)
00265 {
00266   *nml = new NML (f_ptr, buf, proc, file);
00267   if (NULL == nml)
00268     {
00269       return -1;
00270     }
00271   if (!(*nml)->valid ())
00272     {
00273       return -1;
00274     }
00275   if (NULL != (*nml)->cms)
00276     {
00277       (*nml)->cms->sizeof_message_header = (*nml)->sizeof_message_header;
00278       char *forced_type_eq =
00279         strstr ((*nml)->cms->buflineupper, "FORCE_TYPE=");
00280       if (forced_type_eq != NULL)
00281         {
00282 #ifndef UNDER_CE
00283           long temp = strtol (forced_type_eq + 11, NULL, 0);
00284 #else
00285           long temp = atol (forced_type_eq + 11);
00286 #endif
00287           if (temp > 0)
00288             {
00289 
00290               (*nml)->forced_type = temp;
00291             }
00292         }
00293     }
00294   return 0;
00295 }
00296 
00297 RCS_EXPORT void
00298 free_NML (NML * nml)
00299 {
00300   if (NULL != nml)
00301     {
00302       delete nml;
00303     }
00304 }
00305 
00306 int
00307 NML::login (const char *name, const char *passwd)
00308 {
00309   if (NULL == cms)
00310     {
00311       return 1;
00312     }
00313   return cms->login (name, passwd);
00314 }
00315 
00316 
00317 void
00318 NML::reconstruct (NML_FORMAT_PTR f_ptr, char *buf, char *proc,
00319                   char *file, int set_to_server, int set_to_master)
00320 {
00321 
00322   cms = (CMS *) NULL;
00323   format_chain = (RCS_LINKED_LIST *) NULL;
00324   phantom_read = (NMLTYPE (*)())NULL;
00325   phantom_peek = (NMLTYPE (*)())NULL;
00326   phantom_write = (int (*)(NMLmsg *)) NULL;
00327   phantom_write_if_read = (int (*)(NMLmsg *)) NULL;
00328   phantom_check_if_read = (int (*)()) NULL;
00329   phantom_clear = (int (*)()) NULL;
00330   channel_list_id = 0;
00331   error_type = NML_NO_ERROR;
00332   fast_mode = 0;
00333   ignore_format_chain = 0;
00334   info_printed = 0;
00335 
00336 
00337   format_chain = new RCS_LINKED_LIST;
00338   if (NULL != format_chain)
00339     {
00340       prefix_format_chain (f_ptr);
00341     }
00342 
00343   if (NULL == f_ptr)
00344     {
00345       rcs_print_error ("NML:(Format Function Pointer) f_ptr == NULL.\n");
00346     }
00347 
00348   if (-1 == cms_config (&cms, buf, proc, file, set_to_server, set_to_master))
00349     {
00350       set_error ();
00351       if (!info_printed)
00352         {
00353           print_info (buf, proc, file);
00354         }
00355       if (NULL != cms)
00356         {
00357           rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n",
00358                            cms);
00359           delete cms;
00360           cms = (CMS *) NULL;
00361         }
00362       return;
00363     }
00364 
00365   if (NULL == cms)
00366     {
00367       if (!info_printed)
00368         {
00369           print_info (buf, proc, file);
00370         }
00371       error_type = NML_INVALID_CONFIGURATION;
00372       return;
00373     }
00374 
00375   if (cms->status < 0)
00376     {
00377       error_type = NML_INVALID_CONFIGURATION;
00378       if (!info_printed)
00379         {
00380           print_info (buf, proc, file);
00381         }
00382       rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n", cms);
00383       delete cms;
00384       cms = (CMS *) NULL;
00385       return;
00386     }
00387 
00388 #if  !defined(__MSDOS__) || defined(WIN32)
00389   if (!set_to_server)
00390     {
00391       register_with_server ();
00392     }
00393 #endif
00394   add_to_channel_list ();
00395   // FAST MODE is a combination of options which allow certian checks during
00396   // a read or write operation to be avoided and therefore reduce the NML/CMS
00397   // overhead.
00398   if (!cms->is_phantom &&
00399       cms->ProcessType == CMS_LOCAL_TYPE &&
00400       !cms->neutral && !cms->isserver && !cms->enable_diagnostics)
00401     {
00402       fast_mode = 1;
00403     }
00404 
00405   cms_status = (int *) &(cms->status);
00406   cms_inbuffer_header_size = &(cms->header.in_buffer_size);
00407   char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00408   if (forced_type_eq != NULL)
00409     {
00410 #ifndef UNDER_CE
00411       long temp = strtol (forced_type_eq + 11, NULL, 0);
00412 #else
00413       long temp = atol (forced_type_eq + 11);
00414 #endif
00415       if (temp > 0)
00416         {
00417           forced_type = temp;
00418           fast_mode = 0;
00419         }
00420     }
00421   char *brpi_eq = strstr (cms->buflineupper, "BRPI=");
00422   if (brpi_eq != NULL)
00423     {
00424 #ifndef UNDER_CE
00425       blocking_read_poll_interval = strtod (brpi_eq + 5, NULL);
00426 #else
00427       blocking_read_poll_interval = RCS_CE_ATOF (brpi_eq + 5);
00428 #endif
00429     }
00430 
00431 }
00432 
00433 /******************************************************************
00434 * Constructor for NML:
00435 * Parameters:
00436 * char *buf - Name of the buffer to connect to as written in the config file.
00437 * char *proc - Name of the calling process as expected in the config file.
00438 * char *file - Name of the configuration file.
00439 * int set_to_server - If 1 this NML will consider its calling process to
00440 *   be an NML_SERVER, which effects how and when messages are encoded and
00441 *   decoded.
00442 * int set_to_master - Passed to the CMS constructor - how this is used
00443 *   depends on the type of CMS buffer. In general the master is responsible
00444 *   for creating/initializing the buffer. If set_to_master == 1 then this
00445 *   process will be considered the master, if set_to_master == 0 then
00446 *   the the configuration file determines if this is the master, and it
00447 *   set_to_master == -1 then this will not be the master.
00448 * NOTES:
00449 *  1. Borland C++(for DOS and Windows) does not allow default
00450 *   parameters to be specified both here and in the header file.
00451 *  2. All pointers are first initialized to NULL so that it can be determined
00452 *  later if the constructor returned before creating the objects
00453 *  the pointers are intended to point at.
00454 *  3. This constructor does not register itself with the default server.
00455 *  4. The NML object created by this constructor can not be used until
00456 * the format_chain is constructed. (This may be done by
00457 * derived classes. )
00458 ******************************************************************/
00459 NML::NML (char *buf, char *proc, char *file,
00460           int set_to_server, int set_to_master)
00461 {
00462   if (NULL == file)
00463     {
00464       file = default_nml_config_file;
00465     }
00466   cms_for_msg_string_conversions = 0;
00467   strncpy (bufname, buf, 40);
00468   strncpy (procname, proc, 40);
00469   strncpy (cfgfilename, file, 160);
00470   blocking_read_poll_interval = -1.0;
00471   info_printed = 0;
00472   forced_type = 0;
00473   already_deleted = 0;
00474   cms = (CMS *) NULL;
00475   format_chain = (RCS_LINKED_LIST *) NULL;
00476   phantom_read = (NMLTYPE (*)())NULL;
00477   phantom_peek = (NMLTYPE (*)())NULL;
00478   phantom_write = (int (*)(NMLmsg *)) NULL;
00479   phantom_write_if_read = (int (*)(NMLmsg *)) NULL;
00480   phantom_check_if_read = (int (*)()) NULL;
00481   phantom_clear = (int (*)()) NULL;
00482   channel_list_id = 0;
00483   error_type = NML_NO_ERROR;
00484   ignore_format_chain = 0;
00485   fast_mode = 0;
00486 
00487   channel_type = NML_GENERIC_CHANNEL_TYPE;
00488   sizeof_message_header = sizeof (NMLmsg);
00489 
00490   if (-1 == cms_config (&cms, buf, proc, file, set_to_server, set_to_master))
00491     {
00492       if (verbose_nml_error_messages)
00493         {
00494           rcs_print_error ("NML: cms_config returned -1.\n");
00495         }
00496       if (!info_printed)
00497         {
00498           print_info (buf, proc, file);
00499         }
00500       if (NULL != cms)
00501         {
00502           rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n",
00503                            cms);
00504           delete cms;
00505           cms = (CMS *) NULL;
00506         }
00507       error_type = NML_INVALID_CONFIGURATION;
00508       return;
00509     }
00510 
00511   if (NULL == cms)
00512     {
00513       error_type = NML_INVALID_CONFIGURATION;
00514       if (!info_printed)
00515         {
00516           print_info (buf, proc, file);
00517         }
00518       return;
00519     }
00520 
00521   if (cms->status < 0)
00522     {
00523       error_type = NML_INVALID_CONFIGURATION;
00524       if (!info_printed)
00525         {
00526           print_info (buf, proc, file);
00527         }
00528       rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n", cms);
00529       delete cms;
00530       cms = (CMS *) NULL;
00531       return;
00532     }
00533 
00534   add_to_channel_list ();
00535   if (!cms->is_phantom &&
00536       cms->ProcessType == CMS_LOCAL_TYPE && !cms->neutral && !cms->isserver)
00537     {
00538       fast_mode = 1;
00539     }
00540   cms_status = (int *) &(cms->status);
00541   cms_inbuffer_header_size = &(cms->header.in_buffer_size);
00542 
00543   if (NULL != cms)
00544     {
00545       cms->sizeof_message_header = sizeof_message_header;
00546       char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00547       if (forced_type_eq != NULL)
00548         {
00549 #ifndef UNDER_CE
00550           long temp = strtol (forced_type_eq + 11, NULL, 0);
00551 #else
00552           long temp = atol (forced_type_eq + 11);
00553 #endif
00554           if (temp > 0)
00555             {
00556               forced_type = temp;
00557               fast_mode = 0;
00558             }
00559         }
00560       char *brpi_eq = strstr (cms->buflineupper, "BRPI=");
00561       if (brpi_eq != NULL)
00562         {
00563 #ifndef UNDER_CE
00564           blocking_read_poll_interval = strtod (brpi_eq + 5, NULL);
00565 #else
00566           blocking_read_poll_interval = RCS_CE_ATOF (brpi_eq + 5);
00567 #endif
00568         }
00569     }
00570 
00571 }
00572 
00573 /******************************************************************
00574 * Constructor for NML:
00575 * Parameters:
00576 * char *buffer_line - Buffer line  as written in the config file.
00577 * char *proc_line - Process Line as expected in the config file.
00578 * char *file - Name of the configuration file.
00579 * int set_to_server - If 1 this NML will consider its calling process to
00580 *   be an NML_SERVER, which effects how and when messages are encoded and
00581 *   decoded.
00582 * int set_to_master - Passed to the CMS constructor - how this is used
00583 *   depends on the type of CMS buffer. In general the master is responsible
00584 *   for creating/initializing the buffer. If set_to_master == 1 then this
00585 *   process will be considered the master, if set_to_master == 0 then
00586 *   the the configuration file determines if this is the master, and it
00587 *   set_to_master == -1 then this will not be the master.
00588 * NOTES:
00589 *  1. Borland C++(for DOS and Windows) does not allow default
00590 *   parameters to be specified both here and in the header file.
00591 *  2. All pointers are first initialized to NULL so that it can be determined
00592 *  later if the constructor returned before creating the objects
00593 *  the pointers are intended to point at.
00594 *  3. This constructor does not register itself with the default server.
00595 *  4. The NML object created by this constructor can not be used until
00596 * the format_chain is constructed. (This may be done by
00597 * derived classes. )
00598 ******************************************************************/
00599 NML::NML (char *buffer_line, char *proc_line)
00600 {
00601   cms_for_msg_string_conversions = 0;
00602   cms = (CMS *) NULL;
00603   blocking_read_poll_interval = -1.0;
00604   forced_type = 0;
00605   info_printed = 0;
00606   already_deleted = 0;
00607   format_chain = (RCS_LINKED_LIST *) NULL;
00608   phantom_read = (NMLTYPE (*)())NULL;
00609   phantom_peek = (NMLTYPE (*)())NULL;
00610   phantom_write = (int (*)(NMLmsg *)) NULL;
00611   phantom_write_if_read = (int (*)(NMLmsg *)) NULL;
00612   phantom_check_if_read = (int (*)()) NULL;
00613   phantom_clear = (int (*)()) NULL;
00614   channel_list_id = 0;
00615   error_type = NML_NO_ERROR;
00616   ignore_format_chain = 0;
00617   fast_mode = 0;
00618 
00619   channel_type = NML_GENERIC_CHANNEL_TYPE;
00620   sizeof_message_header = sizeof (NMLmsg);
00621 
00622   if (-1 == cms_create_from_lines (&cms, buffer_line, proc_line))
00623     {
00624       if (verbose_nml_error_messages)
00625         {
00626           rcs_print_error ("NML: cms_create_from_lines returned -1.\n");
00627         }
00628       if (!info_printed)
00629         {
00630           print_info ();
00631         }
00632       if (NULL != cms)
00633         {
00634           rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n",
00635                            cms);
00636           delete cms;
00637           cms = (CMS *) NULL;
00638         }
00639       error_type = NML_INVALID_CONFIGURATION;
00640       return;
00641     }
00642   if (NULL == cms)
00643     {
00644       error_type = NML_INVALID_CONFIGURATION;
00645       return;
00646     }
00647   if (cms->status < 0)
00648     {
00649       error_type = NML_INVALID_CONFIGURATION;
00650       if (verbose_nml_error_messages)
00651         {
00652           rcs_print_error ("NML: cms->status = %d.\n", cms->status);
00653         }
00654       if (!info_printed)
00655         {
00656           print_info ();
00657         }
00658       rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n", cms);
00659       delete cms;
00660       cms = (CMS *) NULL;
00661       return;
00662     }
00663   add_to_channel_list ();
00664   if (!cms->is_phantom &&
00665       cms->ProcessType == CMS_LOCAL_TYPE && !cms->neutral && !cms->isserver)
00666     {
00667       fast_mode = 1;
00668     }
00669   cms_status = (int *) &(cms->status);
00670   cms_inbuffer_header_size = &(cms->header.in_buffer_size);
00671   if (NULL != cms)
00672     {
00673       cms->sizeof_message_header = sizeof_message_header;
00674       char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00675       if (forced_type_eq != NULL)
00676         {
00677 #ifndef UNDER_CE
00678           long temp = strtol (forced_type_eq + 11, NULL, 0);
00679 #else
00680           long temp = atol (forced_type_eq + 11);
00681 #endif
00682           if (temp > 0)
00683             {
00684               forced_type = temp;
00685               fast_mode = 0;
00686             }
00687         }
00688       char *brpi_eq = strstr (cms->buflineupper, "BRPI=");
00689       if (brpi_eq != NULL)
00690         {
00691 #ifndef UNDER_CE
00692           blocking_read_poll_interval = strtod (brpi_eq + 5, NULL);
00693 #else
00694           blocking_read_poll_interval = RCS_CE_ATOF (brpi_eq + 5);
00695 #endif
00696         }
00697     }
00698 
00699 }
00700 
00701 /***************************************************************
00702 * NML Member Function: add_to_channel_list()
00703 * Purpose:
00704 *  Adds a pointer to this NML object to the main NML list.
00705 * The list is used by nml_cleanup to delete all NML objects owned by
00706 * a process.
00707 * Under VxWorks the list must be shared by all processes so we must
00708 * remember which process (also known as a task) added it to the list.
00709 * (This is a great reason for tossing VxWorks in the circular file!)
00710 *****************************************************************/
00711 void
00712 NML::add_to_channel_list ()
00713 {
00714 #ifdef VXWORKS
00715   pid = taskIdSelf ();
00716 #endif
00717 #ifdef _Windows
00718 #ifdef __WIN32__
00719   task_handle = (void RCS_FAR *) GetCurrentThread ();
00720 #else
00721   task_handle = GetCurrentTask ();
00722 #endif
00723 #endif
00724   if (NULL == NML_Main_Channel_List)
00725     {
00726       NML_Main_Channel_List = new RCS_LINKED_LIST;
00727     }
00728   if (NULL != NML_Main_Channel_List)
00729     {
00730       channel_list_id =
00731         NML_Main_Channel_List->store_at_tail (this, sizeof (NML), 0);
00732     }
00733 }
00734 
00735 /********************************************************************
00736 * NML Member Function: register_with_server()
00737 * Purpose:
00738 *  The NML_Default_Super_Server keeps a list of all of the NML objects
00739 * that were specified as servers in the config file.
00740 * When nml_start is called servers will be spawned for these buffers.
00741 * The NML_Default_Super_Server also tries to reduce the number of processes
00742 * spawned by grouping buffers with the same buffer number.
00743 ********************************************************************/
00744 void
00745 NML::register_with_server ()
00746 {
00747 #if !defined(__MSDOS__) || defined(WIN32)
00748   if (NULL != cms)
00749     {
00750       if (cms->spawn_server)
00751         {
00752           if (NULL == NML_Default_Super_Server)
00753             {
00754               NML_Default_Super_Server = new NML_SUPER_SERVER;
00755             }
00756           NML_Default_Super_Server->add_to_list (this);
00757         }
00758     }
00759 #endif
00760 }
00761 
00762 /**************************************************************
00763 * NML Constructor:
00764 * Parameters:
00765 * NML *nml; - pointer to NML object to duplicate.
00766 * int set_to_server - If 1 this NML will consider its calling process to
00767 *   be an NML_SERVER, which effects how and when messages are encoded and
00768 *   decoded.
00769 * int set_to_master - Passed to the CMS constructor - how this is used
00770 *   depends on the type of CMS buffer. In general the master is responsible
00771 *   for creating/initializing the buffer. If set_to_master == 1 then this
00772 *   process will be considered the master, if set_to_master == 0 then
00773 *   the the configuration file determines if this is the master, and it
00774 *   set_to_master == -1 then this will not be the master.
00775 * NOTES:
00776 *  1. Borland C++(for DOS and Windows) does not allow default
00777 *   parameters to be specified both here and in the header file.
00778 *  2. All pointers are first initialized to NULL so that it can be determined
00779 *  later if the constructor returned before creating the objects
00780 *  the pointers are intended to point at.
00781 *************************************************************/
00782 NML::NML (NML * nml_ptr, int set_to_server, int set_to_master)
00783 {
00784   cms_for_msg_string_conversions = 0;
00785   already_deleted = 0;
00786   forced_type = 0;
00787   cms = (CMS *) NULL;
00788   format_chain = (RCS_LINKED_LIST *) NULL;
00789   error_type = NML_NO_ERROR;
00790   ignore_format_chain = 0;
00791   channel_list_id = 0;
00792   fast_mode = 0;
00793   info_printed = 0;
00794   blocking_read_poll_interval = -1.0;
00795 
00796 
00797   channel_type = NML_GENERIC_CHANNEL_TYPE;
00798   sizeof_message_header = sizeof (NMLmsg);
00799 
00800 
00801   if (NULL != nml_ptr)
00802     {
00803       strncpy (bufname, nml_ptr->bufname, 40);
00804       strncpy (procname, nml_ptr->procname, 40);
00805       strncpy (cfgfilename, nml_ptr->cfgfilename, 160);
00806       if (NULL != nml_ptr->cms)
00807         {
00808           // Create a CMS channel identitical to the one from the argument
00809           // NML channel accept that the channel may be set_to_server or
00810           // set_to_master differently.
00811           cms_copy (&cms, nml_ptr->cms, set_to_server, set_to_master);
00812           if (NULL != cms)
00813             {
00814               cms->current_subdivision = nml_ptr->cms->current_subdivision;
00815             }
00816         }
00817     }
00818   if (!ignore_format_chain)
00819     {
00820       format_chain = new RCS_LINKED_LIST;
00821       if ((NULL != nml_ptr->format_chain) && (NULL != format_chain))
00822         {
00823           RCS_LINKED_LIST *from, *to;
00824           NML_FORMAT_PTR format_func_ptr;
00825           from = nml_ptr->format_chain;
00826           to = format_chain;
00827           format_func_ptr = (NML_FORMAT_PTR) from->get_head ();
00828           while (NULL != format_func_ptr)
00829             {
00830               to->store_at_tail ((void *) format_func_ptr, 0, 0);
00831               format_func_ptr = (NML_FORMAT_PTR) from->get_next ();
00832             }
00833         }
00834     }
00835   if (NULL == cms)
00836     {
00837       return;
00838     }
00839   add_to_channel_list ();
00840   if (!cms->is_phantom &&
00841       cms->ProcessType == CMS_LOCAL_TYPE && !cms->neutral && !cms->isserver)
00842     {
00843       fast_mode = 1;
00844     }
00845   cms_status = (int *) &(cms->status);
00846   cms_inbuffer_header_size = &(cms->header.in_buffer_size);
00847   char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00848   if (forced_type_eq != NULL)
00849     {
00850 #ifndef UNDER_CE
00851       long temp = strtol (forced_type_eq + 11, NULL, 0);
00852 #else
00853       long temp = atol (forced_type_eq + 11);
00854 #endif
00855       if (temp > 0)
00856         {
00857           forced_type = temp;
00858           fast_mode = 0;
00859         }
00860     }
00861   char *brpi_eq = strstr (cms->buflineupper, "BRPI=");
00862   if (brpi_eq != NULL)
00863     {
00864 #ifndef UNDER_CE
00865       blocking_read_poll_interval = strtod (brpi_eq + 5, NULL);
00866 #else
00867       blocking_read_poll_interval = RCS_CE_ATOF (brpi_eq + 5);
00868 #endif
00869     }
00870   if (NULL != nml_ptr->cms->dpi)
00871     {
00872       CMS_DIAG_PROC_INFO *dpi = cms->get_diag_proc_info ();
00873       *dpi = *(nml_ptr->cms->get_diag_proc_info ());
00874       cms->set_diag_proc_info (dpi);
00875     }
00876   cms->first_diag_store = nml_ptr->cms->first_diag_store;
00877   if (NULL != cms->handle_to_global_data &&
00878       NULL != nml_ptr->cms->handle_to_global_data)
00879     {
00880       cms->handle_to_global_data->total_bytes_moved =
00881         nml_ptr->cms->handle_to_global_data->total_bytes_moved;
00882     }
00883 }
00884 
00885 /**************************************************************
00886 * NML Reset Function
00887 * Can be used instead of deleting and recreating an NML channel.
00888 *************************************************************/
00889 int
00890 NML::reset ()
00891 {
00892   int cms_copy_ret = 0;
00893   if (valid ())
00894     {
00895       return 1;
00896     }
00897   if (NULL != cms)
00898     {
00899       // Recreate a CMS channel identitical to the old one, do not
00900       // re-read the config file.
00901       CMS *oldcms = cms;
00902       cms = NULL;
00903       cms_copy_ret = cms_copy (&cms, oldcms, 0, 0);
00904       if (cms_copy_ret < 0)
00905         {
00906           if (cms != NULL && cms != oldcms)
00907             {
00908               delete oldcms;
00909             }
00910           return 0;
00911         }
00912 
00913 #if  !defined(__MSDOS__) || defined(WIN32)
00914       register_with_server ();
00915 #endif
00916       add_to_channel_list ();
00917       // FAST MODE is a combination of options which allow certian checks during
00918       // a read or write operation to be avoided and therefore reduce the NML/CMS
00919       // overhead.
00920       if (!cms->is_phantom &&
00921           cms->ProcessType == CMS_LOCAL_TYPE &&
00922           !cms->neutral && !cms->isserver && !cms->enable_diagnostics)
00923         {
00924           fast_mode = 1;
00925         }
00926 
00927       cms_status = (int *) &(cms->status);
00928       cms_inbuffer_header_size = &(cms->header.in_buffer_size);
00929       char *forced_type_eq = strstr (cms->buflineupper, "FORCE_TYPE=");
00930       if (forced_type_eq != NULL)
00931         {
00932 #ifndef UNDER_CE
00933           long temp = strtol (forced_type_eq + 11, NULL, 0);
00934 #else
00935           long temp = atol (forced_type_eq + 11);
00936 #endif
00937           if (temp > 0)
00938             {
00939               forced_type = temp;
00940               fast_mode = 0;
00941             }
00942         }
00943       char *brpi_eq = strstr (cms->buflineupper, "BRPI=");
00944       if (brpi_eq != NULL)
00945         {
00946 #ifndef UNDER_CE
00947           blocking_read_poll_interval = strtod (brpi_eq + 5, NULL);
00948 #else
00949           blocking_read_poll_interval = RCS_CE_ATOF (brpi_eq + 5);
00950 #endif
00951         }
00952 
00953       delete oldcms;
00954     }
00955   else
00956     {
00957       // Re-read the config file before creating a new CMS object.
00958       if (cms_config (&cms, bufname, procname, cfgfilename, 0, 0) < 0)
00959         {
00960           return 0;
00961         }
00962     }
00963   return valid ();
00964 }
00965 
00966 
00967 /*********************************************************
00968 * NML Destructor:
00969 * Notes:
00970 *  1. Use if(NULL != ???) to avoid deleting objects that were
00971 * never constructed.
00972 *  2. The delete channel function was added because an error occured in
00973 * running a server unded WIN32. An exception would occur as
00974 * the last NML channel was being deleted from within nml_cleanup.
00975 * After two days of being unable to debug this problem I
00976 * replaced the delete nml with nml->delete_channel() as a workaround.
00977 * The cause of this exception is still not understood.
00978 *********************************************************/
00979 NML::~NML ()
00980 {
00981   if (already_deleted)
00982     {
00983       if (verbose_nml_error_messages)
00984         {
00985           rcs_print_error ("NML channel being deleted more than once.\n");
00986         }
00987     }
00988   already_deleted = 1;
00989   delete_channel ();
00990 }
00991 
00992 void
00993 NML::delete_channel ()
00994 {
00995   rcs_print_debug (PRINT_NML_DESTRUCTORS, "deleting NML (%d)\n",
00996                    channel_list_id);
00997   if (NULL != cms_for_msg_string_conversions
00998       && cms != cms_for_msg_string_conversions)
00999     {
01000       delete cms_for_msg_string_conversions;
01001       cms_for_msg_string_conversions = 0;
01002     }
01003   if (NULL != cms)
01004     {
01005       rcs_print_debug (PRINT_NML_DESTRUCTORS, " delete (CMS *) %X;\n", cms);
01006       delete cms;
01007       cms = (CMS *) NULL;
01008     }
01009   if (NULL != format_chain)
01010     {
01011       delete format_chain;
01012       format_chain = (RCS_LINKED_LIST *) NULL;
01013     }
01014   if (NULL != NML_Main_Channel_List && (0 != channel_list_id))
01015     {
01016       NML_Main_Channel_List->delete_node (channel_list_id);
01017     }
01018   rcs_print_debug (PRINT_NML_DESTRUCTORS, "Leaving ~NML()\n");
01019 }
01020 
01021 /*************************************************************
01022 * NML Member Function: get_address()
01023 * Purpose:
01024 *  Returns the address of the local copy of the buffer.
01025 *  Use this function instead of nml->cms->subdiv_data directly to prevent
01026 *   users from pointing nml->cms->subdiv_data at something else. Or getting
01027 *   a segmentation fault if cms was not properly constructed.
01028 ***************************************************************/
01029 NMLmsg *
01030 NML::get_address ()
01031 {
01032   if (NULL == cms)
01033     {
01034       if (NULL != cms_for_msg_string_conversions)
01035         {
01036           return ((NMLmsg *) cms_for_msg_string_conversions->subdiv_data);
01037         }
01038       error_type = NML_INVALID_CONFIGURATION;
01039       return ((NMLmsg *) NULL);
01040     }
01041   else
01042     {
01043       return ((NMLmsg *) cms->subdiv_data);
01044     }
01045 }
01046 
01047 /*************************************************************
01048 * NML Member Function: get_address_subdivision(int subdiv)
01049 * Purpose:
01050 *  Returns the address of the local copy of the buffer.
01051 *  Use this function instead of nml->cms->subdiv_data directly to prevent
01052 *   users from pointing nml->cms->subdiv_data at something else. Or getting
01053 *   a segmentation fault if cms was not properly constructed.
01054 ***************************************************************/
01055 NMLmsg *
01056 NML::get_address_subdivision (int subdiv)
01057 {
01058   if (NULL == cms)
01059     {
01060       error_type = NML_INVALID_CONFIGURATION;
01061       return ((NMLmsg *) NULL);
01062     }
01063   else
01064     {
01065       cms->set_subdivision (subdiv);
01066       return ((NMLmsg *) cms->subdiv_data);
01067     }
01068 }
01069 
01070 
01071 /*************************************************************
01072 * NML Member Function: get_address_subdivision(int subdiv)
01073 * Purpose:
01074 *  Returns the total number of subdivisions configured for this
01075 * NML channel.
01076 ***************************************************************/
01077 int
01078 NML::get_total_subdivisions ()
01079 {
01080   if (NULL == cms)
01081     {
01082       return (1);
01083     }
01084   else
01085     {
01086       return (cms->total_subdivisions);
01087     }
01088 }
01089 
01090 
01091 /***********************************************************
01092 * NML Member Function: clear()
01093 * Purpose:
01094 *  Clears the CMS buffer associated with this NML channel.
01095 *
01096 *  Returns:
01097 * 0 if no error occured or -1 if error occured.
01098 *
01099 * Notes:
01100 *  1. Some buffers can be identified as PHANTOM in the config file.
01101 * this will cause cms->is_phantom to be set. This will cause this
01102 * function to call the function pointed to by phantom_clear
01103 * if it is not NULL rather than using CMS.
01104 *  2. If an error occurs, users can check error_type before
01105 * making any other NML calls
01106 ************************************************************/
01107 int
01108 NML::clear ()
01109 {
01110   if (NULL == cms)
01111     {
01112       error_type = NML_INVALID_CONFIGURATION;
01113       return (-1);
01114     }
01115   else
01116     {
01117       if (cms->is_phantom)
01118         {
01119           if (NULL != phantom_clear)
01120             {
01121               return ((*phantom_clear) ());
01122             }
01123           else
01124             {
01125               return (0);
01126             }
01127         }
01128       CMS_STATUS return_value;
01129       error_type = NML_NO_ERROR;
01130       if (((int) (return_value = cms->clear ())) > 0)
01131         {
01132           error_type = NML_INTERNAL_CMS_ERROR;
01133         }
01134       if (cms->status == CMS_TIMED_OUT)
01135         {
01136           error_type = NML_TIMED_OUT;
01137         }
01138       return (((int) return_value < 0) ? -1 : 0);
01139     }
01140 }
01141 
01142 /************************************************************
01143 * NML Member Function: clean_buffers()
01144 *  Tells cms to set buffers to zero so that we eliminate strange
01145 * history effects. -- Should only be used by progams testing CMS/NML.
01146 ************************************************************/
01147 void
01148 NML::clean_buffers ()
01149 {
01150   if (NULL != cms)
01151     {
01152       cms->clean_buffers ();
01153     }
01154 }
01155 
01156 /***********************************************************
01157 * NML Member Function: check_if_read()
01158 * Purpose:
01159 *  Returns 1 if the buffer has been read since the last write,
01160 * 0 if it hadn't, or -1 if some communications error prevented
01161 * it from finding out.
01162 * Notes:
01163 *  1. Some buffers can be identified as PHANTOM in the config file.
01164 * this will cause cms->is_phantom to be set. This will cause this
01165 * function to call the function pointed to by phantom_check_if_read
01166 * if it is not NULL rather than using CMS.
01167 *  2. If an error occurs, users can check error_type before
01168 * making any other NML calls
01169 ************************************************************/
01170 int
01171 NML::check_if_read ()
01172 {
01173   if (NULL == cms)
01174     {
01175       error_type = NML_INVALID_CONFIGURATION;
01176       return (-1);
01177     }
01178   else
01179     {
01180       if (cms->is_phantom)
01181         {
01182           if (NULL != phantom_check_if_read)
01183             {
01184               return ((*phantom_check_if_read) ());
01185             }
01186           else
01187             {
01188               return (0);
01189             }
01190         }
01191       int return_value;
01192       error_type = NML_NO_ERROR;
01193       if ((return_value = cms->check_if_read ()) == -1)
01194         {
01195           error_type = NML_INTERNAL_CMS_ERROR;
01196         }
01197       if (cms->status == CMS_TIMED_OUT)
01198         {
01199           error_type = NML_TIMED_OUT;
01200         }
01201       return (return_value);
01202     }
01203 }
01204 
01205 
01206 /*************************************************************
01207 * NML Member Function: valid()
01208 * Purpose:
01209 * Provides a check which can be used after an NML object is
01210 * constructed to determine if everthing is in order.
01211 * Returns: 1 if everything is O.K. 0 otherwise.
01212 *************************************************************/
01213 int
01214 NML::valid ()
01215 {
01216   if (NULL == cms)
01217     {
01218       error_type = NML_INVALID_CONFIGURATION;
01219       return (0);
01220     }
01221 
01222   if (cms->is_phantom)
01223     {
01224       error_type = NML_NO_ERROR;
01225       return (1);
01226     }
01227 
01228   if (CMS_MISC_ERROR == cms->status)
01229     {
01230       error_type = NML_INTERNAL_CMS_ERROR;
01231       return (0);
01232     }
01233 
01234   if (CMS_NO_MASTER_ERROR == cms->status)
01235     {
01236       error_type = NML_NO_MASTER_ERROR;
01237       return (0);
01238     }
01239 
01240   if (NULL == cms->data)
01241     {
01242       error_type = NML_INVALID_CONFIGURATION;
01243       return (0);
01244     }
01245 
01246   if (cms->neutral && (NULL == cms->encoded_data) && !cms->isserver)
01247     {
01248       error_type = NML_INVALID_CONFIGURATION;
01249       return (0);
01250     }
01251 
01252   if (!ignore_format_chain)
01253     {
01254       if (NULL == format_chain)
01255         {
01256           error_type = NML_INVALID_CONFIGURATION;
01257           return (0);
01258         }
01259     }
01260 
01261   error_type = NML_NO_ERROR;
01262   return (1);
01263 }
01264 
01265 /***********************************************************
01266 * NML Member Function: read()
01267 * Purpose: Reads an NMLmsg from a CMS buffer.
01268 * Returns:
01269 *  0 The read was successful but the data was not updated since the last read.
01270 *  -1 The buffer could not be read.
01271 *  o.w. The type of the new NMLmsg is returned.
01272 * Notes:
01273 *   1. Users need to call NML::get_address in order to access the
01274 * messages that were read.
01275 *  2. Some buffers can be identified as PHANTOM in the config file.
01276 * this will cause cms->is_phantom to be set. This will cause this
01277 * function to call the function pointed to by phantom_read
01278 * if it is not NULL rather than using CMS.
01279 *  3. If an error occurs, users can check error_type before
01280 * making any other NML calls
01281 ***********************************************************/
01282 NMLTYPE
01283 NML::read ()
01284 {
01285   error_type = NML_NO_ERROR;
01286   if (fast_mode)
01287     {
01288       cms->read ();
01289       switch (cms->status)
01290         {
01291         case CMS_READ_OLD:
01292           return (0);
01293         case CMS_READ_OK:
01294           if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01295             {
01296               rcs_print_error
01297                 ("NML: New data recieved but type of %d is invalid.\n",
01298                  ((NMLmsg *) cms->subdiv_data)->type);
01299               return -1;
01300             }
01301           return (((NMLmsg *) cms->subdiv_data)->type);
01302 
01303         default:
01304           set_error ();
01305           return -1;
01306         }
01307     }
01308   /* Check pointers. */
01309   if (NULL == cms)
01310     {
01311       if (error_type != NML_INVALID_CONFIGURATION)
01312         {
01313           error_type = NML_INVALID_CONFIGURATION;
01314           rcs_print_error ("NML::read: CMS not configured.\n");
01315         }
01316       return (-1);
01317     }
01318 
01319   /* Handle PHANTOMs */
01320   if (cms->is_phantom)
01321     {
01322       if (NULL != phantom_read)
01323         {
01324           return ((*phantom_read) ());
01325         }
01326       else
01327         {
01328           return (0);
01329         }
01330     }
01331 
01332   /* Read using CMS */
01333   if (!cms->force_raw)
01334     {
01335       cms->set_mode (CMS_READ);
01336     }
01337   cms->read ();
01338 
01339   if (!cms->force_raw)
01340     {
01341       if (cms->status == CMS_READ_OK)
01342         {
01343           if (-1 == format_output ())
01344             {
01345               error_type = NML_FORMAT_ERROR;
01346               return (-1);
01347             }
01348         }
01349     }
01350 
01351   /* Choose the return value. */
01352   switch (cms->status)
01353     {
01354     case CMS_READ_OLD:
01355       error_type = NML_NO_ERROR;
01356       return (0);
01357     case CMS_READ_OK:
01358       error_type = NML_NO_ERROR;
01359       if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01360         {
01361           rcs_print_error
01362             ("NML: New data recieved but type of %d is invalid.\n",
01363              ((NMLmsg *) cms->subdiv_data)->type);
01364           return -1;
01365         }
01366       return (((NMLmsg *) cms->subdiv_data)->type);
01367 
01368     default:
01369       set_error ();
01370       return -1;
01371     }
01372 }
01373 
01374 
01375 /***********************************************************
01376 * NML Member Function: blocking_read(double timeout)
01377 * Purpose: Reads an NMLmsg from a CMS buffer after waiting up to timeout seconds for new data.
01378 * Returns:
01379 *  0 The read was successful but the data was not updated since the last read.
01380 *  -1 The buffer could not be read.
01381 *  o.w. The type of the new NMLmsg is returned.
01382 * Notes:
01383 *   1. Users need to call NML::get_address in order to access the
01384 * messages that were read.
01385 *  2. Some buffers can be identified as PHANTOM in the config file.
01386 * this will cause cms->is_phantom to be set. This will cause this
01387 * function to call the function pointed to by phantom_read
01388 * if it is not NULL rather than using CMS.
01389 *  3. If an error occurs, users can check error_type before
01390 * making any other NML calls
01391 ***********************************************************/
01392 NMLTYPE
01393 NML::blocking_read (double blocking_timeout)
01394 {
01395   error_type = NML_NO_ERROR;
01396   if (fast_mode)
01397     {
01398       cms->blocking_read (blocking_timeout);
01399       switch (cms->status)
01400         {
01401         case CMS_READ_OLD:
01402           return (0);
01403         case CMS_READ_OK:
01404           if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01405             {
01406               rcs_print_error
01407                 ("NML: New data recieved but type of %d is invalid.\n",
01408                  ((NMLmsg *) cms->subdiv_data)->type);
01409               return -1;
01410             }
01411           return (((NMLmsg *) cms->subdiv_data)->type);
01412         case CMS_TIMED_OUT:
01413           error_type = NML_NO_ERROR;
01414           return 0;
01415 
01416         default:
01417           set_error ();
01418           return (-1);
01419         }
01420     }
01421   /* Check pointers. */
01422   if (NULL == cms)
01423     {
01424       if (error_type != NML_INVALID_CONFIGURATION)
01425         {
01426           error_type = NML_INVALID_CONFIGURATION;
01427           rcs_print_error ("NML::blocking_read: CMS not configured.\n");
01428         }
01429       return (-1);
01430     }
01431 
01432   /* Handle PHANTOMs */
01433   if (cms->is_phantom)
01434     {
01435       if (NULL != phantom_read)
01436         {
01437           return ((*phantom_read) ());
01438         }
01439       else
01440         {
01441           return (0);
01442         }
01443     }
01444 
01445   /* Read using CMS */
01446   if (!cms->force_raw)
01447     {
01448       cms->set_mode (CMS_READ);
01449     }
01450   if (cms->BufferType == CMS_SHMEM_TYPE)
01451     {
01452       cms->blocking_read (blocking_timeout);
01453     }
01454   else
01455     {
01456       double time_elapsed = 0.0;
01457       double start_time = 0.0;
01458       if (blocking_timeout > 0.0)
01459         {
01460           start_time = etime ();
01461         }
01462       double current_brpi = blocking_read_poll_interval;
01463       cms->status = CMS_READ_OLD;
01464       if (current_brpi < 2e-2)
01465         {
01466           current_brpi = 2e-2;
01467         }
01468       if (current_brpi > blocking_timeout / 2.0 && blocking_timeout > 1e-6)
01469         {
01470           current_brpi = blocking_timeout / 2.0;
01471         }
01472       while (cms->status == CMS_READ_OLD &&
01473              (time_elapsed < blocking_timeout || blocking_timeout < 0.0))
01474         {
01475 
01476           esleep (current_brpi);
01477           cms->read ();
01478           if (blocking_timeout > 0.0 && cms->status == CMS_READ_OLD)
01479             {
01480               time_elapsed = etime () - start_time;
01481             }
01482           if (time_elapsed < 0.0)
01483             {
01484               break;
01485             }
01486         }
01487     }
01488 
01489 
01490   if (!cms->force_raw)
01491     {
01492       if (cms->status == CMS_READ_OK)
01493         {
01494           if (-1 == format_output ())
01495             {
01496               error_type = NML_FORMAT_ERROR;
01497               return (-1);
01498             }
01499         }
01500     }
01501 
01502   /* Choose the return value. */
01503   switch (cms->status)
01504     {
01505     case CMS_READ_OLD:
01506       return (0);
01507     case CMS_READ_OK:
01508       if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01509         {
01510           rcs_print_error
01511             ("NML: New data recieved but type of %d is invalid.\n",
01512              ((NMLmsg *) cms->subdiv_data)->type);
01513           return -1;
01514         }
01515       return (((NMLmsg *) cms->subdiv_data)->type);
01516     case CMS_TIMED_OUT:
01517       error_type = NML_NO_ERROR;
01518       return 0;
01519 
01520     default:
01521       set_error ();
01522       return (-1);
01523     }
01524 
01525 }
01526 
01527 
01528 void
01529 NML::reconnect ()
01530 {
01531   if (NULL != cms)
01532     {
01533       cms->reconnect ();
01534     }
01535 }
01536 
01537 void
01538 NML::disconnect ()
01539 {
01540   if (NULL != cms)
01541     {
01542       cms->disconnect ();
01543     }
01544 }
01545 
01546 /* Same as the read with no arguments except that the data is
01547  stored in a user supplied location . */
01548 NMLTYPE
01549 NML::read (void *temp_data, long temp_size)
01550 {
01551   NMLTYPE return_value = 0;
01552   void *original_data;
01553   long original_size = cms->size;
01554   long original_max_message_size = cms->max_message_size;
01555   original_data = cms->data;
01556   cms->data = temp_data;
01557   cms->size = temp_size;
01558   if (cms->max_message_size > ((long) temp_size))
01559     {
01560       cms->max_message_size = temp_size;
01561     }
01562   return_value = peek ();
01563   cms->data = original_data;
01564   cms->size = original_size;
01565   cms->max_message_size = original_max_message_size;
01566   return return_value;
01567 }
01568 
01569 /* Same as the peek with no arguments except that the data is
01570  stored in a user supplied location . */
01571 NMLTYPE
01572 NML::peek (void *temp_data, long temp_size)
01573 {
01574   NMLTYPE return_value = 0;
01575   void *original_data;
01576   long original_size = cms->size;
01577   long original_max_message_size = cms->max_message_size;
01578   original_data = cms->data;
01579   cms->data = temp_data;
01580   cms->size = temp_size;
01581   if (cms->max_message_size > ((long) temp_size))
01582     {
01583       cms->max_message_size = temp_size;
01584     }
01585   return_value = peek ();
01586   cms->data = original_data;
01587   cms->size = original_size;
01588   cms->max_message_size = original_max_message_size;
01589   return return_value;
01590 }
01591 
01592 
01593 /***********************************************************
01594 * NML Member Function: peek()
01595 * Purpose: Reads an NMLmsg from a CMS buffer without setting the
01596 * was_read flag. The was_read flag is used by check_if_read and
01597 * write_if_read.
01598 * Returns:
01599 *  0 The read was successful but the data was not updated since the last read.
01600 *  -1 The buffer could not be read.
01601 *  o.w. The type of the new NMLmsg is returned.
01602 * Notes:
01603 *   1. Users need to call NML::get_address in order to access the
01604 * messages that were read.
01605 *  2. Some buffers can be identified as PHANTOM in the config file.
01606 * this will cause cms->is_phantom to be set. This will cause this
01607 * function to call the function pointed to by phantom_read
01608 * if it is not NULL rather than using CMS.
01609 *  3. If an error occurs, users can check error_type before
01610 * making any other NML calls
01611 ***********************************************************/
01612 NMLTYPE
01613 NML::peek ()
01614 {
01615   error_type = NML_NO_ERROR;
01616   if (fast_mode)
01617     {
01618       cms->peek ();
01619       switch (cms->status)
01620         {
01621         case CMS_READ_OLD:
01622           return (0);
01623         case CMS_READ_OK:
01624           if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01625             {
01626               rcs_print_error
01627                 ("NML: New data recieved but type of %d is invalid.\n",
01628                  ((NMLmsg *) cms->subdiv_data)->type);
01629               return -1;
01630             }
01631           return (((NMLmsg *) cms->subdiv_data)->type);
01632 
01633         default:
01634           set_error ();
01635           return -1;
01636         }
01637     }
01638   if (NULL == cms)
01639     {
01640       if (error_type != NML_INVALID_CONFIGURATION)
01641         {
01642           error_type = NML_INVALID_CONFIGURATION;
01643           rcs_print_error ("NML::peek: CMS not configured.\n");
01644         }
01645       return (-1);
01646     }
01647 
01648   if (cms->is_phantom)
01649     {
01650       if (NULL != phantom_peek)
01651         {
01652           return ((*phantom_peek) ());
01653         }
01654       else
01655 
01656 
01657         {
01658           return (0);
01659         }
01660     }
01661   if (!cms->force_raw)
01662     {
01663       cms->set_mode (CMS_READ);
01664     }
01665 
01666   cms->peek ();
01667   if (!cms->force_raw)
01668     {
01669       if (cms->status == CMS_READ_OK)
01670         {
01671           if (-1 == format_output ())
01672             {
01673               error_type = NML_FORMAT_ERROR;
01674               return (-1);
01675             }
01676         }
01677     }
01678 
01679   switch (cms->status)
01680     {
01681     case CMS_READ_OLD:
01682       return (0);
01683     case CMS_READ_OK:
01684       if (((NMLmsg *) cms->subdiv_data)->type <= 0 && !cms->isserver)
01685         {
01686           rcs_print_error
01687             ("NML: New data recieved but type of %d is invalid.\n",
01688              ((NMLmsg *) cms->subdiv_data)->type);
01689           return -1;
01690         }
01691       return (((NMLmsg *) cms->subdiv_data)->type);
01692 
01693     default:
01694       set_error ();
01695       return -1;
01696     }
01697 
01698 }
01699 
01700 /***********************************************************
01701 * NML Member Function: format_output()
01702 * Purpose: Formats the data read from a CMS buffer as required
01703 * by the process that created this NML. The formatting converts
01704 * messages from some platform indepent format to a platform
01705 * specific format or vice versa. (Performing byte-swapping etc.)
01706 * Returns:
01707 *  0  The format was successful.
01708 *  -1 An error occured.
01709 * Notes:
01710 *  1. There are 3 conditions under which format_output may be
01711 * called.
01712 *     i. The data is being read out as is. (cms->mode == CMS_RAW_OUT).
01713 *    ii. A user needs the data in the local platform-specific or raw format
01714 *        but the buffer has been encoded in a platform-independant or
01715 *         neutral format.   (cms->mode == CMS_DECODE).
01716 *   iii. An NML_SERVER needs the data encoded in a platform-independant
01717 *        or neutral format to send it out over the network but the buffer
01718 *        is in a local platform-specific or raw format.
01719 *         (cms->mode == CMS_ENCODE)
01720 *  2. This function uses a list of format functions supplied
01721 * by the user and stored int the format_chain.
01722 * Returns:
01723 * 0 = Success.
01724 * -1 = Error.
01725 ***********************************************************/
01726 int
01727 NML::format_output ()
01728 {
01729   NMLTYPE new_type;
01730   long new_size;
01731 
01732   /* Check pointers */
01733   if (NULL == cms)
01734     {
01735       rcs_print_error ("NML: cms is NULL.\n");
01736       return (-1);
01737     }
01738 
01739   if (cms->force_raw)
01740     {
01741       return 0;
01742     }
01743 
01744   if (forced_type > 0)
01745     {
01746       new_type = forced_type;
01747     }
01748 
01749   switch (cms->mode)
01750     {
01751     case CMS_RAW_OUT:
01752       break;
01753     case CMS_DECODE:
01754       /* Check the status of CMS. */
01755       if (cms->status == CMS_READ_OK)
01756         {
01757           /* Handle the generic part of the message. */
01758           cms->format_low_ptr = cms->format_high_ptr = (char *) NULL;
01759           cms->rewind ();       /* Move to the start of encoded buffer. */
01760           cms->update (new_type);       /* Get the message type from encoded buffer. */
01761           cms->update (new_size);       /* Get the message size from encoded buffer. */
01762           if (forced_type > 0)
01763             {
01764               new_type = forced_type;
01765             }
01766           ((NMLmsg *) cms->subdiv_data)->type = new_type;       /* Store type in message. */
01767           ((NMLmsg *) cms->subdiv_data)->size = new_size;       /* Store size in message. */
01768 
01769 
01770           if (new_size > cms->max_message_size)
01771             {
01772               rcs_print_error ("NML: Message %ld of size  %ld \n", new_type,
01773                                new_size);
01774               rcs_print_error
01775                 ("     too large for local buffer of %s of size %d.\n",
01776                  cms->BufferName, cms->max_message_size);
01777               if (verbose_nml_error_messages)
01778                 {
01779                   rcs_print_error
01780                     ("Check that all processes agree on buffer size.\n");
01781                 }
01782               cms->status = CMS_INSUFFICIENT_SPACE_ERROR;
01783               return (-1);
01784             }
01785 
01786           /* Check the list of format functions. */
01787           if (!ignore_format_chain)
01788             {
01789               cms->format_low_ptr = (char RCS_HUGE *) cms->subdiv_data;
01790               cms->format_high_ptr = cms->format_low_ptr + cms->size;
01791               if (NULL == format_chain)
01792                 {
01793                   rcs_print_error ("NML::read: Format chain is NULL.\n");
01794                   return (-1);
01795                 }
01796               /* Run through the list of format functions. */
01797               if (-1 == run_format_chain (new_type, cms->subdiv_data))
01798                 {
01799                   rcs_print_error ("NMLread: NMLformat error\n");
01800                   if (verbose_nml_error_messages)
01801                     {
01802                       rcs_print_error ("   (Buffer = %s, Process = %s)\n",
01803                                        cms->BufferName, cms->ProcessName);
01804                     }
01805                   return (-1);
01806                 }
01807             }
01808         }
01809       break;
01810     case CMS_ENCODE:
01811       /* Check the status of CMS. */
01812       if (cms->status != CMS_MISC_ERROR)
01813         {
01814           cms->format_low_ptr = cms->format_high_ptr = (char *) NULL;
01815           cms->rewind ();       /* Move to the start of the encoded buffer. */
01816 
01817           /* Get the type and size from the message. */
01818           new_type = ((NMLmsg *) cms->subdiv_data)->type;
01819           new_size = ((NMLmsg *) cms->subdiv_data)->size;
01820 
01821           if (forced_type > 0)
01822             {
01823               new_type = forced_type;
01824               ((NMLmsg *) cms->subdiv_data)->type = forced_type;
01825             }
01826 
01827           /* Store the type and size in the encoded buffer. */
01828           cms->update (new_type);
01829           cms->update (new_size);
01830 
01831           if (new_size > cms->max_message_size)
01832             {
01833               rcs_print_error ("NML: Message %ld of size  %ld\n", new_type,
01834                                new_size);
01835               rcs_print_error
01836                 ("     too large for local buffer of %s of size %d.\n",
01837                  cms->BufferName, cms->max_message_size);
01838               if (verbose_nml_error_messages)
01839                 {
01840                   rcs_print_error
01841                     ("Check that all processes agree on buffer size.\n");
01842                 }
01843               cms->status = CMS_INSUFFICIENT_SPACE_ERROR;
01844               return (-1);
01845             }
01846 
01847 
01848           /* Check the list of format functions. */
01849           if (!ignore_format_chain)
01850             {
01851               cms->format_low_ptr = (char RCS_HUGE *) cms->subdiv_data;
01852               cms->format_high_ptr = cms->format_low_ptr + cms->size;
01853               if (NULL == format_chain)
01854                 {
01855                   rcs_print_error ("NML::read: Format chain is NULL.\n");
01856                   return (-1);
01857                 }
01858 
01859               /* Run through the list of format functions. */
01860               if (-1 == run_format_chain (new_type, cms->subdiv_data))
01861                 {
01862                   rcs_print_error ("NMLread: NMLformat error\n");
01863                   if (verbose_nml_error_messages)
01864                     {
01865                       rcs_print_error ("   (Buffer = %s, Process = %s)\n",
01866                                        cms->BufferName, cms->ProcessName);
01867                     }
01868                   return (-1);
01869                 }
01870 
01871               /* Get the new size of the message now that it's been encoded. */
01872               cms->get_encoded_msg_size ();
01873             }
01874         }
01875       break;
01876     default:
01877       rcs_print_error ("NML::format_output: invalid format mode. (%d)\n",
01878                        cms->mode);
01879       return (-1);
01880     }
01881   if (forced_type > 0)
01882     {
01883       new_type = forced_type;
01884       ((NMLmsg *) cms->subdiv_data)->type = forced_type;
01885     }
01886 
01887   return (((int) cms->status < 0) ? -1 : 0);
01888 }
01889 
01890 /*************************************************************
01891 * NML Member Function: write()
01892 * Purpose: This write function provides users with an alternative
01893 * style of writing a message.
01894 * Parameters:
01895 * NMLmsg &nml_msg - Reference to the message to be written.
01896 * Returns:
01897 *  0 - The message was successfully written.
01898 *  -1 - An error occured. (Timeouts are considered errors.)
01899 *************************************************************/
01900 int
01901 NML::write (NMLmsg & nml_msg)
01902 {
01903   return (write (&nml_msg));    /* Call the other NML::write() */
01904 }
01905 
01906 /*************************************************************
01907 * NML Member Function: write()
01908 * Purpose: Writes a message to the global buffer.
01909 * Parameters:
01910 * NMLmsg *nml_msg - Address of the message to be written.
01911 * Returns:
01912 *  0 - The message was successfully written.
01913 *  -1 - An error occured. (Timeouts are considered errors.)
01914 *************************************************************/
01915 int
01916 NML::write (NMLmsg * nml_msg)
01917 {
01918   error_type = NML_NO_ERROR;
01919   if (fast_mode)
01920     {
01921       *cms_inbuffer_header_size = nml_msg->size;
01922       cms->write (nml_msg);
01923       if (*cms_status == CMS_WRITE_OK)
01924         {
01925           return (0);
01926         }
01927       set_error ();
01928       return (-1);
01929     }
01930   /* Check pointers. */
01931   if (NULL == cms)
01932     {
01933       if (error_type != NML_INVALID_CONFIGURATION)
01934         {
01935           error_type = NML_INVALID_CONFIGURATION;
01936           rcs_print_error ("NML::write: CMS not configured.\n");
01937         }
01938       return (-1);
01939     }
01940 
01941   if (NULL == nml_msg)
01942     {
01943       error_type = NML_INVALID_MESSAGE_ERROR;
01944       rcs_print_error ("NML::write: Message is NULL.\n");
01945       return (-1);
01946     }
01947 
01948   if ((nml_msg->size == 0 || nml_msg->type == 0) && !cms->isserver)
01949     {
01950       error_type = NML_INVALID_MESSAGE_ERROR;
01951       rcs_print_error ("NML::write: Message size or type is zero.\n");
01952       rcs_print_error
01953         ("NML: Check that the message was properly constructed.\n");
01954     }
01955 
01956   /* Handle Phantom Buffers. */
01957   if (cms->is_phantom)
01958     {
01959       if (NULL != phantom_write)
01960         {
01961           return ((*phantom_write) (nml_msg));
01962         }
01963       else
01964         {
01965           return (0);
01966         }
01967     }
01968 
01969   /* Set CMS to a write mode. */
01970   cms->set_mode (CMS_WRITE);
01971 
01972   /* Format the message if neccessary. */
01973   if (-1 == format_input (nml_msg))
01974     {
01975       error_type = NML_FORMAT_ERROR;
01976       return -1;
01977     }
01978 
01979 
01980   if (CMS_RAW_IN == cms->mode)
01981     {
01982       cms->write (nml_msg);     /* Write the unformatted message.  */
01983     }
01984   else
01985     {
01986       cms->write (cms->subdiv_data);    /* Write the formatted message.  */
01987     }
01988 
01989   if (CMS_WRITE_OK == cms->status)
01990     {
01991       error_type = NML_NO_ERROR;
01992       return (0);
01993     }
01994 
01995   return set_error ();
01996 }
01997 
01998 /*************************************************************
01999 * NML Member Function: set_error
02000 * Purpose: This write function provides users with an alternative
02001 * style of writing a message.
02002 * Parameters:
02003 * NMLmsg &nml_msg - Reference to the message to be written.
02004 * Returns:
02005 *  0 - The message was successfully written.
02006 *  -1 - An error occured. (Timeouts are considered errors.)
02007 * Check error_type for more info.
02008 *************************************************************/
02009 int
02010 NML::set_error ()
02011 {
02012   if (error_type != NML_NO_ERROR)
02013     {
02014       return -1;
02015     }
02016 
02017   if (NULL == cms)
02018     {
02019       error_type = NML_INVALID_CONFIGURATION;
02020       return 0;
02021     }
02022 
02023   /* Choose return value. */
02024   switch (cms->status)
02025     {
02026     case CMS_TIMED_OUT:
02027       error_type = NML_TIMED_OUT;
02028       return (-1);
02029 
02030     case CMS_QUEUE_FULL:
02031       error_type = NML_QUEUE_FULL_ERROR;
02032       break;
02033 
02034     case CMS_NO_MASTER_ERROR:
02035       error_type = NML_NO_MASTER_ERROR;
02036       break;
02037 
02038     case CMS_WRITE_WAS_BLOCKED:
02039       error_type = NML_BUFFER_NOT_READ;
02040       break;
02041 
02042     case CMS_STATUS_NOT_SET:    /* The status variable has not been set yet. */
02043     case CMS_READ_OLD:          /* Read successful, but data is old. */
02044     case CMS_READ_OK:           /* Read successful so far. */
02045     case CMS_WRITE_OK:          /* Write successful so far. */
02046     case CMS_CLEAR_OK:          /* A clear operation was successful.  */
02047       error_type = NML_NO_ERROR;
02048       break;
02049 
02050     case CMS_RESOURCE_CONFLICT_ERROR:
02051     case CMS_CREATE_ERROR:
02052     case CMS_CONFIG_ERROR:
02053       error_type = NML_INVALID_CONFIGURATION;
02054       break;
02055 
02056     case CMS_MISC_ERROR:
02057     default:
02058       error_type = NML_INTERNAL_CMS_ERROR;
02059       break;
02060 
02061     }
02062 
02063   if (error_type == NML_NO_ERROR)
02064     {
02065       return 0;
02066     }
02067   if (!info_printed)
02068     {
02069       print_info ();
02070     }
02071 
02072   return -1;
02073 }
02074 
02075 /*************************************************************
02076 * NML Member Function: write_if_read()
02077 * Purpose: This write function provides users with an alternative
02078 * style of writing a message.
02079 * Parameters:
02080 * NMLmsg &nml_msg - Reference to the message to be written.
02081 * Returns:
02082 *  0 - The message was successfully written.
02083 *  -1 - An error occured. (Timeouts are considered errors.)
02084 * Check error_type for more info.
02085 *************************************************************/
02086 int
02087 NML::write_if_read (NMLmsg & nml_msg)
02088 {
02089   return (write_if_read (&nml_msg));
02090 }
02091 
02092 /***********************************************************
02093 * NML Member Function: write_if_read()
02094 * Purpose: Write a message to the global buffer, but do not
02095 *  over-write another message if that message is unread.
02096 * Parameters:
02097 *  NMLmsg *nml_msg - Address of the message to be written.
02098 * Returns:
02099 *  0 - The message was successfully written.
02100 *  -1 - An error occured.
02101 * (Timeouts, and unread buffers  are considered errors.)
02102 * Check error_type for more info.
02103 ************************************************************/
02104 int
02105 NML::write_if_read (NMLmsg * nml_msg)
02106 {
02107   error_type = NML_NO_ERROR;
02108   if (fast_mode)
02109     {
02110       cms->header.in_buffer_size = nml_msg->size;
02111       cms->write (nml_msg);
02112       if (cms->status == CMS_WRITE_OK)
02113         {
02114           return (0);
02115         }
02116       set_error ();
02117       return (-1);
02118     }
02119   if (NULL == cms)
02120     {
02121       if (error_type != NML_INVALID_CONFIGURATION)
02122         {
02123           error_type = NML_INVALID_CONFIGURATION;
02124           rcs_print_error ("NML::write_if_read: CMS not configured.\n");
02125         }
02126       return (-1);
02127     }
02128 
02129   if (NULL == nml_msg)
02130     {
02131       error_type = NML_INVALID_MESSAGE_ERROR;
02132       rcs_print_error ("NML::write_if_read: Message is NULL.\n");
02133       return (-1);
02134     }
02135 
02136   if ((nml_msg->size == 0 || nml_msg->type == 0) && !cms->isserver)
02137     {
02138       error_type = NML_INVALID_MESSAGE_ERROR;
02139       rcs_print_error ("NML::write_if_read: Message size or type is zero.\n");
02140       if (verbose_nml_error_messages)
02141         {
02142           rcs_print_error
02143             ("NML: Check that the message was properly constructed.\n");
02144         }
02145     }
02146 
02147   if (cms->is_phantom)
02148     {
02149       if (NULL != phantom_write_if_read)
02150         {
02151           return ((*phantom_write_if_read) (nml_msg));
02152         }
02153       else
02154         {
02155           return (0);
02156         }
02157     }
02158 
02159 
02160   cms->set_mode (CMS_WRITE);
02161   if (-1 == format_input (nml_msg))
02162     {
02163       error_type = NML_FORMAT_ERROR;
02164       return -1;
02165     }
02166 
02167   if (CMS_RAW_IN == cms->mode)
02168     {
02169       cms->write_if_read (nml_msg);
02170     }
02171   else
02172     {
02173       cms->write_if_read (cms->subdiv_data);
02174     }
02175 
02176   return (set_error ());
02177 }
02178 
02179 /*******************************************************************
02180 * NML Member Function: format_input()
02181 * Purpose: Formats the in an NML message to be writen to a CMS buffer
02182 *  as required by the configuration file. The formatting converts
02183 *  messages from some platform indepent format to a platform
02184 *  specific format or vice versa. (Performing byte-swapping etc.)
02185 * Parameters:
02186 * NMLmsg *nml_msg - The address of the NML message.
02187 * Returns:
02188 * 0 = Success.
02189 * -1 = Error.
02190 * Notes:
02191 *  1. There are 3 conditions that format_input may be called under.
02192 *    i. The message will be written to the buffer without any formatting.
02193 *       (cms->mode == CMS_RAW_IN)
02194 *    ii. The message is in a native or raw format and needs to be encoded
02195 *  in a neutral format before being sent over the network or into a
02196 *  neutral buffer.
02197 *        (cms->mode == CMS_ENCODE)
02198 *   iii. The process calling this is a server which recieved a neutrally
02199 * encoded buffer over the network which must be converted to native
02200 * format before being written into a raw buffer.
02201 *        (cms->mode == CMS_DECODE)
02202 *  2. This function is for internal NML use only.
02203 ******************************************************************/
02204 int
02205 NML::format_input (NMLmsg * nml_msg)
02206 {
02207   NMLTYPE new_type;
02208   long new_size;
02209   if (NULL == cms)
02210     {
02211       return -1;
02212     }
02213 
02214   if (cms->force_raw)
02215     {
02216       cms->mode = CMS_RAW_IN;
02217     }
02218 
02219   switch (cms->mode)
02220     {
02221     case CMS_RAW_IN:
02222       /* Make sure the message size is not larger than the buffer size. */
02223       if (nml_msg->size > cms->max_message_size)
02224         {
02225           rcs_print_error ("NML: Message size(%d) too large for"
02226                            " CMS buffer size of %d.\n",
02227                            nml_msg->size, cms->max_message_size);
02228           cms->status = CMS_INSUFFICIENT_SPACE_ERROR;
02229           return (-1);
02230         }
02231       cms->header.in_buffer_size = nml_msg->size;
02232       break;
02233     case CMS_ENCODE:
02234       /* Make sure the message size is not larger than the buffer size. */
02235       if (nml_msg->size > cms->max_message_size)
02236         {
02237           rcs_print_error ("NML: Message size(%d) too large for"
02238                            " CMS buffer size of %d.\n",
02239                            nml_msg->size, cms->max_message_size);
02240           cms->status = CMS_INSUFFICIENT_SPACE_ERROR;
02241           return (-1);
02242         }
02243 
02244       cms->format_low_ptr = (char RCS_HUGE *) nml_msg;
02245       cms->format_high_ptr = cms->format_low_ptr + nml_msg->size;
02246       /* Handle the generic part of the message. */
02247       cms->rewind ();           /* Move to the start of the encoded buffer. */
02248       cms->update (nml_msg->type);      /* Store message type in encoded buffer. */
02249       cms->update (nml_msg->size);      /* Store message size in encoded buffer. */
02250 
02251       /* Check list of format functions. */
02252       if (!ignore_format_chain)
02253         {
02254           if (NULL == format_chain)
02255             {
02256               rcs_print_error ("NML::read: Format chain is NULL.\n");
02257               return (-1);
02258             }
02259 
02260           /* Run through list of format functions. */
02261           if (-1 == run_format_chain (nml_msg->type, nml_msg))
02262             {
02263               rcs_print_error ("NMLwrite: format error\n");
02264               if (verbose_nml_error_messages)
02265                 {
02266                   rcs_print_error ("   (Buffer = %s, Process = %s)\n",
02267                                    cms->BufferName, cms->ProcessName);
02268                 }
02269               return (-1);
02270             }
02271         }
02272       /* Determine the new  size of the message now that its encoded. */
02273       cms->header.in_buffer_size = cms->get_encoded_msg_size ();
02274       break;
02275     case CMS_DECODE:
02276       cms->format_low_ptr = cms->format_high_ptr = (char *) NULL;
02277       cms->rewind ();           /* Move to the start of the encoded buffer. */
02278       cms->update (new_type);   /* Get message type from encoded buffer. */
02279       cms->update (new_size);   /* Get message size from encoded buffer. */
02280 
02281       /* Make sure the message size is not larger than the buffer size. */
02282       if (new_size > cms->max_message_size)
02283         {
02284           rcs_print_error ("NMLwrite: Message size(%d) too large for"
02285                            " CMS buffer size of %d.\n",
02286                            new_size, cms->max_message_size);
02287           cms->status = CMS_INSUFFICIENT_SPACE_ERROR;
02288           return (-1);
02289         }
02290       cms->format_low_ptr = (char RCS_HUGE *) cms->subdiv_data;
02291       cms->format_high_ptr = cms->format_low_ptr + cms->size;
02292 
02293       /* Store the new type and size in the raw message. */
02294       ((NMLmsg *) cms->subdiv_data)->type = new_type;
02295       ((NMLmsg *) cms->subdiv_data)->size = new_size;
02296 
02297       /* Check the list of format functions. */
02298       if (!ignore_format_chain)
02299         {
02300           if (NULL == format_chain)
02301             {
02302               rcs_print_error ("NML::read: Format chain is NULL.\n");
02303               return (-1);
02304             }
02305 
02306           /* Run through the list of format functions. */
02307           if (-1 == run_format_chain (new_type, cms->subdiv_data))
02308             {
02309               rcs_print_error ("NMLwrite: format error\n");
02310               rcs_print_error ("   (Buffer = %s, Process = %s)\n",
02311                                cms->BufferName, cms->ProcessName);
02312               return (-1);
02313             }
02314         }
02315       /* Choose a size that will ensure the entire message will be read out. */
02316       if (cms->format_size < ((long) sizeof (NMLmsg)))
02317         {
02318           cms->format_size = sizeof (NMLmsg);
02319         }
02320       if (cms->format_size > new_size)
02321         {
02322           ((NMLmsg *) cms->subdiv_data)->size = (long) cms->format_size;
02323         }
02324       cms->header.in_buffer_size = ((NMLmsg *) cms->subdiv_data)->size;
02325       break;
02326     default:
02327       rcs_print_error ("NML::format_input: invalid mode (%d).\n", cms->mode);
02328       return (-1);
02329     }
02330 
02331   return (((int) cms->status < 0) ? -1 : 0);
02332 }
02333 
02334 
02335 int
02336 NML::run_format_chain (NMLTYPE type, void *buf)
02337 {
02338   NML_FORMAT_PTR format_function;
02339 
02340   format_function = (NML_FORMAT_PTR) format_chain->get_head ();
02341   while (NULL != format_function)
02342     {
02343       switch ((*format_function) (type, buf, cms))
02344         {
02345         case -1:
02346           return (-1);
02347         case 0:
02348           break;
02349         case 1:
02350           return (0);
02351         }
02352       format_function = (NML_FORMAT_PTR) format_chain->get_next ();
02353     }
02354   return (0);
02355 }
02356 
02357 
02358 int
02359 NML::prefix_format_chain (NML_FORMAT_PTR f_ptr)
02360 {
02361   if (NULL == format_chain)
02362     {
02363       format_chain = new RCS_LINKED_LIST;
02364     }
02365   if (NULL != format_chain)
02366     {
02367       format_chain->store_at_head ((void *) f_ptr, 0, 0);
02368     }
02369   return (0);
02370 }
02371 
02372 
02373 /**************************************************************************
02374 * NML member function: msg2str
02375 * Parameter: NMLmsg &msg -- Reference to message to be converted into a string.
02376 * Returns: Returns a pointer to the cms->encoded_data buffer if successful
02377 * since this should contain the string or NULL if there was an error.
02378 ***************************************************************************/
02379 int
02380 NML::check_if_transfers_complete ()
02381 {
02382   if (NULL == cms)
02383     {
02384       return 1;
02385     }
02386   return cms->check_if_transfers_complete ();
02387 }
02388 
02389 
02390 /**************************************************************************
02391 * NML member function: msg2str
02392 * Parameter: NMLmsg &msg -- Reference to message to be converted into a string.
02393 * Returns: Returns a pointer to the cms->encoded_data buffer if successful
02394 * since this should contain the string or NULL if there was an error.
02395 ***************************************************************************/
02396 const char *
02397 NML::msg2str (NMLmsg & msg)
02398 {
02399   return msg2str (&msg);
02400 }
02401 
02402 
02403 /**************************************************************************
02404 * NML member function: msg2str
02405 * Parameter: NMLmsg *msg -- Pointer to message to be converted into a string.
02406 * Returns: Returns a pointer to the cms->encoded_data buffer if successful
02407 * since this should contain the string or NULL if there was an error.
02408 ***************************************************************************/
02409 const char *
02410 NML::msg2str (NMLmsg * nml_msg)
02411 {
02412   CMS *orig_cms = cms;
02413   char *str = NULL;
02414   if (NULL == nml_msg)
02415     {
02416       return NULL;
02417     }
02418   if (NULL == cms)
02419     {
02420       int msg_length = nml_msg->size;
02421       if (NULL != cms_for_msg_string_conversions)
02422         {
02423           if ((cms_for_msg_string_conversions->size > 16 * msg_length &&
02424                cms_for_msg_string_conversions->size > 2048) ||
02425               cms_for_msg_string_conversions->size < 4 * msg_length)
02426             {
02427               delete cms_for_msg_string_conversions;
02428               cms_for_msg_string_conversions = 0;
02429             }
02430         }
02431       if (NULL == cms_for_msg_string_conversions)
02432         {
02433           cms_for_msg_string_conversions =
02434             new CMS (nml_msg->size * 4 + 16 + (16 - (nml_msg->size % 16)));
02435         }
02436       cms = cms_for_msg_string_conversions;
02437     }
02438   cms->set_temp_updater (CMS_DISPLAY_ASCII_ENCODING);
02439   cms->set_mode (CMS_ENCODE);
02440   if (-1 == format_input (nml_msg))
02441     {
02442       cms->restore_normal_updater ();
02443       error_type = NML_FORMAT_ERROR;
02444       cms = orig_cms;
02445       return ((char *) NULL);
02446     }
02447   cms->restore_normal_updater ();
02448   str = (char *) cms->encoded_data;
02449   cms = orig_cms;
02450   return (const char *) str;
02451 }
02452 
02453 /**************************************************************************
02454 * NML member function: str2msg
02455 * Parameter: NMLmsg *msg -- Pointer to message to be converted into a NMLmsg.
02456 * Returns: Returns a pointer to the cms->encoded_data buffer if successful
02457 * since this should contain the string or NULL if there was an error.
02458 ***************************************************************************/
02459 NMLTYPE
02460 NML::str2msg (const char *string)
02461 {
02462   CMS *orig_cms = cms;
02463   if (NULL == string)
02464     {
02465       return -1;
02466     }
02467   if (NULL == cms)
02468     {
02469       int string_length = strlen (string);
02470       if (NULL != cms_for_msg_string_conversions)
02471         {
02472           if ((cms_for_msg_string_conversions->size > 16 * string_length &&
02473                cms_for_msg_string_conversions->size > 2048) ||
02474               cms_for_msg_string_conversions->size < 4 * string_length)
02475             {
02476               delete cms_for_msg_string_conversions;
02477               cms_for_msg_string_conversions = 0;
02478             }
02479         }
02480       if (NULL == cms_for_msg_string_conversions)
02481         {
02482           cms_for_msg_string_conversions =
02483             new CMS (string_length * 4 + 16 + (16 - (string_length % 16)));
02484         }
02485       cms = cms_for_msg_string_conversions;
02486     }
02487   cms->set_temp_updater (CMS_DISPLAY_ASCII_ENCODING);
02488   cms->set_mode (CMS_DECODE);
02489   strcpy ((char *) cms->encoded_data, (const char *) string);
02490   cms->status = CMS_READ_OK;
02491   if (-1 == format_output ())
02492     {
02493       cms->restore_normal_updater ();
02494       error_type = NML_FORMAT_ERROR;
02495       cms = orig_cms;
02496       return -1;
02497     }
02498   cms->restore_normal_updater ();
02499   cms = orig_cms;
02500 
02501   switch (cms->status)
02502     {
02503     case CMS_READ_OLD:
02504       error_type = NML_NO_ERROR;
02505       return (0);
02506     case CMS_READ_OK:
02507       error_type = NML_NO_ERROR;
02508       return (((NMLmsg *) cms->subdiv_data)->type);
02509     case CMS_TIMED_OUT:
02510       error_type = NML_TIMED_OUT;
02511       return -1;
02512     case CMS_MISC_ERROR:
02513     case CMS_NO_MASTER_ERROR:
02514       error_type = NML_INTERNAL_CMS_ERROR;
02515     default:
02516       return -1;
02517     }
02518 
02519 }
02520 
02521 static int info_message_printed = 0;
02522 char cwd_buf[256];
02523 char host_name_buf[MAXHOSTNAMELEN];
02524 
02525 char *
02526 get_ip_address (char *hostname)
02527 {
02528   struct sockaddr_in socket_address;
02529   /* Get the IP address of the server using it's BufferHost. */
02530 #ifndef VXWORKS
02531   struct hostent *host_entry;
02532   dl_gethostbyname (hostname, &host_entry);
02533   if (NULL == host_entry)
02534     {
02535       return "UNKNOWN";
02536     }
02537 #ifdef __MSDOS__
02538   socket_address.sin_addr.s_addr = *((u_long *) host_entry->h_addr_list[0]);
02539 #else
02540   socket_address.sin_addr.s_addr = *((int *) host_entry->h_addr_list[0]);
02541 #endif
02542   socket_address.sin_family = host_entry->h_addrtype;
02543 #else
02544   socket_address.sin_addr.s_addr = hostGetByName (hostname);
02545   if (((long) socket_address.sin_addr.s_addr) == ERROR)
02546     {
02547       return "UNKNOWN";
02548     }
02549 #endif
02550   return dl_inet_ntoa (socket_address.sin_addr);
02551 }
02552 
02553 char last_bufname[10];
02554 char last_procname[10];
02555 char last_cfg_file[40];
02556 
02557 /**************************************************************************
02558 * NML member function: print_info()
02559 * Prints the buffer, process names and configuration file information.
02560 ***************************************************************************/
02561 void
02562 NML::print_info (char *bufname, char *procname, char *cfg_file)
02563 {
02564   info_printed = 1;
02565   if (!verbose_nml_error_messages)
02566     {
02567       return;
02568     }
02569   if (NULL == cms || error_type != NML_NO_ERROR)
02570     {
02571       if (max_rcs_errors_to_print <= rcs_errors_printed &&
02572           max_rcs_errors_to_print >= 0)
02573         {
02574           return;
02575         }
02576     }
02577   if (error_type == NML_QUEUE_FULL_ERROR && !cms_print_queue_full_messages)
02578     {
02579       return;
02580     }
02581   if (NULL != cms)
02582     {
02583       if (cms->status < 0)
02584         {
02585           if (max_rcs_errors_to_print <= rcs_errors_printed &&
02586               max_rcs_errors_to_print >= 0)
02587             {
02588               return;
02589             }
02590         }
02591     }
02592   if (NULL != bufname && NULL != procname && NULL != cfg_file)
02593     {
02594       if (!strncmp (bufname, last_bufname, 10)
02595           && !strncmp (procname, last_procname, 10)
02596           && !strncmp (cfg_file, last_cfg_file, 40))
02597         {
02598           return;
02599         }
02600       strncpy (last_bufname, bufname, 10);
02601       strncpy (last_procname, procname, 10);
02602       strncpy (last_cfg_file, cfg_file, 40);
02603     }
02604   if (!info_message_printed)
02605     {
02606       rcs_print
02607         ("\n**********************************************************\n");
02608 #if 0
02609       rcs_print ("* If you are having a problem with NML, \n");
02610       rcs_print ("* please send the following information,\n");
02611       rcs_print ("* a detailed description of the problem, \n");
02612       rcs_print ("* and any other error messages\n");
02613       rcs_print ("* to Will Shackleford (shackle@cme.nist.gov).\n");
02614 #endif
02615 #ifndef WINDOWS
02616       rcs_print ("* Current Directory = %s\n", getcwd (cwd_buf, 256));
02617 #endif
02618       if (nml_print_hostname_on_error)
02619         {
02620           dl_gethostname (host_name_buf, MAXHOSTNAMELEN);
02621           if (host_name_buf[0] != 0)
02622             {
02623               rcs_print ("* Host = %s\n", host_name_buf);
02624             }
02625         }
02626       rcs_print ("* ");
02627       print_rcs_version ();
02628       info_message_printed = 1;
02629     }
02630   rcs_print
02631     ("\n**********************************************************\n");
02632   if (NULL != cms)
02633     {
02634       rcs_print ("* BufferName = %s\n", cms->BufferName);
02635       rcs_print ("* BufferType = %d\n", cms->BufferType);
02636       rcs_print ("* ProcessName = %s\n", cms->ProcessName);
02637       rcs_print ("* Configuration File = %s\n", cfgfilename);
02638       rcs_print ("* CMS Status = %d (%s)\n", cms->status,
02639                  cms->status_string (cms->status));
02640       rcs_print ("* Recent errors repeated:\n");
02641       rcs_print ("%s\n", last_error_bufs[0]);
02642       rcs_print ("%s\n", last_error_bufs[1]);
02643       rcs_print ("%s\n", last_error_bufs[2]);
02644       rcs_print ("%s\n", last_error_bufs[3]);
02645       memset (last_error_bufs[0], 0, 100);
02646       memset (last_error_bufs[1], 0, 100);
02647       memset (last_error_bufs[2], 0, 100);
02648       memset (last_error_bufs[3], 0, 100);
02649       if (NULL == strstr (cms->BufferLine, "\n"))
02650         {
02651           rcs_print ("* BufferLine: %s\n", cms->BufferLine);
02652 
02653         }
02654       else
02655         {
02656           rcs_print ("* BufferLine: %s", cms->BufferLine);
02657         }
02658       if (NULL == strstr (cms->ProcessLine, "\n"))
02659         {
02660           rcs_print ("* ProcessLine: %s\n", cms->ProcessLine);
02661         }
02662       else
02663         {
02664           rcs_print ("* ProcessLine: %s", cms->ProcessLine);
02665         }
02666     }
02667   else
02668     {
02669       if (NULL != bufname)
02670         {
02671           rcs_print ("* BufferName = %s\n", bufname);
02672         }
02673       if (NULL != procname)
02674         {
02675           rcs_print ("* ProcessName = %s\n", procname);
02676         }
02677     }
02678   if (NULL != cfg_file)
02679     {
02680       rcs_print ("* Config File = %s\n", cfg_file);
02681     }
02682   rcs_print ("* error_type = %d (%s)\n", error_type,
02683              NML_ERROR_TYPE_STRINGS[error_type]);
02684   rcs_print
02685     ("************************************************************\n\n");
02686 }
02687 
02688 void RCS_EXPORT
02689 nml_start ()
02690 {
02691 
02692 #ifndef __MSDOS__
02693   spawn_nml_servers ();
02694 #endif /* __MSDOS__ */
02695 }
02696 
02697 void RCS_EXPORT
02698 nml_cleanup ()
02699 {
02700   NML *nml;
02701 #if !defined(__MSDOS__) || defined(WIN32)
02702   nml_server_cleanup ();
02703 #endif /* __MSDOS__ */
02704 
02705 #ifdef VXWORKS
02706   int current_pid;
02707   current_pid = taskIdSelf ();
02708 #endif
02709 
02710 #ifdef _Windows
02711   // HANDLE replaced with void RCS_FAR *
02712   void RCS_FAR *current_task_handle;
02713 #ifdef __WIN32__
02714   current_task_handle = GetCurrentThread ();
02715 #else
02716   current_task_handle = GetCurrentTask ();
02717 #endif
02718 #endif
02719 
02720   if (NULL != NML_Main_Channel_List)
02721     {
02722       rcs_print_debug (PRINT_NML_DESTRUCTORS,
02723                        "Deleting %d channels from the NML_Main_Channel_List.\n",
02724                        NML_Main_Channel_List->list_size);
02725       nml = (NML *) NML_Main_Channel_List->get_head ();
02726       while (NULL != nml)
02727         {
02728 #ifdef VXWORKS
02729           if (current_pid != nml->pid)
02730             {
02731               nml = (NML *) NML_Main_Channel_List->get_next ();
02732               continue;
02733             }
02734 #endif
02735 #ifdef _Windows
02736           if (current_task_handle != nml->task_handle)
02737             {
02738               nml = (NML *) NML_Main_Channel_List->get_next ();
02739               continue;
02740             }
02741 #endif
02742           if (nml->cms != NULL)
02743             {
02744               rcs_print_debug (PRINT_NML_DESTRUCTORS,
02745                                "Deleting %s NML channel from NML_Main_Channel_List.\n",
02746                                nml->cms->BufferName);
02747             }
02748           nml->delete_channel ();
02749 
02750           rcs_print_debug (PRINT_NML_DESTRUCTORS,
02751                            "NML channel deleted from NML_Main_Channel_List\n");
02752           if (NULL == NML_Main_Channel_List)
02753             {
02754               return;
02755             }
02756           NML_Main_Channel_List->delete_current_node ();
02757           nml = (NML *) NML_Main_Channel_List->get_next ();
02758         }
02759       if (NULL != NML_Main_Channel_List)
02760         {
02761 #if defined(VXWORKS) || defined(_Windows)
02762           if (0 == NML_Main_Channel_List->list_size)
02763             {
02764 #endif
02765               delete NML_Main_Channel_List;
02766               NML_Main_Channel_List = (RCS_LINKED_LIST *) NULL;
02767 #if defined(VXWORKS) || defined(_Windows)
02768             }
02769 #endif
02770         }
02771     }
02772 #ifndef WINDOWS
02773   if (NULL != Dynamically_Allocated_NML_Objects)
02774     {
02775       nml = (NML *) Dynamically_Allocated_NML_Objects->get_head ();
02776       while (NULL != nml)
02777         {
02778 #ifdef VXWORKS
02779           if (current_pid != nml->pid)
02780             {
02781               nml = (NML *) Dynamically_Allocated_NML_Objects->get_next ();
02782               continue;
02783             }
02784 #endif
02785 #ifdef _Windows
02786           if (current_task_handle != nml->task_handle)
02787             {
02788               nml = (NML *) Dynamically_Allocated_NML_Objects->get_next ();
02789               continue;
02790             }
02791 #endif
02792           if (nml->cms != NULL)
02793             {
02794               rcs_print_debug (PRINT_NML_DESTRUCTORS,
02795                                "Deleting %s NML channel from Dynamically_Allocated_NML_Objects.\n",
02796                                nml->cms->BufferName);
02797             }
02798           delete nml;
02799 
02800           rcs_print_debug (PRINT_NML_DESTRUCTORS,
02801                            "NML channel deleted from Dynamically_Allocated_NML_Objects\n");
02802           if (NULL == Dynamically_Allocated_NML_Objects)
02803             {
02804               return;
02805             }
02806           Dynamically_Allocated_NML_Objects->delete_current_node ();
02807           nml = (NML *) Dynamically_Allocated_NML_Objects->get_next ();
02808         }
02809       if (NULL != Dynamically_Allocated_NML_Objects)
02810         {
02811 #if defined(VXWORKS) || defined(_Windows)
02812           if (0 == Dynamically_Allocated_NML_Objects->list_size)
02813             {
02814 #endif
02815               delete Dynamically_Allocated_NML_Objects;
02816               Dynamically_Allocated_NML_Objects = (RCS_LINKED_LIST *) NULL;
02817 #if defined(VXWORKS) || defined(_Windows)
02818             }
02819 #endif
02820         }
02821     }
02822 #endif
02823   nmlClearHostAliases ();
02824 }
02825 
02826 void RCS_EXPORT
02827 nml_wipeout_lists ()
02828 {
02829   if (NULL != NML_Main_Channel_List)
02830     {
02831       delete NML_Main_Channel_List;
02832       NML_Main_Channel_List = (RCS_LINKED_LIST *) NULL;
02833     }
02834   if (NULL != Dynamically_Allocated_NML_Objects)
02835     {
02836       delete Dynamically_Allocated_NML_Objects;
02837       Dynamically_Allocated_NML_Objects = (RCS_LINKED_LIST *) NULL;
02838     }
02839 #ifndef __MSDOS__
02840   if (NULL != NML_Default_Super_Server)
02841     {
02842       delete NML_Default_Super_Server;
02843       NML_Default_Super_Server = (NML_SUPER_SERVER *) NULL;
02844     }
02845 #endif
02846 }
02847 
02848 
02849 int
02850 NML::print_queue_info ()
02851 {
02852   if (NULL == cms)
02853     {
02854       rcs_print_error ("NML::print_queue_info() - NULL == cms\n");
02855       return (-1);
02856     }
02857   if (!cms->queuing_enabled)
02858     {
02859       rcs_print_error ("NML::print_queue_info() - Queing Not Enabled.\n");
02860       return (-1);
02861     }
02862   if (cms->ProcessType != CMS_LOCAL_TYPE)
02863     {
02864       rcs_print_error
02865         ("NML::print_queue_info() - REMOTE Connection: Queing Data Not Available.\n");
02866       return (-1);
02867     }
02868   rcs_print
02869     ("head = %d(0x%X); tail=%d(0x%X); queue_length=%d,end_queue_space=%d(0x%X); write_id=%d\n",
02870      cms->queuing_header.head, cms->queuing_header.head,
02871      cms->queuing_header.tail, cms->queuing_header.tail,
02872      cms->queuing_header.queue_length, cms->queuing_header.end_queue_space,
02873      cms->queuing_header.end_queue_space, cms->queuing_header.write_id);
02874   return (0);
02875 }
02876 
02877 // Function added at Steve Balakirsky's request. Polls a channel indefinitely
02878 // waiting for it to open.
02879 NML *
02880 nmlWaitOpen (NML_FORMAT_PTR fPtr, char *buffer, char *name, char *file,
02881              double sleepTime)
02882 {
02883   NML *nmlChannel = 0;
02884 
02885   RCS_PRINT_DESTINATION_TYPE olddest = get_rcs_print_destination ();
02886   set_rcs_print_destination (RCS_PRINT_TO_NULL);
02887   nmlChannel = new NML (fPtr, buffer, name, file);
02888   while (!nmlChannel->reset ())
02889     {
02890       esleep (sleepTime);
02891     }
02892   set_rcs_print_destination (olddest);
02893   return (nmlChannel);
02894 }
02895 
02896 // Special functions for dealing with subdivisions
02897 
02898 /* Write a message. (Use reference) */
02899 int
02900 NML::write_subdivision (int subdiv, NMLmsg & nml_msg)
02901 {
02902   if (NULL != cms)
02903     {
02904       if (cms->set_subdivision (subdiv) < 0)
02905         {
02906           return -1;
02907         }
02908     }
02909   return write (nml_msg);
02910 }
02911 
02912 
02913 /* Write a message. (Use pointer) */
02914 int
02915 NML::write_subdivision (int subdiv, NMLmsg * nml_msg)
02916 {
02917   if (NULL != cms)
02918     {
02919       if (cms->set_subdivision (subdiv) < 0)
02920         {
02921           return -1;
02922         }
02923     }
02924   return write (nml_msg);
02925 }
02926 
02927 
02928 /* Write to subdivision only if buffer was_read. (Use reference) */
02929 int
02930 NML::write_if_read_subdivision (int subdiv, NMLmsg & nml_msg)
02931 {
02932   if (NULL != cms)
02933     {
02934       if (cms->set_subdivision (subdiv) < 0)
02935         {
02936           return -1;
02937         }
02938     }
02939   return write_if_read (nml_msg);
02940 }
02941 
02942 /* Write to subdivision only if buffer was_read. (Use pointer) */
02943 int
02944 NML::write_if_read_subdivision (int subdiv, NMLmsg * nml_msg)
02945 {
02946   if (NULL != cms)
02947     {
02948       if (cms->set_subdivision (subdiv) < 0)
02949         {
02950           return -1;
02951         }
02952     }
02953   return write_if_read (nml_msg);
02954 }
02955 
02956 
02957 /* Read from a particular subdivision. */
02958 NMLTYPE
02959 NML::read_subdivision (int subdiv)
02960 {
02961   if (NULL != cms)
02962     {
02963       if (cms->set_subdivision (subdiv) < 0)
02964         {
02965           return -1;
02966         }
02967     }
02968   return read ();
02969 }
02970 
02971 
02972 /* Read from a particular subdivision. (Wait for new data). */
02973 NMLTYPE
02974 NML::blocking_read_subdivision (int subdiv, double timeout)
02975 {
02976   if (NULL != cms)
02977     {
02978       if (cms->set_subdivision (subdiv) < 0)
02979         {
02980           return -1;
02981         }
02982     }
02983   return blocking_read (timeout);
02984 }
02985 
02986 /* Read buffer without changing was_read */
02987 NMLTYPE
02988 NML::peek_subdivision (int subdiv)
02989 {
02990   if (NULL != cms)
02991     {
02992       if (cms->set_subdivision (subdiv) < 0)
02993         {
02994           return -1;
02995         }
02996     }
02997   return peek ();
02998 }
02999 
03000 // This constructor declared private to prevent copying.
03001 NML::NML (NML & nml)
03002 {
03003 }
03004 
03005 
03006 NMLTYPE
03007 NML::blocking_read_extended (double timeout, double poll_interval)
03008 {
03009   if (cms == NULL)
03010     {
03011       return -1;
03012     }
03013 
03014   if (cms->BufferType == CMS_SHMEM_TYPE)
03015     {
03016       return blocking_read (timeout);
03017     }
03018   else
03019     {
03020       NMLTYPE type = 0;
03021       double time_elapsed = 0.0;
03022       double start_time = etime ();
03023       while (!type && (time_elapsed < timeout || timeout < 0.0))
03024         {
03025           esleep (poll_interval);
03026           type = read ();
03027           if (timeout > 0.0 && !type)
03028             {
03029               time_elapsed = etime () - start_time;
03030             }
03031           if (time_elapsed < 0.0)
03032             {
03033               break;
03034             }
03035         }
03036       return type;
03037     }
03038 }
03039 
03040 
03041 /* Get the number of messages written to this buffer so far. */
03042 int
03043 NML::get_msg_count ()
03044 {
03045   if (NULL == cms)
03046     {
03047       return -1;
03048     }
03049   return cms->get_msg_count ();
03050 }
03051 
03052 
03053 
03054 /* Get Diagnostics Information. */
03055 NML_DIAGNOSTICS_INFO *
03056 NML::get_diagnostics_info ()
03057 {
03058   if (NULL == cms)
03059     {
03060       return NULL;
03061     }
03062   return (NML_DIAGNOSTICS_INFO *) cms->get_diagnostics_info ();
03063 }
03064 
03065 
03066 void
03067 nmlSetHostAlias (const char *hostName, const char *hostAlias)
03068 {
03069   if (NULL == cmsHostAliases)
03070     {
03071       cmsHostAliases = new RCS_LINKED_LIST;
03072     }
03073   CMS_HOST_ALIAS_ENTRY entry;
03074   strncpy (entry.host, hostName, 64);
03075   strncpy (entry.alias, hostAlias, 64);
03076   cmsHostAliases->store_at_tail (&entry, sizeof (entry), 1);
03077 }
03078 
03079 void
03080 nmlClearHostAliases ()
03081 {
03082   if (NULL != cmsHostAliases)
03083     {
03084       delete cmsHostAliases;
03085       cmsHostAliases = NULL;
03086     }
03087 }
03088 
03089 void
03090 nmlAllowNormalConnection ()
03091 {
03092   cms_connection_mode = CMS_NORMAL_CONNECTION_MODE;
03093 }
03094 
03095 void
03096 nmlForceRemoteConnection ()
03097 {
03098   cms_connection_mode = CMS_FORCE_REMOTE_CONNECTION_MODE;
03099 }
03100 
03101 void
03102 nmlForceLocalConnection ()
03103 {
03104   cms_connection_mode = CMS_FORCE_LOCAL_CONNECTION_MODE;
03105 }

Generated on Sun Dec 2 15:56:50 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001