nmxp_base.c 18.9 KB
Newer Older
1 2
/*! \file
 *
Matteo Quintiliani's avatar
Matteo Quintiliani committed
3
 * \brief Base for Nanometrics Protocol Library
4 5 6 7 8 9
 *
 * Author:
 * 	Matteo Quintiliani
 * 	Istituto Nazionale di Geofisica e Vulcanologia - Italy
 *	quintiliani@ingv.it
 *
10
 * $Id: nmxp_base.c,v 1.63 2008-03-05 11:10:51 mtheo Exp $
Matteo Quintiliani's avatar
Matteo Quintiliani committed
11
 *
12 13
 */

14
#include "config.h"
15
#include "nmxp_base.h"
Matteo Quintiliani's avatar
Matteo Quintiliani committed
16
#ifdef HAVE_WINDOWS_H
17
#include "nmxp_win.h"
Matteo Quintiliani's avatar
Matteo Quintiliani committed
18
#endif
19 20 21 22 23 24

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

25 26 27 28
#ifdef HAVE_WINDOWS_H
#include "winsock2.h"
#warning You are compiling on Windows MinGW...
#else
29 30 31 32 33 34 35
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
36
#endif
Matteo Quintiliani's avatar
Matteo Quintiliani committed
37

Matteo Quintiliani's avatar
Matteo Quintiliani committed
38 39 40
#define MAX_OUTDATA 4096


41 42 43 44 45 46 47
int nmxp_openSocket(char *hostname, int portNum)
{
  static int sleepTime = 1;
  int isock = 0;
  struct hostent *hostinfo = NULL;
  struct sockaddr_in psServAddr;
  struct in_addr hostaddr;
48

49
#ifdef HAVE_WINDOWS_H
50
  nmxp_initWinsock();
51
#endif
52

53 54
  if (!hostname)
  {
55
    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Empty host name?\n");
56 57 58 59
    return -1;
  }

  if ( (hostinfo = gethostbyname(hostname)) == NULL) {
60 61
    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Cannot lookup host: %s\n",
	    NMXP_LOG_STR(hostname));
62 63 64 65 66 67
    return -1;
  }

  while(1)
  {
    isock = socket (AF_INET, SOCK_STREAM, 0);
68 69 70 71 72 73 74 75

#ifdef HAVE_WINDOWS_H
    if (isock == INVALID_SOCKET) {
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW,"Error at socket()\n");
	    WSACleanup();
	    exit(1);
    }
#else
76 77
    if (isock < 0)
    {
78
      nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Can't open stream socket\n");
79 80
      exit(1);
    }
81
#endif
82 83 84 85 86 87

    /* Fill in the structure "psServAddr" with the address of server
       that we want to connect with */
    memset (&psServAddr, 0, sizeof(psServAddr));
    psServAddr.sin_family = AF_INET;
    psServAddr.sin_port = htons((unsigned short) portNum);
88 89 90 91 92
#ifdef HAVE_WINDOWS_H
    unsigned long address;
    memcpy(&address, hostinfo->h_addr, (size_t) hostinfo->h_length);
    psServAddr.sin_addr.s_addr = address;
#else
93
    psServAddr.sin_addr = *(struct in_addr *)hostinfo->h_addr_list[0];
94
#endif
95 96 97 98

    /* Report action and resolved address */
    memcpy(&hostaddr.s_addr, *hostinfo->h_addr_list,
	   sizeof (hostaddr.s_addr));
99
    nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Attempting to connect to %s port %d\n",
100
	    NMXP_LOG_STR(inet_ntoa(hostaddr)), portNum);
101 102 103 104

    if (connect(isock, (struct sockaddr *)&psServAddr, sizeof(psServAddr)) >= 0)
    {
      sleepTime = 1;
105
      nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Connection established: socket=%i,IP=%s,port=%d\n",
106
	      isock, NMXP_LOG_STR(inet_ntoa(hostaddr)), portNum);
107 108 109 110
      return isock;
    }
    else
    {
111
      nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Connecting to %s port %d. Trying again after %d seconds...\n",
112
	      NMXP_LOG_STR(inet_ntoa(hostaddr)), portNum, sleepTime);
113
      nmxp_closeSocket(isock);
