SDDSlib
Loading...
Searching...
No Matches
sddslogserver.c File Reference

Server program to log data to SDDS (Self Describing Data Sets) files. More...

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/stat.h>
#include <dirent.h>
#include "mdb.h"
#include "SDDS.h"
#include "scan.h"

Go to the source code of this file.

Macros

#define BUFLEN   16384
 
#define DISCONNECT   0 /* Disconnect from the server—forces server to terminate the forked process */
 
#define ADD_VALUE   1
 
#define MAKE_DIRECTORY   2
 
#define CHANGE_DIRECTORY   3
 
#define GET_TIME_SPAN   4 /* Get values between two times */
 
#define GET_LAST_N   5 /* Get last N values */
 
#define SDDSPLOT   6 /* Make an sddsplot and return its URL */
 
#define ADD_CHANNEL   7
 
#define DELETE_VALUE   8
 
#define UPDATE_CHD   9
 
#define LIST_DIRS   10
 
#define LIST_CHANNELS   11
 
#define N_COMMANDS   12
 
#define CLI_PORT   0
 
#define CLI_ROOT   1
 
#define CLI_FORBID   2
 
#define CLI_SDDSPLOT_PATH   3
 
#define N_OPTIONS   4
 

Functions

int dostuff (int)
 
int createChannel (char *spec)
 
int addValue (char *spec)
 
int runSddsplot (char *returnBuffer, char *options)
 
void updateChannelDescription (void)
 
int makeDirectoryList (int64_t *returnNumber, char ***returnBuffer)
 
int getChannelList (int64_t *returnNumber, char ***returnBuffer)
 
void error (const char *msg, char *progName)
 
int writeReply (int sock, const char *message, int code)
 
int writeReplyList (int sock, int64_t nItems, char **messageList)
 
void freeReplyList (int64_t nItems, char **item)
 
int chdirFromRoot (char *path)
 
void shutdownServer (int arg)
 
int main (int argc, char *argv[])
 

Variables

char * rootDir
 
char * command [N_COMMANDS]
 
short forbid [N_COMMANDS]
 
char * option [N_OPTIONS]
 
const char * USAGE
 
char * sddsplotPath = NULL
 
static int sockfd = -1
 

Detailed Description

Server program to log data to SDDS (Self Describing Data Sets) files.

This program listens on a specified port and handles multiple client connections to log data into SDDS files. It supports various commands such as adding values, creating channels, making directories, and generating SDDS plots.

Features:

  • Handles multiple client connections using forked processes.
  • Supports dynamic creation and management of SDDS channels.
  • Provides command restrictions through the forbid option.
  • Generates SDDS plots and returns their URLs.

Usage:

sddslogserver -port=<portNumber> [-root=<rootDirectory>] [-forbid=<command1,command2,...>] [-sddsplotPath=<path>]

Options:

  • -port Port number on which the server listens (required).
  • -root Path of the root directory (optional, defaults to current directory).
  • -forbid Comma-separated list of commands to forbid (optional).
  • -sddsplotPath Pathname for SDDS plot output files (optional).
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Author
M. Borland, R. Soliday

Definition in file sddslogserver.c.

Macro Definition Documentation

◆ ADD_CHANNEL

#define ADD_CHANNEL   7

Definition at line 71 of file sddslogserver.c.

◆ ADD_VALUE

#define ADD_VALUE   1

Definition at line 65 of file sddslogserver.c.

◆ BUFLEN

#define BUFLEN   16384

Definition at line 52 of file sddslogserver.c.

◆ CHANGE_DIRECTORY

#define CHANGE_DIRECTORY   3

Definition at line 67 of file sddslogserver.c.

◆ CLI_FORBID

#define CLI_FORBID   2

Definition at line 164 of file sddslogserver.c.

◆ CLI_PORT

#define CLI_PORT   0

Definition at line 162 of file sddslogserver.c.

◆ CLI_ROOT

#define CLI_ROOT   1

Definition at line 163 of file sddslogserver.c.

