| //------------------------------------------------------------------ |
| // |
| // @@@ START COPYRIGHT @@@ |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| // @@@ END COPYRIGHT @@@ |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <sys/shm.h> |
| #include <sys/time.h> |
| |
| #include "seabed/fserr.h" |
| #include "seabed/ms.h" |
| #include "seabed/pctl.h" |
| #include "seabed/pevents.h" |
| |
| #include "t284.h" |
| |
| char name[BUFSIZ]; |
| char *shm; |
| unsigned long *shml; |
| bool shook = false; |
| bool verbose = false; |
| |
| // forwards |
| void do_reply(BMS_SRE *sre, char *reply, int len, short ec); |
| |
| |
| // |
| // initialize |
| // |
| void do_init(int argc, char **argv) { |
| int arg; |
| char *argp; |
| bool attach; |
| int ferr; |
| |
| attach = false; |
| for (arg = 1; arg < argc; arg++) { |
| argp = argv[arg]; |
| if (strcmp(argp, "-attach") == 0) |
| attach = true; |
| else if (strcmp(argp, "-shook") == 0) |
| shook = true; |
| else if (strcmp(argp, "-v") == 0) |
| verbose = true; |
| } |
| if (attach) |
| ferr = msg_init_attach(&argc, &argv, false, (char *) "$TSID0"); |
| else |
| ferr = msg_init(&argc, &argv); |
| assert(ferr == XZFIL_ERR_OK); |
| |
| if (shook) |
| msg_debug_hook("s", "s"); |
| } |
| |
| // |
| // process monitor message. |
| // |
| // if shutdown, set done |
| // |
| void do_mon_msg(BMS_SRE *sre, bool *done) { |
| int ferr; |
| MS_Mon_Msg mon_msg; |
| |
| ferr = BMSG_READDATA_(sre->sre_msgId, // msgid |
| (char *) &mon_msg, // reqdata |
| (int) sizeof(mon_msg)); // bytecount |
| assert(ferr == XZFIL_ERR_OK); |
| if (mon_msg.type == MS_MsgType_Shutdown) |
| *done = true; |
| if (verbose) |
| printf("srv: received mon message\n"); |
| do_reply(sre, NULL, 0, 0); |
| } |
| |
| // |
| // Convert a time id generated by us back to a timespec |
| // |
| struct timespec long_to_timespec(unsigned long pv_time_id) { |
| |
| if (verbose) |
| printf("srv: long_to_timespec, current pv_time_id Ox%lx %s", pv_time_id, ctime((time_t *)&pv_time_id)); |
| |
| struct timespec lv_orig_ts; |
| |
| // To restore the original timespec we get the usecs by taking the bottom 20 bits |
| // lv_curr_ts.tv_nsec 00000000000000000000000000000000000000000000zzzzzzzzzzzzzzzzzzzz |
| lv_orig_ts.tv_nsec = (unsigned long) (pv_time_id & 0x00000000000FFFFFL); // bottom 20 bits only |
| |
| // Then for the seconds we right shift 20 bits to get the original number |
| // consisting of the top 44 bits |
| // pv_time_is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyy |
| // lv_orig_ts.tv_sec xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
| lv_orig_ts.tv_sec = (unsigned long)(pv_time_id >> 20); |
| if (verbose) |
| printf("srv: long_to_timespec, tv_sec=0x%lx, tv_nsec=0x%lx\n", lv_orig_ts.tv_sec, lv_orig_ts.tv_nsec); |
| |
| return lv_orig_ts; |
| |
| } |
| |
| int timespec_to_str(char *buf, size_t max_len, struct timespec *ppv_timespec) { |
| |
| if (verbose) |
| printf("srv: enter timespec_to_str %ld\n", ppv_timespec->tv_sec); |
| |
| unsigned int len; |
| char * ptr; |
| char tmp_buffer[MAX_DATE_TIME_BUFF_LEN * 2]; |
| char mon_buff[5]; |
| char day_buff[3]; |
| char year_buff[5]; |
| char time_buff[10]; |
| |
| // ctime adds a new line character at the end of the string, which we don't want |
| strcpy(tmp_buffer, ctime(&ppv_timespec->tv_sec)); |
| len = (unsigned int) (strlen(tmp_buffer) - 1); |
| tmp_buffer[len] = '\0'; |
| |
| // The current date/time string only has second resolution, and is of |
| // this format: 'Fri May 6 03:01:52 2016'. We need to append the |
| // usecs to the time portion (4th token) and create a new string |
| // of the format'2016-05-06 03:01:52.123456' |
| ptr = strtok(tmp_buffer, " "); |
| |
| // Skip the day of the week and get the month |
| ptr = strtok(NULL, " "); |
| strcpy(mon_buff, ptr); |
| |
| ptr = strtok(NULL, " "); |
| if(strlen(ptr) == 1){ |
| // Pad it with a leading '0' |
| day_buff[0] = '0'; |
| strcpy(&day_buff[1], ptr); |
| } |
| else { |
| strcpy(day_buff, ptr); |
| } |
| |
| ptr = strtok(NULL, " "); |
| strcpy(time_buff, ptr); |
| |
| ptr = strtok(NULL, " "); |
| strcpy(year_buff, ptr); |
| |
| // Convert the name of the month to numerical equivalent |
| if(strncmp(mon_buff, "Jan", 3) == 0 ) { |
| strcpy(mon_buff, "01"); |
| } |
| else if(strncmp(mon_buff, "Feb", 3) == 0 ) { |
| strcpy(mon_buff, "02"); |
| } |
| else if(strncmp(mon_buff, "Mar", 3) == 0 ) { |
| strcpy(mon_buff, "03"); |
| } |
| else if(strncmp(mon_buff, "Apr", 3) == 0 ) { |
| strcpy(mon_buff, "04"); |
| } |
| else if(strncmp(mon_buff, "May", 3) == 0 ) { |
| strcpy(mon_buff, "05"); |
| } |
| else if(strncmp(mon_buff, "Jun", 3) == 0 ) { |
| strcpy(mon_buff, "06"); |
| } |
| else if(strncmp(mon_buff, "Jul", 3) == 0 ) { |
| strcpy(mon_buff, "07"); |
| } |
| else if(strncmp(mon_buff, "Aug", 3) == 0 ) { |
| strcpy(mon_buff, "08"); |
| } |
| else if(strncmp(mon_buff, "Sep", 3) == 0 ) { |
| strcpy(mon_buff, "09"); |
| } |
| else if(strncmp(mon_buff, "Oct", 3) == 0 ) { |
| strcpy(mon_buff, "10"); |
| } |
| else if(strncmp(mon_buff, "Nov", 3) == 0 ) { |
| strcpy(mon_buff, "11"); |
| } |
| else if(strncmp(mon_buff, "Dec", 3) == 0 ) { |
| strcpy(mon_buff, "12"); |
| } |
| else { |
| printf("srv: timespec_to_string unrecognized month string %s\n", mon_buff); |
| return XZFIL_ERR_FSERR; |
| } |
| |
| // Now put it all together |
| sprintf(tmp_buffer, "%s-%s-%s %s.%ld", year_buff, mon_buff, day_buff, time_buff, ppv_timespec->tv_nsec); |
| len = (unsigned int)strlen(tmp_buffer); |
| if(len > max_len) { |
| return XZFIL_ERR_BADCOUNT; |
| } |
| strcpy(buf, tmp_buffer); |
| if (verbose) |
| printf("srv: exit timespec_to_str %s\n", buf); |
| |
| return XZFIL_ERR_OK; |
| |
| } |
| |
| int str_to_tm_id(char *buf, unsigned long *ppv_tm_id) { |
| |
| if (verbose) |
| printf("srv: enter str_to_tm_id for %s\n", buf); |
| |
| char * ptr; |
| char tmp_buffer[MAX_DATE_TIME_BUFF_LEN * 2]; |
| char date_buff[12]; |
| char mon_buff[3]; |
| char day_buff[3]; |
| char year_buff[5]; |
| char time_buff[20]; |
| char hour_buff[3]; |
| char min_buff[3]; |
| char sec_usec_buff[12]; |
| char sec_buff[3]; |
| char usec_buff[10]; |
| struct tm loc_tm; |
| struct timespec loc_ts; |
| |
| // The format of the passed in date string is '2016-05-06 03:01:52.123456' |
| // Using a 'space' we separate the input string into date and time components |
| strcpy(tmp_buffer, buf); |
| ptr = strtok(tmp_buffer, " "); |
| strcpy(date_buff, ptr); |
| ptr = strtok(NULL, " "); |
| strcpy(time_buff, ptr); |
| |
| // Tokenize the date using the '-' character |
| ptr = strtok(date_buff, "-"); |
| strcpy(year_buff, ptr); |
| ptr = strtok(NULL, "-"); |
| strcpy(mon_buff, ptr); |
| ptr = strtok(NULL, "-"); |
| strcpy(day_buff, ptr); |
| |
| // Tokenize the time using the ':' character |
| ptr = strtok(time_buff, ":"); |
| strcpy(hour_buff, ptr); |
| ptr = strtok(NULL, ":"); |
| strcpy(min_buff, ptr); |
| ptr = strtok(NULL, ":"); |
| strcpy(sec_usec_buff, ptr); |
| |
| // Tokenize the sec_usec_buff using the '.' character |
| ptr = strtok(sec_usec_buff, "."); |
| strcpy(sec_buff, ptr); |
| ptr = strtok(NULL, "."); |
| strcpy(usec_buff, ptr); |
| |
| memset(&loc_tm, 0, sizeof(struct tm)); |
| loc_tm.tm_year = atoi(year_buff) - 1900; |
| loc_tm.tm_mon = atoi(mon_buff) - 1; // Months are 0 based from January |
| loc_tm.tm_mday = atoi(day_buff); |
| loc_tm.tm_hour = atoi(hour_buff); |
| loc_tm.tm_min = atoi(min_buff); |
| loc_tm.tm_sec = atoi(sec_buff); |
| |
| // Take the tm struct we have created and translate it into the time_t (seconds) |
| // portion of a timespec. We set the nsec portion directly. |
| loc_ts.tv_sec = mktime(&loc_tm); |
| if (loc_ts.tv_sec == -1){ |
| |
| // Unsuccessful conversion |
| return XZFIL_ERR_FSERR; |
| } |
| loc_ts.tv_nsec = (atol(usec_buff) * 1000L); |
| |
| *ppv_tm_id = ((unsigned long) loc_ts.tv_sec << 20) | |
| ((unsigned long) loc_ts.tv_nsec / 1000); |
| |
| if (verbose) |
| printf("srv: str_to_tm_id loc_ts =0x%lx,0x%lx converted time %ld\n", loc_ts.tv_sec, loc_ts.tv_nsec, *ppv_tm_id); |
| |
| return XZFIL_ERR_OK; |
| } |
| |
| // |
| // process non-mon message |
| // |
| void do_req(BMS_SRE *sre) { |
| short ec; |
| int ferr; |
| int len; |
| long req_id; |
| GID_Rep rep; |
| GID_Req req; |
| const char *req_type; |
| struct timeval tv; |
| struct timespec orig_ts; |
| unsigned long converted_tm_id; |
| |
| ec = XZFIL_ERR_OK; |
| len = 0; |
| if (verbose) |
| printf("srv: received NON-mon message\n"); |
| if (sre->sre_reqDataSize < (int) sizeof(req)) { |
| if (verbose) |
| printf("srv: received short data - sre_reqDataSize=%d, expecting len=%d, setting BADCOUNT\n", |
| sre->sre_reqDataSize, (int) sizeof(req)); |
| ec = XZFIL_ERR_BADCOUNT; |
| } else { |
| ferr = BMSG_READDATA_(sre->sre_msgId, // msgid |
| (char *) &req, // reqdata |
| (int) sizeof(req)); // bytecount |
| assert(ferr == XZFIL_ERR_OK); |
| if (verbose) { |
| switch (req.req_type) { |
| case GID_REQ_PING: |
| req_type = "ping"; |
| break; |
| case GID_REQ_ID: |
| req_type = "id"; |
| break; |
| case GID_REQ_ID_TO_STRING: |
| req_type = "id_to_string"; |
| break; |
| case GID_REQ_STRING_TO_ID: |
| req_type = "string_to_id"; |
| break; |
| default: |
| req_type = "unknown"; |
| break; |
| } |
| if (verbose) |
| printf("srv: received msg. req-type=%d(%s), tag=%ld, len=%d\n", |
| req.req_type, req_type, req.req_tag, req.req_len); |
| } |
| switch (req.req_type) { |
| case GID_REQ_PING: |
| if (req.req_len == (int) sizeof(req.u.ping)) { |
| if (verbose) |
| printf("srv: received ping request\n"); |
| rep.rep_type = GID_REP_PING; |
| rep.rep_tag = req.req_tag; |
| rep.rep_len = (int) sizeof(rep.u.ping); |
| rep.u.ping.com.error = GID_ERR_OK; |
| gettimeofday(&tv, NULL); |
| rep.u.ping.ts_sec = tv.tv_sec; |
| rep.u.ping.ts_us = tv.tv_usec; |
| } else { |
| if (verbose) |
| printf("srv: received ping, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| req.req_len, (int) sizeof(req.u.ping)); |
| ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_ID: |
| if (req.req_len == (int) sizeof(req.u.id)) { |
| if (verbose) |
| printf("srv: received id request\n"); |
| rep.rep_type = GID_REP_ID; |
| rep.rep_tag = req.req_tag; |
| rep.rep_len = (int) sizeof(rep.u.id); |
| rep.u.id.com.error = GID_ERR_OK; |
| rep.u.id.id = __sync_add_and_fetch_8(shm, 1); |
| } else { |
| if (verbose) |
| printf("srv: received id, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| req.req_len, (int) sizeof(req.u.id)); |
| ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_ID_TO_STRING: |
| if (req.req_len == (int) sizeof(req.u.id_to_string)) { |
| if (verbose) |
| printf("srv: received id_to_string request\n"); |
| rep.rep_type = GID_REP_ID_TO_STRING; |
| rep.rep_tag = req.req_tag; |
| req_id = req.u.id_to_string.id_to_string; |
| orig_ts = long_to_timespec(req_id); |
| ferr = timespec_to_str(rep.u.id_to_string.id_to_string, sizeof(rep.u.id_to_string.id_to_string) |
| , &orig_ts); |
| rep.rep_len = sizeof(rep.u.id_to_string); |
| rep.u.id_to_string.com.error = (GID_Err_Type) ferr; |
| } else { |
| if (verbose) |
| printf("srv: received id_to_string, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| req.req_len, (int) sizeof(req.u.id_to_string)); |
| ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_STRING_TO_ID: |
| if (req.req_len == (int) sizeof(req.u.string_to_id)) { |
| if (verbose) |
| printf("srv: received string_to_id request for %s\n", req.u.string_to_id.string_to_id); |
| rep.rep_type = GID_REP_STRING_TO_ID; |
| rep.rep_tag = req.req_tag; |
| ferr = str_to_tm_id(req.u.string_to_id.string_to_id, &converted_tm_id); |
| rep.u.string_to_id.id = converted_tm_id; |
| rep.rep_len = sizeof(rep.u.string_to_id); |
| rep.u.string_to_id.com.error = GID_ERR_OK; |
| } else { |
| if (verbose) |
| printf("srv: received string_to_id, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| req.req_len, (int) sizeof(req.u.string_to_id)); |
| ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| default: |
| if (verbose) |
| printf("srv: received unknown req-type=%d, setting INVALOP\n", |
| req.req_type); |
| ec = XZFIL_ERR_INVALOP; |
| break; |
| } |
| } |
| |
| if (ec == XZFIL_ERR_OK) { |
| if (verbose) |
| printf("srv: reply, rep-type=%d, tag=%ld, len=%d\n", |
| rep.rep_type, rep.rep_tag, rep.rep_len); |
| len = (int) sizeof(rep); |
| } else { |
| len = 0; |
| } |
| |
| do_reply(sre, (char *) &rep, len, ec); |
| } |
| |
| // |
| // do reply |
| // |
| void do_reply(BMS_SRE *sre, char *reply, int len, short ec) { |
| if (verbose) |
| printf("srv: reply, len=%d, ec=%d\n", len, ec); |
| BMSG_REPLY_(sre->sre_msgId, // msgid |
| NULL, // replyctrl |
| 0, // replyctrlsize |
| reply, // replydata |
| len, // replydatasize |
| ec, // errorclass |
| NULL); // newphandle |
| } |
| |
| // |
| // setup shared memory. |
| // |
| // if shared memory created, then initialize to current time. |
| // |
| void do_shm() { |
| bool created; |
| int ferr; |
| int key; |
| int msid; |
| struct timespec ts; |
| unsigned long xts; |
| |
| ferr = msg_mon_get_my_segid(&key); |
| assert(ferr == XZFIL_ERR_OK); |
| if (verbose) |
| printf("srv: shm key=%d\n", key); |
| msid = shmget(key, sizeof(long), 0640); |
| if (msid == -1) { |
| created = true; |
| if (verbose) |
| printf("srv: shmget failed, errno=%d\n", errno); |
| msid = shmget(key, sizeof(long), IPC_CREAT | 0640); |
| if (msid == -1) { |
| if (verbose) |
| printf("srv: shmget(IPC_CREAT) failed, errno=%d\n", errno); |
| assert(msid != -1); |
| } else { |
| if (verbose) |
| printf("srv: shmget(IPC_CREAT) ok\n"); |
| } |
| } else { |
| created = false; |
| if (verbose) |
| printf("srv: shmget ok\n"); |
| } |
| shm = (char *) shmat(msid, NULL, 0); |
| if (shm == NULL) { |
| if (verbose) |
| printf("srv: shmat failed, errno=%d\n", errno); |
| assert(shm != NULL); |
| } else { |
| shml = (unsigned long *) shm; |
| if (verbose) |
| printf("srv: shmat ok, shm=%p\n", shm); |
| if (created) { |
| clock_gettime(CLOCK_REALTIME, &ts); |
| // nsec / 1000 => usec |
| // 1,000,000 usec requires 20 bits. i.e. 2^20=1,048,576 |
| // unsigned long is 64 bits, so squeeze secs into leftover 44 bits |
| // 100(yrs) * 365(days) * 24(hrs) * 60(min) * 60(sec)=3,153,600,000 |
| // requires 32 bits |
| xts = ((unsigned long) ts.tv_sec << 20) | ((unsigned long) ts.tv_nsec / 1000); |
| *shml = xts; |
| if (verbose) |
| printf("srv: initializing shm=0x%lx\n", xts); |
| } |
| } |
| } |
| |
| // |
| // server main |
| // |
| int main(int argc, char *argv[]) { |
| bool done; |
| int ferr; |
| int lerr; |
| BMS_SRE sre; |
| |
| do_init(argc, argv); |
| |
| ferr = msg_mon_process_startup(true); // system messages |
| assert(ferr == XZFIL_ERR_OK); |
| msg_mon_enable_mon_messages(true); |
| ferr = msg_mon_get_my_process_name(name, sizeof(name)); |
| assert(ferr == XZFIL_ERR_OK); |
| |
| do_shm(); |
| |
| done = false; |
| while (!done) { |
| do { |
| lerr = XWAIT(LREQ, -1); |
| lerr = BMSG_LISTEN_((short *) &sre, // sre |
| 0, // listenopts |
| 0); // listenertag |
| } while (lerr == XSRETYPE_NOWORK); |
| if (sre.sre_flags & XSRE_MON) { |
| do_mon_msg(&sre, &done); |
| } else { |
| do_req(&sre); |
| } |
| } |
| |
| if (verbose) |
| printf("server %s shutting down\n", name); |
| ferr = msg_mon_process_shutdown(); |
| assert(ferr == XZFIL_ERR_OK); |
| return 0; |
| } |