114
      nmxp_sleep (sleepTime);
115 116 117 118 119 120 121 122
      sleepTime *= 2;
      if (sleepTime > NMXP_SLEEPMAX)
        sleepTime = NMXP_SLEEPMAX;
    }
  }
}


123 124 125 126 127 128 129 130 131 132
int nmxp_closeSocket(int isock) {
	int ret;
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_CONNFLOW, "Closed connection.\n");
#ifdef HAVE_WINDOWS_H
	ret = closesocket(isock);
	WSACleanup();
#else
	ret = close(isock);
#endif
	return ret;
133 134 135 136 137 138 139 140 141 142 143 144 145
}


int nmxp_send_ctrl(int isock, void* buffer, int length)
{
  int sendCount = send(isock, (char*) buffer, length, 0);
  
  if (sendCount != length)
    return NMXP_SOCKET_ERROR;

  return NMXP_SOCKET_OK;
}

146 147 148 149 150 151 152 153
#ifdef HAVE_BROKEN_SO_RCVTIMEO
#warning Managing non-blocking I/O using select()
int nmxp_recv_select_timeout(int s, char *buf, int len, int timeout)
{
    fd_set fds;
    int n;
    struct timeval tv;

154
    /* set up the file descriptor set*/
155 156 157
    FD_ZERO(&fds);
    FD_SET(s, &fds);

158
    /* set up the struct timeval for the timeout*/
159 160 161
    tv.tv_sec = timeout;
    tv.tv_usec = 0;

162
    /* wait until timeout or data received*/
163
    n = select(s+1, &fds, NULL, NULL, &tv);
164 165
    if (n == 0) return -2; /* timeout!*/
    if (n == -1) return -1; /* error*/
166
 
167
    /* data must be here, so do a normal recv()*/
168 169 170
    return recv(s, buf, len, 0);
}
#endif
171

172
int nmxp_recv_ctrl(int isock, void *buffer, int length, int timeoutsec, int *recv_errno )
173 174
{
  int recvCount;
175 176 177
  int cc;
  char *buffer_char = buffer;

178 179 180
#ifdef HAVE_WINDOWS_H
  char *recv_errno_str;
#else
181 182 183 184
#ifdef HAVE_STRERROR_R
#define MAXLEN_RECV_ERRNO_STR 200
  char recv_errno_str[MAXLEN_RECV_ERRNO_STR];
#else
185
  char *recv_errno_str;
186
#endif
187
#endif
188 189

#ifdef HAVE_WINDOWS_H
190 191
  int timeos;
#else
192 193

#ifndef HAVE_BROKEN_SO_RCVTIMEO
194
  struct timeval timeo;
195
#endif
196

197 198
#endif

199

Matteo Quintiliani's avatar
Matteo Quintiliani committed
200 201 202 203 204 205
  /*
  struct timeval timeout;
  socklen_t size_timeout = sizeof(timeout);
  getsockopt(isock, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size_timeout);
  */

206
  if(timeoutsec > 0) {
207
#ifdef HAVE_WINDOWS_H
208
      timeos  = timeoutsec * 1000;
209 210 211 212 213
      if (setsockopt(isock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeos, sizeof(timeos)) < 0)
      {
	  perror("setsockopt SO_RCVTIMEO");
      }
#else
214 215

#ifndef HAVE_BROKEN_SO_RCVTIMEO
216 217 218 219 220
      timeo.tv_sec  = timeoutsec;
      timeo.tv_usec = 0;
      if (setsockopt(isock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)) < 0) {
	  perror("setsockopt SO_RCVTIMEO");
      }
221 222
#endif

223
#endif
224 225
  }
  
226
  cc = 1;
227 228
  *recv_errno  = 0;
  recvCount = 0;
