SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddslogserver.c File Reference

Detailed Description

Server program to log data to SDDS 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. Key features include:

  • Handling multiple client connections using forked processes.
  • Dynamic creation and management of SDDS channels.
  • Command restrictions through the forbid option.
  • Generating SDDS plots and returning their URLs.

Usage

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

Options

Required Description
-port Port number on which the server listens.
Optional Description
-root Path of the root directory. Defaults to current directory.
-forbid Comma-separated list of commands to forbid.
-sddsplotPath Pathname for SDDS plot output files.

Requirements

  • -port must be a valid positive integer.
  • -root must specify an existing directory.
  • -sddsplotPath requires a valid directory path.
License
This file is distributed under the terms of the Software License Agreement found in the file LICENSE included with this distribution.
Authors
M. Borland, R. Soliday

Definition in file sddslogserver.c.

#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.

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[])
 

Function Documentation

◆ addValue()

int addValue ( char * spec)

Definition at line 526 of file sddslogserver.c.

531{
532 char *ptr;
533 char buffer[BUFLEN];
534 int32_t type;
535 int64_t rows;
536 SDDS_DATASET SDDSin;
537 void *data = NULL;
538
539 if (!(ptr = strchr(spec, ',')))
540 return 1;
541 *ptr++ = 0;
542
543 snprintf(buffer, sizeof(buffer), "%s.sdds", spec);
544 if (!SDDS_InitializeAppendToPage(&SDDSin, buffer, 1, &rows)) {
545 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
546 return 2;
547 }
548 printf("Initialized, %" PRId64 " rows\n", rows);
549 fflush(stdout);
550 if (!SDDS_LengthenTable(&SDDSin, 1)) {
551 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
552 return 3;
553 }
554 printf("Lengthened table\n");
555 fflush(stdout);
556
557 if (SDDS_GetColumnInformation(&SDDSin, "type", &type, SDDS_GET_BY_NAME, spec) != SDDS_LONG) {
558 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
559 SDDS_Terminate(&SDDSin);
560 return 4;
561 }
562 printf("Got type information\n");
563 fflush(stdout);
564
565 if (type != SDDS_STRING)
566 data = SDDS_Malloc(SDDS_type_size[type - 1]);
567 if (SDDS_ScanData(ptr, type, 0, data, 0, 0) == 0) {
568 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
569 SDDS_Terminate(&SDDSin);
570 return 5;
571 }
572 printf("Scanned data\n");
573 fflush(stdout);
574
575 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, "SampleIDNumber", rows, "Time", getTimeInSecs(), NULL)) {
576 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
577 SDDS_Terminate(&SDDSin);
578 return 6;
579 }
580 printf("Set row values\n");
581 fflush(stdout);
582
583 switch (type) {
584 case SDDS_STRING:
585 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, ptr, NULL)) {
586 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
587 return 7;
588 }
589 break;
590 case SDDS_FLOAT:
591 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((float *)data), NULL)) {
592 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
593 return 7;
594 }
595 break;
596 case SDDS_DOUBLE:
597 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((double *)data), NULL)) {
598 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
599 return 7;
600 }
601 break;
602 case SDDS_SHORT:
603 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((short *)data), NULL)) {
604 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
605 return 7;
606 }
607 break;
608 case SDDS_LONG:
609 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int32_t *)data), NULL)) {
610 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
611 return 7;
612 }
613 break;
614 case SDDS_LONG64:
615 if (!SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int64_t *)data), NULL)) {
616 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
617 return 7;
618 }
619 break;
620 default:
621 break;
622 }
623 printf("Set row value\n");
624 fflush(stdout);
625 if (data)
626 free(data);
627
628 if (!SDDS_UpdatePage(&SDDSin, FLUSH_TABLE)) {
629 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
630 return 8;
631 }
632 printf("Updated page\n");
633 fflush(stdout);
634 if (!SDDS_Terminate(&SDDSin)) {
635 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
636 return 9;
637 }
638 printf("Terminated\n");
639 fflush(stdout);
640 return 0;
641}
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 169 of file sddslogserver.c.

169 {
170 char buffer[BUFLEN];
171 snprintf(buffer, sizeof(buffer), "%s/%s", rootDir, (path && *path) ? path : "");
172 fprintf(stderr, "Changing directory to %s\n", buffer);
173 return chdir(buffer);
174}

◆ createChannel()

int createChannel ( char * spec)

Definition at line 472 of file sddslogserver.c.

474{
475 char *chName, *chType, *chUnits, *chDescription;
476 char buffer[BUFLEN];
477 SDDS_DATASET SDDSout;
478 int32_t type;
479
480 chName = spec;
481 if (!(chType = strchr(spec, ',')))
482 return 1;
483 *chType++ = 0;
484 if (!(chUnits = strchr(chType, ',')))
485 return 2;
486 *chUnits++ = 0;
487 if ((type = SDDS_IdentifyType(chType)) == 0)
488 return 2;
489 if (!(chDescription = strchr(chUnits, ',')))
490 return 3;
491 *chDescription++ = 0;
492
493 if (strcmp(chName, "Time") == 0)
494 return 4;
495
496 snprintf(buffer, sizeof(buffer), "%s.sdds", chName);
497 if (fexists(buffer))
498 return 5;
499
500 if (!SDDS_InitializeOutput(&SDDSout, SDDS_BINARY, 0, NULL, NULL, buffer) ||
501 !SDDS_DefineSimpleColumn(&SDDSout, "SampleIDNumber", NULL, SDDS_LONG64) ||
502 !SDDS_DefineSimpleColumn(&SDDSout, "Time", "s", SDDS_DOUBLE) ||
503 SDDS_DefineColumn(&SDDSout, chName, NULL, chUnits, chDescription, NULL, type, 0) < 0 ||
504 !SDDS_WriteLayout(&SDDSout) ||
505 !SDDS_StartPage(&SDDSout, 1) ||
506 !SDDS_WritePage(&SDDSout) ||
507 !SDDS_Terminate(&SDDSout))
508 return 6;
509
510 snprintf(buffer, sizeof(buffer), "sddsquery %s.sdds -sddsOutput=%s.chd -column", chName, chName);
511 system(buffer);
512 snprintf(buffer, sizeof(buffer), "%s.chd", chName);
513 if (!fexists(buffer))
514 return 6;
515
516 updateChannelDescription();
517
518 return 0;
519}
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 354 of file sddslogserver.c.

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