◆ CLI_SDDSPLOT_PATH

#define CLI_SDDSPLOT_PATH   3

Definition at line 165 of file sddslogserver.c.

◆ DELETE_VALUE

#define DELETE_VALUE   8

Definition at line 72 of file sddslogserver.c.

◆ DISCONNECT

#define DISCONNECT   0 /* Disconnect from the server—forces server to terminate the forked process */

Definition at line 64 of file sddslogserver.c.

◆ GET_LAST_N

#define GET_LAST_N   5 /* Get last N values */

Definition at line 69 of file sddslogserver.c.

◆ GET_TIME_SPAN

#define GET_TIME_SPAN   4 /* Get values between two times */

Definition at line 68 of file sddslogserver.c.

◆ LIST_CHANNELS

#define LIST_CHANNELS   11

Definition at line 75 of file sddslogserver.c.

◆ LIST_DIRS

#define LIST_DIRS   10

Definition at line 74 of file sddslogserver.c.

◆ MAKE_DIRECTORY

#define MAKE_DIRECTORY   2

Definition at line 66 of file sddslogserver.c.

◆ N_COMMANDS

#define N_COMMANDS   12

Definition at line 76 of file sddslogserver.c.

◆ N_OPTIONS

#define N_OPTIONS   4

Definition at line 166 of file sddslogserver.c.

◆ SDDSPLOT

#define SDDSPLOT   6 /* Make an sddsplot and return its URL */

Definition at line 70 of file sddslogserver.c.

◆ UPDATE_CHD

#define UPDATE_CHD   9

Definition at line 73 of file sddslogserver.c.

Function Documentation

◆ addValue()

int addValue ( char * spec)

Definition at line 512 of file sddslogserver.c.

517{
518 char *ptr;
519 char buffer[BUFLEN];
520 int32_t type;
521 int64_t rows;
522 SDDS_DATASET SDDSin;
523 void *data = NULL;
524
525 if (!(ptr = strchr(spec, ',')))
526 return 1;
527 *ptr++ = 0;
528
529 snprintf(buffer, sizeof(buffer), "%s.sdds", spec);
530 if (!SDDS_InitializeAppendToPage(&SDDSin, buffer, 1, &rows)) {
531 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
532 return 2;
533 }
534 printf("Initialized, %" PRId64 " rows\n", rows);
535 fflush(stdout);
536 if (!SDDS_LengthenTable(&SDDSin, 1)) {
537 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
538 return 3;
539 }
540 printf("Lengthened table\n");
541 fflush(stdout);
542
543 if (SDDS_GetColumnInformation(&SDDSin, "type", &type, SDDS_GET_BY_NAME, spec) != SDDS_LONG) {
544 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
545 SDDS_Terminate(&SDDSin);
546 return 4;
547 }
548 printf("Got type information\n");
549 fflush(stdout);
550
551 if (type != SDDS_STRING)
552 data = SDDS_Malloc(SDDS_type_size[type - 1]);
553 if (SDDS_ScanData(ptr, type, 0, data, 0, 0) == 0) {
554 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
555 SDDS_Terminate(&SDDSin);
556 return 5;
557 }
558 printf("Scanned data\n");
559 fflush(stdout);
560
561 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, "SampleIDNumber", rows, "Time", getTimeInSecs(), NULL)) {
562 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
563 SDDS_Terminate(&SDDSin);
564 return 6;
565 }
566 printf("Set row values\n");
567 fflush(stdout);
568
569 switch (type) {
570 case SDDS_STRING:
571 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, ptr, NULL)) {
572 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
573 return 7;
574 }
575 break;
576 case SDDS_FLOAT:
577 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((float *)data), NULL)) {
578 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
579 return 7;
580 }
581 break;
582 case SDDS_DOUBLE:
583 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((double *)data), NULL)) {
584 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
585 return 7;
586 }
587 break;
588 case SDDS_SHORT:
589 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((short *)data), NULL)) {
590 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
591 return 7;
592 }
593 break;
594 case SDDS_LONG:
595 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int32_t *)data), NULL)) {
596 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
597 return 7;
598 }
599 break;
600 case SDDS_LONG64:
601 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int64_t *)data), NULL)) {
602 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
603 return 7;
604 }
605 break;
606 default:
607 break;
608 }
609 printf("Set row value\n");
610 fflush(stdout);
611 if (data)
612 free(data);
613
614 if (!SDDS_UpdatePage(&SDDSin, FLUSH_TABLE)) {
615 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
616 return 8;
617 }
618 printf("Updated page\n");
619 fflush(stdout);
620 if (!SDDS_Terminate(&SDDSin)) {
621 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
622 return 9;
623 }
624 printf("Terminated\n");
625 fflush(stdout);
626 return 0;
627}
int32_t SDDS_ScanData(char *string, int32_t type, int32_t field_length, void *data, int64_t index, int32_t is_parameter)
Scans a string and saves the parsed value into a data pointer according to the specified data type.
int32_t SDDS_type_size[SDDS_NUM_TYPES]
Array of sizes for each supported data type.
Definition SDDS_data.c:62
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_SetRowValues(SDDS_DATASET *SDDS_dataset, int32_t mode, int64_t row,...)
int32_t SDDS_GetColumnInformation(SDDS_DATASET *SDDS_dataset, char *field_name, void *memory, int32_t mode,...)
Retrieves information about a specified column in the SDDS dataset.
Definition SDDS_info.c:41
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeAppendToPage(SDDS_DATASET *SDDS_dataset, const char *filename, int64_t updateInterval, int64_t *rowsPresentReturn)
Initializes the SDDS dataset for appending data to the last page of an existing file.
int32_t SDDS_UpdatePage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the current page of the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
Definition SDDS_utils.c:639
#define SDDS_FLOAT
Identifier for the float data type.
Definition SDDStypes.h:43
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
Definition SDDStypes.h:61
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
Definition SDDStypes.h:49
double getTimeInSecs()
Get the current time in seconds since the Epoch with high resolution.

