1 /*
2
3 Copyright (C) 2009,2016 Alois Schloegl <alois.schloegl@gmail.com>
4 This file is part of the "BioSig for C/C++" repository
5 (biosig4c++) at http://biosig.sf.net/
6
7 BioSig is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 3
10 of the License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 */
21
22 #include "biosig-network.h"
23
24 #include <ctype.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <time.h>
32 #include <syslog.h>
33 #include <sys/wait.h>
34 #include <signal.h>
35
36 #ifdef WITH_MICROMED
37 void sopen_trc_read(HDRTYPE *hdr);
38 #endif
39 #ifdef WITH_PDP
40 void sopen_pdp_read(HDRTYPE *hdr);
41 #endif
42
43 const char *LOGFILE = "/tmp/biosig/biosigd.log";
44
45 /*
46 Key ID table and related functions
47 */
48 struct IDTABLE_T {
49 uint64_t id;
50 uint64_t gtime; // time of file generation
51 struct sockaddr_in addr;
52 } *IdTablePtr;
53 size_t IdTableLen;
54
55
56 /*
57 compare uint32_t
58 */
u64cmp(const void * a,const void * b)59 int u64cmp(const void *a,const void *b)
60 {
61 unsigned int k=7;
62 int r=0;
63 while (!r && (k<sizeof(uint64_t))) {
64 r = ((uint8_t*)a)[k] - ((uint8_t*)b)[k];
65 k--;
66 }
67 return(r);
68 }
69
70 /*
71 generate new unique id
72 */
GetNewId()73 uint64_t GetNewId() {
74
75 int k;
76 uint64_t c;
77 FILE *fid = fopen("/dev/urandom","r");
78 do {
79 fread(&c,sizeof(c),1,fid);
80 } while (bsearch(&c, IdTablePtr, IdTableLen, sizeof(IDTABLE_T), &u64cmp));
81 fclose(fid);
82
83 k = IdTableLen;
84 IdTableLen++;
85 IdTablePtr = (IDTABLE_T*)realloc(IdTablePtr,IdTableLen*sizeof(IDTABLE_T));
86 while ((c < IdTablePtr[k].id) && (k>0)) {
87 IdTablePtr[k].id = IdTablePtr[k-1].id;
88 k--;
89 }
90 IdTablePtr[k].id = c;
91 IdTablePtr[k].gtime = t_time2gdf_time(time(NULL));
92 // memcpy(&IdTablePtr[k].addr, addr, sizeof(struct sockaddr_in));
93
94 return(c);
95 };
96
97
98 /*TODO: semaphore */
LoadIdTable(const char * path)99 size_t LoadIdTable(const char *path) {
100
101 IdTableLen = 0;
102 DIR *d = opendir(path);
103 if (d==NULL) {
104 mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
105 return(0);
106 }
107
108 uint64_t ID;
109 size_t N=0;
110 struct dirent *dp;
111 do {
112 errno = 0;
113 if ((dp = readdir(d)) != NULL) {
114 IdTablePtr = (IDTABLE_T*)realloc(IdTablePtr,(N+1)*sizeof(IDTABLE_T));
115 cat64(dp->d_name,&ID);
116 if (ID != 0) {
117 IdTablePtr[N].id = ID;
118 N++;
119 }
120 }
121 } while (dp != NULL);
122 closedir(d);
123
124 qsort(IdTablePtr,N,sizeof(IDTABLE_T),&u64cmp);
125 IdTableLen = N;
126
127 fprintf(stdout,"Load Id Table: %i entries found.\n",N);
128
129 if (VERBOSE_LEVEL>8)
130 for (int k=0; k<N; k++)
131 fprintf(stdout,"%3i %016lx\n",k+1,IdTablePtr[k].id);
132
133 return(N);
134 };
135
136
sigchld_handler(int s)137 void sigchld_handler(int s)
138 {
139 while(waitpid(-1, NULL, WNOHANG) > 0);
140 }
141
142
143 //#define VERBOSE_LEVEL 8
144
145 const char path[] = "/tmp/biosig/\0 .gdf";
DoJob(int ns)146 void DoJob(int ns)
147 {
148 char fullfilename[] = "/tmp/biosig/ .gdf";
149 const size_t pathlen = strlen(path);
150 char *filename = fullfilename+pathlen;
151
152 // size_t sizbuf = BSCS_MAX_BUFSIZ+8;
153 uint8_t inbuf[BSCS_MAX_BUFSIZ+8];
154 HDRTYPE *hdr = NULL;
155 uint64_t ID = 0;
156 uint32_t STATUS = STATE_INIT;
157 char stopflag = 0;
158 size_t datalen = 0;
159 mesg_t msg;
160
161 if ((VERBOSE_LEVEL>7) && errno) {
162 errno = 0;
163 fprintf(stdout,"## errno=%i %s\n",errno,strerror(errno));
164 }
165
166 /* Create a new SID for the child process */
167 pid_t sid = setsid();
168 if (sid < 0) {
169 exit(-1);
170 }
171
172 /*server identification */
173 const char *greeting="Hi there,\n this is your experimental BSCS server. \n It is useful for testing the BioSig client-server architecture.\n";
174 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_MSG | STATE_INIT | BSCS_NO_ERROR;
175 msg.LEN = htobe32(strlen(greeting));
176 int s;
177 s = send(ns,&msg,8,0);
178 s = send(ns, greeting, strlen(greeting), 0);
179
180 while (!stopflag) // wait for command
181 {
182 fprintf(stdout,":> ");
183 ssize_t count = recv(ns, &msg, 8, 0);
184 fprintf(stdout,"STATUS=%08x c=%i MSG=%08x len=%i,errno=%i %s\n",STATUS,count,be32toh(msg.STATE),be32toh(msg.LEN),errno,strerror(errno));
185 size_t LEN = be32toh(msg.LEN);
186
187 FILE *fid = fopen(LOGFILE,"a");
188 fprintf(stdout,"STATUS=%08x c=%i MSG=%08x len=%i,errno=%i %s\n",STATUS,count,be32toh(msg.STATE),be32toh(msg.LEN),errno,strerror(errno));
189 fclose(fid);
190 errno = 0;
191
192 if (count==0) {
193 fprintf(stdout,"connection lost! %i %i %i %s\n",stopflag,count,errno,strerror(errno));
194 LEN = 0;
195 stopflag=1;
196 continue;
197 }
198 else if (count<0) {
199 fprintf(stdout,"invalid packet! %i %i %i %s\n",stopflag,count,errno,strerror(errno));
200 LEN = 0;
201 }
202 else if ((msg.STATE & CMD_MASK) == BSCS_NOP)
203 { // no operation
204
205 count = 0;
206 while (count<LEN) {
207 count += recv(ns, inbuf, min(BSCS_MAX_BUFSIZ,LEN-count), 0);
208 }
209 msg.STATE = BSCS_VERSION_01 | BSCS_NOP | BSCS_REPLY | (msg.STATE & STATE_MASK) | BSCS_NO_ERROR;
210
211 // send reply
212 msg.LEN = htobe32(0);
213 s = send(ns, &msg, 8, 0);
214 }
215
216 else if ((STATUS == STATE_INIT) &&
217 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_OPEN | STATE_INIT)))
218 {
219 /****************************************************************************************
220 OPEN FILE with ID
221 ****************************************************************************************/
222
223 if (VERBOSE_LEVEL>7) fprintf(stdout,"open %i %i %016lx\n",LEN,count,ID);
224
225 hdr = constructHDR(0,0);
226 if (LEN==0) //|| ((LEN==8) && (ID==0))) // no ID, send back id, open(w)
227 {
228 ID = GetNewId();
229 c64ta(ID, filename);
230 hdr->FLAG.ANONYMOUS = 1; // do not store name
231 STATUS = STATE_OPEN_WRITE_HDR;
232 msg.STATE = BSCS_VERSION_01 | BSCS_OPEN_W | BSCS_REPLY | STATE_OPEN_WRITE_HDR;
233 msg.LEN = htobe32(8);
234 leu64a(ID, &msg.LOAD);
235 s = send(ns, &msg, 16, 0);
236
237 FILE *fid = fopen(LOGFILE,"a");
238 fprintf(fid,"\t> %s",filename);
239 fclose(fid);
240
241 }
242 else if (LEN == 8) // open(r)
243 {
244 count = recv(ns, &msg.LOAD, 8, 0);
245 ID = leu64p((uint8_t*)&msg.LOAD);
246
247 c64ta(ID, filename);
248 // ToDo: replace SOPEN with simple function, e.g. access to event table not needed here
249 hdr->FLAG.ANONYMOUS = 1; // do not store name
250 hdr->FileName = fullfilename;
251 hdr = sopen(fullfilename,"r",hdr);
252 msg.LEN = htobe32(0);
253 if (hdr->FILE.OPEN==0) {
254 msg.STATE = BSCS_VERSION_01 | BSCS_OPEN_R | BSCS_REPLY | STATE_INIT | BSCS_ERROR_CANNOT_OPEN_FILE;
255 STATUS = STATE_INIT;
256 } else if (serror2(hdr) || (hdr->NRec < 0)) {
257 sclose(hdr);
258 msg.STATE = BSCS_VERSION_01 | BSCS_OPEN_R | BSCS_REPLY | STATE_INIT | BSCS_ERROR_CANNOT_OPEN_FILE;
259 STATUS = STATE_INIT;
260 } else {
261 msg.STATE = BSCS_VERSION_01 | BSCS_OPEN_R | BSCS_REPLY | STATE_OPEN_READ;
262 STATUS = STATE_OPEN_READ;
263 }
264 s = send(ns, &msg, 8, 0);
265 FILE *fid = fopen(LOGFILE,"a");
266 fprintf(fid,"\t< %s",filename);
267 fclose(fid);
268 }
269 else //if (LEN != 8)
270 {
271 STATUS = STATE_INIT;
272 msg.STATE = BSCS_VERSION_01 | BSCS_OPEN_W | BSCS_REPLY | STATE_INIT | BSCS_ERROR_INCORRECT_PACKET_LENGTH;
273 msg.LEN = htobe32(0);
274 s = send(ns, &msg, 8, 0);
275 }
276 }
277
278 else if ((STATUS == (msg.STATE & STATE_MASK)) &&
279 (LEN == 0) &&
280 ((msg.STATE & (VER_MASK | CMD_MASK)) == (BSCS_VERSION_01 | BSCS_CLOSE)))
281 { // close
282 /****************************************************************************************
283 CLOSE FILE
284 ****************************************************************************************/
285
286 if (STATUS != (msg.STATE & STATE_MASK)) fprintf(stdout,"Close: status does not fit\n");
287
288 msg.STATE = BSCS_VERSION_01 | BSCS_CLOSE | BSCS_REPLY | STATE_INIT;
289 msg.LEN = htobe32(0);
290
291 if (LEN != 0)
292 msg.STATE = BSCS_VERSION_01 | BSCS_CLOSE | BSCS_REPLY | STATE_INIT | BSCS_ERROR_INCORRECT_PACKET_LENGTH;
293
294 if ((STATUS == STATE_OPEN_WRITE_HDR) || (STATUS == STATE_OPEN_WRITE)) {
295 if (hdr->NRec != datalen/hdr->AS.bpb)
296 hdr->NRec = -1; // this triggers sclose to compute the correct size
297 }
298
299 if ((hdr!=NULL) && ((STATUS != STATE_OPEN_READ) || (STATUS != STATE_OPEN_READ)) )
300 sclose(hdr);
301
302 if (STATUS != STATE_INIT) {
303 destructHDR(hdr);
304 hdr = NULL;
305 }
306
307 hdr = NULL;
308 if (serror2(hdr))
309 msg.STATE = BSCS_VERSION_01 | BSCS_CLOSE | BSCS_REPLY | STATE_INIT | BSCS_ERROR_CLOSE_FILE;
310
311 STATUS = STATE_INIT;
312
313 s = send(ns, &msg, 8, 0);
314
315 }
316
317 else if ((STATUS == STATE_OPEN_WRITE_HDR) &&
318 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_SEND_HDR | STATE_OPEN_WRITE_HDR)))
319 {
320 /****************************************************************************************
321 SEND HEADER
322 ****************************************************************************************/
323
324 //case BSCS_SEND_HDR: // send header information
325 hdr->AS.Header = (uint8_t*)realloc(hdr->AS.Header,LEN);
326 hdr->HeadLen = LEN;
327 count = 0;
328 while (count<LEN) {
329 if (VERBOSE_LEVEL>8) fprintf(stdout,"SND HDR: c=%i,LEN=%i\n",count,LEN);
330 count += recv(ns, hdr->AS.Header+count, LEN-count, 0);
331 }
332 if (VERBOSE_LEVEL>8) fprintf(stdout,"SND HDR: c=%i,LEN=%i\n",count,LEN);
333
334 hdr->TYPE = GDF;
335 hdr->FLAG.ANONYMOUS = 1; // do not store name
336 gdfbin2struct(hdr);
337
338 hdr->EVENT.N = 0;
339 hdr->EVENT.POS = NULL;
340 hdr->EVENT.TYP = NULL;
341 hdr->EVENT.DUR = NULL;
342 hdr->EVENT.CHN = NULL;
343
344 c64ta(ID, filename);
345 hdr->FileName = fullfilename;
346 hdr->FILE.COMPRESSION = 0;
347 ifopen(hdr,"w");
348 hdr->FILE.OPEN = 2;
349 count=ifwrite(hdr->AS.Header, 1, hdr->HeadLen, hdr);
350 datalen = 0;
351
352 if (VERBOSE_LEVEL>8) fprintf(stdout,"SND HDR: count=%i\n",count);
353
354 if (errno) {
355 // check for errors in gdfbin2struct, ifopen and ifwrite
356 STATUS = STATE_OPEN_WRITE_HDR;
357 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_HDR | BSCS_REPLY | STATE_OPEN_WRITE_HDR | BSCS_ERROR_COULD_NOT_WRITE_HDR;
358 }
359 else {
360 STATUS = STATE_OPEN_WRITE;
361 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_HDR | BSCS_REPLY | STATE_OPEN_WRITE;
362 }
363 msg.LEN = htobe32(0);
364 if (VERBOSE_LEVEL>8) fprintf(stdout,"SND HDR RPLY: %08x\n",msg.STATE);
365 s = send(ns, &msg, 8, 0);
366 }
367
368
369 else if ((STATUS == STATE_OPEN_WRITE) &&
370 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_SEND_DAT | STATE_OPEN_WRITE)))
371 {
372 /****************************************************************************************
373 SEND DATA
374 ****************************************************************************************/
375 //case BSCS_SEND_DAT: // send data block
376 // ToDo: check corrupt packet
377 count = 0;
378 while (count<LEN) {
379 // ToDo: check if streams would be faster
380 // fprintf(stdout,"SEND_DAT %li %li %li\n",datalen,count,LEN);
381 ssize_t c = recv(ns, inbuf, min(BSCS_MAX_BUFSIZ,LEN-count), 0);
382 datalen += ifwrite(inbuf, 1, c, hdr);
383 count += c;
384 }
385 //STATUS = STATE_OPEN_WRITE;
386
387 if (errno) {
388 // check for errors in ifwrite
389 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_DAT | BSCS_REPLY | STATE_OPEN_WRITE | BSCS_ERROR_COULD_NOT_WRITE_DAT;
390 }
391 else {
392 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_DAT | BSCS_REPLY | STATE_OPEN_WRITE;
393 }
394 msg.LEN = htobe32(0);
395 s = send(ns, &msg, 8, 0);
396 }
397
398 else if ((STATUS == STATE_OPEN_WRITE) &&
399 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_SEND_EVT | STATE_OPEN_WRITE)))
400 {
401 /****************************************************************************************
402 SEND EVENTS
403 ****************************************************************************************/
404 //case BSCS_SEND_EVT: // send event information
405
406
407 count = recv(ns, inbuf+8, min(8,LEN), 0);
408 if (count<8) continue;
409
410 char flag = inbuf[8];
411 int N = inbuf[9] + (inbuf[10] + inbuf[11]*256)*256;
412 //float Fs = lef32p(inbuf+12);
413
414 if (LEN != (8 + N * (flag==3 ? 12u : 6u)))
415 {
416 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_EVT | BSCS_REPLY | STATE_OPEN_WRITE | BSCS_ERROR_INCORRECT_PACKET_LENGTH;
417 }
418
419 else if (N>0) {
420 size_t n = hdr->EVENT.N;
421 hdr->EVENT.N += N;
422 hdr->EVENT.POS = (uint32_t*) realloc(hdr->EVENT.POS, hdr->EVENT.N*sizeof(*hdr->EVENT.POS) );
423 hdr->EVENT.TYP = (uint16_t*) realloc(hdr->EVENT.TYP, hdr->EVENT.N*sizeof(*hdr->EVENT.TYP) );
424 hdr->EVENT.DUR = (uint32_t*) realloc(hdr->EVENT.DUR, hdr->EVENT.N*sizeof(*hdr->EVENT.DUR) );
425 hdr->EVENT.CHN = (uint16_t*) realloc(hdr->EVENT.CHN, hdr->EVENT.N*sizeof(*hdr->EVENT.CHN) );
426
427 // read EVENT.POS
428 count = 0;
429 LEN = N*sizeof(*hdr->EVENT.POS);
430 while (count < LEN) {
431 count += recv(ns, (uint8_t*)(hdr->EVENT.POS+n)+count, LEN-count, 0);
432 }
433 // read EVENT.TYP
434 count = 0;
435 LEN = N*sizeof(*hdr->EVENT.TYP);
436 while (count < LEN) {
437 count += recv(ns, (uint8_t*)(hdr->EVENT.TYP+n)+count, LEN-count, 0);
438 }
439 // read EVENT.DUR and EVENT.CHN
440 if (flag==3) {
441 count = 0;
442 LEN = N*sizeof(*hdr->EVENT.POS);
443 while (count < LEN) {
444 count += recv(ns, (uint8_t*)(hdr->EVENT.DUR+n)+count, LEN-count, 0);
445 }
446 count = 0;
447 LEN = N*sizeof(*hdr->EVENT.TYP);
448 while (count < LEN) {
449 count += recv(ns, (uint8_t*)(hdr->EVENT.CHN+n)+count, LEN-count, 0);
450 }
451 }
452 else {
453 for (size_t k=n; k<hdr->EVENT.N; k++) {
454 hdr->EVENT.DUR[k] = 0;
455 hdr->EVENT.CHN[k] = 0;
456 }
457 }
458 #if __BYTE_ORDER == __BIG_ENDIAN
459 // do byte swapping if needed
460 for (size_t k=n; k<hdr->EVENT.N; k++) {
461 hdr->EVENT.POS[k] = htole32(hdr->EVENT.POS[k]);
462 hdr->EVENT.TYP[k] = htole16(hdr->EVENT.TYP[k]);
463 }
464 if (flag==3) {
465 for (size_t k=n; k<hdr->EVENT.N; k++) {
466 hdr->EVENT.DUR[k] = htole32(hdr->EVENT.DUR[k]);
467 hdr->EVENT.CHN[k] = htole16(hdr->EVENT.CHN[k]);
468 }
469 }
470 #endif
471 msg.STATE = BSCS_VERSION_01 | BSCS_SEND_EVT | BSCS_REPLY | STATE_OPEN_WRITE;
472 }
473 msg.LEN = htobe32(0);
474 s = send(ns, &msg, 8, 0);
475 }
476
477 else if ((msg.STATE & CMD_MASK) == BSCS_SEND_MSG )
478 { // might become obsolet (?)
479 // ToDo: check corrupt packet
480 count = 0;
481 ssize_t c=0;
482 while (count<LEN) {
483 int len = min(BSCS_MAX_BUFSIZ-1,LEN-count);
484 c = recv(ns, inbuf, len, 0);
485 inbuf[c-1]=0;
486 fprintf(stdout,"got message <%s>\n",(char*)(inbuf));
487 count += c;
488 }
489 //system((char*)(inbuf));
490 // TODO: reply message
491 }
492
493 else if ((STATUS == STATE_OPEN_READ) &&
494 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_REQU_HDR | STATE_OPEN_READ)))
495 {
496 /****************************************************************************************
497 REQUEST HEADER
498 ****************************************************************************************/
499 msg.STATE = BSCS_VERSION_01 | BSCS_REQU_HDR | BSCS_REPLY | STATE_OPEN_READ;
500 msg.LEN = htobe32(hdr->HeadLen);
501 s = send(ns, &msg, 8, 0);
502 s = send(ns, hdr->AS.Header, hdr->HeadLen, 0);
503
504 }
505
506 else if ((STATUS == STATE_OPEN_READ) &&
507 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_REQU_DAT | STATE_OPEN_READ)))
508 {
509 /****************************************************************************************
510 REQUEST DATA
511 ****************************************************************************************/
512 count += recv(ns, inbuf, 8, 0);
513 size_t length = leu32p(inbuf);
514 size_t start = leu32p(inbuf+4);
515 sread_raw(start, length, hdr, 0);
516
517 length = min(length, hdr->AS.first + hdr->AS.length - start);
518 msg.STATE = BSCS_VERSION_01 | BSCS_REQU_DAT | BSCS_REPLY | STATE_OPEN_READ;
519 msg.LEN = htobe32(hdr->AS.bpb*length);
520 s = send(ns, &msg, 8, 0);
521 s = send(ns, hdr->AS.rawdata + hdr->AS.bpb*(start-hdr->AS.first), hdr->AS.bpb*length, 0);
522 //send(ns, hdr->AS.rawdata, (hdr->AS.length-hdr->AS.first)*hdr->AS.bpb,0);
523 }
524
525 else if ((STATUS == STATE_OPEN_READ) &&
526 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_REQU_EVT | STATE_OPEN_READ)))
527 {
528 /****************************************************************************************
529 REQUEST EVENT TABLE
530 ****************************************************************************************/
531 size_t len = 0;
532 if ((hdr->TYPE == GDF) && (hdr->AS.rawEventData == NULL) && (hdr->NRec>=0)) {
533 // event table from GDF file
534 ifseek(hdr, hdr->HeadLen + hdr->AS.bpb*hdr->NRec, SEEK_SET);
535 // READ EVENTTABLE
536 hdr->AS.rawEventData = (uint8_t*)realloc(hdr->AS.rawEventData,8);
537 int c = ifread(hdr->AS.rawEventData, sizeof(uint8_t), 8, hdr);
538 uint8_t *buf = hdr->AS.rawEventData;
539
540 if (c<8) {
541 hdr->EVENT.N = 0;
542 }
543 else if (hdr->VERSION < 1.94) {
544 hdr->EVENT.N = leu32p(buf + 4);
545 }
546 else {
547 hdr->EVENT.N = buf[1] + (buf[2] + buf[3]*256)*256;
548 }
549 int sze = (buf[0]>1) ? 12 : 6;
550 len = 8+hdr->EVENT.N*sze;
551 hdr->AS.rawEventData = (uint8_t*)realloc(hdr->AS.rawEventData,len);
552 ifread(hdr->AS.rawEventData+8, 1, len-8, hdr);
553 ifseek(hdr, hdr->HeadLen+hdr->AS.bpb*hdr->FILE.POS, SEEK_SET);
554 // note: no conversion to HDR.EVENT structure needed on server-side
555 }
556 else if ((hdr->TYPE != GDF) && (hdr->AS.rawEventData == NULL))
557 len = hdrEVT2rawEVT(hdr);
558
559 else if ((hdr->TYPE == GDF) && (hdr->AS.rawEventData != NULL)){
560 uint8_t *buf = hdr->AS.rawEventData;
561 if (hdr->VERSION < 1.94)
562 hdr->EVENT.N = leu32p(buf + 4);
563 else
564 hdr->EVENT.N = buf[1] + (buf[2] + buf[3]*256)*256;
565
566 int sze = (buf[0]>1) ? 12 : 6;
567
568 if (hdr->EVENT.N>0) {
569 len = 8+sze*hdr->EVENT.N;
570 }
571 }
572
573 msg.STATE = BSCS_VERSION_01 | BSCS_REQU_HDR | BSCS_REPLY | STATE_OPEN_READ;
574 if (len <= 8) {
575 msg.LEN = htobe32(0);
576 s = send(ns, &msg, 8, 0);
577 } else {
578 msg.LEN = htobe32(len);
579 s = send(ns, &msg, 8, 0);
580 s = send(ns, hdr->AS.rawEventData, len, 0);
581 }
582 }
583
584 else if ((STATUS == STATE_OPEN_WRITE_HDR) &&
585 ((msg.STATE & ~ERR_MASK) == (BSCS_VERSION_01 | BSCS_PUT_FILE | STATE_OPEN_WRITE_HDR)))
586 {
587 /****************************************************************************************
588 PUT FILE
589 ****************************************************************************************/
590
591
592 //case BSCS_PUT_FILE: // send header information
593 uint32_t errcode = 0;
594
595 c64ta(ID, filename);
596 char *f2 = (char*)malloc(strlen(fullfilename)+5);
597 strcpy(f2,fullfilename);
598 strcat(f2,".tmp");
599
600 /*********** temporary file - not checked *********/
601 int sdo = open(f2,O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
602
603 HDRTYPE *hdr = constructHDR(0,0);
604 hdr->FileName = f2;
605 #ifdef WITH_PDP
606 hdr->AS.Header = (uint8_t*) malloc(LEN+1);
607 #endif
608
609 const int BUFLEN = 1024;
610 char buf[BUFLEN];
611
612 count = 0;
613 while (count<LEN) {
614 size_t len = recv(ns, buf, min(LEN-count, BUFLEN), 0);
615 #ifdef WITH_PDP
616 memcpy(hdr->AS.Header+count,buf,len);
617 #endif
618 count += write(sdo, buf, len);
619 //fprintf(stdout,"\b\b\b\b%02i%% ",100.0*count/LEN);
620 }
621 close(sdo);
622 hdr->AS.Header[count]=0;
623 hdr->HeadLen = count;
624
625 if (LEN-count) {
626 errcode = 1;
627 //fprintf(stdout,"errcode=1 %i\n",LEN-count);
628 }
629 else {
630 /************ read temporary file, ... ************/
631 int status = 0;
632 #ifdef WITH_PDP
633 sopen_pdp_read(hdr);
634
635 sread(NULL,0,hdr->NRec,hdr); // rawdata -> data.block
636 status=serror2(hdr);
637
638 if (status) {
639 errcode = 2;
640 #else
641 {
642 #endif
643 sopen(f2,"r",hdr);
644 if ((status=serror2(hdr)))
645 errcode = 11;
646
647 else {
648 count = sread(NULL,0,hdr->NRec,hdr);
649 if ((status=serror2(hdr)))
650 errcode = 12;
651
652 sclose(hdr);
653 if ((status=serror2(hdr)))
654 errcode = 13;
655
656 }
657 }
658
659 if (VERBOSE_LEVEL>7) fprintf(stdout,"put file: errcode=%i\n",errcode);
660
661 /********* ... and convert to GDF file *************/
662 if (!status) {
663 hdr->FileName = fullfilename;
664 hdr->TYPE = GDF;
665 hdr->VERSION = 2;
666 sopen(fullfilename,"w",hdr);
667 if ((status=serror2(hdr))) {
668 errcode = 21;
669 } else {
670 //count = swrite(hdr->data.block, hdr->NRec, hdr);
671 ifwrite(hdr->AS.rawdata,hdr->AS.bpb,hdr->NRec,hdr);
672 if ((status=serror2(hdr)))
673 errcode = 22;
674 sclose(hdr);
675 if ((status=serror2(hdr)))
676 errcode = 23;
677 }
678 }
679
680 if (VERBOSE_LEVEL>7) fprintf(stdout,"put file: errcode=%i\n",errcode);
681
682 }
683 destructHDR(hdr);
684 free(f2);
685
686 STATUS = STATE_INIT;
687 msg.STATE = BSCS_VERSION_01 | BSCS_PUT_FILE | BSCS_REPLY | STATE_INIT | htobe32(errcode);
688 msg.LEN = htobe32(0);
689 s = send(ns, &msg, 8, 0);
690 }
691
692 else if ((
693 (msg.STATE & ~ERR_MASK & ~STATE_MASK) == (BSCS_VERSION_01 | BSCS_GET_FILE)))
694 {
695 /****************************************************************************************
696 GET FILE
697 ****************************************************************************************/
698
699 count = recv(ns, &msg.LOAD, 8, 0);
700 ID = leu64p((uint8_t*)&msg.LOAD);
701 c64ta(ID, filename);
702
703 if (VERBOSE_LEVEL>7) fprintf(stdout,"get file: %s\n",filename);
704
705 fprintf(stdout,"get file: %016lx\n",ID);
706
707 int sdi = open(fullfilename,O_RDONLY,S_IFREG);
708
709 fprintf(stdout,"get file: %016lx %i\n",ID,sdi);
710
711 if (sdi<0) {
712 msg.STATE = BSCS_VERSION_01 | BSCS_GET_FILE | BSCS_REPLY | STATUS | BSCS_ERROR_CANNOT_OPEN_FILE;
713 msg.LEN = htobe32(0);
714 s = send(ns, &msg, 8, 0);
715 }
716 else {
717 struct stat FileBuf;
718 stat(fullfilename,&FileBuf);
719 uint32_t LEN = FileBuf.st_size;
720
721 msg.STATE = BSCS_VERSION_01 | BSCS_GET_FILE | BSCS_REPLY | STATUS | BSCS_NO_ERROR;
722 msg.LEN = htobe32(LEN);
723 s = send(ns, &msg, 8, 0);
724
725 const int BUFLEN = 1024;
726 char *buf[BUFLEN];
727 count = 0;
728 while (count<LEN) {
729 size_t len = read(sdi, buf, min(LEN-count,BUFLEN));
730 count += send(ns, buf, len, 0);
731 }
732 //if (FileBuf.st_size-count); // TODO: error handling
733 close(sdi);
734 }
735 s = send(ns, &msg, 8, 0);
736 }
737
738 else if ((msg.STATE & CMD_MASK) == BSCS_NOP)
739 {
740 /****************************************************************************************
741 NO OPERATION
742 ****************************************************************************************/
743 ;
744 }
745
746
747 else if (msg.STATE & BSCS_REPLY)
748 { // ignore reply messages
749 ;
750 }
751 else
752 {
753 fprintf(stdout,"unknown packet: state=%08x len=%i\n",be32toh(msg.STATE),(int32_t)be32toh(msg.LEN));
754 msg.STATE = BSCS_VERSION_01 | BSCS_ERROR;
755 msg.LEN = htobe32(0);
756 s = send(ns, &msg, 8, 0);
757 }
758 }
759 }
760
761 //int main (int argc, char *argv[]) {
762 int main () {
763
764 int sd, ns;
765 socklen_t fromlen;
766 int addrlen;
767 struct sigaction sa;
768 time_t timer;
769 pid_t sid;
770
771 fprintf(stdout,"01## errno=%i %s\n",errno,strerror(errno));
772 LoadIdTable(path);
773 fprintf(stdout,"11## errno=%i %s\n",errno,strerror(errno));
774
775 timer=time(NULL);
776 char *t = asctime(localtime(&timer));
777 t[24]=0;
778
779 FILE *fid = fopen(LOGFILE,"a");
780 fprintf(fid,"\n%s\tserver started",t);
781 fclose(fid);
782
783
784 #ifdef IPv6 // IPv4 and IPv6
785 int status;
786 struct addrinfo hints, *servinfo, *p;
787 struct sockaddr_storage sain;
788 char s[INET6_ADDRSTRLEN];
789 int rv;
790 int yes=1;
791
792
793 memset(&hints, 0, sizeof hints); // make sure the struct is empty
794 hints.ai_family = AF_UNSPEC; // don't care IPv4 or IPv6
795 hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
796 hints.ai_flags = AI_PASSIVE; // use my IP
797
798
799 // get ready to connect
800 status = getaddrinfo(NULL, "SERVER_PORT", &hints, &servinfo);
801 if(status<0) {
802 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
803 return(BSCS_UNKNOWN_HOST);
804 }
805 if(servinfo==NULL) return(BSCS_UNKNOWN_HOST);
806
807 // loop through all the results and bind to the first we can
808 for(p = servinfo; p != NULL; p = p->ai_next) {
809 if ((sd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
810 perror("server: socket");
811 continue;
812 }
813
814 if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
815 perror("setsockopt");
816 exit(1);
817 }
818
819 if (bind(sd, p->ai_addr, p->ai_addrlen) == -1) {
820 close(sd);
821 perror("server: bind");
822 continue;
823 }
824 break;
825 }
826 if (p == NULL) {
827 fprintf(stderr, "server: failed to bind\n");
828 return(BSCS_CANNOT_BIND_PORT);
829 }
830
831 freeaddrinfo(servinfo); // all done with this structure
832
833
834 #else
835
836 struct sockaddr_in sain;
837 fromlen = sizeof(sain);
838
839 /*
840 * Get a socket to work with. This socket will
841 * be in the UNIX domain, and will be a
842 * stream socket.
843 */
844 if ((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
845 perror("server: socket");
846 exit(1);
847 }
848
849 /* bind server port */
850 sain.sin_family = AF_INET;
851 sain.sin_addr.s_addr = htonl(INADDR_ANY);
852 sain.sin_port = htons(SERVER_PORT);
853
854 if(bind(sd, (struct sockaddr *) &sain, sizeof(sain))<0) {
855 perror("cannot bind port ");
856 return(-1);
857 }
858
859 #endif
860
861 /*
862 * Listen on the socket.
863 */
864 if (listen(sd, 10) < 0) {
865 perror("server: listen");
866 exit(1);
867 }
868
869 sa.sa_handler = sigchld_handler; // reap all dead processes
870 sigemptyset(&sa.sa_mask);
871 sa.sa_flags = SA_RESTART;
872 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
873 perror("sigaction");
874 exit(1);
875 }
876
877 printf("server: waiting for connections...\n");
878
879 while(1) {
880 /*
881 * Accept connections. When we accept one, ns
882 * will be connected to the client. fsain will
883 * contain the address of the client.
884 */
885 fromlen = sizeof(sain);
886 if ((ns = accept(sd, (struct sockaddr*)&sain, &fromlen)) < 0) {
887 perror("server: accept");
888 exit(1);
889 }
890 #ifdef IPv6
891 inet_ntop(sain.ss_family, get_in_addr((struct sockaddr *)&sain),s, sizeof s);
892 printf("server: got connection from %s\n", s);
893 #else
894 char hostname[100],service[100];
895 bzero(hostname,100);
896 bzero(service,100);
897 addrlen = sizeof(struct sockaddr);
898 if (getnameinfo((struct sockaddr *)&sain,addrlen,hostname,100,service,100,0) != 0)
899 {
900 fprintf(stdout,"--- errno=%i %s\n",errno,strerror(errno));
901 // perror("getnameinfo");
902 }
903
904 printf("Connection received from host (%s) on remote port (%s)\n",hostname,service);
905 #endif
906
907 #ifndef VERBOSE_LEVEL
908 //VERBOSE_LEVEL = 8;
909 #endif
910
911 // TODO: LOG FILE
912
913 char dst[INET6_ADDRSTRLEN];
914 inet_ntop(AF_INET, &sain.sin_addr,dst, INET6_ADDRSTRLEN);
915 timer=time(NULL);
916 char *t = asctime(localtime(&timer));
917 t[24]=0;
918
919
920 FILE *fid = fopen(LOGFILE,"a");
921 fprintf(fid,"\n%s\t%s\t%s",t,dst,hostname);
922 fclose(fid);
923
924 if (!fork()) { // this is the child process
925 close(sd); // child doesn't need the listener
926
927 /* Change the file mode mask */
928 umask(0);
929
930 /* Change the current working directory. This prevents the current
931 directory from being locked; hence not being able to remove it. */
932
933 if ((chdir("/")) < 0) {
934 syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)","/", errno, strerror(errno) );
935 exit(-1);
936 }
937
938 /* Redirect standard files to /dev/null */
939
940 freopen( "/dev/null", "r", stdin);
941 freopen( "/dev/null", "w", stdout);
942 freopen( "/dev/null", "w", stderr);
943
944 if (VERBOSE_LEVEL>7) fprintf(stdout,"server123 err=%i %s\n",errno,strerror(errno));
945
946 errno = 0;
947 DoJob(ns);
948
949 close(ns);
950 exit(0);
951 }
952 close(ns);
953 }
954
955 close(sd);
956 exit(0);
957 }
958