229
  while(cc > 0 && *recv_errno == 0  && recvCount < length) {
230 231 232 233 234 235 236 237 238 239 240 241 242

#ifdef HAVE_BROKEN_SO_RCVTIMEO
      if(timeoutsec == 0) {
#endif

	  cc = recv(isock, buffer_char + recvCount, length - recvCount, 0);

#ifdef HAVE_BROKEN_SO_RCVTIMEO
      } else {
	  cc = nmxp_recv_select_timeout(isock, buffer_char + recvCount, length - recvCount, timeoutsec);
      }
#endif

243 244 245
#ifdef HAVE_WINDOWS_H
      *recv_errno  = WSAGetLastError();
#else
246 247 248 249 250
      if(cc == -2) {
	  *recv_errno  = EWOULDBLOCK;
      } else {
	  *recv_errno  = errno;
      }
251
#endif
252
      if(cc <= 0) {
253
	  /*
254 255
	  nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "nmxp_recv_ctrl(): (cc=%d <= 0) errno=%d  recvCount=%d  length=%d\n",
	  cc, *recv_errno, recvCount, length);
256
	  */
257 258 259
      } else {
	  recvCount += cc;
      }
260
  }
261

262
  if(timeoutsec > 0) {
263 264 265 266 267 268 269
#ifdef HAVE_WINDOWS_H
      timeos  = 0;
      if (setsockopt(isock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeos, sizeof(timeos))
	      < 0) {
	  perror("setsockopt SO_RCVTIMEO");
      }
#else
270 271

#ifndef HAVE_BROKEN_SO_RCVTIMEO
272 273 274 275 276
      timeo.tv_sec  = 0;
      timeo.tv_usec = 0;
      if (setsockopt(isock, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)) < 0) {
	  perror("setsockopt SO_RCVTIMEO");
      }
277 278
#endif

279
#endif
280
  }
281

282
  if (recvCount != length  ||  *recv_errno != 0  ||  cc <= 0) {
283 284 285
#ifdef HAVE_WINDOWS_H
      recv_errno_str = WSAGetLastErrorMessage(*recv_errno);
#else
286
#ifdef HAVE_STRERROR_R
287
      strerror_r(*recv_errno, recv_errno_str, MAXLEN_RECV_ERRNO_STR);
288 289
#else
      recv_errno_str = strerror(*recv_errno);
290
#endif
291
#endif
292

293
#ifdef HAVE_WINDOWS_H
294
      if(*recv_errno != WSAEWOULDBLOCK  &&  *recv_errno != WSAETIMEDOUT)
295 296 297 298
#else
      if(*recv_errno != EWOULDBLOCK)
#endif
      {
299 300
	  nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "nmxp_recv_ctrl(): %s (errno=%d recvCount=%d length=%d cc=%d)\n",
		  NMXP_LOG_STR(recv_errno_str), *recv_errno, recvCount, length, cc);
301 302 303 304 305 306 307 308
      }

      /* TO IMPROVE 
       * Fixed bug receiving zero byte from recv() 'TCP FIN or EOF received'
       * */
      if(cc == 0  &&  *recv_errno == 0) {
	  *recv_errno = -100;
      }
309

310
#ifdef HAVE_WINDOWS_H
311
      if(recvCount != length || (*recv_errno != WSAEWOULDBLOCK  &&  *recv_errno != WSAETIMEDOUT))
312
#else
313
      if(recvCount != length || *recv_errno != EWOULDBLOCK)
314
#endif
315 316 317
      {
	  return NMXP_SOCKET_ERROR;
      }
318 319 320 321 322 323
  }
  
  return NMXP_SOCKET_OK;
}


324
int nmxp_sendHeader(int isock, NMXP_MSG_CLIENT type, int32_t length)
325
{  
Matteo Quintiliani's avatar
Matteo Quintiliani committed
326
    NMXP_MESSAGE_HEADER msg;
327 328 329 330 331

    msg.signature = htonl(NMX_SIGNATURE);
    msg.type      = htonl(type);
    msg.length    = htonl(length);

Matteo Quintiliani's avatar
Matteo Quintiliani committed
332
    return nmxp_send_ctrl(isock, &msg, sizeof(NMXP_MESSAGE_HEADER));
333 334 335
}