◆ chdirFromRoot()

int chdirFromRoot ( char * path)

Definition at line 155 of file sddslogserver.c.

155 {
156 char buffer[BUFLEN];
157 snprintf(buffer, sizeof(buffer), "%s/%s", rootDir, (path && *path) ? path : "");
158 fprintf(stderr, "Changing directory to %s\n", buffer);
159 return chdir(buffer);
160}

◆ createChannel()

int createChannel ( char * spec)

Definition at line 458 of file sddslogserver.c.

460{
461 char *chName, *chType, *chUnits, *chDescription;
462 char buffer[BUFLEN];
463 SDDS_DATASET SDDSout;
464 int32_t type;
465
466 chName = spec;
467 if (!(chType = strchr(spec, ',')))
468 return 1;
469 *chType++ = 0;
470 if (!(chUnits = strchr(chType, ',')))
471 return 2;
472 *chUnits++ = 0;
473 if ((type = SDDS_IdentifyType(chType)) == 0)
474 return 2;
475 if (!(chDescription = strchr(chUnits, ',')))
476 return 3;
477 *chDescription++ = 0;
478
479 if (strcmp(chName, "Time") == 0)
480 return 4;
481
482 snprintf(buffer, sizeof(buffer), "%s.sdds", chName);
483 if (fexists(buffer))
484 return 5;
485
486 if (!SDDS_InitializeOutput(&SDDSout, SDDS_BINARY, 0, NULL, NULL, buffer) ||
487 !SDDS_DefineSimpleColumn(&SDDSout, "SampleIDNumber", NULL, SDDS_LONG64) ||
488 !SDDS_DefineSimpleColumn(&SDDSout, "Time", "s", SDDS_DOUBLE) ||
489 SDDS_DefineColumn(&SDDSout, chName, NULL, chUnits, chDescription, NULL, type, 0) < 0 ||
490 !SDDS_WriteLayout(&SDDSout) ||
491 !SDDS_StartPage(&SDDSout, 1) ||
492 !SDDS_WritePage(&SDDSout) ||
493 !SDDS_Terminate(&SDDSout))
494 return 6;
495
496 snprintf(buffer, sizeof(buffer), "sddsquery %s.sdds -sddsOutput=%s.chd -column", chName, chName);
497 system(buffer);
498 snprintf(buffer, sizeof(buffer), "%s.chd", chName);
499 if (!fexists(buffer))
500 return 6;
501
502 updateChannelDescription();
503
504 return 0;
505}
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
int32_t SDDS_DefineSimpleColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *unit, int32_t type)
Defines a simple data column within the SDDS dataset.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_IdentifyType(char *typeName)
Identifies the SDDS data type based on its string name.
long fexists(const char *filename)
Checks if a file exists.
Definition fexists.c:27

