blob: 5692ff844859228a54feef1cc38af0220c59acef [file] [log] [blame]
//------------------------------------------------------------------
//
// @@@ 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;
}