336
int nmxp_receiveHeader(int isock, NMXP_MSG_SERVER *type, int32_t *length, int timeoutsec, int *recv_errno )
337 338
{  
    int ret ;
Matteo Quintiliani's avatar
Matteo Quintiliani committed
339
    NMXP_MESSAGE_HEADER msg;
340

341
    ret = nmxp_recv_ctrl(isock, &msg, sizeof(NMXP_MESSAGE_HEADER), timeoutsec, recv_errno);
342 343 344 345 346 347 348 349 350 351 352 353

    *type = 0;
    *length = 0;

    if(ret == NMXP_SOCKET_OK) {
	msg.signature = ntohl(msg.signature);
	msg.type      = ntohl(msg.type);
	msg.length    = ntohl(msg.length);

	if (msg.signature != NMX_SIGNATURE)
	{
	    ret = NMXP_SOCKET_ERROR;
354 355
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW,
		    "nmxp_receiveHeader(): signature mismatches. signature = %d, type = %d, length = %d\n",
356 357 358 359 360 361 362 363 364 365 366
		    msg.signature, msg.type, msg.length);
	} else {
	    *type = msg.type;
	    *length = msg.length;
	}
    }

    return ret;
}


367
int nmxp_sendMessage(int isock, NMXP_MSG_CLIENT type, void *buffer, int32_t length) {
368 369 370 371 372 373 374 375 376 377 378
    int ret;
    ret = nmxp_sendHeader(isock, type, length);
    if( ret == NMXP_SOCKET_OK) {
	if(buffer && length > 0) {
	    ret = nmxp_send_ctrl(isock, buffer, length);
	}
    }
    return ret;
}


379 380 381 382 383 384 385 386 387 388 389 390 391 392
int32_t nmxp_display_error_from_server(char *buffer, int32_t length) {
    /* NMXP_MSG_TERMINATESUBSCRIPTION */
    char *str_msg = NULL;
    int32_t reason;
    memcpy(&reason, buffer, sizeof(reason));
    reason = ntohl(reason);
    str_msg = buffer + sizeof(reason);
    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_ANY, "%d %s shutdown: %s\n",
	    reason,
	    (reason == 0)? "Normal" : (reason == 1)? "Error" : (reason == 2)? "Timeout" : "Unknown",
	    str_msg);
    return reason;
}

393
int nmxp_receiveMessage(int isock, NMXP_MSG_SERVER *type, void **buffer, int32_t *length, int timeoutsec, int *recv_errno ) {
394 395 396 397
    int ret;
    *buffer = NULL;
    *length = 0;

398
    ret = nmxp_receiveHeader(isock, type, length, timeoutsec, recv_errno);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
399

Matteo Quintiliani's avatar
Matteo Quintiliani committed
400
    if( ret == NMXP_SOCKET_OK  ) {
Matteo Quintiliani's avatar
Matteo Quintiliani committed
401 402
	if (*length > 0) {
	    *buffer = malloc(*length);
403
	    ret = nmxp_recv_ctrl(isock, *buffer, *length, 0, recv_errno);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
404

405 406 407 408
	    if(*type == NMXP_MSG_TERMINATESUBSCRIPTION) {
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Received TerminateSubscritption.\n");
		nmxp_display_error_from_server(*buffer, *length);
	    } else if(*type == NMXP_MSG_ERROR) {
409
		nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Received ErrorMessage: %s\n", NMXP_LOG_STR(*buffer));
Matteo Quintiliani's avatar
Matteo Quintiliani committed
410
	    } else {
411
		nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_PACKETMAN, "Received message type: %d  length=%d\n", *type, *length);
Matteo Quintiliani's avatar
Matteo Quintiliani committed
412 413 414
	    }

	}
Matteo Quintiliani's avatar
Matteo Quintiliani committed
415 416 417
    }

    if(*recv_errno != 0) {
418
#ifdef HAVE_WINDOWS_H
419
	if(*recv_errno == WSAEWOULDBLOCK  ||  *recv_errno == WSAETIMEDOUT) {
420
#else
421
	if(*recv_errno == EWOULDBLOCK) {
422
#endif
423
	    nmxp_log(NMXP_LOG_WARN, NMXP_LOG_D_DOD, "Timeout receiving in nmxp_receiveMessage()\n");
Matteo Quintiliani's avatar
Matteo Quintiliani committed
424
	} else {
425 426
	    /* Log message is not necessary because managed by nmxp_recv_ctrl() */
	    /* nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_CONNFLOW, "Error in nmxp_receiveMessage()\n"); */
427
	}
428
    }
Matteo Quintiliani's avatar
Matteo Quintiliani committed
429

430 431 432
    return ret;
}