◆ dostuff()

int dostuff ( int sock)

Definition at line 340 of file sddslogserver.c.

340 {
341 int n, code;
342 char buffer[BUFLEN];
343 char *ptr1;
344 short persist = 1;
345 int64_t nItems;
346 char **itemValue;
347
348 while (persist) {
349 memset(buffer, 0, BUFLEN);
350 n = read(sock, buffer, BUFLEN - 1);
351 if (n < 0)
352 error("ERROR reading from socket", "sddslogserver");
353 if (strlen(buffer) == 0)
354 continue;
355 chop_nl(buffer);
356 printf("Here is the message: <%s>\n", buffer);
357
358 if ((ptr1 = strchr(buffer, ':')))
359 *ptr1++ = 0;
360 if ((code = match_string(buffer, command, N_COMMANDS, EXACT_MATCH)) < 0 || forbid[code]) {
361 writeReply(sock, "Forbidden operation.", 0);
362 continue;
363 }
364 switch (code) {
365 case DISCONNECT:
366 printf("Disconnecting\n");
367 fflush(stdout);
368 persist = 0;
369 break;
370 case ADD_VALUE:
371 /* syntax: channel=value */
372 printf("Add value: %s\n", ptr1);
373 if ((code = addValue(ptr1)) == 0)
374 writeReply(sock, "ok", code);
375 else
376 writeReply(sock, "Error: Failed to add value.", code);
377 break;
378 case DELETE_VALUE:
379 /* syntax: channel,sampleID */
380 printf("Delete value: %s\n", ptr1);
381 writeReply(sock, "Error: Can't do that yet.", EXIT_FAILURE);
382 break;
383 case ADD_CHANNEL:
384 /* syntax: channel,type */
385 printf("Add channel: %s\n", ptr1);
386 if ((code = createChannel(ptr1)) == 0)
387 writeReply(sock, "ok", code);
388 else
389 writeReply(sock, "Error: Failed to create channel.", code);
390 break;
391 case MAKE_DIRECTORY:
392 /* syntax: directoryName */
393 printf("Make directory: %s\n", ptr1);
394 if ((code = mkdir(ptr1, 0700))) {
395 writeReply(sock, "Error: Making directory.", code);
396 } else {
397 writeReply(sock, "ok", code);
398 }
399 break;
400 case CHANGE_DIRECTORY:
401 /* syntax: path */
402 if (ptr1 && *ptr1 && strstr(ptr1, "..")) {
403 /* Only absolute paths are allowed */
404 writeReply(sock, "Error: Relative paths not supported.", EXIT_FAILURE);
405 } else {
406 printf("Change directory: %s\n", ptr1 && *ptr1 ? ptr1 : "base");
407 if ((code = chdirFromRoot(ptr1)))
408 writeReply(sock, "Error: CD failed.", code);
409 else
410 writeReply(sock, "CD ok.", code);
411 }
412 break;
413 case GET_TIME_SPAN:
414 /* syntax: channel,startTime,endTime */
415 printf("Get time span: %s\n", ptr1);
416 writeReply(sock, "Error: Can't do that yet.", EXIT_FAILURE);
417 break;
418 case GET_LAST_N:
419 /* syntax: channel,N; if N<=0, return all data */
420 printf("Get last N: %s\n", ptr1);
421 writeReply(sock, "Error: Can't do that yet.", EXIT_FAILURE);
422 break;
423 case SDDSPLOT:
424 /* syntax:<sddsplotCommand> */
425 printf("sddsplot: %s\n", ptr1);
426 code = runSddsplot(buffer, ptr1);
427 writeReply(sock, buffer, code);
428 break;
429 case UPDATE_CHD:
430 updateChannelDescription();
431 writeReply(sock, "ok", EXIT_SUCCESS);
432 break;
433 case LIST_DIRS:
434 if (makeDirectoryList(&nItems, &itemValue))
435 writeReply(sock, "Failed to retrieve directory list.", EXIT_FAILURE);
436 else {
437 writeReplyList(sock, nItems, itemValue);
438 freeReplyList(nItems, itemValue);
439 }
440 break;
441 case LIST_CHANNELS:
442 if (getChannelList(&nItems, &itemValue))
443 writeReply(sock, "Failed to retrieve channel list.", EXIT_FAILURE);
444 else {
445 writeReplyList(sock, nItems, itemValue);
446 freeReplyList(nItems, itemValue);
447 }
448 break;
449 default:
450 printf("Unknown command: %s\n", buffer);
451 writeReply(sock, "Error: Unknown command.", EXIT_FAILURE);
452 break;
453 }
454 }
455 return EXIT_SUCCESS;
456}
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.