◆ error()

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

Definition at line 122 of file sddslogserver.c.

122 {
123 char s[BUFLEN];
124 snprintf(s, sizeof(s), "%s (%s)", msg, progName);
125 perror(s);
126 exit(EXIT_FAILURE);
127}

◆ freeReplyList()

void freeReplyList ( int64_t nItems,
char ** item )

Definition at line 159 of file sddslogserver.c.

159 {
160 int64_t i;
161 if (!item)
162 return;
163 for (i = 0; i < nItems; i++)
164 if (item[i])
165 free(item[i]);
166 free(item);
167}

◆ getChannelList()

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

Definition at line 743 of file sddslogserver.c.

743 {
744 SDDS_DATASET SDDSin;
745
746 *returnBuffer = NULL;
747 *returnNumber = 0;
748
749 updateChannelDescription();
750 if (!fexists("allChd.sdds"))
751 return 0;
752 if (!SDDS_InitializeInput(&SDDSin, "allChd.sdds")) {
753 printf("Problem reading allChd.sdds\n");
754 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
755 return 1;
756 }
757 if (SDDS_ReadPage(&SDDSin) < 0)
758 /* Assume file is empty */
759 return 0;
760 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
761 printf("Row count: %" PRId64 "\n", *returnNumber);
762 return 2;
763 }
764 if (*returnNumber == 0)
765 return 0;
766 if (!(*returnBuffer = SDDS_GetColumn(&SDDSin, "Name"))) {
767 printf("Problem getting Name\n");
768 return 3;
769 }
770 return 0;
771}
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 212 of file sddslogserver.c.

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

709 {
710 SDDS_DATASET SDDSin;
711 char command[BUFLEN];
712
713 if (returnNumber)
714 *returnNumber = 0;
715 if (returnBuffer)
716 *returnBuffer = NULL;
717
718 remove("dirList.sdds");
719 snprintf(command, sizeof(command),
720 "find . -type d -maxdepth 1 | tail -n +2 | plaindata2sdds -pipe=in dirList.sdds -input=ascii -column=DirectoryName,string -norow");
721 system(command);
722 if (!SDDS_InitializeInput(&SDDSin, "dirList.sdds")) {
723 printf("Problem reading dirList.sdds\n");
724 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
725 return 1;
726 }
727 if (SDDS_ReadPage(&SDDSin) < 0)
728 /* Assume file is empty */
729 return 0;
730 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
731 printf("Row count: %" PRId64 "\n", *returnNumber);
732 return 2;
733 }
734 if (*returnNumber == 0)
735 return 0;
736 if (!(*returnBuffer = SDDS_GetColumn(&SDDSin, "DirectoryName"))) {
737 printf("Problem getting DirectoryName\n");
738 return 3;
739 }
740 return 0;
741}

◆ runSddsplot()

int runSddsplot ( char * returnBuffer,
char * options )

Definition at line 643 of file sddslogserver.c.

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

◆ shutdownServer()

void shutdownServer ( int arg)

Definition at line 204 of file sddslogserver.c.

204 {
205 printf("Closing sockfd=%d\n", sockfd);
206 fflush(stdout);
207 if (sockfd >= 0)
208 close(sockfd);
209 exit(EXIT_SUCCESS);
210}

◆ updateChannelDescription()

void updateChannelDescription ( void )

Definition at line 521 of file sddslogserver.c.

521 {
522 char *command = "sddscombine *.chd -merge -pipe=out | sddsprocess -pipe=in -match=col,Name=SampleIDNumber,! -match=col,Name=Time,! allChd.sdds";
523 system(command);
524}

◆ writeReply()

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

Definition at line 129 of file sddslogserver.c.

129 {
130 char buffer[BUFLEN + 20];
131 if (code) {
132 snprintf(buffer, sizeof(buffer), "error:%s (code %d)\n", message, code);
133 return write(sock, buffer, strlen(buffer));
134 } else {
135 // snprintf(buffer, sizeof(buffer), "ok:%s\n", message);
136 return write(sock, message, strlen(message));
137 }
138}
write(SddsFile sdds_file, output_file)
Mostly backward compatible with the PyLHC sdds module write() function.
Definition sdds.py:1967

◆ writeReplyList()

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

Definition at line 140 of file sddslogserver.c.

140 {
141 int64_t i;
142 char message[BUFLEN];
143 strncpy(message, "ok:", sizeof(message) - 1);
144 message[sizeof(message) - 1] = 0;
145
146 /* Need to check for buffer overflow */
147 printf("%" PRId64 " reply items\n", nItems);
148 for (i = 0; i < nItems; i++) {
149 printf("Item %" PRId64 ": %s\n", i, messageList[i]);
150 strncat(message, messageList[i], sizeof(message) - strlen(message) - 1);
151 if (i != (nItems - 1))
152 strncat(message, ",", sizeof(message) - strlen(message) - 1);
153 }
154 strncat(message, "\n", sizeof(message) - strlen(message) - 1);
155 printf("message: %s", message);
156 return write(sock, message, strlen(message));
157}