433

434
NMXP_DATA_PROCESS *nmxp_processDecompressedData(char* buffer_data, int length_data, NMXP_CHAN_LIST_NET *channelList, const char *network_code_default)
435 436 437 438 439 440
{
  int32_t   netInt    = 0;
  int32_t   pKey      = 0;
  double    pTime     = 0.0;
  int32_t   pNSamp    = 0;
  int32_t   pSampRate = 0;
441
  int32_t  *pDataPtr  = NULL;
442 443
  int       swap      = 0;
  int       idx;
444
  static int32_t outdata[MAX_OUTDATA];
445

446 447
  char station_code[20];
  char channel_code[20];
448
  char network_code[20];
449

450
  char *nmxp_channel_name = NULL;
451 452 453 454 455 456 457
  static NMXP_DATA_PROCESS pd;

  /* copy the header contents into local fields and swap */
  memcpy(&netInt, &buffer_data[0], 4);
  pKey = ntohl(netInt);
  if ( pKey != netInt ) { swap = 1; }

458 459 460 461 462 463
  nmxp_data_init(&pd);

  nmxp_channel_name = nmxp_chan_lookupName(pKey, channelList);

  if(nmxp_channel_name) {

464
  memcpy(&pTime, &buffer_data[4], 8);
465
  if ( swap ) { nmxp_data_swap_8b(&pTime); }
466 467 468 469 470 471 472

  memcpy(&netInt, &buffer_data[12], 4);
  pNSamp = ntohl(netInt);
  memcpy(&netInt, &buffer_data[16], 4);
  pSampRate = ntohl(netInt);

  /* There should be (length_data - 20) bytes of data as 32-bit ints here */
Matteo Quintiliani's avatar
Matteo Quintiliani committed
473 474
  memcpy(outdata , (int32_t *) &buffer_data[20], length_data - 20);
  pDataPtr = outdata;
475 476 477 478 479 480 481

  /* Swap the data samples to host order */
  for ( idx=0; idx < pNSamp; idx++ ) {
      netInt = ntohl(pDataPtr[idx]);
      pDataPtr[idx] = netInt;
  }

482
  if(!nmxp_chan_cpy_sta_chan(nmxp_channel_name, station_code, channel_code, network_code)) {
483 484
    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Channel name not in STA.CHAN format: %s\n",
	    NMXP_LOG_STR(nmxp_channel_name));
485 486 487
  }
  
  pd.key = pKey;
488
  if(network_code[0] != 0) {
489
      strcpy(pd.network, network_code);
490 491
  } else {
      strcpy(pd.network, network_code_default);
492
  }
493 494
  if(station_code[0] != 0) {
      strncpy(pd.station, station_code, STATION_LENGTH);
495
  }
496 497
  if(channel_code[0] != 0) {
      strncpy(pd.channel, channel_code, CHANNEL_LENGTH);
498
  }
499
  pd.packet_type = NMXP_MSG_DECOMPRESSED;
500 501 502
  pd.x0 = -1;
  pd.xn = -1;
  pd.x0n_significant = 0;
503 504 505
  /* TODO*/
  /* pd.oldest_seq_no = ;*/
  /* pd.seq_no = ;*/
506 507 508 509 510 511 512
  pd.time = pTime;
  pd.buffer = buffer_data;
  pd.length = length_data;
  pd.nSamp = pNSamp;
  pd.pDataPtr = pDataPtr;
  pd.sampRate = pSampRate;

513 514
  } else {
      nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Channel name not found for key %d\n", pKey);
515 516
  }

517 518 519 520
  return &pd;
}