◆ error()

void error ( const char * msg,
char * progName )

Definition at line 108 of file sddslogserver.c.

108 {
109 char s[BUFLEN];
110 snprintf(s, sizeof(s), "%s (%s)", msg, progName);
111 perror(s);
112 exit(EXIT_FAILURE);
113}

◆ freeReplyList()

void freeReplyList ( int64_t nItems,
char ** item )

Definition at line 145 of file sddslogserver.c.

145 {
146 int64_t i;
147 if (!item)
148 return;
149 for (i = 0; i < nItems; i++)
150 if (item[i])
151 free(item[i]);
152 free(item);
153}

◆ getChannelList()

int getChannelList ( int64_t * returnNumber,
char *** returnBuffer )

Definition at line 729 of file sddslogserver.c.

729 {
730 SDDS_DATASET SDDSin;
731
732 *returnBuffer = NULL;
733 *returnNumber = 0;
734
735 updateChannelDescription();
736 if (!fexists("allChd.sdds"))
737 return 0;
738 if (!SDDS_InitializeInput(&SDDSin, "allChd.sdds")) {
739 printf("Problem reading allChd.sdds\n");
740 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
741 return 1;
742 }
743 if (SDDS_ReadPage(&SDDSin) < 0)
744 /* Assume file is empty */
745 return 0;
746 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
747 printf("Row count: %" PRId64 "\n", *returnNumber);
748 return 2;
749 }
750 if (*returnNumber == 0)
751 return 0;
752 if (!(*returnBuffer = SDDS_GetColumn(&SDDSin, "Name"))) {
753 printf("Problem getting Name\n");
754 return 3;
755 }
756 return 0;
757}
void * SDDS_GetColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves a copy of the data for a specified column, including only rows marked as "of interest".
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)

◆ main()

int main ( int argc,
char * argv[] )

Definition at line 198 of file sddslogserver.c.

