| //------------------------------------------------------------------ |
| // |
| // @@@ 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 "SCMVersHelp.h" |
| |
| #include "seabed/fserr.h" |
| #include "seabed/ms.h" |
| #include "seabed/pctl.h" |
| #include "seabed/pevents.h" |
| #include "seabed/timer.h" |
| #include "seabed/thread.h" |
| #include "idtmsrv.h" |
| |
| short gv_tleid; |
| short gv_time_refresh_delay; // time in tics (10ms) |
| char ga_name[BUFSIZ]; |
| char *gp_shm; |
| unsigned long *gp_shml; |
| bool gv_shook = false; |
| bool gv_verbose = false; |
| |
| DEFINE_EXTERN_COMP_DOVERS(idtmsrv) |
| |
| // forwards |
| void do_reply(BMS_SRE *pp_sre, char *pp_reply, int pv_len, short pv_ec); |
| |
| |
| // |
| // Reset the global time counter |
| // |
| void reset_time_counter() { |
| |
| struct timespec lv_new_ts; |
| |
| clock_gettime(CLOCK_REALTIME, &lv_new_ts); |
| unsigned long lv_new_tsl = ((unsigned long) lv_new_ts.tv_sec << 20) | |
| ((unsigned long) lv_new_ts.tv_nsec / 1000); |
| |
| if (gv_verbose) |
| printf("srv: reset_time_counter, original ts =0x%lx,0x%lx converted time 0x%lx\n", lv_new_ts.tv_sec, lv_new_ts.tv_nsec, lv_new_tsl); |
| |
| unsigned long lv_existing_tsl = __sync_add_and_fetch_8(gp_shm, 0); |
| __sync_add_and_fetch_8(gp_shm, lv_new_tsl - lv_existing_tsl); |
| |
| if (gv_verbose) |
| printf("srv: reset_time_counter, adjustment=0x%lx, shm=0x%lx\n", lv_new_tsl - lv_existing_tsl, *gp_shml); |
| } |
| |
| // |
| // Convert a time id generated by us back to a timespec |
| // |
| struct timespec long_to_timespec(unsigned long pv_time_id) { |
| |
| if (gv_verbose) |
| printf("srv: long_to_timespec, current pv_time_id Ox%lx\n", 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 (gv_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 (gv_verbose) |
| printf("srv: enter timespec_to_str\n"); |
| |
| 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); |
| return XZFIL_ERR_OK; |
| } |
| |
| int str_to_tm_id(char *buf, unsigned long *ppv_tm_id) { |
| |
| if (gv_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 lv_tm; |
| struct timespec lv_ts; |
| |
| // Initialize the output parameter in case an error occurs to avoid confusion |
| *ppv_tm_id = 0L; |
| |
| // 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, " "); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a space between date and time: %s\n", tmp_buffer ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(date_buff, ptr); |
| |
| ptr = strtok(NULL, " "); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a space between date and time: %s\n", tmp_buffer ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(time_buff, ptr); |
| |
| // Tokenize the date using the '-' character |
| ptr = strtok(date_buff, "-"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(year_buff, ptr); |
| |
| ptr = strtok(NULL, "-"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(mon_buff, ptr); |
| |
| ptr = strtok(NULL, "-"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a hyphen in the date: %s\n", date_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(day_buff, ptr); |
| |
| // Tokenize the time using the ':' character |
| ptr = strtok(time_buff, ":"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(hour_buff, ptr); |
| |
| ptr = strtok(NULL, ":"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(min_buff, ptr); |
| |
| ptr = strtok(NULL, ":"); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a colon in the time: %s\n", time_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(sec_usec_buff, ptr); |
| |
| // Tokenize the sec_usec_buff using the '.' character |
| ptr = strtok(sec_usec_buff, "."); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a period separating seconds and usecs: %s\n", sec_usec_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(sec_buff, ptr); |
| |
| ptr = strtok(NULL, "."); |
| if (ptr == NULL){ |
| if (gv_verbose) |
| printf("srv: str_to_tm_id time string requires a period separating secons and usecs: %s\n", sec_usec_buff ); |
| return XZFIL_ERR_BADPARMVALUE; |
| } |
| strcpy(usec_buff, ptr); |
| |
| memset(&lv_tm, 0, sizeof(struct tm)); |
| lv_tm.tm_year = atoi(year_buff) - 1900; |
| lv_tm.tm_mon = atoi(mon_buff) - 1; // Months are 0 based from January |
| lv_tm.tm_mday = atoi(day_buff); |
| lv_tm.tm_hour = atoi(hour_buff); |
| lv_tm.tm_min = atoi(min_buff); |
| lv_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. |
| lv_ts.tv_sec = mktime(&lv_tm); |
| if (lv_ts.tv_sec == -1){ |
| |
| // Unsuccessful conversion |
| return XZFIL_ERR_FSERR; |
| } |
| lv_ts.tv_nsec = (atol(usec_buff) * 1000L); |
| |
| *ppv_tm_id = ((unsigned long) lv_ts.tv_sec << 20) | |
| ((unsigned long) lv_ts.tv_nsec / 1000); |
| |
| if (gv_verbose) |
| printf("srv: str_to_tm_id lv_ts =0x%lx,0x%lx converted time 0x%lx\n", lv_ts.tv_sec, lv_ts.tv_nsec, *ppv_tm_id); |
| |
| return XZFIL_ERR_OK; |
| } |
| |
| // |
| // Timer callback |
| // |
| void timer_callback(int tleid, int toval, short parm1, long parm2) { |
| int ferr; |
| |
| if (gv_verbose) |
| printf("timer_callback \n"); |
| reset_time_counter(); |
| ferr = timer_start_cb(gv_time_refresh_delay, 0, 0, &gv_tleid, &timer_callback); |
| assert(ferr == XZFIL_ERR_OK); |
| } |
| |
| // |
| // initialize |
| // |
| void do_init(int pv_argc, char **ppp_argv) { |
| char *lp_arg; |
| int lv_arg; |
| bool lv_attach; |
| int lv_ferr; |
| char *lv_delay_s; |
| |
| lv_attach = false; |
| for (lv_arg = 1; lv_arg < pv_argc; lv_arg++) { |
| lp_arg = ppp_argv[lv_arg]; |
| if (strcmp(lp_arg, "-attach") == 0) |
| lv_attach = true; |
| else if (strcmp(lp_arg, "-shook") == 0) |
| gv_shook = true; |
| else if (strcmp(lp_arg, "-v") == 0) |
| gv_verbose = true; |
| } |
| if (lv_attach) |
| lv_ferr = msg_init_attach(&pv_argc, &ppp_argv, false, (char *) "$TSID0"); |
| else |
| lv_ferr = msg_init(&pv_argc, &ppp_argv); |
| assert(lv_ferr == XZFIL_ERR_OK); |
| |
| gv_time_refresh_delay = 200; // 2 seconds |
| lv_delay_s = getenv("TM_IDTMSRV_REFRESH_DELAY_SECONDS"); |
| if (lv_delay_s != NULL) { |
| gv_time_refresh_delay = 100 * (atoi(lv_delay_s)); |
| } |
| if (gv_verbose){ |
| printf("TM_IDTMSRV_REFRESH_DELAY_SECONDS is %s. Setting gv_time_refresh_delay to %d \n", lv_delay_s, gv_time_refresh_delay); |
| } |
| |
| if (gv_shook) |
| msg_debug_hook("s", "s"); |
| } |
| |
| // |
| // process monitor message. |
| // |
| // if shutdown, set done |
| // |
| void do_mon_msg(BMS_SRE *pp_sre, bool *pp_done) { |
| int lv_ferr; |
| MS_Mon_Msg lv_mon_msg; |
| |
| lv_ferr = BMSG_READDATA_(pp_sre->sre_msgId, // msgid |
| (char *) &lv_mon_msg, // reqdata |
| (int) sizeof(lv_mon_msg)); // bytecount |
| assert(lv_ferr == XZFIL_ERR_OK); |
| if (lv_mon_msg.type == MS_MsgType_Shutdown) |
| *pp_done = true; |
| if (gv_verbose) |
| printf("srv: received mon message\n"); |
| do_reply(pp_sre, NULL, 0, 0); |
| } |
| |
| // |
| // process non-mon message |
| // |
| void do_req(BMS_SRE *pp_sre) { |
| const char *lp_req_type; |
| short lv_ec; |
| int lv_ferr; |
| int lv_len; |
| GID_Rep lv_rep; |
| GID_Req lv_req; |
| long lv_req_id; |
| struct timeval lv_tv; |
| struct timespec lv_orig_ts; |
| unsigned long lv_converted_tm_id; |
| |
| lv_ec = XZFIL_ERR_OK; |
| lv_len = 0; |
| if (gv_verbose) |
| printf("srv: received NON-mon message\n"); |
| if (pp_sre->sre_reqDataSize < (int) sizeof(lv_req)) { |
| if (gv_verbose) |
| printf("srv: received short data - sre_reqDataSize=%d, expecting len=%d, setting BADCOUNT\n", |
| pp_sre->sre_reqDataSize, (int) sizeof(lv_req)); |
| lv_ec = XZFIL_ERR_BADCOUNT; |
| } else { |
| lv_ferr = BMSG_READDATA_(pp_sre->sre_msgId, // msgid |
| (char *) &lv_req, // reqdata |
| (int) sizeof(lv_req)); // bytecount |
| if (lv_ferr != XZFIL_ERR_OK){ |
| printf("srv: received lv_ferr %d in do_req \n", lv_ferr); |
| if((lv_ferr = XMSG_ISCANCELED_(pp_sre->sre_msgId))){ |
| printf("srv: XMSG_ISCANCELED_ returned %d in do_req. Most likely the client timeout was exceeded \n", lv_ferr); |
| return; |
| } |
| else{ |
| printf("srv: XMSG_ISCANCELED_ returned %d in do_req after FEEOF on BMSG_READDATA_. ABORTING \n", lv_ferr); |
| abort(); |
| } |
| } |
| |
| if (gv_verbose) { |
| switch (lv_req.iv_req_type) { |
| case GID_REQ_PING: |
| lp_req_type = "ping"; |
| break; |
| case GID_REQ_ID: |
| lp_req_type = "id"; |
| break; |
| case GID_REQ_ID_TO_STRING: |
| lp_req_type = "id_to_string"; |
| break; |
| case GID_REQ_STRING_TO_ID: |
| lp_req_type = "string_to_id"; |
| break; |
| default: |
| lp_req_type = "unknown"; |
| break; |
| } |
| if (gv_verbose) |
| printf("srv: received msg. req-type=%d(%s), tag=%ld, len=%d\n", |
| lv_req.iv_req_type, lp_req_type, lv_req.iv_req_tag, lv_req.iv_req_len); |
| } |
| switch (lv_req.iv_req_type) { |
| case GID_REQ_PING: |
| if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_ping)) { |
| if (gv_verbose) |
| printf("srv: received ping request\n"); |
| lv_rep.iv_rep_type = GID_REP_PING; |
| lv_rep.iv_rep_tag = lv_req.iv_req_tag; |
| lv_rep.iv_rep_len = (int) sizeof(lv_rep.u.iv_ping); |
| lv_rep.u.iv_ping.iv_com.iv_error = GID_ERR_OK; |
| gettimeofday(&lv_tv, NULL); |
| lv_rep.u.iv_ping.iv_ts_sec = lv_tv.tv_sec; |
| lv_rep.u.iv_ping.iv_ts_us = lv_tv.tv_usec; |
| } else { |
| if (gv_verbose) |
| printf("srv: received ping, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_ping)); |
| lv_ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_ID: |
| if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_id)) { |
| if (gv_verbose) |
| printf("srv: received id request\n"); |
| lv_rep.iv_rep_type = GID_REP_ID; |
| lv_rep.iv_rep_tag = lv_req.iv_req_tag; |
| lv_rep.iv_rep_len = (int) sizeof(lv_rep.u.iv_id); |
| lv_rep.u.iv_id.iv_com.iv_error = GID_ERR_OK; |
| lv_rep.u.iv_id.iv_id = __sync_add_and_fetch_8(gp_shm, 1); |
| } else { |
| if (gv_verbose) |
| printf("srv: received id, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_id)); |
| lv_ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_ID_TO_STRING: |
| if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_id_to_string)) { |
| lv_rep.iv_rep_type = GID_REP_ID_TO_STRING; |
| lv_rep.iv_rep_tag = lv_req.iv_req_tag; |
| lv_req_id = lv_req.u.iv_id_to_string.iv_req_id_to_string; |
| if (gv_verbose) |
| printf("srv: received id_to_string request for id:Ox%lx\n", lv_req_id); |
| lv_orig_ts = long_to_timespec(lv_req_id); |
| lv_ferr = timespec_to_str(lv_rep.u.iv_id_to_string.iv_id_to_string, sizeof(lv_rep.u.iv_id_to_string.iv_id_to_string) |
| , &lv_orig_ts); |
| lv_rep.iv_rep_len = sizeof(lv_rep.u.iv_id_to_string); |
| lv_rep.u.iv_id_to_string.iv_com.iv_error = (GID_Err_Type) lv_ferr; |
| if (gv_verbose){ |
| printf("srv: replying to id_to_string request with err=%d, reply-size %d, string %s, and len%d\n", |
| lv_rep.u.iv_id_to_string.iv_com.iv_error, |
| lv_rep.iv_rep_len, lv_rep.u.iv_id_to_string.iv_id_to_string, |
| (int) strlen(lv_rep.u.iv_id_to_string.iv_id_to_string)); |
| } |
| } else { |
| if (gv_verbose) |
| printf("srv: received id_to_string, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_id_to_string)); |
| lv_ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| case GID_REQ_STRING_TO_ID: |
| if (lv_req.iv_req_len == (int) sizeof(lv_req.u.iv_string_to_id)) { |
| if (gv_verbose) |
| printf("srv: received string_to_id request, string: %s\n", lv_req.u.iv_string_to_id.iv_string_to_id); |
| lv_rep.iv_rep_type = GID_REP_STRING_TO_ID; |
| lv_rep.iv_rep_tag = lv_req.iv_req_tag; |
| lv_ferr = str_to_tm_id(lv_req.u.iv_string_to_id.iv_string_to_id, &lv_converted_tm_id); |
| lv_rep.u.iv_string_to_id.iv_string_to_id = lv_converted_tm_id; |
| lv_rep.iv_rep_len = sizeof(lv_rep.u.iv_string_to_id); |
| lv_rep.u.iv_string_to_id.iv_com.iv_error = (GID_Err_Type) lv_ferr; |
| if (lv_ferr != XZFIL_ERR_OK) |
| lv_ec = lv_ferr; |
| if (gv_verbose) |
| printf("srv: replying to string_to_id request with err=%d, size %d, and id %ld\n", |
| lv_ferr, lv_rep.iv_rep_len, lv_converted_tm_id); |
| } else { |
| if (gv_verbose) |
| printf("srv: received string_to_id, req-len=%d, expecting len=%d, setting BADCOUNT\n", |
| lv_req.iv_req_len, (int) sizeof(lv_req.u.iv_string_to_id)); |
| lv_ec = XZFIL_ERR_BADCOUNT; |
| } |
| break; |
| |
| default: |
| if (gv_verbose) |
| printf("srv: received unknown req-type=%d, setting INVALOP\n", |
| lv_req.iv_req_type); |
| lv_ec = XZFIL_ERR_INVALOP; |
| break; |
| } |
| } |
| |
| if (gv_verbose){ |
| if(lv_rep.iv_rep_type == GID_REP_ID_TO_STRING){ |
| printf("srv: reply, rep-type=%d, tag=%ld, id_to_string=%s, len=%d\n", |
| lv_rep.iv_rep_type, lv_rep.iv_rep_tag, lv_rep.u.iv_id_to_string.iv_id_to_string, lv_rep.iv_rep_len); |
| } |
| else { |
| printf("srv: reply, rep-type=%d, tag=%ld, id=%ld, len=%d\n", |
| lv_rep.iv_rep_type, lv_rep.iv_rep_tag, lv_rep.u.iv_id.iv_id, lv_rep.iv_rep_len); |
| } |
| } |
| lv_len = (int) sizeof(lv_rep); |
| do_reply(pp_sre, (char *) &lv_rep, lv_len, lv_ec); |
| } |
| |
| // |
| // do reply |
| // |
| void do_reply(BMS_SRE *pp_sre, char *pp_reply, int pv_len, short pv_ec) { |
| GID_Rep * lv_rep = (GID_Rep *) pp_reply; |
| int lv_error = 0; |
| |
| if (lv_rep != NULL) |
| lv_error = lv_rep->u.iv_id.iv_com.iv_error; |
| |
| if (gv_verbose){ |
| printf("srv: reply, len=%d, ec=%d, error=%d\n", pv_len, pv_ec, lv_error); |
| } |
| |
| if (pv_ec == XZFIL_ERR_OK){ |
| pv_ec = lv_error; |
| } |
| BMSG_REPLY_(pp_sre->sre_msgId, // msgid |
| NULL, // replyctrl |
| 0, // replyctrlsize |
| pp_reply, // replydata |
| pv_len, // replydatasize |
| pv_ec, // errorclass |
| NULL); // newphandle |
| } |
| |
| // |
| // setup shared memory. |
| // |
| // if shared memory created, then initialize to current time. |
| // |
| void do_shm() { |
| bool lv_created; |
| int lv_ferr; |
| int lv_key; |
| int lv_msid; |
| struct timespec lv_ts; |
| unsigned long lv_tsl; |
| |
| lv_ferr = msg_mon_get_my_segid(&lv_key); |
| assert(lv_ferr == XZFIL_ERR_OK); |
| if (gv_verbose) |
| printf("srv: shm key=%d\n", lv_key); |
| lv_msid = shmget(lv_key, sizeof(long), 0640); |
| if (lv_msid == -1) { |
| lv_created = true; |
| if (gv_verbose) |
| printf("srv: shmget failed, errno=%d\n", errno); |
| lv_msid = shmget(lv_key, sizeof(long), IPC_CREAT | 0640); |
| if (lv_msid == -1) { |
| if (gv_verbose) |
| printf("srv: shmget(IPC_CREAT) failed, errno=%d\n", errno); |
| assert(lv_msid != -1); |
| } else { |
| if (gv_verbose) |
| printf("srv: shmget(IPC_CREAT) ok\n"); |
| } |
| } else { |
| lv_created = false; |
| if (gv_verbose) |
| printf("srv: shmget ok\n"); |
| } |
| gp_shm = (char *) shmat(lv_msid, NULL, 0); |
| if (gp_shm == NULL) { |
| if (gv_verbose) |
| printf("srv: shmat failed, errno=%d\n", errno); |
| assert(gp_shm != NULL); |
| } else { |
| gp_shml = (unsigned long *) gp_shm; |
| if (gv_verbose) |
| printf("srv: shmat ok, shm=%p\n", gp_shm); |
| if (lv_created) { |
| clock_gettime(CLOCK_REALTIME, &lv_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 |
| lv_tsl = ((unsigned long) lv_ts.tv_sec << 20) | ((unsigned long) lv_ts.tv_nsec / 1000); |
| *gp_shml = lv_tsl; |
| if (gv_verbose) |
| printf("srv: initializing shm=0x%lx\n", lv_tsl); |
| } |
| } |
| } |
| |
| // |
| // server main |
| // |
| int main(int pv_argc, char *pa_argv[]) { |
| bool lv_done; |
| int lv_ferr; |
| int lv_lerr; |
| BMS_SRE lv_sre; |
| |
| CALL_COMP_DOVERS(idtmsrv, pv_argc, pa_argv); |
| |
| do_init(pv_argc, pa_argv); |
| |
| lv_ferr = msg_mon_process_startup(true); // system messages |
| assert(lv_ferr == XZFIL_ERR_OK); |
| msg_mon_enable_mon_messages(true); |
| lv_ferr = msg_mon_get_my_process_name(ga_name, sizeof(ga_name)); |
| assert(lv_ferr == XZFIL_ERR_OK); |
| |
| do_shm(); |
| lv_ferr = timer_start_cb(gv_time_refresh_delay, 0, 0, &gv_tleid, &timer_callback); |
| assert(lv_ferr == XZFIL_ERR_OK); |
| |
| lv_done = false; |
| while (!lv_done) { |
| do { |
| lv_lerr = XWAIT(LREQ, -1); |
| lv_lerr = BMSG_LISTEN_((short *) &lv_sre, // sre |
| 0, // listenopts |
| 0); // listenertag |
| } while (lv_lerr == XSRETYPE_NOWORK); |
| if (lv_sre.sre_flags & XSRE_MON) { |
| do_mon_msg(&lv_sre, &lv_done); |
| } else { |
| do_req(&lv_sre); |
| } |
| } |
| |
| if (gv_verbose) |
| printf("server %s shutting down\n", ga_name); |
| lv_ferr = msg_mon_process_shutdown(); |
| assert(lv_ferr == XZFIL_ERR_OK); |
| |
| return 0; |
| } |