56#include <sys/socket.h>
57#include <netinet/in.h>
69int createChannel(
char *spec);
70int addValue(
char *spec);
71int runSddsplot(
char *returnBuffer,
char *options);
72void updateChannelDescription(
void);
73int makeDirectoryList(int64_t *returnNumber,
char ***returnBuffer);
74int getChannelList(int64_t *returnNumber,
char ***returnBuffer);
80#define MAKE_DIRECTORY 2
81#define CHANGE_DIRECTORY 3
82#define GET_TIME_SPAN 4
89#define LIST_CHANNELS 11
92char *command[N_COMMANDS] = {
107short forbid[N_COMMANDS] = {
122void error(
const char *msg,
char *progName) {
124 snprintf(s,
sizeof(s),
"%s (%s)", msg, progName);
129int writeReply(
int sock,
const char *message,
int code) {
130 char buffer[BUFLEN + 20];
132 snprintf(buffer,
sizeof(buffer),
"error:%s (code %d)\n", message, code);
133 return write(sock, buffer, strlen(buffer));
136 return write(sock, message, strlen(message));
140int writeReplyList(
int sock, int64_t nItems,
char **messageList) {
142 char message[BUFLEN];
143 strncpy(message,
"ok:",
sizeof(message) - 1);
144 message[
sizeof(message) - 1] = 0;
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);
154 strncat(message,
"\n",
sizeof(message) - strlen(message) - 1);
155 printf(
"message: %s", message);
156 return write(sock, message, strlen(message));
159void freeReplyList(int64_t nItems,
char **item) {
163 for (i = 0; i < nItems; i++)
169int chdirFromRoot(
char *path) {
171 snprintf(buffer,
sizeof(buffer),
"%s/%s", rootDir, (path && *path) ? path :
"");
172 fprintf(stderr,
"Changing directory to %s\n", buffer);
173 return chdir(buffer);
179#define CLI_SDDSPLOT_PATH 3
182char *option[N_OPTIONS] = {
190 "Usage: sddslogserver -port=<portNumber> [-root=<rootDirectory>] \n"
191 " [-forbid=<command1,command2,...>] \n"
192 " [-sddsplotPath=<path>]\n\n"
194 " -port Port number on which the server listens (required).\n"
195 " -root Path of the root directory (optional, defaults to current directory).\n"
196 " -forbid Comma-separated list of commands to forbid (optional).\n"
197 " -sddsplotPath Pathname for SDDS plot output files (optional).\n\n"
198 "Program by Michael Borland. (" __DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
200char *sddsplotPath = NULL;
202static int sockfd = -1;
204void shutdownServer(
int arg) {
205 printf(
"Closing sockfd=%d\n", sockfd);
212int main(
int argc,
char *argv[]) {
213 int newsockfd, portno, pid;
216 struct sockaddr_in serv_addr, cli_addr;
221 signal(SIGCHLD, SIG_IGN);
222 signal(SIGINT, shutdownServer);
226 argc =
scanargs(&s_arg, argc, argv);
228 fprintf(stderr,
"%s", USAGE);
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)) {
238 if (s_arg[i_arg].n_items != 2 ||
239 sscanf(s_arg[i_arg].list[1],
"%d", &portno) != 1 ||
241 fprintf(stderr,
"Error: Invalid syntax/values for -port argument\n%s", USAGE);
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);
253 if (s_arg[i_arg].n_items < 2) {
254 fprintf(stderr,
"Error: Invalid syntax/values for -forbid argument\n%s", USAGE);
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]);
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);
270 sddsplotPath = s_arg[i_arg].list[1];
273 fprintf(stderr,
"Invalid or ambiguous option: %s\n%s", s_arg[i_arg].list[0], USAGE);
278 fprintf(stderr,
"Invalid or ambiguous option: %s\n%s", s_arg[i_arg].list[0], USAGE);
287 error(
"Error: Root directory not found", argv[0]);
291 sockfd = socket(AF_INET, SOCK_STREAM, 0);
293 error(
"Error opening socket", argv[0]);
294 printf(
"sockfd = %d\n", sockfd);
295 memset(&serv_addr, 0,
sizeof(serv_addr));
298 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (
const char *)&reuse,
sizeof(reuse)) < 0)
299 perror(
"setsockopt(SO_REUSEADDR) failed");
302 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (
const char *)&reuse,
sizeof(reuse)) < 0)
303 perror(
"setsockopt(SO_REUSEPORT) failed");
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]);
314 clilen =
sizeof(cli_addr);
316 printf(
"Waiting for new socket connection\n");
318 newsockfd = accept(sockfd, (
struct sockaddr *)&cli_addr, &clilen);
319 printf(
"Got new socket connection\n");
324 error(
"Error on accept", argv[0]);
328 error(
"Error on fork", argv[0]);
332 printf(
"Returned from dostuff\n");
336 printf(
"Forked process\n");
341 printf(
"Exited while loop\n");
354int dostuff(
int sock) {
363 memset(buffer, 0, BUFLEN);
364 n =
read(sock, buffer, BUFLEN - 1);
366 error(
"ERROR reading from socket",
"sddslogserver");
367 if (strlen(buffer) == 0)
370 printf(
"Here is the message: <%s>\n", buffer);
372 if ((ptr1 = strchr(buffer,
':')))
374 if ((code =
match_string(buffer, command, N_COMMANDS, EXACT_MATCH)) < 0 || forbid[code]) {
375 writeReply(sock,
"Forbidden operation.", 0);
380 printf(
"Disconnecting\n");
386 printf(
"Add value: %s\n", ptr1);
387 if ((code = addValue(ptr1)) == 0)
388 writeReply(sock,
"ok", code);
390 writeReply(sock,
"Error: Failed to add value.", code);
394 printf(
"Delete value: %s\n", ptr1);
395 writeReply(sock,
"Error: Can't do that yet.", EXIT_FAILURE);
399 printf(
"Add channel: %s\n", ptr1);
400 if ((code = createChannel(ptr1)) == 0)
401 writeReply(sock,
"ok", code);
403 writeReply(sock,
"Error: Failed to create channel.", code);
407 printf(
"Make directory: %s\n", ptr1);
408 if ((code = mkdir(ptr1, 0700))) {
409 writeReply(sock,
"Error: Making directory.", code);
411 writeReply(sock,
"ok", code);
414 case CHANGE_DIRECTORY:
416 if (ptr1 && *ptr1 && strstr(ptr1,
"..")) {
418 writeReply(sock,
"Error: Relative paths not supported.", EXIT_FAILURE);
420 printf(
"Change directory: %s\n", ptr1 && *ptr1 ? ptr1 :
"base");
421 if ((code = chdirFromRoot(ptr1)))
422 writeReply(sock,
"Error: CD failed.", code);
424 writeReply(sock,
"CD ok.", code);
429 printf(
"Get time span: %s\n", ptr1);
430 writeReply(sock,
"Error: Can't do that yet.", EXIT_FAILURE);
434 printf(
"Get last N: %s\n", ptr1);
435 writeReply(sock,
"Error: Can't do that yet.", EXIT_FAILURE);
439 printf(
"sddsplot: %s\n", ptr1);
440 code = runSddsplot(buffer, ptr1);
441 writeReply(sock, buffer, code);
444 updateChannelDescription();
445 writeReply(sock,
"ok", EXIT_SUCCESS);
448 if (makeDirectoryList(&nItems, &itemValue))
449 writeReply(sock,
"Failed to retrieve directory list.", EXIT_FAILURE);
451 writeReplyList(sock, nItems, itemValue);
452 freeReplyList(nItems, itemValue);
456 if (getChannelList(&nItems, &itemValue))
457 writeReply(sock,
"Failed to retrieve channel list.", EXIT_FAILURE);
459 writeReplyList(sock, nItems, itemValue);
460 freeReplyList(nItems, itemValue);
464 printf(
"Unknown command: %s\n", buffer);
465 writeReply(sock,
"Error: Unknown command.", EXIT_FAILURE);
472int createChannel(
char *spec)
475 char *chName, *chType, *chUnits, *chDescription;
481 if (!(chType = strchr(spec,
',')))
484 if (!(chUnits = strchr(chType,
',')))
489 if (!(chDescription = strchr(chUnits,
',')))
491 *chDescription++ = 0;
493 if (strcmp(chName,
"Time") == 0)
496 snprintf(buffer,
sizeof(buffer),
"%s.sdds", chName);
503 SDDS_DefineColumn(&SDDSout, chName, NULL, chUnits, chDescription, NULL, type, 0) < 0 ||
510 snprintf(buffer,
sizeof(buffer),
"sddsquery %s.sdds -sddsOutput=%s.chd -column", chName, chName);
512 snprintf(buffer,
sizeof(buffer),
"%s.chd", chName);
516 updateChannelDescription();
521void updateChannelDescription(
void) {
522 char *command =
"sddscombine *.chd -merge -pipe=out | sddsprocess -pipe=in -match=col,Name=SampleIDNumber,! -match=col,Name=Time,! allChd.sdds";
526int addValue(
char *spec)
539 if (!(ptr = strchr(spec,
',')))
543 snprintf(buffer,
sizeof(buffer),
"%s.sdds", spec);
548 printf(
"Initialized, %" PRId64
" rows\n", rows);
554 printf(
"Lengthened table\n");
562 printf(
"Got type information\n");
572 printf(
"Scanned data\n");
580 printf(
"Set row values\n");
585 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, ptr, NULL)) {
591 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((
float *)data), NULL)) {
597 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((
double *)data), NULL)) {
603 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((
short *)data), NULL)) {
609 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int32_t *)data), NULL)) {
615 if (!
SDDS_SetRowValues(&SDDSin, SDDS_SET_BY_NAME | SDDS_PASS_BY_VALUE, rows, spec, *((int64_t *)data), NULL)) {
623 printf(
"Set row value\n");
632 printf(
"Updated page\n");
638 printf(
"Terminated\n");
643int runSddsplot(
char *returnBuffer,
char *options) {
644 char command[BUFLEN];
645 char template[BUFLEN];
650 fprintf(stderr,
"Error: sddsplotPath is not set.\n");
656 snprintf(
template,
sizeof(
template),
"%s/png-XXXXXX.png", sddsplotPath);
659 char *tempTemplate = strdup(
template);
666 fd = mkstemps(tempTemplate, 4);
677 snprintf(command,
sizeof(command),
"sddsplot -device=png -output=%s %s", tempTemplate, options);
678 printf(
"Executing: %s\n", command);
682 strncpy(returnBuffer, tempTemplate, BUFLEN - 1);
683 returnBuffer[BUFLEN - 1] =
'\0';
689 return system(command);
709int makeDirectoryList(int64_t *returnNumber,
char ***returnBuffer) {
711 char command[BUFLEN];
716 *returnBuffer = NULL;
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");
723 printf(
"Problem reading dirList.sdds\n");
730 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
731 printf(
"Row count: %" PRId64
"\n", *returnNumber);
734 if (*returnNumber == 0)
736 if (!(*returnBuffer =
SDDS_GetColumn(&SDDSin,
"DirectoryName"))) {
737 printf(
"Problem getting DirectoryName\n");
743int getChannelList(int64_t *returnNumber,
char ***returnBuffer) {
746 *returnBuffer = NULL;
749 updateChannelDescription();
753 printf(
"Problem reading allChd.sdds\n");
760 if ((*returnNumber = SDDS_RowCount(&SDDSin)) < 0) {
761 printf(
"Row count: %" PRId64
"\n", *returnNumber);
764 if (*returnNumber == 0)
767 printf(
"Problem getting Name\n");
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
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.
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_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
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.
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_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_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_UpdatePage(SDDS_DATASET *SDDS_dataset, uint32_t mode)
Updates the current page of 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.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void * SDDS_Malloc(size_t size)
Allocates memory of a specified size.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
int32_t SDDS_IdentifyType(char *typeName)
Identifies the SDDS data type based on its string name.
#define SDDS_FLOAT
Identifier for the float data type.
#define SDDS_STRING
Identifier for the string data type.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_SHORT
Identifier for the signed short integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
char * cp_str(char **s, char *t)
Copies a string, allocating memory for storage.
long fexists(const char *filename)
Checks if a file exists.
double getTimeInSecs()
Get the current time in seconds since the Epoch with high resolution.
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.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
write(SddsFile sdds_file, output_file)
Mostly backward compatible with the PyLHC sdds module write() function.
SddsFile read(input_file)
Mostly backward compatible with the PyLHC sdds module read() function.