198 {
199 int newsockfd, portno, pid;
200 int reuse = 1;
201 socklen_t clilen;
202 struct sockaddr_in serv_addr, cli_addr;
203 int i_arg, j, code;
204 SCANNED_ARG *s_arg;
205
206 /* Allow zombie children to die */
207 signal(SIGCHLD, SIG_IGN);
208 signal(SIGINT, shutdownServer);
209
210 /* Parse arguments */
212 argc = scanargs(&s_arg, argc, argv);
213 if (argc < 2) {
214 fprintf(stderr, "%s", USAGE);
215 exit(EXIT_FAILURE);
216 }
217
218 portno = -1;
219 rootDir = NULL;
220 for (i_arg = 1; i_arg < argc; i_arg++) {
221 if (s_arg[i_arg].arg_type == OPTION) {
222 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
223 case CLI_PORT:
224 if (s_arg[i_arg].n_items != 2 ||
225 sscanf(s_arg[i_arg].list[1], "%d", &portno) != 1 ||
226 portno <= 0) {
227 fprintf(stderr, "Error: Invalid syntax/values for -port argument\n%s", USAGE);
228 exit(EXIT_FAILURE);
229 }
230 break;
231 case CLI_ROOT:
232 if (s_arg[i_arg].n_items != 2 ||
233 strlen(rootDir = s_arg[i_arg].list[1]) == 0) {
234 fprintf(stderr, "Error: Invalid syntax/values for -root argument\n%s", USAGE);
235 exit(EXIT_FAILURE);
236 }
237 break;
238 case CLI_FORBID:
239 if (s_arg[i_arg].n_items < 2) {
240 fprintf(stderr, "Error: Invalid syntax/values for -forbid argument\n%s", USAGE);
241 exit(EXIT_FAILURE);
242 }
243 for (j = 1; j < s_arg[i_arg].n_items; j++) {
244 if ((code = match_string(s_arg[i_arg].list[j], command, N_COMMANDS, 0)) < 0) {
245 fprintf(stderr, "Error: Unknown command for -forbid: %s\n", s_arg[i_arg].list[j]);
246 exit(EXIT_FAILURE);
247 }
248 forbid[code] = 1;
249 }
250 break;
251 case CLI_SDDSPLOT_PATH:
252 if (s_arg[i_arg].n_items != 2) {
253 fprintf(stderr, "Error: Invalid syntax for -sddsplotPath option\n%s", USAGE);
254 exit(EXIT_FAILURE);
255 }
256 sddsplotPath = s_arg[i_arg].list[1];
257 break;
258 default:
259 fprintf(stderr, "Invalid or ambiguous option: %s\n%s", s_arg[i_arg].list[0], USAGE);
260 exit(EXIT_FAILURE);
261 break;
262 }
263 } else {
264 fprintf(stderr, "Invalid or ambiguous option: %s\n%s", s_arg[i_arg].list[0], USAGE);
265 exit(EXIT_FAILURE);
266 }
267 }
268
269 if (!rootDir) {
270 cp_str(&rootDir, ".");
271 }
272 if (!fexists(rootDir))
273 error("Error: Root directory not found", argv[0]);
274 chdir(rootDir);
275
276 /* Create socket */
277 sockfd = socket(AF_INET, SOCK_STREAM, 0);
278 if (sockfd < 0)
279 error("Error opening socket", argv[0]);
280 printf("sockfd = %d\n", sockfd);
281 memset(&serv_addr, 0, sizeof(serv_addr));
282
283 /* Set the socket to SO_REUSEADDR */
284 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse)) < 0)
285 perror("setsockopt(SO_REUSEADDR) failed");
286
287#ifdef SO_REUSEPORT
288 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char *)&reuse, sizeof(reuse)) < 0)
289 perror("setsockopt(SO_REUSEPORT) failed");
290#endif
291
292 /* Bind the socket to a port number */
293 serv_addr.sin_family = AF_INET;
294 serv_addr.sin_addr.s_addr = INADDR_ANY;
295 serv_addr.sin_port = htons(portno);
296 if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
297 error("Error on port binding. Check port number.", argv[0]);
298
299 listen(sockfd, 5);
300 clilen = sizeof(cli_addr);
301 while (1) {
302 printf("Waiting for new socket connection\n");
303 fflush(stdout);
304 newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
305 printf("Got new socket connection\n");
306 fflush(stdout);
307 if (newsockfd < 0) {
308 if (sockfd >= 0)
309 close(sockfd);
310 error("Error on accept", argv[0]);
311 }
312 pid = fork();
313 if (pid < 0)
314 error("Error on fork", argv[0]);
315 if (pid == 0) {
316 close(sockfd);
317 dostuff(newsockfd);
318 printf("Returned from dostuff\n");
319 fflush(stdout);
320 exit(EXIT_SUCCESS);
321 } else {
322 printf("Forked process\n");
323 fflush(stdout);
324 close(newsockfd);
325 }
326 } /* end of while */
327 printf("Exited while loop\n");
328 fflush(stdout);
329 if (sockfd > 0)
330 close(sockfd);
331 return EXIT_SUCCESS; /* We never get here */
332}
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
Definition cp_str.c:28
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36