521
NMXP_DATA_PROCESS *nmxp_processCompressedData(char* buffer_data, int length_data, NMXP_CHAN_LIST_NET *channelList, const char *network_code_default)
522 523 524 525 526
{
    int32_t   pKey      = 0;
    double    pTime     = 0.0;
    int32_t   pNSamp    = 0;
    int32_t   pSampRate = 0;
527
    int32_t  *pDataPtr  = NULL;
528

529 530
    char station_code[20];
    char channel_code[20];
531
    char network_code[20];
532 533 534

    static NMXP_DATA_PROCESS pd;

535
    int32_t nmx_rate_code_to_sample_rate[32] = {
536 537 538 539 540
	0,1,2,5,10,20,40,50,
	80,100,125,200,250,500,1000,25,
	120,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0};

541
	int32_t nmx_oldest_sequence_number;
542 543
	char nmx_hdr[25];
	unsigned char nmx_ptype;
544
	int32_t nmx_seconds;
545
	double nmx_seconds_double;
546 547
	int16_t nmx_ticks, nmx_instr_id;
	int32_t nmx_seqno;
548
	unsigned char nmx_sample_rate;
549 550
	int32_t nmx_x0;
	int32_t rate_code, chan_code, this_sample_rate;
551

552
	int32_t comp_bytecount;
553
	unsigned char *indata;
554
	static int32_t outdata[MAX_OUTDATA];
555 556
	int32_t nout, i, k;
	int32_t prev_xn;
557 558
	const uint32_t high_scale = 4096 * 2048;
	const uint32_t high_scale_p = 4096 * 4096;
559

560 561
	char *nmxp_channel_name = NULL;

562
	/* TOREMOVE int my_order = get_my_wordorder();*/
Matteo Quintiliani's avatar
Matteo Quintiliani committed
563
	int my_host_is_bigendian = nmxp_data_bigendianhost();
564
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "my_host_is_bigendian %d\n", my_host_is_bigendian);
565 566

	memcpy(&nmx_oldest_sequence_number, buffer_data, 4);
567 568 569
	if (my_host_is_bigendian) {
	    nmxp_data_swap_4b (&nmx_oldest_sequence_number);
	}
570
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Oldest sequence number = %d\n", nmx_oldest_sequence_number);
571 572 573 574 575 576

	memcpy(nmx_hdr, buffer_data+4, 17);
	/* Decode the Nanometrics packet header bundle. */
	memcpy (&nmx_ptype, nmx_hdr+0, 1);
	if ( (nmx_ptype & 0xf) == 9) {
	    /* Filler packet.  Discard entire packet.   */
577
	    nmxp_log (NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Filler packet - discarding\n");
578
	    /*m continue;*/
579 580 581 582 583 584 585 586 587 588 589
	    exit(0);
	}

	nmx_x0 = 0;
	memcpy (&nmx_seconds, nmx_hdr+1, 4);
	memcpy (&nmx_ticks, nmx_hdr+5, 2);
	memcpy (&nmx_instr_id, nmx_hdr+7, 2);
	memcpy (&nmx_seqno, nmx_hdr+9, 4);
	memcpy (&nmx_sample_rate, nmx_hdr+13, 1);
	memcpy (&nmx_x0, nmx_hdr+14, 3);

590
	if (my_host_is_bigendian) {
591
	    nmxp_data_swap_4b ((int32_t *)&nmx_seconds);
592 593 594 595
	    nmxp_data_swap_2b (&nmx_ticks);
	    nmxp_data_swap_2b (&nmx_instr_id);
	    nmxp_data_swap_4b (&nmx_seqno);
	    nmxp_data_swap_4b (&nmx_x0);
596
	}
597 598 599 600 601 602 603

	/* check if nmx_x0 is negative like as signed 3-byte int */
	if( (nmx_x0 & high_scale) ==  high_scale) {
	    /* nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "WARNING: changed nmx_x0, old value = %d\n",  nmx_x0);*/
	    nmx_x0 -= high_scale_p;
	}

604 605 606 607 608
	nmx_seconds_double = (double) nmx_seconds + ( (double) nmx_ticks / 10000.0 );
	rate_code = nmx_sample_rate>>3;
	chan_code = nmx_sample_rate&7;
	this_sample_rate = nmx_rate_code_to_sample_rate[rate_code];

609 610 611
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_ptype          = %d\n", nmx_ptype);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_seconds        = %d\n", nmx_seconds);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_ticks          = %d\n", nmx_ticks);
612

613 614
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_seconds_double = %f\n", nmx_seconds_double);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_x0             = %d\n", nmx_x0);
615

616 617 618 619
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_instr_id       = %d\n", nmx_instr_id);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_seqno          = %d\n", nmx_seqno);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "nmx_sample_rate    = %d\n", nmx_sample_rate);
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "this_sample_rate    = %d\n", this_sample_rate);
620

