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 2161 2006-05-19 16:55:03Z paulf $ 00007 * 00008 * Revision history: 00009 * $Log$ 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 }