◆ makeDirectoryList()

int makeDirectoryList ( int64_t * returnNumber,
char *** returnBuffer )

Definition at line 695 of file sddslogserver.c.

695 {
696 SDDS_DATASET SDDSin;
697 char command[BUFLEN];
698
699 if (returnNumber)
700 *returnNumber = 0;
701 if (returnBuffer)
702 *returnBuffer = NULL;
703
704 remove("dirList.sdds");
705 snprintf(command, sizeof(command),
706 "find . -type d -maxdepth 1 | tail -n +2 | plaindata2sdds -pipe=in dirList.sdds -input=ascii -column=DirectoryName,string -norow");
707 system(command);
708 if (!SDDS_InitializeInput(&SDDSin, "dirList.sdds")) {
709 printf("Problem reading dirList.sdds\n");
710 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
711 return 1;
712 }
713 if (SDDS_ReadPage(&SDDSin) < 0)
714 /* Assume file is empty */
715 return 0;
716 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
717 printf("Row count: %" PRId64 "\n", *returnNumber);
718 return 2;
719 }
720 if (*returnNumber == 0)
721 return 0;
722 if (!(*returnBuffer = SDDS_GetColumn(&SDDSin, "DirectoryName"))) {
723 printf("Problem getting DirectoryName\n");
724 return 3;
725 }
726 return 0;
727}

◆ runSddsplot()

int runSddsplot ( char * returnBuffer,
char * options )

Definition at line 629 of file sddslogserver.c.

629 {
630 char command[BUFLEN];
631 char template[BUFLEN];
632 int fd;
633
634 // Ensure sddsplotPath is set
635 if (!sddsplotPath) {
636 fprintf(stderr, "Error: sddsplotPath is not set.\n");
637 return 1;
638 }
639
640 // Create the template with sddsplotPath and "png-XXXXXX.png"
641 // mkstemps requires the template to end with "XXXXXX" followed by the suffix
642 snprintf(template, sizeof(template), "%s/png-XXXXXX.png", sddsplotPath);
643
644 // Create a mutable copy of the template for mkstemps
645 char *tempTemplate = strdup(template);
646 if (!tempTemplate) {
647 perror("strdup");
648 return 1;
649 }
650
651 // mkstemps replaces "XXXXXX" with a unique suffix and keeps the ".png" extension
652 fd = mkstemps(tempTemplate, 4); // 4 is the length of ".png"
653 if (fd == -1) {
654 perror("mkstemps");
655 free(tempTemplate);
656 return 1;
657 }
658
659 // Close the file descriptor as we don't need it
660 close(fd);
661
662 // tempTemplate now contains the unique filename with ".png"
663 snprintf(command, sizeof(command), "sddsplot -device=png -output=%s %s", tempTemplate, options);
664 printf("Executing: %s\n", command);
665 fflush(stdout);
666
667 // Copy the filename to returnBuffer
668 strncpy(returnBuffer, tempTemplate, BUFLEN - 1);
669 returnBuffer[BUFLEN - 1] = '\0';
670
671 // Free the duplicated template
672 free(tempTemplate);
673
674 // Execute the command
675 return system(command);
676}

◆ shutdownServer()

void shutdownServer ( int arg)

Definition at line 190 of file sddslogserver.c.

190 {
191 printf("Closing sockfd=%d\n", sockfd);
192 fflush(stdout);
193 if (sockfd >= 0)
194 close(sockfd);
195 exit(EXIT_SUCCESS);
196}