621 622 623 624 625 626
	pKey = (nmx_instr_id << 16) | ( 1 << 8) | ( chan_code);

	pTime = nmx_seconds_double;

	pSampRate = this_sample_rate;

627 628 629 630 631 632 633
	nmxp_data_init(&pd);

	nmxp_channel_name = nmxp_chan_lookupName(pKey, channelList);

	if(nmxp_channel_name) {

	if(!nmxp_chan_cpy_sta_chan(nmxp_channel_name, station_code, channel_code, network_code)) {
634 635
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Channel name not in STA.CHAN format: %s\n",
		    NMXP_LOG_STR(nmxp_channel_name));
636 637
	}
  
638 639
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Channel key %d for %s.%s\n",
		pKey, NMXP_LOG_STR(station_code), NMXP_LOG_STR(channel_code));
640

641 642 643 644 645 646 647 648 649
	comp_bytecount = length_data-21;
	indata = (unsigned char *) buffer_data + 21;

	/* Unpack the data bundles, each 17 bytes long. */
	prev_xn = nmx_x0;
	outdata[0] = nmx_x0;
	nout = 1;
	for (i=0; i<comp_bytecount; i+=17) {
	    if (i+17>comp_bytecount) {
650
		nmxp_log (NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "comp_bytecount = %d, i+17 = %d\n",
651 652 653 654
			comp_bytecount, i+17);
		exit(1);
	    }
	    if (nout+16 > MAX_OUTDATA)  {
655
		nmxp_log (NMXP_LOG_ERR,  NMXP_LOG_D_PACKETMAN, "Output buffer size too small\n");
656 657 658
		exit(1);
	    }
	    k = nmxp_data_unpack_bundle (outdata+nout,indata+i,&prev_xn);
659 660 661 662 663
	    if (k < 0) nmxp_log (NMXP_LOG_WARN, NMXP_LOG_D_PACKETMAN, "Null bundle: %s.%s.%s (k=%d) %s %d\n",
		    NMXP_LOG_STR(network_code),
		    NMXP_LOG_STR(station_code),
		    NMXP_LOG_STR(channel_code), k,
		    __FILE__,  __LINE__);
664 665 666 667 668 669
	    if (k < 0) break;
	    nout += k;
	    /* prev_xn = outdata[nout-1]; */
	}
	nout--;

670
	nmxp_log(NMXP_LOG_NORM, NMXP_LOG_D_PACKETMAN, "Unpacked %d samples.\n", nout);
671 672 673 674 675 676

	pDataPtr = outdata;

	pNSamp = nout;

	pd.key = pKey;
677
	if(network_code[0] != 0) {
678
	    strcpy(pd.network, network_code);
679 680
	} else {
	    strcpy(pd.network, network_code_default);
681
	}
682 683
	if(station_code[0] != 0) {
	    strncpy(pd.station, station_code, STATION_LENGTH);
684
	}
685 686
	if(channel_code[0] != 0) {
	    strncpy(pd.channel, channel_code, CHANNEL_LENGTH);
687
	}
688 689
	pd.packet_type = nmx_ptype;
	pd.x0 = nmx_x0;
690
	pd.xn = pDataPtr[nout];
691
	pd.x0n_significant = 1;
692
	pd.oldest_seq_no = nmx_oldest_sequence_number;
693 694 695 696 697 698 699 700
	pd.seq_no = nmx_seqno;
	pd.time = pTime;
	pd.buffer = buffer_data;
	pd.length = length_data;
	pd.nSamp = pNSamp;
	pd.pDataPtr = pDataPtr;
	pd.sampRate = pSampRate;

701 702
	} else {
	    nmxp_log(NMXP_LOG_ERR, NMXP_LOG_D_PACKETMAN, "Channel name not found for key %d\n", pKey);
703 704
	}

705 706 707
	return &pd;
}

708 709 710

unsigned int nmxp_sleep(unsigned int sleep_time) {
#ifdef HAVE_WINDOWS_H
711 712
    Sleep(sleep_time);
    return 0;
713 714 715 716 717
#else
    return sleep(sleep_time);
#endif
}