Main Page Class Hierarchy Compound List File List Compound Members File Members

# ws_clientII.c

Go to the documentation of this file.

    00001
    00002 /*
    00003  *   THIS FILE IS UNDER RCS - DO NOT MODIFY UNLESS YOU HAVE
    00004  *   CHECKED IT OUT USING THE COMMAND CHECKOUT.
    00005  *
    00006  *    $Id: ws__clientII_8c-source.html,v 1.1 2006/05/19 16:55:03 paulf Exp $
    00007  *
    00008  *    Revision history:
    00009  *     $Log: ws__clientII_8c-source.html,v $
    00009  *     Revision 1.1  2006/05/19 16:55:03  paulf
    00009  *     first inclusion
    00009  *
    00010  *     Revision 1.5  2002/03/19 22:15:15  davidk
    00011  *     Fixed bug reported by IlyaDricker in wsGetTraceBin() where the function
    00012  *     was not correctly handling the return code from wsParseBinHeaderReply().
    00013  *
    00014  *     Revision 1.4  2001/04/17 17:31:41  davidk
    00015  *     Added explicit (SOCKET) typecasts in FD_SET to get rid of compiler warnings on NT.
    00016  *
    00017  *     Revision 1.3  2000/09/17 18:37:57  lombard
    00018  *     wsSearchSCN now really returns the first menu with matching scn.
    00019  *     wsGetTraceBin will now try another server if the first returns a gap.
    00020  *
    00021  *     Revision 1.2  2000/03/08 18:14:06  luetgert
    00022  *     fixed memmove problem in wsParseAsciiHeaderReply.
    00023  *
    00024  *     Revision 1.1  2000/02/14 18:51:48  lucky
    00025  *     Initial revision
    00026  *
    00027  *
    00028  */
    00029
    00030 /* Version II of WaveServerIV client utility routines. This file contains
    00031  * various routines useful for dealing with WaveServerIV and beyond. */
    00032
    00033 /* 5/17/98: Fixed bug in wsWaitAscii: it would fill reply buffer but never
    00034  * report overflow. PNL */
    00035
    00036 /* The philosophy behind the version II changes is:
    00037  * - Leave sockets open unless there is an error on the socket; calling
    00038  *   progam should ensure all sockets are closed before it quits.
    00039  * - Routines are thread-safe. However, the calling thread must ensure its
    00040  *   socket descriptors are unique or mutexed so that requests and replies
    00041  *   can't overlap.
    00042  * - Routines are layered on top of Dave Kragness's socket wrappers and thus
    00043  *   do no timing themselves. Exceptions to this are wsWaitAscii and
    00044  *   wsWaitBinHeader which need special timing of recv().
    00045  * Pete Lombard, University of Washington Geophysics; 1/4/98
    00046  */
    00047
    00048 #include <stdio.h>
    00049 #include <stdlib.h>
    00050 #include <string.h>
    00051 #include <time.h>
    00052 #include <errno.h>
    00053 #include <earthworm.h>
    00054 #include <ws_clientII.h>
    00055 #include <socket_ew.h>
    00056 #include <time_ew.h>
    00057
    00058 #define WS_MAX_RECV_BUF_LEN 4096
    00059
    00060 static int menu_reqid = 0;
    00061 int WS_CL_DEBUG = 0;
    00062
    00063 extern int recv_all (SOCKET, char FAR*,int,int,int);
    00064
    00065
    00066 /* Protoypes for internal functions */
    00067 static int  wsWaitAscii( WS_MENU, char*, int, int );
    00068 static int  wsWaitBinHeader( WS_MENU, char*, int, int );
    00069 static int  wsParseMenuReply( WS_MENU, char* );
    00070 static int  wsParseBinHeaderReply( TRACE_REQ*, char* );
    00071 static int  wsParseAsciiHeaderReply( TRACE_REQ*, char* );
    00072 static void wsSkipN( char*, int, int* );
    00073 struct timeval FAR * resetTimeout(struct timeval FAR *);
    00074 Time_ew adjustTimeoutLength(int timeout_msec);
    00075
    00076 /**************************************************************************
    00077  *      wsAppendMenu: builds a combined menu from many waveservers.       *
    00078  *      Called with the address and port of one waveserver.               *
    00079  *      On the first call it creates a linked list to store the 'menu'    *
    00080  *      reply from the indicated waveserver.                              *
    00081  *      On subsequent calls, it appends the menu replies to the list.     *
    00082  **************************************************************************/
    00083
    00084 int wsAppendMenu( char* ipAdr, char* port, WS_MENU_QUEUE_REC* menu_queue,
    00085                   int timeout )
    00086      /*
    00087 Arguments:
    00088          ipAdr:  is the dot form of the IP address as a char string.
    00089           port:  TCP port number as a char string.
    00090     menu_queue:  caller-supplied pointer to the list of menus.
    00091        timeout:  timeout interval in milliseconds,
    00092         return:  WS_ERR_NONE:  if all went well.
    00093                  WS_ERR_NO_CONNECTION: if we could not get a connection.
    00094                  WS_ERR_SOCKET: if we could not create a socket.
    00095                  WS_ERR_BROKEN_CONNECTION:  if the connection broke.
    00096                  WS_ERR_TIMEOUT: if a timeout occured.
    00097                  WS_ERR_MEMORY: if out of memory.
    00098                  WS_ERR_INPUT: if bad input parameters.
    00099                  WS_ERR_PARSE: if parser failed.
    00100 */
    00101 {
    00102   int ret, len, err;
    00103   WS_MENU menu = NULL;
    00104   char request[wsREQLEN];
    00105   char* reply = NULL;
    00106
    00107   if ( !ipAdr || !port ||
    00108        (strlen(ipAdr) >= wsADRLEN) || (strlen(port) >= wsADRLEN) )
    00109     {
    00110       ret = WS_ERR_INPUT;
    00111       if (WS_CL_DEBUG) logit("e","wsAppendMenu: bad address: %s port: %s\n",
    00112                              ipAdr, port);
    00113       goto Abort;
    00114     }
    00115
    00116   menu = ( WS_MENU_REC* )calloc(sizeof(WS_MENU_REC),1);
    00117   reply = ( char* )malloc( wsREPLEN );
    00118   if ( !menu || !reply )
    00119     {
    00120       ret = WS_ERR_MEMORY;
    00121       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: memory allocation error\n");
    00122       goto Abort;
    00123     }
    00124
    00125   strcpy( menu->addr, ipAdr );
    00126   strcpy( menu->port, port );
    00127   if ( wsAttachServer( menu, timeout ) != WS_ERR_NONE )
    00128     {
    00129       ret = WS_ERR_NO_CONNECTION;
    00130       goto Abort;
    00131     }
    00132
    00133   sprintf( request, "MENU: %d \n", menu_reqid++ );
    00134   len = strlen(request);
    00135   if ( ( ret =  send_ew( menu->sock, request, len, 0, timeout ) ) != len ) {
    00136     if (ret < 0 )
    00137     {
    00138       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: connection broke to server %s:%s\n",
    00139                              ipAdr, port);
    00140       ret = WS_ERR_BROKEN_CONNECTION;
    00141     } else {
    00142       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: server %s:%s timed out\n",
    00143                              ipAdr, port);
    00144       ret = WS_ERR_TIMEOUT;
    00145     }
    00146     goto Abort;
    00147   }
    00148
    00149   ret = wsWaitAscii( menu, reply, wsREPLEN, timeout );
    00150   if ( ret != WS_ERR_NONE && ret != WS_ERR_BUFFER_OVERFLOW )
    00151     /* we might have received some useful data in spite of the overflow */
    00152     {
    00153       goto Abort;
    00154     }
    00155
    00156   if ( ( err = wsParseMenuReply( menu, reply ) ) != WS_ERR_NONE )
    00157     {
    00158       if ( ret == WS_ERR_BUFFER_OVERFLOW && err == WS_ERR_PARSE )
    00159         {
    00160           if (WS_CL_DEBUG) logit("e", "wsAppendMenu: buffer overflow; parse failure\n");
    00161         }
    00162       else
    00163         {
    00164           ret = err;
    00165         }
    00166       goto Abort;
    00167     }
    00168
    00169   if ( menu->pscn == NULL )
    00170     {
    00171       if (WS_CL_DEBUG) logit("e", "wsAppendMenu: no SCN at server %s:%s\n",
    00172                              menu->addr, menu->port);
    00173       ret = WS_ERR_EMPTY_MENU;
    00174       goto Abort;
    00175     }
    00176
    00177   /* Add the menu to the possibly empty menu queue */
    00178   if ( !menu_queue->head )
    00179     {
    00180       menu_queue->head = menu_queue->tail = menu;
    00181     }
    00182   else
    00183     {
    00184       menu_queue->tail->next = menu;
    00185       menu_queue->tail = menu;
    00186     }
    00187   if ( reply ) free( reply );
    00188   return WS_ERR_NONE;
    00189
    00190 Abort:
    00191   /* An error occured, so clean up the mess */
    00192   wsDetachServer( menu );
    00193   if ( reply ) free( reply );
    00194   if ( menu )
    00195     {
    00196       wsKillPSCN( menu->pscn );
    00197       free( menu );
    00198     }
    00199   return ret;
    00200 }
    00201
    00202
    00203 /**************************************************************************
    00204  * wsKillMenu: Gracefully closes all the server sockets and releases the  *
    00205  *             linked list of menus created by wsAppendMenu               *
    00206  **************************************************************************/
    00207 void wsKillMenu( WS_MENU_QUEUE_REC* menu_queue )
    00208      /*
    00209 Arguments:
    00210     menu_queue:  caller-supplied pointer to the list of menus.
    00211     */
    00212 {
    00213   WS_MENU menu = menu_queue->head;
    00214
    00215   while ( menu )
    00216     {
    00217       WS_MENU next = menu->next;
    00218
    00219       if ( menu->sock != -1 )
    00220         closesocket_ew( menu->sock, SOCKET_CLOSE_GRACEFULLY_EW );
    00221       wsKillPSCN( menu->pscn );
    00222       free( menu );
    00223       menu = next;
    00224     }
    00225   menu_queue->head = menu_queue->tail = NULL;
    00226   menu_reqid = 0;
    00227
    00228   return;
    00229 }
    00230
    00231
    00232 /*********************************************************************
    00233  * wsGetTraceBin: retrieves the piece of raw trace data specified in *
    00234  * the structure 'getThis': The current menu list, as built by the   *
    00235  * routines above will be searched for a matching SCN. If a match    *
    00236  * is found, the associated wave server will be contacted, and a     *
    00237  * request for the trace snippet will be made.                       *
    00238  *********************************************************************/
    00239 int wsGetTraceBin( TRACE_REQ* getThis, WS_MENU_QUEUE_REC* menu_queue,
    00240                    int timeout )
    00241      /*
    00242 Arguments:
    00243         getThis:   a TRACE_REQ structure (see ws_client.h), with the
    00244                    request portion filled in.
    00245      menu_queue:   pointer to the list of server menus.
    00246         timeout:   Time in milliseconds to wait for reply
    00247          return:   WS_ERR_NONE: all went well.
    00248                    WS_WRN_FLAGGED: wave server returned error flag instead
    00249                       of trace data.
    00250                    WS_ERR_EMPTY_MENU: No menu list found.
    00251                    WS_ERR_SCN_NOT_IN_MENU: SCN not found in menu list.
    00252                    WS_ERR_NO_CONNECTION: if socket was already closed
    00253           The socket will be closed for the following:
    00254                    WS_ERR_BUFFER_OVERFLOW: trace buffer supplied too small.
    00255                    WS_ERR_TIMEOUT: if a timeout occured
    00256                    WS_ERR_BROKEN_CONNECTION: if a connection broke.
    00257                    WS_ERR_SOCKET: problem changing socket options.
    00258      */
    00259 {
    00260   int ret, len, err = WS_ERR_NONE;
    00261   WS_MENU menu = NULL;
    00262   WS_PSCN pscn = NULL;
    00263   char request[wsREQLEN];
    00264
    00265   if ( menu_queue->head == NULL )
    00266     {
    00267       if (WS_CL_DEBUG) logit("e", "wsGetTraceBin: empty menu\n");
    00268       return WS_ERR_EMPTY_MENU;
    00269     }
    00270
    00271  next_menu:
    00272   if ( ( ret = wsSearchSCN( getThis, &menu, &pscn, menu_queue )) != WS_ERR_NONE )
    00273     {
    00274       if (err != WS_ERR_NONE)
    00275         return err;
    00276       else
    00277         return ret;  /* WS_ERR_SCN_NOT_IN_MENU */
    00278     }
    00279
    00280   if (menu->sock < 0)
    00281     {
    00282       if (WS_CL_DEBUG) logit("e", "wsGetTraceBin: no socket for %s:%s\n",
    00283                              menu->addr, menu->port );
    00284       return WS_ERR_NO_CONNECTION;
    00285     }
    00286
    00287   sprintf( request, "GETSCNRAW: %d %s %s %s %lf %lf\n",
    00288            menu_reqid++, pscn->sta, pscn->chan, pscn->net,
    00289            getThis->reqStarttime, getThis->reqEndtime );
    00290
    00291   len = strlen(request);
    00292   if ( (ret = send_ew( menu->sock, request, len, 0, timeout )) != len )
    00293     {
    00294       if (ret < 0 )
    00295         {
    00296           ret = WS_ERR_BROKEN_CONNECTION;
    00297         } else {
    00298           ret = WS_ERR_TIMEOUT;
    00299         }
    00300       goto Abort;
    00301     }
    00302
    00303   ret = wsWaitBinHeader( menu, getThis->pBuf, getThis->bufLen, timeout );
    00304   switch (ret) {
    00305   case WS_ERR_INPUT:
    00306     return ret;
    00307     break;
    00308   case WS_ERR_NONE:
    00309     break;
    00310   default:
    00311     /* buffer overflow, timeout, socket error, or broken connection */
    00312       goto Abort;
    00313   }
    00314
    00315   err = wsParseBinHeaderReply( getThis, getThis->pBuf );
    00316   switch (err) {
    00317   case WS_ERR_INPUT:
    00318   case WS_WRN_FLAGGED:  /* no trace data to get */
    00319     goto next_menu;
    00320     break;
    00321   case WS_ERR_PARSE:  /* can't get pending trace data, so close socket */
    00322     /* DK 03192002 setting ret due to bug reported by Ilya Dricker */
    00323     if(ret == WS_ERR_NONE)
    00324       ret = err;
    00325     /* end DK 0319 change */
    00326     goto Abort;
    00327     break;
    00328   default:  /* no error, so continue */
    00329     break;
    00330   }
    00331
    00332   if ( getThis->actLen )
    00333     {
    00334       long int binLen = getThis->actLen;
    00335
    00336       if ( (int)getThis->bufLen < binLen )
    00337         binLen = (int)getThis->bufLen;
    00338       ret = recv_all( menu->sock, getThis->pBuf, binLen, 0, timeout );
    00339
    00340       if ( ret != binLen )
    00341         {
    00342           if ( ret < 0 )
    00343             {
    00344               ret = WS_ERR_BROKEN_CONNECTION;
    00345             }
    00346           else
    00347             {
    00348               ret = WS_ERR_TIMEOUT;
    00349             }
    00350           goto Abort;
    00351         }
    00352
    00353       if ( binLen < getThis->actLen )
    00354         {
    00355           getThis->actLen = binLen;
    00356           ret = WS_ERR_BUFFER_OVERFLOW;
    00357           if (WS_CL_DEBUG) logit ( "e", "wsGetTraceBin(): buffer full, trace truncated\n" );
    00358           goto Abort;
    00359         }
    00360     }
    00361   return WS_ERR_NONE;
    00362
    00363 Abort:
    00364   wsDetachServer( menu );
    00365   if (WS_CL_DEBUG)
    00366     {
    00367       if  ( ret == WS_ERR_TIMEOUT ) {
    00368         logit( "e","wsGetTraceBin(): server %s:%s timed out\n", menu->addr,
    00369                menu->sock );
    00370       } else if ( ret == WS_ERR_BROKEN_CONNECTION ) {
    00371         logit( "e","wsGetTraceBin(): broken connection to server %s:%s\n",
    00372                menu->addr, menu->port);
    00373       }
    00374     }
    00375
    00376   return ret;
    00377 }
    00378
    00379 /**************************************************************************
    00380  *      wsGetTraceAscii: retrieves the ascii trace data specified in      *
    00381  *      the structure 'getThis': The current menu list, as buit by the    *
    00382  *      routines above will be searched for a matching SCN. If a match    *
    00383  *      is found, the associated wave server will be contacted, and a     *
    00384  *      request for the trace snippet will be made.                       *
    00385  **************************************************************************/
    00386
    00387 int wsGetTraceAscii( TRACE_REQ* getThis, WS_MENU_QUEUE_REC* menu_queue,
    00388                      int timeout )
    00389      /*
    00390 Arguments:
    00391         getThis:   a TRACE_REQ structure (see ws_client.h), with the
    00392                    request portion filled in.
    00393      menu_queue:   pointer to list of menues.
    00394         timeout:   timeout interval in milliseconds.
    00395         return:    WS_ERR_NONE: all went well.
    00396                    WS_ERR_EMPTY_MENU: No menu list found.
    00397                    WS_ERR_SCN_NOT_IN_MENU: SCN not found in menu list.
    00398                    WS_ERR_BUFFER_OVERFLOW: buffer too small for reply
    00399                    WS_ERR_BROKEN_CONNECTION: couldn't talk to server
    00400                    WS_ERR_TIMEOUT: if a timeout occured
    00401                    WS_ERR_NO_CONNECTION: There was no connection for the server
    00402                    WS_WRN_FLAGGED: wave server returned flag warning.
    00403                      the flag character is in the TRACE_REQ structure.
    00404                      */
    00405 {
    00406   int ret, len, err;
    00407   WS_MENU menu = NULL;
    00408   WS_PSCN pscn = NULL;
    00409   char request[wsREQLEN];
    00410   double expire = (double) 0.0;
    00411
    00412   if ( menu_queue->head == NULL )
    00413     {
    00414       if (WS_CL_DEBUG) logit("e", "wsGetTraceAscii: empty menu\n");
    00415       return WS_ERR_EMPTY_MENU;
    00416     }
    00417
    00418   if ( (ret = wsSearchSCN( getThis, &menu, &pscn, menu_queue  )) != WS_ERR_NONE )
    00419     {
    00420       return ret; /* WS_ERR_SCN_NOT_IN_MENU */
    00421     }
    00422
    00423   if ( menu->sock < 0 )
    00424     {
    00425       if (WS_CL_DEBUG) logit("e", "wsGetTraceAscii: no socket for %s:%s\n",
    00426                              menu->addr, menu->port );
    00427       return WS_ERR_NO_CONNECTION;
    00428     }
    00429
    00430   sprintf( request, "GETSCN: %d %s %s %s %lf %lf %d\n",
    00431            menu_reqid++, pscn->sta, pscn->chan, pscn->net,
    00432            getThis->reqStarttime, getThis->reqEndtime, getThis->fill );
    00433   len = strlen( request );
    00434
    00435   if ( ( ret = send_ew( menu->sock, request, len, 0, timeout )) != len )
    00436     {
    00437       if (ret < 0 )
    00438         {
    00439           if (WS_CL_DEBUG)
    00440             logit("e", "wsGetTraceAscii: connection broke to server %s:%s\n",
    00441                   menu->addr, menu->port );
    00442           ret = WS_ERR_BROKEN_CONNECTION;
    00443         } else {
    00444           if (WS_CL_DEBUG)
    00445             logit("e", "wsGetTraceAscii: server %s:%s timed out\n",
    00446                   menu->addr, menu->port );
    00447           ret = WS_ERR_TIMEOUT;
    00448         }
    00449       goto Abort;
    00450     }
    00451
    00452   ret = wsWaitAscii( menu, getThis->pBuf, getThis->bufLen, timeout );
    00453   if ( ret != WS_ERR_NONE && ret != WS_ERR_BUFFER_OVERFLOW )
    00454     {
    00455       goto Abort;
    00456     }
    00457   else
    00458     {
    00459     err = wsParseAsciiHeaderReply( getThis, getThis->pBuf );
    00460     if ( err < WS_ERR_NONE )
    00461         {
    00462           if ( ( ret == WS_ERR_BUFFER_OVERFLOW ) && WS_CL_DEBUG )
    00463             logit ( "e", "wsGetTraceAscii(): buffer overflow; parse error\n" );
    00464           return err;
    00465         }
    00466     }
    00467   /* wsParseAsciiReply puts the trace data into getThis, so now we're done */
    00468   return WS_ERR_NONE;
    00469
    00470 Abort:
    00471   wsDetachServer( menu );
    00472   return ret;
    00473 }
    00474
    00475 /*******************************************
    00476  *  wsKillPSCN: Deallocates the PSCN list  *
    00477  *******************************************/
    00478 void wsKillPSCN( WS_PSCN pscn )
    00479      /*
    00480 Arguments:
    00481        pscn: pointer to a list of scn structures
    00482        */
    00483 {
    00484   while ( pscn )
    00485     {
    00486       WS_PSCN next = pscn->next;
    00487
    00488       free( pscn );
    00489       pscn = next;
    00490     }
    00491   return;
    00492 }
    00493
    00494 /*****************************************************************************
    00495  * wsGetServerPSCN: Return the pscn list for this server from the menu queue *
    00496  *****************************************************************************/
    00497 int wsGetServerPSCN( char* addr, char* port, WS_PSCN* pscnp,
    00498                      WS_MENU_QUEUE_REC* menu_queue )
    00499      /*
    00500 Arguments:
    00501        addr: IP address of the server
    00502        port: port number of the server
    00503       pscnp: pointer to the pscn list to be returned
    00504  menu_queue: pointer to list of menus.
    00505      return: WS_ERR_NONE: all went well
    00506              WS_ERR_EMPTY_MENU: no menu in the queue
    00507              WS_ERR_SERVER_NOT_IN_MENU: server's menu not in the queue
    00508              */
    00509 {
    00510   int ret = menu_queue->head ? WS_ERR_SERVER_NOT_IN_MENU : WS_ERR_EMPTY_MENU;
    00511   WS_MENU menu = menu_queue->head;
    00512
    00513   *pscnp = NULL;
    00514   while ( menu )
    00515     {
    00516       if ( strcmp( addr, menu->addr ) == 0 &&
    00517            strcmp( port, menu->port ) == 0 )
    00518         {
    00519           ret = WS_ERR_NONE;
    00520           *pscnp = menu->pscn;
    00521           break;
    00522         }
    00523       menu = menu->next;
    00524     }
    00525
    00526     if (WS_CL_DEBUG)
    00527       {
    00528         if ( ret == WS_ERR_SERVER_NOT_IN_MENU )
    00529           logit( "e","wsGetServerPSCN(): WS_ERR_SERVER_NOT_IN_MENU\n" );
    00530         else if ( ret == WS_ERR_EMPTY_MENU )
    00531           logit( "e","wsGetServerPSCN(): WS_ERR_EMPTY_MENU\n" );
    00532       }
    00533
    00534   return ret;
    00535 }
    00536
    00537
    00538 /***********************************************************************
    00539  * wsSearchSCN: Find menu and PSCN in queue which will serve this scn  *
    00540  *              If menup points to a menu in the menu_queue, search    *
    00541  *              starts at the next menu after *menup; otherwise,       *
    00542  *              search starts at menu_queue->head.                     *
    00543  *              If the SCN is listed more than once in the queue, only *
    00544  *              the first menu and PSCN will be returned.              *
    00545  ***********************************************************************/
    00546 int wsSearchSCN( TRACE_REQ* getThis, WS_MENU* menup, WS_PSCN* pscnp,
    00547                         WS_MENU_QUEUE_REC* menu_queue )
    00548      /*
    00549 Arguments:
    00550       getThis: a TRACE_REQ structure with the SCN to search for.
    00551         menup: pointer to the menu to return.
    00552         pscnp: pointer to the pscn list to return.
    00553       returns: WS_ERR_NONE: if all went well
    00554                WS_ERR_EMPTY_MENU: no menus in the queue
    00555                WS_ERR_SERVER_NOT_IN_MENU: scn not in the queue
    00556                */
    00557 {
    00558   int ret;
    00559   WS_MENU menu;
    00560
    00561   if ( *menup != NULL)
    00562     menu = (*menup)->next;
    00563   else
    00564     menu  = menu_queue->head;
    00565   ret = menu ? WS_ERR_SCN_NOT_IN_MENU : WS_ERR_EMPTY_MENU;
    00566   *pscnp = NULL;
    00567
    00568   while ( menu )
    00569     {
    00570       WS_PSCN pscn = menu->pscn;
    00571       while ( pscn )
    00572         {
    00573           if ( strcmp( getThis->sta, pscn->sta ) == 0 &&
    00574                strcmp( getThis->chan, pscn->chan ) == 0 &&
    00575                strcmp( getThis->net, pscn->net ) == 0 )
    00576             {
    00577               ret = WS_ERR_NONE;
    00578               *menup = menu;
    00579               *pscnp = pscn;
    00580               goto exit;
    00581             }
    00582           pscn = pscn->next;
    00583         }
    00584       menu = menu->next;
    00585     }
    00586
    00587  exit:
    00588   if (WS_CL_DEBUG)
    00589     {
    00590       if ( ret == WS_ERR_SCN_NOT_IN_MENU )
    00591         logit( "e","wsSearchSCN(): WS_ERR_SCN_NOT_IN_MENU\n" );
    00592       else if ( ret == WS_ERR_EMPTY_MENU )
    00593         logit( "e","wsSearchSCN(): WS_ERR_EMPTY_MENU\n" );
    00594     }
    00595
    00596   return ret;
    00597 }
    00598
    00599 /***********************************************************************
    00600  *  wsAttachServer: Open a connection to a server. The timeout starts  *
    00601  *    when connect() is called by connect_ew() in socket_ew_common.c   *
    00602  ***********************************************************************/
    00603 int wsAttachServer( WS_MENU menu, int timeout )
    00604      /*
    00605 Arguemnts:
    00606        menu: pointer to the menu of the server
    00607     timeout: time interval in milliseconds; use -1 for no timeout.
    00608     returns: WS_ERR_NONE: if all went well.
    00609              WS_ERR_INPUT: if menu is missing.
    00610              WS_ERR_SOCKET: if a socket error occurred.
    00611              WS_ERR_NO_CONNECTION: if a connection could not be established
    00612              */
    00613 {
    00614   int                ret = WS_ERR_NONE;
    00615   int                sock = 0;   /* Socket descriptor                  */
    00616   struct sockaddr_in s_in ;      /* Server's socket address stucture   */
    00617
    00618   if ( !menu )
    00619     {
    00620       ret = WS_ERR_INPUT;
    00621       if (WS_CL_DEBUG) logit( "e", "wsAttachServer(): WS_ERR_INPUT\n");
    00622       goto Abort;
    00623     }
    00624   if ( menu->sock > 0 )  /* maybe already connected, so disconnect first */
    00625     {
    00626       wsDetachServer( menu );
    00627     }
    00628
    00629   /* open a non_blocking socket
    00630   *****************************/
    00631   if ( ( sock = socket_ew( AF_INET, SOCK_STREAM, 0 ) ) == -1 )
    00632     {
    00633       ret = WS_ERR_SOCKET;
    00634       if (WS_CL_DEBUG)
    00635         logit( "e", "wsAttachServer(): socket_ew() call failed\n" );
    00636       goto Abort;
    00637     }
    00638
    00639   /* Stuff address and port into socket structure
    00640   ********************************************/
    00641   memset( (char *)&s_in, '\0', sizeof(s_in) );
    00642   s_in.sin_family = AF_INET;
    00643   s_in.sin_port   = htons( (short)atoi(menu->port) );
    00644
    00645 #ifdef _LINUX
    00646   if ((int)(s_in.sin_addr.s_addr = inet_addr(menu->addr)) == -1)
    00647 #else
    00648   if ((int)(s_in.sin_addr.S_un.S_addr = inet_addr(menu->addr)) == -1)
    00649 #endif
    00650     {
    00651       ret = WS_ERR_NO_CONNECTION;
    00652       if (WS_CL_DEBUG)
    00653         logit( "e", "wsAttachServer(): inet_addr failed on <%s>\n",
    00654                menu->addr );
    00655       goto Abort;
    00656     }
    00657
    00658   if ( connect_ew( sock, (struct sockaddr *)&s_in, sizeof(s_in), timeout) == -1 )
    00659     {
    00660       ret = WS_ERR_NO_CONNECTION;
    00661       if (WS_CL_DEBUG)
    00662         logit( "e", "wsAttachServer(): connect() call failed\n" );
    00663       goto Abort;
    00664     }
    00665   menu->sock = sock;
    00666
    00667   ret = WS_ERR_NONE;
    00668   return ret;
    00669
    00670   /* An error occured;
    00671    * don't blab about here since we already did earlier. */
    00672 Abort:
    00673   menu->sock = -1; /* mark the socket as dead */
    00674   return ret;
    00675 }
    00676
    00677
    00678 /*********************************************************************
    00679  * wsDetachServer: Immediately disconnect from a socket if it's open *
    00680  *********************************************************************/
    00681 void wsDetachServer( WS_MENU menu )
    00682      /*
    00683 Arguments:
    00684            menu: menu of server to be detached
    00685       */
    00686 {
    00687   if ( !menu || menu->sock == -1 )
    00688     return;
    00689   closesocket_ew( menu->sock, SOCKET_CLOSE_IMMEDIATELY_EW );
    00690   menu->sock = -1;
    00691 }
    00692
    00693
    00694 /*********************************************************************
    00695  * wsWaitBinHeader: Retrieve the ASCII header of a binary message.   *
    00696  * The header will be terminated by a newline, but binary characters *
    00697  * will follow in the same message. Thus this routine must read one  *
    00698  * character at a time. Since the header is relatively short, this   *
    00699  * should not be much a performance hit.                             *
    00700  * Returns after newline is read, when timeout expires if set,       *
    00701  * or on error.                                                      *
    00702  *********************************************************************/
    00703 static int wsWaitBinHeader( WS_MENU menu, char* buf, int buflen,
    00704                             int timeout_msec )
    00705      /*
    00706 Arguments:
    00707            menu: menu of server from which message is received
    00708             buf: buffer in which to place the message, terminated by null.
    00709          buflen: number of bytes in the buffer.
    00710    timeout_msec: timout interval in milliseconds.
    00711          return: WS_ERR_NONE: all went well.
    00712                  WS_ERR_BUFFER_OVERFLOW: ran out of space before the message
    00713                   end; calling program will have to decide how serious this is.
    00714                  WS_ERR_INPUT: missing input parameters.
    00715                  WS_ERR_SOCKET: error setting socket options.
    00716                  WS_ERR_TIMEOUT: time expired before we read everything.
    00717                  WS_ERR_BROKEN_CONNECTION: if the connection failed.
    00718                  */
    00719 {
    00720   int ir = 0;
    00721   int nr = 0;
    00722   char c = '\0';
    00723   int ret, ioctl_ret;
    00724   fd_set ReadableSockets;
    00725   Time_ew StartTime;
    00726   struct timeval SelectTimeout;
    00727   Time_ew timeout = adjustTimeoutLength(timeout_msec);
    00728   long lOnOff;
    00729
    00730   if ( !buf || buflen <= 0 )
    00731     {
    00732       if (WS_CL_DEBUG) logit( "e", "wsWaitBinHeader(): no input buffer\n");
    00733       return WS_ERR_INPUT;
    00734     }
    00735
    00736   /* If there is no timeout, make the socket blocking */
    00737   if (timeout_msec == -1)
    00738     {
    00739       timeout = 0;
    00740       lOnOff = 0;
    00741       ioctl_ret = ioctlsocket(menu->sock, FIONBIO, &lOnOff);
    00742       if (ioctl_ret == SOCKET_ERROR)
    00743         {
    00744           ret = WS_ERR_SOCKET;
    00745           if (WS_CL_DEBUG)
    00746             logit("et", "wsWaitBinHeader: error %s occurred during change to blocking\n",
    00747                 socketGetError_ew());
    00748           goto Done;
    00749         }
    00750     }
    00751
    00752   StartTime = GetTime_ew(); /* the timer starts here */
    00753   /* Start reading the socket, one character at a time */
    00754   while ( c != '\n' )
    00755     {
    00756       if ((timeout) && (GetTime_ew() - timeout) > StartTime )
    00757         {
    00758           ret = WS_ERR_TIMEOUT;
    00759           if (WS_CL_DEBUG) logit("et", "wsWaitBinHeader timed out\n");
    00760           goto Done;
    00761         }
    00762       if ( ir == buflen - 1 )
    00763         {
    00764           /* stop if there's no more room  */
    00765           if (WS_CL_DEBUG)
    00766             logit( "e", "wsWaitBinHeader(): reply buffer overflows\n" );
    00767           ret = WS_ERR_BUFFER_OVERFLOW;
    00768           goto Done;
    00769         }
    00770
    00771       /* try to get a char from socket */
    00772       nr = recv( menu->sock, &c, 1, 0 );
    00773       if ( nr == -1 && socketGetError_ew() == WOULDBLOCK_EW )
    00774         {
    00775           FD_ZERO( &ReadableSockets );
    00776           FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
    00777           while (( !select(menu->sock + 1, &ReadableSockets, 0, 0,
    00778                            resetTimeout( &SelectTimeout))))
    00779             {
    00780               if ((timeout) && (GetTime_ew() - timeout) > StartTime )
    00781                 {
    00782                   ret = WS_ERR_TIMEOUT;
    00783                   if (WS_CL_DEBUG) logit("et", "wsWaitBinHeader timed out\n");
    00784                   goto Done;
    00785                 }
    00786               FD_ZERO( &ReadableSockets );
    00787               FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
    00788               sleep_ew(100); /* wait a little and try again */
    00789             }
    00790           /* select() says won't block */
    00791           nr = recv( menu->sock, &c, 1, 0 );
    00792         }
    00793       if ( nr == 1 && c != 0 )
    00794         {
    00795           /* got a character; save it      */
    00796           buf[ir++] = c;
    00797         }
    00798       else if ( nr == -1 )
    00799         {
    00800           /* trouble reading socket        */
    00801           ret = WS_ERR_BROKEN_CONNECTION;
    00802           if (WS_CL_DEBUG)
    00803             logit( "e", "wsWaitBinHeader(): Error on socket recv()\n" );
    00804           goto Done;
    00805         }
    00806     }
    00807   buf[ir] = '\0';                   /* null-terminate the buf      */
    00808
    00809   ret = WS_ERR_NONE;
    00810
    00811 Done:
    00812   buf[ir] = '\0';                 /* null-terminate the buf      */
    00813   /* If there was no timeout, then change the socket back to non-blocking */
    00814   if (timeout_msec == -1)
    00815     {
    00816       lOnOff = 1;
    00817       ioctl_ret = ioctlsocket( menu->sock, FIONBIO, &lOnOff);
    00818       if (ioctl_ret == SOCKET_ERROR)
    00819         {
    00820
    00821           if (WS_CL_DEBUG)
    00822             logit("et","wsWaitBinHeader: error %s occurred during change to non-blocking\n",
    00823               socketGetError_ew() );
    00824           ret = WS_ERR_SOCKET;
    00825         }
    00826     }
    00827   return ret;
    00828 }
    00829
    00830
    00831 /*******************************************************************
    00832  * wsWaitAscii: Retrieve an ASCII message.                         *
    00833  * The message will be terminated by a newline; nothing else is    *
    00834  * expected after the newline, so we can read several characters   *
    00835  * at a time without fear of reading past the newline.             *
    00836  * This message may have internal nulls which will be converted to *
    00837  * spaces.                                                         *
    00838  * Returns after newline is read, when timeout expires if set,     *
    00839  * or on error.                                                    *
    00840  *******************************************************************/
    00841 static int wsWaitAscii( WS_MENU menu, char* buf, int buflen, int timeout_msec )
    00842      /*
    00843 Arguments:
    00844            menu: menu of server from which message is received
    00845             buf: buffer in which to place the message, terminated by null.
    00846          buflen: number of bytes in the buffer.
    00847    timeout_msec: timout interval in milliseconds.
    00848          return: WS_ERR_NONE: all went well.
    00849                  WS_ERR_BUFFER_OVERFLOW: ran out of space before the message
    00850                   end; calling program will have to decide how serious this is.
    00851                  WS_ERR_INPUT: missing input parameters.
    00852                  WS_ERR_SOCKET: error setting socket options.
    00853                  WS_ERR_TIMEOUT: time expired before we read everything.
    00854                  WS_ERR_BROKEN_CONNECTION: if the connection failed.
    00855                  */
    00856 {
    00857   int ii, ir = 0;  /* character counters */
    00858   int nr = 0;
    00859   char c = '\0';
    00860   int len = 0;
    00861   int ret, ioctl_ret;
    00862   fd_set ReadableSockets;
    00863   Time_ew StartTime;
    00864   struct timeval SelectTimeout;
    00865   Time_ew timeout = adjustTimeoutLength(timeout_msec);
    00866   long lOnOff;
    00867
    00868   if ( !buf || buflen <= 0 )
    00869     {
    00870       if (WS_CL_DEBUG) logit( "e", "wsWaitAscii(): no input buffer\n");
    00871       return WS_ERR_INPUT;
    00872     }
    00873
    00874   /* If there is no timeout, make the socket blocking */
    00875   if (timeout_msec == -1)
    00876     {
    00877       timeout = 0;
    00878       lOnOff = 0;
    00879       ioctl_ret = ioctlsocket(menu->sock, FIONBIO, &lOnOff);
    00880       if (ioctl_ret == SOCKET_ERROR)
    00881         {
    00882           ret = WS_ERR_SOCKET;
    00883           if (WS_CL_DEBUG) logit("et",
    00884                 "wsWaitAscii: error %s occurred during change to blocking\n",
    00885                                  socketGetError_ew());
    00886         goto Done;
    00887         }
    00888     }
    00889
    00890   StartTime = GetTime_ew(); /* the timer starts here */
    00891   while ( c != '\n' )
    00892     {
    00893       if ((timeout) && (GetTime_ew() - timeout) > StartTime )
    00894         {
    00895           ret = WS_ERR_TIMEOUT;
    00896           if (WS_CL_DEBUG) logit("et", "wsWaitAscii timed out\n");
    00897           goto Done;
    00898         }
    00899       if ( ir >= buflen - 2 )
    00900         {
    00901           if (WS_CL_DEBUG)
    00902             logit( "e", "wsWaitAscii(): reply buffer overflows\n" );
    00903           ret = WS_ERR_BUFFER_OVERFLOW;
    00904           goto Done;
    00905         }
    00906       len = WS_MAX_RECV_BUF_LEN;
    00907       if ( ir + len >= buflen - 1 )
    00908         len = buflen - ir - 2; /* leave room for the terminating null */
    00909       nr = recv( menu->sock, &buf[ir], len, 0 );
    00910       if ( nr == -1 && socketGetError_ew() == WOULDBLOCK_EW )
    00911         {
    00912           FD_ZERO( &ReadableSockets );
    00913           FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
    00914           while (( !select(menu->sock + 1, &ReadableSockets, 0, 0,
    00915                            resetTimeout( &SelectTimeout))))
    00916             {
    00917               if ((timeout) && (GetTime_ew() - timeout) > StartTime )
    00918                 {
    00919                   ret = WS_ERR_TIMEOUT;
    00920                   if (WS_CL_DEBUG) logit("et", "wsWaitAscii timed out\n");
    00921                   goto Done;
    00922                 }
    00923               FD_ZERO( &ReadableSockets );
    00924               FD_SET( (SOCKET)(menu->sock), &ReadableSockets );
    00925               sleep_ew(100); /* wait a little and try again */
    00926             }
    00927           /* poll() says won't block */
    00928           nr = recv( menu->sock, &buf[ir], len, 0 );
    00929         }
    00930
    00931       if ( nr == -1 || nr > len )
    00932         {
    00933           /* trouble reading socket        */
    00934           ret = WS_ERR_BROKEN_CONNECTION;
    00935           if (WS_CL_DEBUG) logit( "e", "wsWaitAscii(): Error on socket recv()\n" );
    00936           goto Done;
    00937         }
    00938       if ( nr > 0 )
    00939         {
    00940           ii = 0;
    00941           /* got something, adjust ir and c  */
    00942           ir += nr;
    00943           c = buf[ir-1];
    00944
    00945           /* replace NULL char in ascii string with SPACE char */
    00946           while ( ii < nr )
    00947             {
    00948               if ( !buf[ir-nr+ii] ) buf[ir-nr+ii] = ' ';
    00949               ++ii;
    00950             }
    00951         }
    00952     }
    00953
    00954   ret = WS_ERR_NONE;
    00955 Done:
    00956   buf[ir] = '\0';                 /* null-terminate the reply      */
    00957   /* If there was no timeout, then change the socket back to non-blocking */
    00958   if (timeout_msec == -1)
    00959     {
    00960       lOnOff = 1;
    00961       ioctl_ret = ioctlsocket( menu->sock, FIONBIO, &lOnOff);
    00962       if (ioctl_ret == SOCKET_ERROR)
    00963         {
    00964
    00965           if (WS_CL_DEBUG) logit("et", "wsWaitAScii: error %s occurred during change to non-blocking\n",
    00966                                  socketGetError_ew() );
    00967           ret = WS_ERR_SOCKET;
    00968         }
    00969     }
    00970   return ret;
    00971 }
    00972
    00973 /***********************************************************************
    00974  * wsParseMenuReply: parse the reply we got from the waveserver into   *
    00975  * a menu list. Handles replies to MENU, MENUPIN and MENUSCN requests. *
    00976  ***********************************************************************/
    00977 static int wsParseMenuReply( WS_MENU menu, char* reply )
    00978 {
    00979   /* Arguments:
    00980    *       menu: pointer to menu structure to be allocated and filled in.
    00981    *      reply: pointer to reply to be parsed.
    00982    *   Returns: WS_ERR_NONE:  if all went well
    00983    *            WS_ERR_INPUT: if bad input parameters
    00984    *            WS_ERR_PARSE: if we couldn't parse the reply
    00985    *            WS_ERR_MEMORY: if out of memory
    00986    */
    00987   int reqid = 0;
    00988   int pinno = 0;
    00989   char sta[7];
    00990   char chan[9];
    00991   char net[9];
    00992   double tankStarttime = 0.0, tankEndtime = 0.0;
    00993   char datatype[3];
    00994   int scn_pos = 0;
    00995
    00996   if ( !reply || !menu )
    00997     {
    00998       if (WS_CL_DEBUG) logit("e", "wsParseMenuReply: WS_ERR_INPUT\n");
    00999       return WS_ERR_INPUT;
    01000     }
    01001
    01002   if ( sscanf( &reply[scn_pos], "%d", &reqid ) < 1 )
    01003     {
    01004       if (WS_CL_DEBUG)
    01005         logit( "e","wsParseMenuReply(): error parsing reqid\n" );
    01006       return WS_ERR_PARSE;
    01007     }
    01008   wsSkipN( reply, 1, &scn_pos );
    01009   while ( reply[scn_pos] && reply[scn_pos] != '\n' )
    01010     {
    01011       WS_PSCN pscn = NULL;
    01012       if ( sscanf( &reply[scn_pos], "%d %s %s %s %lf %lf %s",
    01013                    &pinno, sta, chan, net,
    01014                    &tankStarttime, &tankEndtime, datatype ) < 7 )
    01015         {
    01016           if (WS_CL_DEBUG)
    01017             logit( "e","wsParseMenuReply(): error decoding reply<%s>\n",
    01018                  &reply[scn_pos] );
    01019           return WS_ERR_PARSE;
    01020         }
    01021       pscn = ( WS_PSCN_REC* )calloc(sizeof(WS_PSCN_REC),1);
    01022       if ( !pscn )
    01023         {
    01024           if (WS_CL_DEBUG)
    01025             logit("e", "wsParseMenuReply(): error allocating memory\n");
    01026           return WS_ERR_MEMORY;
    01027         }
    01028
    01029       pscn->next = menu->pscn;
    01030       pscn->pinno = pinno;
    01031       strcpy( pscn->sta, sta );
    01032       strcpy( pscn->chan, chan );
    01033       strcpy( pscn->net, net );
    01034       pscn->tankStarttime = tankStarttime;
    01035       pscn->tankEndtime = tankEndtime;
    01036       menu->pscn = pscn;
    01037       wsSkipN( reply, 7, &scn_pos );
    01038     }
    01039
    01040   return WS_ERR_NONE;
    01041 }
    01042
    01043 /***********************************************************************
    01044  * wsParseBinHeaderReply: parse the reply we got from the waveserver   *
    01045  * into a TRACE_REQ structure. Handles the header for replies reply to *
    01046  * GETSCNRAW requests.                                                 *
    01047  ***********************************************************************/
    01048 static int wsParseBinHeaderReply( TRACE_REQ* getThis, char* reply )
    01049 {
    01050   /* Arguments:
    01051    *    getThis: pointer to TRACE_REQ structure to be filled with reply info
    01052    *      reply: pointer to reply to be parsed.
    01053    *   Returns: WS_ERR_NONE:  if all went well
    01054    *            WS_ERR_INPUT: if bad input parameters
    01055    *            WS_ERR_PARSE: if we couldn't parse part of the reply
    01056    *            WS_WRN_FLAGGED: server sent us a no-data flag
    01057    */
    01058   int reqid = 0;
    01059   int pinno = 0;
    01060   char sta[7];
    01061   char chan[9];
    01062   char net[9];
    01063   char flag[9];
    01064   char datatype[3];
    01065   double tankStarttime = 0.0, tankEndtime = 0.0;
    01066   int bin_len = 0;
    01067   int scn_pos = 0;
    01068   char *buf = NULL;
    01069
    01070   if ( !reply || !getThis )
    01071     {
    01072       if (WS_CL_DEBUG)
    01073         logit( "e", "wsParseBinHeaderReply(): bad input parameters\n");
    01074       return WS_ERR_INPUT;
    01075     }
    01076
    01077   if ( sscanf( &reply[scn_pos], "%d %d", &reqid, &pinno ) < 2 )
    01078     {
    01079       if (WS_CL_DEBUG)
    01080         logit( "e","wsParseBinHeaderReply(): error parsing reqid/pinno\n" );
    01081       return WS_ERR_PARSE;
    01082     }
    01083   wsSkipN( reply, 2, &scn_pos );
    01084
    01085   if ( sscanf( &reply[scn_pos], "%s %s %s", sta, chan, net ) < 3 )
    01086     {
    01087       if (WS_CL_DEBUG) logit( "e","wsParseBinHeaderReply(): error parsing SCN\n" );
    01088       return WS_ERR_PARSE;
    01089     }
    01090   wsSkipN( reply, 3, &scn_pos );
    01091
    01092   if ( sscanf( &reply[scn_pos], "%s %s", flag, datatype ) < 2 )
    01093     {
    01094       if (WS_CL_DEBUG)
    01095         logit( "e","wsParseBinHeaderReply(): error parsing flag/datatype\n" );
    01096       return WS_ERR_PARSE;
    01097     }
    01098   wsSkipN( reply, 2, &scn_pos );
    01099
    01100   if ( strlen(flag) == 1 )
    01101     {
    01102       if ( sscanf( &reply[scn_pos], "%lf %lf", &tankStarttime,
    01103                    &tankEndtime ) < 2 )
    01104         {
    01105           if (WS_CL_DEBUG)
    01106             logit( "e","wsParseBinHeaderReply(): error parsing starttime/endtime\n" );
    01107           return WS_ERR_PARSE;
    01108         }
    01109       wsSkipN( reply, 2, &scn_pos );
    01110
    01111       if ( sscanf( &reply[scn_pos], "%d", &bin_len ) < 1 )
    01112         {
    01113           if (WS_CL_DEBUG)
    01114             logit( "e","wsParseBinHeaderReply(): error parsing bin_len\n" );
    01115           return WS_ERR_PARSE;
    01116         }
    01117       wsSkipN( reply, 1, &scn_pos );
    01118
    01119     }
    01120   else if ( strlen(flag) == 2 )
    01121     {
    01122       tankStarttime = 0.0;
    01123       tankEndtime = 0.0;
    01124       bin_len = 0;
    01125       if ( strcmp(flag,"FL") == 0 )
    01126         {
    01127           if ( sscanf( &reply[scn_pos], "%lf", &tankStarttime) < 1 )
    01128             {
    01129               if (WS_CL_DEBUG)
    01130                 logit( "e","wsParseBinHeaderReply(): error parsing starttime\n" );
    01131               return WS_ERR_PARSE;
    01132             }
    01133           wsSkipN( reply, 1, &scn_pos );
    01134         }
    01135       else if ( strcmp(flag,"FR") == 0 )
    01136         {
    01137           if ( sscanf( &reply[scn_pos], "%lf", &tankEndtime) < 1 )
    01138             {
    01139               if (WS_CL_DEBUG)
    01140                 logit( "e","wsParseBinHeaderReply(): error parsing endtime\n" );
    01141               return WS_ERR_PARSE;
    01142             }
    01143           wsSkipN( reply, 1, &scn_pos );
    01144         }
    01145     }
    01146   else
    01147     {
    01148       if (WS_CL_DEBUG)
    01149         logit( "e","wsParseBinHeaderReply(): bad flag[%s]\n", flag );
    01150       return WS_ERR_PARSE;
    01151     }
    01152
    01153   getThis->pinno = pinno;
    01154   getThis->actStarttime = tankStarttime;
    01155   getThis->actEndtime = tankEndtime;
    01156   getThis->samprate = (double) 0.0; /* server doesn't send this */
    01157   getThis->actLen = bin_len;
    01158   if ( strlen( flag ) >= 2 ) {
    01159     getThis->retFlag = flag[1];
    01160     return WS_WRN_FLAGGED;
    01161   } else {
    01162     getThis->retFlag = '\0';
    01163     return WS_ERR_NONE;
    01164   }
    01165 }
    01166
    01167
    01168 /***********************************************************************
    01169  * wsParseAsciiHeaderReply: parse the reply we got from the waveserver *
    01170  * into a TRACE_REQ structure. Handles the header for replies reply to *
    01171  * GETSCN and GETPIN requests.                                         *
    01172  ***********************************************************************/
    01173 static int wsParseAsciiHeaderReply( TRACE_REQ* getThis, char* reply )
    01174 {
    01175   /* Arguments:
    01176    *    getThis: pointer to TRACE_REQ structure to be filled with reply info
    01177    *      reply: pointer to reply to be parsed.
    01178    *   Returns: WS_ERR_NONE:  if all went well
    01179    *            WS_ERR_INPUT: if bad input parameters
    01180    *            WS_ERR_PARSE: if we couldn't parse part of the reply
    01181    *            WS_WRN_FLAGGED: server sent us a no-data flag
    01182    */
    01183   int reqid = 0;
    01184   int pinno = 0;
    01185   char sta[7];
    01186   char chan[9];
    01187   char net[9];
    01188   char flag[9];
    01189   char datatype[3];
    01190   double tankStarttime = 0.0, samprate = 0.0;
    01191   int scn_pos = 0;
    01192
    01193   if ( !reply )
    01194     {
    01195       if (WS_CL_DEBUG)
    01196         logit( "e", "wsParseAsciiHeaderReply(): bad input parameters\n");
    01197       return WS_ERR_INPUT;
    01198     }
    01199
    01200   if ( sscanf( &reply[scn_pos], "%d %d", &reqid, &pinno ) < 2 )
    01201     {
    01202       if (WS_CL_DEBUG)
    01203         logit( "e","wsParseAsciiHeaderReply(): error parsing reqid/pinno\n" );
    01204       return WS_ERR_PARSE;
    01205     }
    01206   wsSkipN( reply, 2, &scn_pos );
    01207
    01208   if ( sscanf( &reply[scn_pos], "%s %s %s", sta, chan, net ) < 3 )
    01209     {
    01210       if (WS_CL_DEBUG)
    01211         logit( "e","wsParseAsciiHeaderReply(): error parsing SCN\n" );
    01212       return WS_ERR_PARSE;
    01213     }
    01214   wsSkipN( reply, 3, &scn_pos );
    01215
    01216   if ( sscanf( &reply[scn_pos], "%s %s", flag, datatype ) < 2 )
    01217     {
    01218       if (WS_CL_DEBUG)
    01219         logit( "e","wsParseAsciiHeaderReply(): error parsing flag/datatype\n" );
    01220       return WS_ERR_PARSE;
    01221     }
    01222   wsSkipN( reply, 2, &scn_pos );
    01223
    01224   if ( strlen(flag) == 1 || strcmp(flag,"FG") == 0 )
    01225     {
    01226       if ( sscanf( &reply[scn_pos], "%lf %lf", &tankStarttime, &samprate ) < 2 )
    01227         {
    01228           if (WS_CL_DEBUG)
    01229             logit( "e","wsParseAsciiHeaderReply(): error parsing startT/samprate\n" );
    01230           return WS_ERR_PARSE;
    01231         }
    01232       wsSkipN( reply, 2, &scn_pos );
    01233     }
    01234   else if ( strlen(flag) == 2 )
    01235     {
    01236       tankStarttime = 0.0;
    01237       samprate = 0.0;
    01238       if ( strcmp(flag,"FL") == 0 )
    01239         {
    01240           if ( sscanf( &reply[scn_pos], "%lf", &tankStarttime) < 1 )
    01241             {
    01242               if (WS_CL_DEBUG)
    01243                 logit( "e","wsParseAsciiHeaderReply(): error parsing startTime\n" );
    01244               return WS_ERR_PARSE;
    01245             }
    01246           wsSkipN( reply, 1, &scn_pos );
    01247         }
    01248       else if ( strcmp(flag,"FR") == 0 )
    01249         {
    01250           if ( sscanf( &reply[scn_pos], "%lf", &samprate) < 1 )
    01251             {
    01252               if (WS_CL_DEBUG)
    01253                 logit( "e","wsParseAsciiHeaderReply(): error parsing samprate\n" );
    01254               return WS_ERR_PARSE;
    01255             }
    01256           wsSkipN( reply, 1, &scn_pos );
    01257         }
    01258     }
    01259
    01260   getThis->pinno = pinno;
    01261   getThis->actStarttime = tankStarttime;
    01262   getThis->actEndtime = (double) 0.0;
    01263   getThis->samprate = samprate;
    01264   getThis->actLen = strlen( reply ) - scn_pos;
    01265   memmove(reply, &reply[scn_pos], getThis->actLen);
    01266   reply[getThis->actLen] = 0;
    01267
    01268   if ( strlen( flag ) >= 2 ) {
    01269     getThis->retFlag = flag[1];
    01270     return WS_WRN_FLAGGED;
    01271   } else {
    01272     getThis->retFlag = '\0';
    01273     return WS_ERR_NONE;
    01274   }
    01275 }
    01276
    01277
    01278 /**************************************************************************
    01279  *      wsSkipN: moves forward the pointer *posp in buf by moving forward *
    01280  *      cnt words.  Words are delimited by either space or horizontal     *
    01281  *      tabs; newline marks the end of the buffer.                        *
    01282  **************************************************************************/
    01283 static void wsSkipN( char* buf, int cnt, int* posp )
    01284 {
    01285   int pos = *posp;
    01286
    01287   while ( cnt )
    01288     {
    01289       while ( buf[pos] != ' ' && buf[pos] != '\t' )
    01290         {
    01291           if ( !buf[pos] )
    01292             {
    01293               goto done;
    01294             }
    01295           if ( buf[pos] == '\n' )
    01296             {
    01297               ++pos;
    01298               goto done;
    01299             }
    01300           ++pos;
    01301         }
    01302       --cnt;
    01303       while ( buf[pos] == ' ' || buf[pos] == '\t' )
    01304         {
    01305           ++pos;
    01306         }
    01307     }
    01308 done:
    01309   *posp = pos;
    01310 }
    01311
    01312 int setWsClient_ewDebug(int debug)
    01313 {
    01314   /* setWsClient_ewDebug() turns debugging on or off for
    01315      the ws_clientII routines
    01316      */
    01317   WS_CL_DEBUG=debug;
    01318   return(0);
    01319 }