◆ updateChannelDescription()

void updateChannelDescription ( void )

Definition at line 507 of file sddslogserver.c.

507 {
508 char *command = "sddscombine *.chd -merge -pipe=out | sddsprocess -pipe=in -match=col,Name=SampleIDNumber,! -match=col,Name=Time,! allChd.sdds";
509 system(command);
510}

◆ writeReply()

int writeReply ( int sock,
const char * message,
int code )

Definition at line 115 of file sddslogserver.c.

115 {
116 char buffer[BUFLEN + 20];
117 if (code) {
118 snprintf(buffer, sizeof(buffer), "error:%s (code %d)\n", message, code);
119 return write(sock, buffer, strlen(buffer));
120 } else {
121 // snprintf(buffer, sizeof(buffer), "ok:%s\n", message);
122 return write(sock, message, strlen(message));
123 }
124}

◆ writeReplyList()

int writeReplyList ( int sock,
int64_t nItems,
char ** messageList )

Definition at line 126 of file sddslogserver.c.

126 {
127 int64_t i;
128 char message[BUFLEN];
129 strncpy(message, "ok:", sizeof(message) - 1);
130 message[sizeof(message) - 1] = 0;
131
132 /* Need to check for buffer overflow */
133 printf("%" PRId64 " reply items\n", nItems);
134 for (i = 0; i < nItems; i++) {
135 printf("Item %" PRId64 ": %s\n", i, messageList[i]);
136 strncat(message, messageList[i], sizeof(message) - strlen(message) - 1);
137 if (i != (nItems - 1))
138 strncat(message, ",", sizeof(message) - strlen(message) - 1);
139 }
140 strncat(message, "\n", sizeof(message) - strlen(message) - 1);
141 printf("message: %s", message);
142 return write(sock, message, strlen(message));
143}

Variable Documentation

◆ command

char* command[N_COMMANDS]
Initial value:
= {
"disconnect",
"addValue",
"mkdir",
"cd",
"getTimeSpan",
"getLastN",
"sddsplot",
"addChannel",
"deleteValue",
"updateChDesc",
"listDirs",
"listChannels",
}

Definition at line 78 of file sddslogserver.c.

78 {
79 "disconnect",
80 "addValue",
81 "mkdir",
82 "cd",
83 "getTimeSpan",
84 "getLastN",
85 "sddsplot",
86 "addChannel",
87 "deleteValue",
88 "updateChDesc",
89 "listDirs",
90 "listChannels",
91};

◆ forbid

short forbid[N_COMMANDS]
Initial value:
= {
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
}

Definition at line 93 of file sddslogserver.c.

93 {
94 0,
95 0,
96 0,
97 0,
98 0,
99 0,
100 0,
101 0,
102 0,
103 0,
104 0,
105 0,
106};

◆ option

char* option[N_OPTIONS]
Initial value:
= {
"port",
"root",
"forbid",
"sddsplotpath"
}

Definition at line 168 of file sddslogserver.c.

168 {
169 "port",
170 "root",
171 "forbid",
172 "sddsplotpath"
173};

◆ rootDir

char* rootDir

Definition at line 62 of file sddslogserver.c.

◆ sddsplotPath

char* sddsplotPath = NULL

Definition at line 186 of file sddslogserver.c.

◆ sockfd

int sockfd = -1
static

Definition at line 188 of file sddslogserver.c.

◆ USAGE

const char* USAGE
Initial value:
=
"Usage: sddslogserver -port=<portNumber> [-root=<rootDirectory>] \n"
" [-forbid=<command1,command2,...>] \n"
" [-sddsplotPath=<path>]\n\n"
"Options:\n"
" -port Port number on which the server listens (required).\n"
" -root Path of the root directory (optional, defaults to current directory).\n"
" -forbid Comma-separated list of commands to forbid (optional).\n"
" -sddsplotPath Pathname for SDDS plot output files (optional).\n\n"
"Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n"

Definition at line 175 of file sddslogserver.c.