mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-29 15:43:56 +00:00
Merge branch 'andrew' into 'master'
This commit is contained in:
commit
04b95d2590
@ -434,6 +434,11 @@ int app_echo(int argc, const char *const *argv, struct command_line_option *o)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cli_lookup_did(const char *text)
|
||||
{
|
||||
return text[0] == '\0' || strcmp(text, "*") == 0 || str_is_did(text);
|
||||
}
|
||||
|
||||
int app_dna_lookup(int argc, const char *const *argv, struct command_line_option *o)
|
||||
{
|
||||
int i;
|
||||
@ -447,7 +452,7 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option
|
||||
char uris[MAXREPLIES][MAXURILEN];
|
||||
|
||||
const char *did;
|
||||
if (cli_arg(argc, argv, o, "did", &did, NULL, "*") == -1)
|
||||
if (cli_arg(argc, argv, o, "did", &did, cli_lookup_did, "*") == -1)
|
||||
return -1;
|
||||
|
||||
/* Bind to MDP socket and await confirmation */
|
||||
@ -503,28 +508,32 @@ int app_dna_lookup(int argc, const char *const *argv, struct command_line_option
|
||||
else if ((rx.packetTypeAndFlags&MDP_TYPE_MASK)==MDP_TX) {
|
||||
/* Extract DID, Name, URI from response. */
|
||||
if (strlen((char *)rx.in.payload)<512) {
|
||||
char sidhex[512];
|
||||
char did[512];
|
||||
char name[512];
|
||||
char sidhex[SID_STRLEN + 1];
|
||||
char did[DID_MAXSIZE + 1];
|
||||
char name[64];
|
||||
char uri[512];
|
||||
if (!parseDnaReply(rx.in.payload,rx.in.payload_length,
|
||||
sidhex,did,name,uri))
|
||||
{
|
||||
/* Have we seen this response before? */
|
||||
int i;
|
||||
for(i=0;i<uri_count;i++)
|
||||
if (!strcmp(uri,uris[i])) break;
|
||||
if (i==uri_count) {
|
||||
/* Not previously seen, so report it */
|
||||
cli_puts(uri); cli_delim(":");
|
||||
cli_puts(did); cli_delim(":");
|
||||
cli_puts(name); cli_delim("\n");
|
||||
/* Remember that we have seen it */
|
||||
if (uri_count<MAXREPLIES&&strlen(uri)<MAXURILEN) {
|
||||
strcpy(uris[uri_count++],uri);
|
||||
}
|
||||
if ( !parseDnaReply((char *)rx.in.payload, rx.in.payload_length, sidhex, did, name, uri, NULL)
|
||||
|| !str_is_subscriber_id(sidhex)
|
||||
|| !str_is_did(did)
|
||||
|| !str_is_uri(uri)
|
||||
) {
|
||||
WHYF("Received malformed DNA reply: %s", alloca_toprint(160, (const char *)rx.in.payload, rx.in.payload_length));
|
||||
} else {
|
||||
/* Have we seen this response before? */
|
||||
int i;
|
||||
for(i=0;i<uri_count;i++)
|
||||
if (!strcmp(uri,uris[i])) break;
|
||||
if (i==uri_count) {
|
||||
/* Not previously seen, so report it */
|
||||
cli_puts(uri); cli_delim(":");
|
||||
cli_puts(did); cli_delim(":");
|
||||
cli_puts(name); cli_delim("\n");
|
||||
/* Remember that we have seen it */
|
||||
if (uri_count<MAXREPLIES&&strlen(uri)<MAXURILEN) {
|
||||
strcpy(uris[uri_count++],uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else WHYF("packettype=0x%x",rx.packetTypeAndFlags);
|
||||
@ -1423,15 +1432,19 @@ int app_keyring_add(int argc, const char *const *argv, struct command_line_optio
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cli_optional_did(const char *text)
|
||||
{
|
||||
return text[0] == '\0' || str_is_did(text);
|
||||
}
|
||||
|
||||
int app_keyring_set_did(int argc, const char *const *argv, struct command_line_option *o)
|
||||
{
|
||||
const char *sid, *did, *pin, *name;
|
||||
cli_arg(argc, argv, o, "sid", &sid, NULL, "");
|
||||
cli_arg(argc, argv, o, "did", &did, NULL, "");
|
||||
cli_arg(argc, argv, o, "sid", &sid, str_is_subscriber_id, "");
|
||||
cli_arg(argc, argv, o, "did", &did, cli_optional_did, "");
|
||||
cli_arg(argc, argv, o, "name", &name, NULL, "");
|
||||
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
|
||||
|
||||
if (strlen(did)>31) return WHY("DID too long (31 digits max)");
|
||||
if (strlen(name)>63) return WHY("Name too long (31 char max)");
|
||||
|
||||
if (!(keyring = keyring_open_with_pins(pin)))
|
||||
@ -1647,14 +1660,18 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
char sidhex[512];
|
||||
char did[512];
|
||||
char name[512];
|
||||
{
|
||||
char sidhex[SID_STRLEN + 1];
|
||||
char did[DID_MAXSIZE + 1];
|
||||
char name[64];
|
||||
char uri[512];
|
||||
if (!parseDnaReply(m2.in.payload,m2.in.payload_length,
|
||||
sidhex,did,name,uri))
|
||||
{
|
||||
if ( !parseDnaReply((char *)m2.in.payload, m2.in.payload_length, sidhex, did, name, uri, NULL)
|
||||
|| !str_is_subscriber_id(sidhex)
|
||||
|| !str_is_did(did)
|
||||
|| !str_is_uri(uri)
|
||||
) {
|
||||
WHYF("Received malformed DNA reply: %s", alloca_toprint(160, (const char *)m2.in.payload, m2.in.payload_length));
|
||||
} else {
|
||||
/* Got a good DNA reply, copy it into place */
|
||||
bcopy(did,mdp.nodeinfo.did,32);
|
||||
bcopy(name,mdp.nodeinfo.name,64);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
/*
|
||||
Serval Distributed Numbering Architecture (DNA)
|
||||
Copyright (C) 2010 Paul Gardner-Stephen
|
||||
Copyright (C) 2010 Paul Gardner-Stephen
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@ -99,7 +99,8 @@ int fromhexstr(unsigned char *dstBinary, const char *srcHex, size_t nbinary)
|
||||
|
||||
int str_is_subscriber_id(const char *sid)
|
||||
{
|
||||
return strcasecmp(sid, "broadcast") == 0 || _is_xstring(sid, SID_STRLEN);
|
||||
size_t len = 0;
|
||||
return strn_is_subscriber_id(sid, &len) && sid[len] == '\0';
|
||||
}
|
||||
|
||||
int strn_is_subscriber_id(const char *sid, size_t *lenp)
|
||||
@ -157,6 +158,29 @@ int rhizome_str_is_file_hash(const char *hash)
|
||||
return _is_xstring(hash, RHIZOME_FILEHASH_STRLEN);
|
||||
}
|
||||
|
||||
int str_is_did(const char *did)
|
||||
{
|
||||
size_t len = 0;
|
||||
return strn_is_did(did, &len) && did[len] == '\0';
|
||||
}
|
||||
|
||||
int is_didchar(char c)
|
||||
{
|
||||
return isdigit(c) || c == '*' || c == '#' || c == '+';
|
||||
}
|
||||
|
||||
int strn_is_did(const char *did, size_t *lenp)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < DID_MAXSIZE && is_didchar(did[i]); ++i)
|
||||
;
|
||||
if (i < DID_MINSIZE)
|
||||
return 0;
|
||||
if (lenp)
|
||||
*lenp = i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int extractDid(unsigned char *packet,int *ofs,char *did)
|
||||
{
|
||||
int d=0;
|
||||
@ -337,3 +361,45 @@ int safeZeroField(unsigned char *packet,int start,int count)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int is_uri_char_scheme(char c)
|
||||
{
|
||||
return isalpha(c) || isdigit(c) || c == '+' || c == '-' || c == '.';
|
||||
}
|
||||
|
||||
int is_uri_char_unreserved(char c)
|
||||
{
|
||||
return isalpha(c) || isdigit(c) || c == '-' || c == '.' || c == '_' || c == '~';
|
||||
}
|
||||
|
||||
int is_uri_char_reserved(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case ':': case '/': case '?': case '#': case '[': case ']': case '@':
|
||||
case '!': case '$': case '&': case '\'': case '(': case ')':
|
||||
case '*': case '+': case ',': case ';': case '=':
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return true if the string resembles a URI.
|
||||
Based on RFC-3986 generic syntax, assuming nothing about the hierarchical part.
|
||||
@author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
int str_is_uri(const char *uri)
|
||||
{
|
||||
const char *p = uri;
|
||||
// Scheme is ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
if (!isalpha(*p++))
|
||||
return 0;
|
||||
while (is_uri_char_scheme(*p))
|
||||
++p;
|
||||
// Scheme is followed by colon ":".
|
||||
if (*p++ != ':')
|
||||
return 0;
|
||||
// Hierarchical part must contain only valid characters.
|
||||
const char *q = p;
|
||||
while (is_uri_char_unreserved(*p) || is_uri_char_reserved(*p))
|
||||
++p;
|
||||
return p != q && *p == '\0';
|
||||
}
|
||||
|
686
dna_helper.c
686
dna_helper.c
@ -17,7 +17,12 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include "serval.h"
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
|
||||
/*
|
||||
The challenge with making an interface for calling an external program to
|
||||
@ -38,194 +43,563 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
main loop.
|
||||
*/
|
||||
|
||||
int
|
||||
parseDnaReply(const char *buf, size_t len, char *token, char *did, char *name, char *uri, const char **bufp)
|
||||
{
|
||||
/* Replies look like: TOKEN|URI|DID|NAME| where TOKEN is usually a hex SID */
|
||||
const char *b = buf;
|
||||
const char *e = buf + len;
|
||||
char *p, *q;
|
||||
for (p = token, q = token + SID_STRLEN; b != e && *b != '|' && p != q; ++p, ++b)
|
||||
*p = *b;
|
||||
*p = '\0';
|
||||
if (b == e || *b++ != '|')
|
||||
return 0;
|
||||
for (p = uri, q = uri + 511; b != e && *b != '|' && p != q; ++p, ++b)
|
||||
*p = *b;
|
||||
*p = '\0';
|
||||
if (b == e || *b++ != '|')
|
||||
return 0;
|
||||
for (p = did, q = did + DID_MAXSIZE; b != e && *b != '|' && p != q; ++p, ++b)
|
||||
*p = *b;
|
||||
*p = '\0';
|
||||
if (b == e || *b++ != '|')
|
||||
return 0;
|
||||
for (p = name, q = name + 63; b != e && *b != '|' && p != q; ++p, ++b)
|
||||
*p = *b;
|
||||
*p = '\0';
|
||||
if (b == e || *b++ != '|')
|
||||
return 0;
|
||||
if (bufp)
|
||||
*bufp = b;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static pid_t dna_helper_pid = -1;
|
||||
static int dna_helper_stdin = -1;
|
||||
static int dna_helper_stdout = -1;
|
||||
static int dna_helper_stderr = -1;
|
||||
static int dna_helper_started = 0;
|
||||
|
||||
int
|
||||
parseDnaReply(unsigned char *bytes, int count,
|
||||
char *sidhex, char *did, char *name, char *uri) {
|
||||
bzero(sidhex, SID_SIZE*2+1);
|
||||
bzero(did, SID_SIZE);
|
||||
bzero(name,64);
|
||||
bzero(uri,512);
|
||||
int i,l,maxlen;
|
||||
static struct sched_ent sched_requests = STRUCT_SCHED_ENT_UNUSED;
|
||||
static struct sched_ent sched_replies = STRUCT_SCHED_ENT_UNUSED;
|
||||
static struct sched_ent sched_harvester = STRUCT_SCHED_ENT_UNUSED;
|
||||
static struct sched_ent sched_errors = STRUCT_SCHED_ENT_UNUSED;
|
||||
static struct sched_ent sched_restart = STRUCT_SCHED_ENT_UNUSED;
|
||||
static struct sched_ent sched_timeout = STRUCT_SCHED_ENT_UNUSED;
|
||||
|
||||
l=0;
|
||||
|
||||
/* Replies look like: TOKEN|URI|DID|CALLERID| */
|
||||
// This buffer must hold "SID|DID|\n\0"
|
||||
static char request_buffer[SID_STRLEN + DID_MAXSIZE + 4];
|
||||
static char *request_bufptr = NULL;
|
||||
static char *request_bufend = NULL;
|
||||
static overlay_mdp_data_frame request_mdp_data;
|
||||
static char request_did[DID_MAXSIZE + 1];
|
||||
|
||||
maxlen=SID_SIZE*2+1;
|
||||
for(i=0;l<maxlen&&i<count&&bytes[i]!='|';i++)
|
||||
sidhex[l++]=bytes[i];
|
||||
sidhex[l]=0;
|
||||
static int awaiting_reply = 0;
|
||||
static int discarding_until_nl = 0;
|
||||
static char reply_buffer[2048];
|
||||
static char *reply_bufend = NULL;
|
||||
|
||||
if (l>=count) return WHY("DNA helper response does not contain URI field");
|
||||
if (l>=maxlen) return WHY("DNA helper response SID field too long");
|
||||
l=0; i++; maxlen=511;
|
||||
for(;l<maxlen&&i<count&&bytes[i]!='|';i++)
|
||||
uri[l++]=bytes[i];
|
||||
uri[l]=0;
|
||||
static void monitor_requests(struct sched_ent *alarm);
|
||||
static void monitor_replies(struct sched_ent *alarm);
|
||||
static void monitor_errors(struct sched_ent *alarm);
|
||||
static void harvester(struct sched_ent *alarm);
|
||||
static void restart_delayer(struct sched_ent *alarm);
|
||||
static void reply_timeout(struct sched_ent *alarm);
|
||||
|
||||
if (l>=count) return WHY("DNA helper response does not contain DID field");
|
||||
if (l>=maxlen) return WHY("DNA helper response URI field too long");
|
||||
l=0; i++; maxlen=SID_SIZE;
|
||||
for(;l<maxlen&&i<count&&bytes[i]!='|';i++)
|
||||
did[l++]=bytes[i];
|
||||
did[l]=0;
|
||||
|
||||
if (l>=count) return WHY("DNA helper response does not contain CALLERID field");
|
||||
if (l>=maxlen) return WHY("DNA helper response DID field too long");
|
||||
l=0; i++; maxlen=SID_SIZE;
|
||||
for(;l<maxlen&&i<count&&bytes[i]!='|';i++)
|
||||
name[l++]=bytes[i];
|
||||
name[l]=0;
|
||||
|
||||
if (l>=count) return WHY("DNA helper response does not contain terminator");
|
||||
if (l>=maxlen) return WHY("DNA helper response CALLERID field too long");
|
||||
|
||||
/* DEBUGF("did='%s', name='%s', uri='%s'",did,name,uri); */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dna_helper_monitor(int fd)
|
||||
static void
|
||||
dna_helper_close_pipes()
|
||||
{
|
||||
return;
|
||||
if (dna_helper_stdin != -1) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stdin pipe fd=%d", dna_helper_stdin);
|
||||
close(dna_helper_stdin);
|
||||
dna_helper_stdin = -1;
|
||||
}
|
||||
if (sched_requests.poll.fd != -1) {
|
||||
unwatch(&sched_requests);
|
||||
sched_requests.poll.fd = -1;
|
||||
}
|
||||
if (dna_helper_stdout != -1) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stdout pipe fd=%d", dna_helper_stdout);
|
||||
close(dna_helper_stdout);
|
||||
dna_helper_stdout = -1;
|
||||
}
|
||||
if (sched_replies.poll.fd != -1) {
|
||||
unwatch(&sched_replies);
|
||||
sched_replies.poll.fd = -1;
|
||||
}
|
||||
if (dna_helper_stderr != -1) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stderr pipe fd=%d", dna_helper_stderr);
|
||||
close(dna_helper_stderr);
|
||||
dna_helper_stderr = -1;
|
||||
}
|
||||
if (sched_errors.poll.fd != -1) {
|
||||
unwatch(&sched_errors);
|
||||
sched_errors.poll.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct sched_ent dna_helper_sched;
|
||||
|
||||
static int
|
||||
dna_helper_start(const char *command, const char *arg) {
|
||||
int stdin_fds[2], stdout_fds[2];
|
||||
pid_t pid;
|
||||
|
||||
DEBUG("Starting DNA helper");
|
||||
|
||||
if (pipe(stdin_fds))
|
||||
dna_helper_start(const char *command, const char *arg)
|
||||
{
|
||||
dna_helper_close_pipes();
|
||||
int stdin_fds[2], stdout_fds[2], stderr_fds[2];
|
||||
if (pipe(stdin_fds) == -1)
|
||||
return WHY_perror("pipe");
|
||||
|
||||
if (pipe(stdout_fds)) {
|
||||
if (pipe(stdout_fds) == -1) {
|
||||
WHY_perror("pipe");
|
||||
close(stdin_fds[0]);
|
||||
close(stdin_fds[1]);
|
||||
return WHY_perror("pipe");
|
||||
close(stdin_fds[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((pid = fork()) == 0) {
|
||||
if (pipe(stderr_fds) == -1) {
|
||||
WHY_perror("pipe");
|
||||
close(stdin_fds[0]);
|
||||
close(stdin_fds[1]);
|
||||
close(stdout_fds[0]);
|
||||
close(stdout_fds[1]);
|
||||
return -1;
|
||||
}
|
||||
switch (dna_helper_pid = fork()) {
|
||||
case 0:
|
||||
/* Child, should exec() to become helper after installing file descriptors. */
|
||||
if (dup2(stdin_fds[1], 0)) /* replace stdin */
|
||||
exit(-1);
|
||||
if (dup2(stdout_fds[0], 1)) /* replace stdout */
|
||||
exit(-1);
|
||||
if (dup2(stdout_fds[0], 2)) /* replace stderr */
|
||||
exit(-1);
|
||||
execl(command, command, arg, NULL);
|
||||
DEBUG("execl() failed");
|
||||
abort(); /* Can't get here */
|
||||
} else {
|
||||
if (pid == -1) {
|
||||
/* fork failed */
|
||||
WHY_perror("fork");
|
||||
close(stdin_fds[0]);
|
||||
close(stdin_fds[1]);
|
||||
close(stdout_fds[0]);
|
||||
close(stdout_fds[1]);
|
||||
return -1;
|
||||
} else {
|
||||
/* Parent, should put file descriptors into place for use */
|
||||
dna_helper_stdin = stdin_fds[0];
|
||||
dna_helper_stdout = stdout_fds[1];
|
||||
|
||||
/* Need to watch dna_helper_stdout */
|
||||
// XXX need to initialise structure before calling watch
|
||||
// XXX watch(&dna_helper_sched);
|
||||
// XXX need to add unwatch() when we detect that the process has died.
|
||||
return 0;
|
||||
set_logging(stderr);
|
||||
signal(SIGTERM, SIG_DFL);
|
||||
close(stdin_fds[1]);
|
||||
close(stdout_fds[0]);
|
||||
close(stderr_fds[0]);
|
||||
if (dup2(stderr_fds[1], 2) == -1 || dup2(stdout_fds[1], 1) == -1 || dup2(stdin_fds[0], 0) == -1) {
|
||||
LOG_perror(LOG_LEVEL_FATAL, "dup2");
|
||||
fflush(stderr);
|
||||
_exit(-1);
|
||||
}
|
||||
execl(command, command, arg, NULL);
|
||||
LOGF_perror(LOG_LEVEL_FATAL, "execl(%s, %s, %s, NULL)", command, command, arg ? arg : "NULL");
|
||||
fflush(stderr);
|
||||
do { _exit(-1); } while (1);
|
||||
break;
|
||||
case -1:
|
||||
/* fork failed */
|
||||
WHY_perror("fork");
|
||||
close(stdin_fds[0]);
|
||||
close(stdin_fds[1]);
|
||||
close(stdout_fds[0]);
|
||||
close(stdout_fds[1]);
|
||||
close(stderr_fds[0]);
|
||||
close(stderr_fds[1]);
|
||||
return -1;
|
||||
default:
|
||||
/* Parent, should put file descriptors into place for use */
|
||||
close(stdin_fds[0]);
|
||||
close(stdout_fds[1]);
|
||||
close(stderr_fds[1]);
|
||||
dna_helper_started = 0;
|
||||
dna_helper_stdin = stdin_fds[1];
|
||||
dna_helper_stdout = stdout_fds[0];
|
||||
dna_helper_stderr = stderr_fds[0];
|
||||
INFOF("STARTED DNA HELPER pid=%u stdin=%d stdout=%d stderr=%d executable=%s arg=%s",
|
||||
dna_helper_pid,
|
||||
dna_helper_stdin,
|
||||
dna_helper_stdout,
|
||||
dna_helper_stderr,
|
||||
command,
|
||||
arg ? arg : "NULL"
|
||||
);
|
||||
sched_requests.function = monitor_requests;
|
||||
sched_requests.context = NULL;
|
||||
sched_requests.poll.fd = -1;
|
||||
sched_requests.poll.events = POLLOUT;
|
||||
sched_requests.stats = NULL;
|
||||
sched_timeout.function = reply_timeout;
|
||||
sched_timeout.context = NULL;
|
||||
sched_timeout.stats = NULL;
|
||||
sched_replies.function = monitor_replies;
|
||||
sched_replies.context = NULL;
|
||||
sched_replies.poll.fd = dna_helper_stdout;
|
||||
sched_replies.poll.events = POLLIN;
|
||||
sched_replies.stats = NULL;
|
||||
sched_errors.function = monitor_errors;
|
||||
sched_errors.context = NULL;
|
||||
sched_errors.poll.fd = dna_helper_stderr;
|
||||
sched_errors.poll.events = POLLIN;
|
||||
sched_errors.stats = NULL;
|
||||
sched_harvester.function = harvester;
|
||||
sched_harvester.stats = NULL;
|
||||
sched_harvester.alarm = overlay_gettime_ms() + 1000;
|
||||
sched_harvester.deadline = sched_harvester.alarm + 1000;
|
||||
reply_bufend = reply_buffer;
|
||||
discarding_until_nl = 0;
|
||||
awaiting_reply = 0;
|
||||
watch(&sched_replies);
|
||||
watch(&sched_errors);
|
||||
schedule(&sched_harvester);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
dna_helper_enqueue(char *did, unsigned char *requestorSid) {
|
||||
const char *dna_helper, *dna_helper_arg;
|
||||
char buffer[1024];
|
||||
|
||||
if (dna_helper_stdin == -2)
|
||||
return -1;
|
||||
static int
|
||||
dna_helper_kill()
|
||||
{
|
||||
if (awaiting_reply) {
|
||||
unschedule(&sched_timeout);
|
||||
awaiting_reply = 0;
|
||||
}
|
||||
if (dna_helper_pid > 0) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER sending SIGTERM to pid=%d", dna_helper_pid);
|
||||
if (kill(dna_helper_pid, SIGTERM) == -1)
|
||||
WHYF_perror("kill(%d, SIGTERM)", dna_helper_pid);
|
||||
// The process is wait()ed for in dna_helper_monitor() so that we do not block here.
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dna_helper_stdin == -1) {
|
||||
dna_helper = confValueGet("dna.helper", NULL);
|
||||
if (!dna_helper || !dna_helper[0]) {
|
||||
/* Check if we have a helper configured. If not, then set
|
||||
dna_helper_stdin to magic value of -2 so that we don't waste time
|
||||
in future looking up the dna helper configuration value. */
|
||||
DEBUG("We have no DNA helper configured");
|
||||
dna_helper_stdin = -2;
|
||||
return -1;
|
||||
static int
|
||||
dna_helper_harvest(int blocking)
|
||||
{
|
||||
if (dna_helper_pid > 0) {
|
||||
if (blocking && (debug & DEBUG_DNAHELPER))
|
||||
DEBUGF("DNAHELPER waiting for pid=%d to die", dna_helper_pid);
|
||||
int status;
|
||||
pid_t pid = waitpid(dna_helper_pid, &status, blocking ? 0 : WNOHANG);
|
||||
if (pid == dna_helper_pid) {
|
||||
strbuf b = strbuf_alloca(80);
|
||||
INFOF("DNAHELPER process pid=%u %s", pid, strbuf_str(strbuf_append_exit_status(b, status)));
|
||||
unschedule(&sched_harvester);
|
||||
dna_helper_pid = -1;
|
||||
if (awaiting_reply) {
|
||||
unschedule(&sched_timeout);
|
||||
awaiting_reply = 0;
|
||||
}
|
||||
return 1;
|
||||
} else if (pid == -1) {
|
||||
return WHYF_perror("waitpid(%d, %s)", dna_helper_pid, blocking ? "0" : "WNOHANG");
|
||||
} else if (pid) {
|
||||
return WHYF("waitpid(%d, %s) returned %d", dna_helper_pid, blocking ? "0" : "WNOHANG", pid);
|
||||
}
|
||||
|
||||
/* Look for optional argument */
|
||||
dna_helper_arg = confValueGet("dna.helperarg", NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Okay, so we have a helper configured.
|
||||
Run it */
|
||||
if (dna_helper_start(dna_helper, dna_helper_arg) < 0) {
|
||||
int dna_helper_shutdown()
|
||||
{
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUG("DNAHELPER shutting down");
|
||||
dna_helper_close_pipes();
|
||||
switch (dna_helper_kill()) {
|
||||
case -1:
|
||||
return -1;
|
||||
case 0:
|
||||
return 0;
|
||||
default:
|
||||
return dna_helper_harvest(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_requests(struct sched_ent *alarm)
|
||||
{
|
||||
if (debug & DEBUG_DNAHELPER) {
|
||||
DEBUGF("sched_requests.poll.revents=%s",
|
||||
strbuf_str(strbuf_append_poll_events(strbuf_alloca(40), sched_requests.poll.revents))
|
||||
);
|
||||
}
|
||||
if (sched_requests.poll.revents & (POLLHUP | POLLERR)) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stdin fd=%d", dna_helper_stdin);
|
||||
close(dna_helper_stdin);
|
||||
dna_helper_stdin = -1;
|
||||
unwatch(&sched_requests);
|
||||
sched_requests.poll.fd = -1;
|
||||
dna_helper_kill();
|
||||
}
|
||||
else if (sched_requests.poll.revents & POLLOUT) {
|
||||
if (request_bufptr) {
|
||||
if (request_bufptr < request_bufend) {
|
||||
size_t remaining = request_bufend - request_bufptr;
|
||||
sigPipeFlag = 0;
|
||||
ssize_t written = write_nonblock(dna_helper_stdin, request_bufptr, remaining);
|
||||
if (sigPipeFlag) {
|
||||
/* Broken pipe is probably due to a dead helper, but make sure the helper is dead, just to be
|
||||
sure. It will be harvested at the next harvester() timeout, and restarted on the first
|
||||
request that arrives after a suitable pause has elapsed. Losing the current request is not
|
||||
a big problem, because DNA preemptively retries.
|
||||
*/
|
||||
INFO("DNAHELPER got SIGPIPE on write -- stopping process");
|
||||
dna_helper_kill();
|
||||
} else if (written > 0) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER wrote request %s", alloca_toprint(-1, request_bufptr, written));
|
||||
request_bufptr += written;
|
||||
}
|
||||
}
|
||||
if (request_bufptr >= request_bufend) {
|
||||
// Request sent successfully. Start watching for reply.
|
||||
request_bufptr = request_bufend = NULL;
|
||||
awaiting_reply = 1;
|
||||
sched_timeout.alarm = overlay_gettime_ms() + 1500;
|
||||
sched_timeout.deadline = sched_timeout.alarm + 3000;
|
||||
schedule(&sched_timeout);
|
||||
}
|
||||
}
|
||||
// If no request to send, stop monitoring the helper's stdin pipe.
|
||||
if (!request_bufptr) {
|
||||
unwatch(&sched_requests);
|
||||
sched_requests.poll.fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char *strnstr(char *haystack, size_t haystack_len, const char *needle)
|
||||
{
|
||||
size_t needle_len = strlen(needle);
|
||||
for (; haystack_len >= needle_len; ++haystack, --haystack_len) {
|
||||
if (strncmp(haystack, needle, needle_len) == 0)
|
||||
return haystack;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void handle_reply_line(const char *bufp, size_t len)
|
||||
{
|
||||
if (!dna_helper_started) {
|
||||
if (len == 8 && strncmp(bufp, "STARTED\n", 8) == 0) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER got STARTED ACK");
|
||||
dna_helper_started = 1;
|
||||
// Start sending request if there is one pending.
|
||||
if (request_bufptr) {
|
||||
sched_requests.poll.fd = dna_helper_stdin;
|
||||
watch(&sched_requests);
|
||||
}
|
||||
} else {
|
||||
WHYF("DNAHELPER malformed start ACK %s", alloca_toprint(-1, bufp, len));
|
||||
dna_helper_kill();
|
||||
}
|
||||
} else if (awaiting_reply) {
|
||||
if (len == 5 && strncmp(bufp, "DONE\n", 5) == 0) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUG("DNAHELPER reply DONE");
|
||||
unschedule(&sched_timeout);
|
||||
awaiting_reply = 0;
|
||||
} else {
|
||||
char sidhex[SID_STRLEN + 1];
|
||||
char did[DID_MAXSIZE + 1];
|
||||
char name[64];
|
||||
char uri[512];
|
||||
const char *replyend = NULL;
|
||||
if (!parseDnaReply(bufp, len, sidhex, did, name, uri, &replyend))
|
||||
WHYF("DNAHELPER reply %s invalid -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (uri[0] == '\0')
|
||||
WHYF("DNAHELPER reply %s contains empty URI -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (!str_is_uri(uri))
|
||||
WHYF("DNAHELPER reply %s contains invalid URI -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (sidhex[0] == '\0')
|
||||
WHYF("DNAHELPER reply %s contains empty token -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (!str_is_subscriber_id(sidhex))
|
||||
WHYF("DNAHELPER reply %s contains invalid token -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (did[0] == '\0')
|
||||
WHYF("DNAHELPER reply %s contains empty DID -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (!str_is_did(did))
|
||||
WHYF("DNAHELPER reply %s contains invalid DID -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (strcmp(did, request_did) != 0)
|
||||
WHYF("DNAHELPER reply %s contains mismatched DID -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else if (*replyend != '\n')
|
||||
WHYF("DNAHELPER reply %s contains spurious trailing chars -- ignored", alloca_toprint(-1, bufp, len));
|
||||
else {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER reply %s", alloca_toprint(-1, bufp, len));
|
||||
unsigned char sid[SID_SIZE];
|
||||
fromhex(sid, sidhex, SID_SIZE);
|
||||
overlay_mdp_dnalookup_reply(&request_mdp_data, sid, uri, did, name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WARNF("DNAHELPER spurious output %s -- ignored", alloca_toprint(-1, bufp, len));
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_replies(struct sched_ent *alarm)
|
||||
{
|
||||
if (debug & DEBUG_DNAHELPER) {
|
||||
DEBUGF("sched_replies.poll.revents=%s",
|
||||
strbuf_str(strbuf_append_poll_events(strbuf_alloca(40), sched_replies.poll.revents))
|
||||
);
|
||||
}
|
||||
if (sched_replies.poll.revents & POLLIN) {
|
||||
size_t remaining = reply_buffer + sizeof reply_buffer - reply_bufend;
|
||||
ssize_t nread = read_nonblock(sched_replies.poll.fd, reply_bufend, remaining);
|
||||
if (nread > 0) {
|
||||
char *bufp = reply_buffer;
|
||||
char *readp = reply_bufend;
|
||||
reply_bufend += nread;
|
||||
char *nl;
|
||||
while (nread > 0 && (nl = strnstr(readp, nread, "\n"))) {
|
||||
size_t len = nl - bufp + 1;
|
||||
if (discarding_until_nl) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("Discarding %s", alloca_toprint(-1, bufp, len));
|
||||
discarding_until_nl = 0;
|
||||
} else {
|
||||
handle_reply_line(bufp, len);
|
||||
}
|
||||
readp = bufp = nl + 1;
|
||||
nread = reply_bufend - readp;
|
||||
}
|
||||
if (bufp != reply_buffer) {
|
||||
size_t len = reply_bufend - bufp;
|
||||
memmove(reply_buffer, bufp, len);
|
||||
reply_bufend = reply_buffer + len;
|
||||
} else if (reply_bufend >= reply_buffer + sizeof reply_buffer) {
|
||||
WHY("DNAHELPER reply buffer overrun");
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("Discarding %s", alloca_toprint(-1, reply_buffer, sizeof reply_buffer));
|
||||
reply_bufend = reply_buffer;
|
||||
discarding_until_nl = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sched_replies.poll.revents & (POLLHUP | POLLERR)) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stdout fd=%d", dna_helper_stdout);
|
||||
close(dna_helper_stdout);
|
||||
dna_helper_stdout = -1;
|
||||
unwatch(&sched_replies);
|
||||
sched_replies.poll.fd = -1;
|
||||
dna_helper_kill();
|
||||
}
|
||||
}
|
||||
|
||||
static void monitor_errors(struct sched_ent *alarm)
|
||||
{
|
||||
if (debug & DEBUG_DNAHELPER) {
|
||||
DEBUGF("sched_errors.poll.revents=%s",
|
||||
strbuf_str(strbuf_append_poll_events(strbuf_alloca(40), sched_errors.poll.revents))
|
||||
);
|
||||
}
|
||||
if (sched_errors.poll.revents & POLLIN) {
|
||||
char buffer[1024];
|
||||
ssize_t nread = read_nonblock(sched_errors.poll.fd, buffer, sizeof buffer);
|
||||
if (nread > 0)
|
||||
WHYF("DNAHELPER stderr %s", alloca_toprint(-1, buffer, nread));
|
||||
}
|
||||
if (sched_errors.poll.revents & (POLLHUP | POLLERR)) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER closing stderr fd=%d", dna_helper_stderr);
|
||||
close(dna_helper_stderr);
|
||||
dna_helper_stderr = -1;
|
||||
unwatch(&sched_errors);
|
||||
sched_errors.poll.fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void harvester(struct sched_ent *alarm)
|
||||
{
|
||||
// While the helper process appears to still be running, keep calling this function.
|
||||
// Otherwise, wait a while before re-starting the helper.
|
||||
if (dna_helper_harvest(0) <= 0) {
|
||||
sched_harvester.alarm = overlay_gettime_ms() + 1000;
|
||||
sched_harvester.deadline = sched_harvester.alarm + 1000;
|
||||
schedule(&sched_harvester);
|
||||
} else {
|
||||
const int delay_ms = 500;
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER process died, pausing %d ms before restart", delay_ms);
|
||||
dna_helper_pid = 0; // Will be set to -1 after delay
|
||||
sched_restart.function = restart_delayer;
|
||||
sched_restart.alarm = overlay_gettime_ms() + delay_ms;
|
||||
sched_restart.deadline = sched_restart.alarm + 500;
|
||||
schedule(&sched_restart);
|
||||
}
|
||||
}
|
||||
|
||||
static void restart_delayer(struct sched_ent *alarm)
|
||||
{
|
||||
if (dna_helper_pid == 0) {
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUG("DNAHELPER re-enable restart");
|
||||
dna_helper_pid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void reply_timeout(struct sched_ent *alarm)
|
||||
{
|
||||
if (awaiting_reply) {
|
||||
WHY("DNAHELPER reply timeout");
|
||||
dna_helper_kill();
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dna_helper_enqueue(overlay_mdp_frame *mdp, const char *did, const unsigned char *requestorSid)
|
||||
{
|
||||
if (debug & DEBUG_DNAHELPER)
|
||||
DEBUGF("DNAHELPER request did=%s sid=%s", did, alloca_tohex_sid(requestorSid));
|
||||
if (dna_helper_pid == 0)
|
||||
return 0;
|
||||
// Only try to restart a DNA helper process if the previous one is well and truly gone.
|
||||
if (dna_helper_pid == -1 && dna_helper_stdin == -1 && dna_helper_stdout == -1 && dna_helper_stderr == -1) {
|
||||
const char *dna_helper_executable = confValueGet("dna.helper.executable", NULL);
|
||||
const char *dna_helper_arg1 = confValueGet("dna.helper.argv.1", NULL);
|
||||
if (!dna_helper_executable || !dna_helper_executable[0]) {
|
||||
/* Check if we have a helper configured. If not, then set
|
||||
dna_helper_pid to magic value of 0 so that we don't waste time
|
||||
in future looking up the dna helper configuration value. */
|
||||
INFO("DNAHELPER none configured");
|
||||
dna_helper_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
if (dna_helper_start(dna_helper_executable, dna_helper_arg1) == -1) {
|
||||
/* Something broke, bail out */
|
||||
DEBUG("Failed to start dna helper");
|
||||
WHY("DNAHELPER start failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write request to dna helper.
|
||||
Request takes form: SID-of-Requestor|DID|\n
|
||||
By passing the requestor's SID to the helper, we don't need to maintain
|
||||
any state, as all we have to do is wait for responses from the helper,
|
||||
which will include the requestor's SID.
|
||||
*/
|
||||
bzero(buffer, sizeof(buffer));
|
||||
if (snprintf(buffer, sizeof(buffer) - 1, "%s|%s|\n", alloca_tohex_sid(requestorSid), did) >
|
||||
sizeof(buffer) - 1)
|
||||
return WHY("Command to helper is too long");
|
||||
|
||||
sigPipeFlag = 0;
|
||||
write_str(dna_helper_stdin, buffer);
|
||||
|
||||
if (sigPipeFlag) {
|
||||
/* Assume broken pipe due to dead helper.
|
||||
Next request will cause it to be restarted.
|
||||
(Losing the current request is not a big problem, because
|
||||
DNA preemptively retries, anyway.
|
||||
XXX In fact, we should probably have a limit to the number of restarts
|
||||
in quick succession so that we don't waste lots of time with a buggy or
|
||||
suicidal helper.
|
||||
*/
|
||||
close(dna_helper_stdin);
|
||||
close(dna_helper_stdout);
|
||||
dna_helper_stdin = -1;
|
||||
dna_helper_stdout = -1;
|
||||
DEBUG("Sigpipe encountered");
|
||||
return -1;
|
||||
if (dna_helper_stdin == -1)
|
||||
return 0;
|
||||
if (request_bufptr && request_bufptr != request_buffer) {
|
||||
WARNF("DNAHELPER currently sending request %s -- dropping new request", request_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dna_return_resolution(overlay_mdp_frame *mdp, unsigned char *fromSid,
|
||||
const char *did,const char *name, const char *uri) {
|
||||
/* copy SID out into source address of frame */
|
||||
bcopy(fromSid,&mdp->out.src.sid[0],SID_SIZE);
|
||||
|
||||
/* and build reply as did\nname\nURI<NUL> */
|
||||
snprintf((char *)&mdp->out.payload[0],512,"%s\n%s\n%s",
|
||||
did,name,uri);
|
||||
mdp->out.payload_length=strlen((char *)mdp->out.payload)+1;
|
||||
|
||||
/* Dispatch response */
|
||||
mdp->packetTypeAndFlags&=MDP_FLAG_MASK;
|
||||
mdp->packetTypeAndFlags|=MDP_TX;
|
||||
overlay_mdp_dispatch(mdp,0 /* system generated */,
|
||||
NULL,0);
|
||||
|
||||
return 0;
|
||||
if (awaiting_reply) {
|
||||
WARNF("DNAHELPER currently awaiting reply -- dropping new request", request_buffer);
|
||||
return 0;
|
||||
}
|
||||
char buffer[sizeof request_buffer];
|
||||
strbuf b = strbuf_local(request_bufptr == request_buffer ? buffer : request_buffer, sizeof buffer);
|
||||
strbuf_tohex(b, requestorSid, SID_SIZE);
|
||||
strbuf_putc(b, '|');
|
||||
strbuf_puts(b, did);
|
||||
strbuf_putc(b, '|');
|
||||
strbuf_putc(b, '\n');
|
||||
if (strbuf_overrun(b)) {
|
||||
WHYF("DNAHELPER request buffer overrun: %s -- request not sent", strbuf_str(b));
|
||||
request_bufptr = request_bufend = NULL;
|
||||
} else {
|
||||
if (strbuf_str(b) != request_buffer) {
|
||||
if (strcmp(strbuf_str(b), request_buffer) != 0)
|
||||
WARNF("DNAHELPER overwriting unsent request %s", request_buffer);
|
||||
strcpy(request_buffer, strbuf_str(b));
|
||||
}
|
||||
request_bufptr = request_buffer;
|
||||
request_bufend = request_buffer + strbuf_len(b);
|
||||
request_mdp_data = mdp->out;
|
||||
strncpy(request_did, did, sizeof request_did);
|
||||
request_did[sizeof request_did - 1] = '\0';
|
||||
}
|
||||
if (dna_helper_started) {
|
||||
sched_requests.poll.fd = dna_helper_stdin;
|
||||
watch(&sched_requests);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -137,6 +137,7 @@ int watch(struct sched_ent *alarm){
|
||||
if (fdcount>=MAX_WATCHED_FDS)
|
||||
return WHY("Too many file handles to watch");
|
||||
fd_callbacks[fdcount]=alarm;
|
||||
alarm->poll.revents = 0;
|
||||
alarm->_poll_index=fdcount;
|
||||
fdcount++;
|
||||
}
|
||||
|
84
log.c
84
log.c
@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "strbuf.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
@ -39,9 +40,20 @@ static char _log_buf[8192];
|
||||
static struct strbuf logbuf = STRUCT_STRBUF_EMPTY;
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <android/log.h>
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
void set_logging(FILE *f)
|
||||
{
|
||||
logfile = f;
|
||||
if (f == stdout)
|
||||
INFO("Logging to stdout");
|
||||
else if (f == stderr)
|
||||
INFO("Logging to stderr");
|
||||
else if (f != NULL)
|
||||
INFOF("Logging to stream with fd=%d", fileno(f));
|
||||
}
|
||||
|
||||
FILE *open_logging()
|
||||
{
|
||||
if (!logfile) {
|
||||
@ -231,7 +243,7 @@ unsigned int debugFlagMask(const char *flagname) {
|
||||
else if (!strcasecmp(flagname,"verbio")) return DEBUG_VERBOSE_IO;
|
||||
else if (!strcasecmp(flagname,"peers")) return DEBUG_PEERS;
|
||||
else if (!strcasecmp(flagname,"dnaresponses")) return DEBUG_DNARESPONSES;
|
||||
else if (!strcasecmp(flagname,"dnarequests")) return DEBUG_DNAREQUESTS;
|
||||
else if (!strcasecmp(flagname,"dnahelper")) return DEBUG_DNAHELPER;
|
||||
else if (!strcasecmp(flagname,"simulation")) return DEBUG_SIMULATION;
|
||||
else if (!strcasecmp(flagname,"packetformats")) return DEBUG_PACKETFORMATS;
|
||||
else if (!strcasecmp(flagname,"packetconstruction")) return DEBUG_PACKETCONSTRUCTION;
|
||||
@ -251,40 +263,54 @@ unsigned int debugFlagMask(const char *flagname) {
|
||||
else if (!strcasecmp(flagname,"manifests")) return DEBUG_MANIFESTS;
|
||||
else if (!strcasecmp(flagname,"mdprequests")) return DEBUG_MDPREQUESTS;
|
||||
else if (!strcasecmp(flagname,"timing")) return DEBUG_TIMING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static strbuf _toprint(strbuf sb, const char *srcBuf, size_t srcBytes)
|
||||
{
|
||||
strbuf_putc(sb, '"');
|
||||
for (; srcBytes && !strbuf_overrun(sb); ++srcBuf, --srcBytes) {
|
||||
if (*srcBuf == '\0')
|
||||
strbuf_puts(sb, "\\0");
|
||||
else if (*srcBuf == '\n')
|
||||
strbuf_puts(sb, "\\n");
|
||||
else if (*srcBuf == '\r')
|
||||
strbuf_puts(sb, "\\r");
|
||||
else if (*srcBuf == '\t')
|
||||
strbuf_puts(sb, "\\t");
|
||||
else if (*srcBuf == '\\')
|
||||
strbuf_puts(sb, "\\\\");
|
||||
else if (*srcBuf >= ' ' && *srcBuf <= '~')
|
||||
strbuf_putc(sb, *srcBuf);
|
||||
else
|
||||
strbuf_sprintf(sb, "\\x%02x", *srcBuf);
|
||||
}
|
||||
strbuf_putc(sb, '"');
|
||||
if (strbuf_overrun(sb)) {
|
||||
strbuf_trunc(sb, -4);
|
||||
strbuf_puts(sb, "\"...");
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
/* Format a buffer of data as a printable representation, eg: "Abc\x0b\n\0", for display
|
||||
in log messages.
|
||||
in log messages. If dstStrLen == -1 then assumes the dstStr buffer is large enough to
|
||||
hold the representation of the entire srcBuf.
|
||||
@author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
char *toprint(char *dstStr, size_t dstChars, const unsigned char *srcBuf, size_t srcBytes)
|
||||
char *toprint(char *dstStr, ssize_t dstStrLen, const char *srcBuf, size_t srcBytes)
|
||||
{
|
||||
strbuf b = strbuf_local(dstStr, dstChars);
|
||||
strbuf_putc(b, '"');
|
||||
for (; srcBytes && !strbuf_overrun(b); ++srcBuf, --srcBytes) {
|
||||
if (*srcBuf == '\0')
|
||||
strbuf_puts(b, "\\0");
|
||||
else if (*srcBuf == '\n')
|
||||
strbuf_puts(b, "\\n");
|
||||
else if (*srcBuf == '\r')
|
||||
strbuf_puts(b, "\\r");
|
||||
else if (*srcBuf == '\t')
|
||||
strbuf_puts(b, "\\t");
|
||||
else if (*srcBuf == '\\')
|
||||
strbuf_puts(b, "\\\\");
|
||||
else if (*srcBuf >= ' ' && *srcBuf <= '~')
|
||||
strbuf_putc(b, *srcBuf);
|
||||
else
|
||||
strbuf_sprintf(b, "\\x%02x", *srcBuf);
|
||||
}
|
||||
strbuf_putc(b, '"');
|
||||
if (strbuf_overrun(b)) {
|
||||
strbuf_trunc(b, -4);
|
||||
strbuf_puts(b, "\"...");
|
||||
}
|
||||
return dstStr;
|
||||
return strbuf_str(_toprint(strbuf_local(dstStr, (dstStrLen == -1 ? 2 + srcBytes * 4 : dstStrLen) + 1), srcBuf, srcBytes));
|
||||
}
|
||||
|
||||
/* Compute the length of the printable string produced by toprint(). If dstStrLen == -1 then
|
||||
returns the exact number of characters in the printable representation, otherwise returns
|
||||
dstStrLen.
|
||||
@author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
size_t toprint_strlen(ssize_t dstStrLen, const char *srcBuf, size_t srcBytes)
|
||||
{
|
||||
return dstStrLen == -1 ? strbuf_count(_toprint(strbuf_local(NULL, 0), srcBuf, srcBytes)) : dstStrLen;
|
||||
}
|
||||
|
||||
/* Read the symbolic link into the supplied buffer and add a terminating nul. Return -1 if the
|
||||
|
12
net.c
12
net.c
@ -47,7 +47,7 @@ int _set_block(int fd, const char *file, unsigned int line, const char *function
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _read_nonblock(int fd, void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _read_nonblock(int fd, void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
ssize_t nread = read(fd, buf, len);
|
||||
if (nread == -1) {
|
||||
@ -66,7 +66,7 @@ int _read_nonblock(int fd, void *buf, size_t len, const char *file, unsigned int
|
||||
return nread;
|
||||
}
|
||||
|
||||
int _write_all(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _write_all(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
ssize_t written = write(fd, buf, len);
|
||||
if (written == -1) {
|
||||
@ -82,7 +82,7 @@ int _write_all(int fd, const void *buf, size_t len, const char *file, unsigned i
|
||||
return written;
|
||||
}
|
||||
|
||||
int _write_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _write_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
ssize_t written = write(fd, buf, len);
|
||||
if (written == -1) {
|
||||
@ -101,7 +101,7 @@ int _write_nonblock(int fd, const void *buf, size_t len, const char *file, unsig
|
||||
return written;
|
||||
}
|
||||
|
||||
int _write_all_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _write_all_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
ssize_t written = _write_nonblock(fd, buf, len, file, line, function);
|
||||
if (written != -1 && written != len) {
|
||||
@ -112,12 +112,12 @@ int _write_all_nonblock(int fd, const void *buf, size_t len, const char *file, u
|
||||
return written;
|
||||
}
|
||||
|
||||
int _write_str(int fd, const char *str, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _write_str(int fd, const char *str, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
return _write_all(fd, str, strlen(str), file, line, function);
|
||||
}
|
||||
|
||||
int _write_str_nonblock(int fd, const char *str, const char *file, unsigned int line, const char *function)
|
||||
ssize_t _write_str_nonblock(int fd, const char *str, const char *file, unsigned int line, const char *function)
|
||||
{
|
||||
return _write_all_nonblock(fd, str, strlen(str), file, line, function);
|
||||
}
|
||||
|
@ -16,8 +16,9 @@ along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include <sys/stat.h>
|
||||
#include "serval.h"
|
||||
#include "strbuf.h"
|
||||
|
||||
struct sched_ent mdp_abstract;
|
||||
struct sched_ent mdp_named;
|
||||
@ -502,53 +503,26 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now)
|
||||
if (mdp->out.payload_length<1) {
|
||||
RETURN(WHY("Empty DID in DNA resolution request")); }
|
||||
bcopy(&mdp->out.payload[0],&did[0],pll);
|
||||
/* make sure it is null terminated */
|
||||
did[pll]=0;
|
||||
/* remember source sid for putting back later */
|
||||
overlay_mdp_frame mdpreply;
|
||||
|
||||
int results=0;
|
||||
while(keyring_find_did(keyring,&cn,&in,&kp,did))
|
||||
{
|
||||
bzero(&mdpreply,sizeof(mdpreply));
|
||||
|
||||
/* mark as outgoing MDP message */
|
||||
mdpreply.packetTypeAndFlags=MDP_TX;
|
||||
|
||||
/* Set source and destination addresses */
|
||||
bcopy(&mdp->out.dst.sid,mdpreply.out.src.sid,SID_SIZE);
|
||||
bcopy(&mdp->out.src.sid,mdpreply.out.dst.sid,SID_SIZE);
|
||||
mdpreply.out.src.port=mdp->out.dst.port;
|
||||
mdpreply.out.dst.port=mdp->out.src.port;
|
||||
|
||||
/* package DID and Name into reply (we include the DID because
|
||||
it could be a wild-card DID search, but the SID is implied
|
||||
in the source address of our reply). */
|
||||
if (keyring->contexts[cn]->identities[in]->keypairs[kp]
|
||||
->private_key_len>64)
|
||||
if (keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len > DID_MAXSIZE)
|
||||
/* skip excessively long DID records */
|
||||
continue;
|
||||
/* and null-terminated DID */
|
||||
unsigned char *unpackedDid=
|
||||
keyring->contexts[cn]->identities[in]->keypairs[kp]
|
||||
->private_key;
|
||||
unsigned char *packedSid=
|
||||
keyring->contexts[cn]->identities[in]->keypairs[0]
|
||||
->public_key;
|
||||
char *name=
|
||||
(char *)keyring->contexts[cn]->identities[in]->keypairs[kp]
|
||||
->public_key;
|
||||
/* copy SID out into source address of frame */
|
||||
bcopy(packedSid,&mdpreply.out.src.sid[0],SID_SIZE);
|
||||
/* and build reply as did\nname\nURI<NUL> */
|
||||
snprintf((char *)&mdpreply.out.payload[0],512,"%s|sid://%s/%s|%s|%s|",
|
||||
alloca_tohex_sid(packedSid),
|
||||
alloca_tohex_sid(packedSid),unpackedDid,
|
||||
unpackedDid,name);
|
||||
mdpreply.out.payload_length=strlen((char *)mdpreply.out.payload)+1;
|
||||
|
||||
/* deliver reply */
|
||||
overlay_mdp_dispatch(&mdpreply,0 /* system generated */,NULL,0);
|
||||
const unsigned char *packedSid = keyring->contexts[cn]->identities[in]->keypairs[0]->public_key;
|
||||
const char *unpackedDid = (const char *) keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key;
|
||||
const char *name = (const char *)keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key;
|
||||
// URI is sid://SIDHEX/DID
|
||||
strbuf b = strbuf_alloca(SID_STRLEN + DID_MAXSIZE + 10);
|
||||
strbuf_puts(b, "sid://");
|
||||
strbuf_tohex(b, packedSid, SID_SIZE);
|
||||
strbuf_putc(b, '/');
|
||||
strbuf_puts(b, unpackedDid);
|
||||
overlay_mdp_dnalookup_reply(&mdp->out, packedSid, strbuf_str(b), unpackedDid, name);
|
||||
kp++;
|
||||
results++;
|
||||
}
|
||||
@ -563,8 +537,7 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now)
|
||||
when results become available, so this function will return
|
||||
immediately, so as not to cause blockages and delays in servald.
|
||||
*/
|
||||
DEBUGF("Asking DNA helper to resolve '%s'",did);
|
||||
dna_helper_enqueue(did,mdp->out.src.sid);
|
||||
dna_helper_enqueue(mdp, did, mdp->out.src.sid);
|
||||
}
|
||||
RETURN(0);
|
||||
DEBUG("Got here");
|
||||
@ -624,6 +597,26 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now)
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
int overlay_mdp_dnalookup_reply(const overlay_mdp_data_frame *mdpd, const unsigned char *sid, const char *uri, const char *did, const char *name)
|
||||
{
|
||||
overlay_mdp_frame mdpreply;
|
||||
bzero(&mdpreply, sizeof mdpreply);
|
||||
mdpreply.packetTypeAndFlags = MDP_TX; // outgoing MDP message
|
||||
bcopy(mdpd->src.sid, mdpreply.out.dst.sid, SID_SIZE);
|
||||
mdpreply.out.dst.port = mdpd->src.port;
|
||||
mdpreply.out.src.port = mdpd->dst.port;
|
||||
bcopy(sid, mdpreply.out.src.sid, SID_SIZE);
|
||||
/* build reply as TOKEN|URI|DID|NAME|<NUL> */
|
||||
strbuf b = strbuf_local((char *)mdpreply.out.payload, sizeof mdpreply.out.payload);
|
||||
strbuf_tohex(b, sid, SID_SIZE);
|
||||
strbuf_sprintf(b, "|%s|%s|%s|", uri, did, name);
|
||||
if (strbuf_overrun(b))
|
||||
return WHY("MDP payload overrun");
|
||||
mdpreply.out.payload_length = strbuf_len(b) + 1;
|
||||
/* deliver reply */
|
||||
return overlay_mdp_dispatch(&mdpreply, 0 /* system generated */, NULL, 0);
|
||||
}
|
||||
|
||||
int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
|
||||
struct sockaddr_un *recvaddr,
|
||||
int recvaddrlen)
|
||||
|
@ -296,7 +296,7 @@ int extractRequest(unsigned char *packet,int *packet_ofs,int packet_len,
|
||||
*bytes|=packet[(*packet_ofs)++];
|
||||
|
||||
*flags=packet[(*packet_ofs)++];
|
||||
if (debug&DEBUG_DNAREQUESTS) printf("Write flags = 0x%02x\n",*flags);
|
||||
if (debug&DEBUG_PACKETFORMATS) printf("Write flags = 0x%02x\n",*flags);
|
||||
|
||||
if (*packet_ofs<0||(*packet_ofs)+(*bytes)>=packet_len)
|
||||
{
|
||||
|
@ -141,7 +141,7 @@ int rhizome_read_manifest_file(rhizome_manifest *m, const char *filename, int bu
|
||||
m->errors++;
|
||||
WARNF(bufferP ? "Malformed manifest line in buffer %p: %s"
|
||||
: "Malformed manifest line in file %s: %s",
|
||||
filename, alloca_toprint(80, (unsigned char *)line, linelen));
|
||||
filename, alloca_toprint(80, line, linelen));
|
||||
} else {
|
||||
*p++ = '\0';
|
||||
char *var = line;
|
||||
|
@ -869,7 +869,7 @@ void rhizome_fetch_poll(struct sched_ent *alarm)
|
||||
q->request_len += bytes;
|
||||
if (http_header_complete(q->request, q->request_len, bytes + 4)) {
|
||||
if (debug & DEBUG_RHIZOME_RX)
|
||||
DEBUGF("Got HTTP reply: %s", alloca_toprint(160, (unsigned char *)q->request, q->request_len));
|
||||
DEBUGF("Got HTTP reply: %s", alloca_toprint(160, q->request, q->request_len));
|
||||
/* We have all the reply headers, so parse them, taking care of any following bytes of
|
||||
content. */
|
||||
char *p = NULL;
|
||||
|
@ -564,7 +564,7 @@ static int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
if (path) {
|
||||
char *id = NULL;
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("GET %s", alloca_toprint(1024, (unsigned char *)path, pathlen));
|
||||
DEBUGF("GET %s", alloca_toprint(1024, path, pathlen));
|
||||
if (strcmp(path, "/favicon.ico") == 0) {
|
||||
r->request_type = RHIZOME_HTTP_REQUEST_FAVICON;
|
||||
rhizome_server_http_response_header(r, 200, "image/vnd.microsoft.icon", favicon_len);
|
||||
@ -605,7 +605,7 @@ static int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
}
|
||||
} else {
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("Received malformed HTTP request: %s", alloca_toprint(120, (unsigned char *)r->request, r->request_length));
|
||||
DEBUGF("Received malformed HTTP request: %s", alloca_toprint(120, (const char *)r->request, r->request_length));
|
||||
rhizome_server_simple_http_response(r, 400, "<html><h1>Malformed request</h1></html>\r\n");
|
||||
}
|
||||
|
||||
@ -669,7 +669,7 @@ static int rhizome_server_set_response(rhizome_http_request *r, const struct htt
|
||||
r->buffer_offset = 0;
|
||||
r->request_type |= RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("Sending HTTP response: %s", alloca_toprint(120, r->buffer, r->buffer_length));
|
||||
DEBUGF("Sending HTTP response: %s", alloca_toprint(120, (const char *)r->buffer, r->buffer_length));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
55
serval.h
55
serval.h
@ -299,7 +299,8 @@ void keyring_identity_extract(const keyring_identity *id, const unsigned char **
|
||||
get - 8 bit variable value
|
||||
|
||||
*/
|
||||
#define SID_SIZE 32
|
||||
#define SID_SIZE 32
|
||||
#define DID_MINSIZE 5
|
||||
#define DID_MAXSIZE 32
|
||||
#define SIDDIDFIELD_LEN (SID_SIZE+1)
|
||||
#define PINFIELD_LEN 32
|
||||
@ -501,6 +502,7 @@ struct sched_ent{
|
||||
int _poll_index;
|
||||
};
|
||||
|
||||
#define STRUCT_SCHED_ENT_UNUSED ((struct sched_ent){NULL, NULL, NULL, NULL, {-1, 0, 0}, 0LL, 0LL, NULL, -1})
|
||||
|
||||
extern int overlayMode;
|
||||
#define OVERLAY_INTERFACE_UNKNOWN 0
|
||||
@ -703,6 +705,9 @@ char *str_toupper_inplace(char *s);
|
||||
|
||||
int str_is_subscriber_id(const char *sid);
|
||||
int strn_is_subscriber_id(const char *sid, size_t *lenp);
|
||||
int str_is_did(const char *did);
|
||||
int strn_is_did(const char *did, size_t *lenp);
|
||||
int str_is_uri(const char *uri);
|
||||
|
||||
int stowSid(unsigned char *packet, int ofs, const char *sid);
|
||||
int stowDid(unsigned char *packet,int *ofs,char *did);
|
||||
@ -798,6 +803,7 @@ int overlay_frame_resolve_addresses(overlay_frame *f);
|
||||
#define LOG_LEVEL_FATAL (4)
|
||||
|
||||
extern unsigned int debug;
|
||||
void set_logging(FILE *f);
|
||||
FILE *open_logging();
|
||||
void close_logging();
|
||||
void logMessage(int level, const char *file, unsigned int line, const char *function, const char *fmt, ...);
|
||||
@ -805,42 +811,48 @@ void vlogMessage(int level, const char *file, unsigned int line, const char *fun
|
||||
unsigned int debugFlagMask(const char *flagname);
|
||||
char *catv(const char *data, char *buf, size_t len);
|
||||
int dump(char *name, unsigned char *addr, size_t len);
|
||||
char *toprint(char *dstStr, size_t dstChars, const unsigned char *srcBuf, size_t srcBytes);
|
||||
int log_backtrace();
|
||||
char *toprint(char *dstStr, ssize_t dstStrLen, const char *srcBuf, size_t srcBytes);
|
||||
size_t toprint_strlen(ssize_t dstStrLen, const char *srcBuf, size_t srcBytes);
|
||||
|
||||
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) + 1), (dstlen) + 1, (buf), (len))
|
||||
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca(toprint_strlen((dstlen), (buf), (len)) + 1), (dstlen), (buf), (len))
|
||||
|
||||
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
|
||||
#define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE)
|
||||
|
||||
const char *trimbuildpath(const char *s);
|
||||
|
||||
#define LOGF(L,F,...) (logMessage(L, __FILE__, __LINE__, __FUNCTION__, F, ##__VA_ARGS__))
|
||||
#define logMessage_perror(L,file,line,func,F,...) \
|
||||
(logMessage(L, file, line, func, F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno))
|
||||
|
||||
#define LOGF(L,F,...) logMessage(L, __FILE__, __LINE__, __FUNCTION__, F, ##__VA_ARGS__)
|
||||
#define LOGF_perror(L,F,...) logMessage_perror(L, __FILE__, __LINE__, __FUNCTION__, F, ##__VA_ARGS__)
|
||||
#define LOG_perror(L,X) LOGF_perror(L, "%s", (X))
|
||||
|
||||
#define FATALF(F,...) do { LOGF(LOG_LEVEL_FATAL, F, ##__VA_ARGS__); exit(-1); } while (1)
|
||||
#define FATAL(X) FATALF("%s", (X))
|
||||
#define FATAL_perror(X) FATALF("%s: %s [errno=%d]", (X), strerror(errno), errno)
|
||||
#define FATALF_perror(F,...) do { LOGF_perror(LOG_LEVEL_FATAL, F, ##__VA_ARGS__); exit(-1); } while (1)
|
||||
#define FATAL_perror(X) FATALF_perror("%s", (X))
|
||||
|
||||
#define WHYF(F,...) (LOGF(LOG_LEVEL_ERROR, F, ##__VA_ARGS__), -1)
|
||||
#define WHY(X) WHYF("%s", (X))
|
||||
#define WHYNULL(X) (LOGF(LOG_LEVEL_ERROR, "%s", X), NULL)
|
||||
#define WHYF_perror(F,...) WHYF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
|
||||
#define WHY_perror(X) WHYF("%s: %s [errno=%d]", (X), strerror(errno), errno)
|
||||
#define WHYF_perror(F,...) (LOGF_perror(LOG_LEVEL_ERROR, F, ##__VA_ARGS__), -1)
|
||||
#define WHY_perror(X) WHYF_perror("%s", (X))
|
||||
|
||||
#define WARNF(F,...) LOGF(LOG_LEVEL_WARN, F, ##__VA_ARGS__)
|
||||
#define WARN(X) WARNF("%s", (X))
|
||||
#define WARN_perror(X) WARNF("%s: %s [errno=%d]", (X), strerror(errno), errno)
|
||||
#define WARNF_perror(F,...) LOGF_perror(LOG_LEVEL_WARN, F, ##__VA_ARGS__)
|
||||
#define WARN_perror(X) WARNF_perror("%s", (X))
|
||||
|
||||
#define INFOF(F,...) LOGF(LOG_LEVEL_INFO, F, ##__VA_ARGS__)
|
||||
#define INFO(X) INFOF("%s", (X))
|
||||
|
||||
#define DEBUGF(F,...) LOGF(LOG_LEVEL_DEBUG, F, ##__VA_ARGS__)
|
||||
#define DEBUG(X) DEBUGF("%s", (X))
|
||||
#define DEBUGF_perror(F,...) DEBUGF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
|
||||
#define DEBUG_perror(X) DEBUGF("%s: %s [errno=%d]", (X), strerror(errno), errno)
|
||||
#define D DEBUG("D")
|
||||
#define DEBUGF_perror(F,...) LOGF_perror(LOG_LEVEL_DEBUG, F, ##__VA_ARGS__)
|
||||
#define DEBUG_perror(X) DEBUGF_perror("%s", (X))
|
||||
#define D DEBUG("D")
|
||||
|
||||
overlay_buffer *ob_new(int size);
|
||||
overlay_buffer *ob_static(unsigned char *bytes, int size);
|
||||
@ -1112,7 +1124,7 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now);
|
||||
#define DEBUG_VERBOSE_IO (1 << 3)
|
||||
#define DEBUG_PEERS (1 << 4)
|
||||
#define DEBUG_DNARESPONSES (1 << 5)
|
||||
#define DEBUG_DNAREQUESTS (1 << 6)
|
||||
#define DEBUG_DNAHELPER (1 << 6)
|
||||
#define DEBUG_SIMULATION (1 << 7)
|
||||
#define DEBUG_RHIZOME_RX (1 << 8)
|
||||
#define DEBUG_PACKETFORMATS (1 << 9)
|
||||
@ -1380,6 +1392,7 @@ int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
|
||||
int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp);
|
||||
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
|
||||
struct sockaddr_un *recvaddr,int recvaddlen);
|
||||
int overlay_mdp_dnalookup_reply(const overlay_mdp_data_frame *mdpd, const unsigned char *sid, const char *uri, const char *did, const char *name);
|
||||
|
||||
int dump_payload(overlay_frame *p,char *message);
|
||||
|
||||
@ -1575,11 +1588,11 @@ int stopAudio();
|
||||
#define SERVER_RUNNING 4
|
||||
int server_probe(int *pid);
|
||||
|
||||
int dna_helper_enqueue(char *did, unsigned char *requestorSid);
|
||||
int dna_helper_shutdown();
|
||||
int dna_helper_enqueue(overlay_mdp_frame *mdp, const char *did, const unsigned char *requestorSid);
|
||||
int dna_return_resolution(overlay_mdp_frame *mdp, unsigned char *fromSid,
|
||||
const char *did,const char *name,const char *uri);
|
||||
int parseDnaReply(unsigned char *bytes, int count,
|
||||
char *sidhex, char *did, char *name, char *uri);
|
||||
int parseDnaReply(const char *buf, size_t len, char *token, char *did, char *name, char *uri, const char **bufp);
|
||||
extern int sigPipeFlag;
|
||||
extern int sigIoFlag;
|
||||
void sigPipeHandler(int signal);
|
||||
@ -1599,12 +1612,12 @@ void sigIoHandler(int signal);
|
||||
|
||||
int _set_nonblock(int fd, const char *file, unsigned int line, const char *function);
|
||||
int _set_block(int fd, const char *file, unsigned int line, const char *function);
|
||||
int _read_nonblock(int fd, void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
int _write_all(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
int _write_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
int _write_all_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
int _write_str(int fd, const char *str, const char *file, unsigned int line, const char *function);
|
||||
int _write_str_nonblock(int fd, const char *str, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _read_nonblock(int fd, void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _write_all(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _write_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _write_all_nonblock(int fd, const void *buf, size_t len, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _write_str(int fd, const char *str, const char *file, unsigned int line, const char *function);
|
||||
ssize_t _write_str_nonblock(int fd, const char *str, const char *file, unsigned int line, const char *function);
|
||||
|
||||
int rhizome_http_server_start();
|
||||
int overlay_mdp_setup_sockets();
|
||||
|
7
server.c
7
server.c
@ -309,6 +309,7 @@ void serverCleanUp()
|
||||
} else {
|
||||
overlay_mdp_client_done();
|
||||
}
|
||||
dna_helper_shutdown();
|
||||
}
|
||||
|
||||
static void signame(char *buf, size_t len, int signal)
|
||||
@ -486,7 +487,7 @@ int processRequest(unsigned char *packet,int len,
|
||||
|
||||
while(pofs<len)
|
||||
{
|
||||
if (debug&DEBUG_DNAREQUESTS) DEBUGF(" processRequest: len=%d, pofs=%d, pofs_prev=%d",len,pofs,prev_pofs);
|
||||
if (debug&DEBUG_DNARESPONSES) DEBUGF(" processRequest: len=%d, pofs=%d, pofs_prev=%d",len,pofs,prev_pofs);
|
||||
/* Avoid infinite loops */
|
||||
if (pofs<=prev_pofs) break;
|
||||
prev_pofs=pofs;
|
||||
@ -517,7 +518,7 @@ int processRequest(unsigned char *packet,int len,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debug&DEBUG_DNAREQUESTS) DEBUGF("Looking at action code 0x%02x @ packet offset 0x%x",
|
||||
if (debug&DEBUG_DNARESPONSES) DEBUGF("Looking at action code 0x%02x @ packet offset 0x%x",
|
||||
packet[pofs],pofs);
|
||||
switch(packet[pofs])
|
||||
{
|
||||
@ -572,7 +573,7 @@ int processRequest(unsigned char *packet,int len,
|
||||
|
||||
pofs+=2;
|
||||
|
||||
if (debug&DEBUG_DNAREQUESTS) DEBUGF("Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)",var_id,instance,pofs,len);
|
||||
if (debug&DEBUG_DNARESPONSES) DEBUGF("Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)",var_id,instance,pofs,len);
|
||||
|
||||
if (debug&DEBUG_HLR) DEBUGF("Looking for identities with sid='%s' / did='%s'",(sid&&sid[0])?sid:"null",did?did:"null");
|
||||
|
||||
|
18
strbuf.c
18
strbuf.c
@ -69,6 +69,24 @@ strbuf strbuf_puts(strbuf sb, const char *text)
|
||||
return sb;
|
||||
}
|
||||
|
||||
strbuf strbuf_tohex(strbuf sb, const unsigned char *data, size_t len)
|
||||
{
|
||||
static char hexdigit[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
char *p = sb->current;
|
||||
sb->current += len * 2;
|
||||
if (sb->start) {
|
||||
char *e = sb->current < sb->end ? sb->current : sb->end;
|
||||
// The following loop could overwrite the '\0' at *sp->end.
|
||||
for (; p < e; ++data) {
|
||||
*p++ = hexdigit[*data >> 4];
|
||||
*p++ = hexdigit[*data & 0xf];
|
||||
}
|
||||
// This will restore the '\0' at *sp->end if it was overwritten.
|
||||
*e = '\0';
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
strbuf strbuf_putc(strbuf sb, char ch)
|
||||
{
|
||||
if (sb->start && sb->current < sb->end) {
|
||||
|
17
strbuf.h
17
strbuf.h
@ -254,6 +254,23 @@ strbuf strbuf_ncat(strbuf sb, const char *text, size_t len);
|
||||
strbuf strbuf_puts(strbuf sb, const char *text);
|
||||
|
||||
|
||||
/** Append binary data strbuf, in uppercase hexadecimal format, truncating if
|
||||
* necessary to avoid buffer overrun. Return a pointer to the strbuf.
|
||||
*
|
||||
* After these operations:
|
||||
* n = strbuf_len(sb);
|
||||
* c = strbuf_count(sb);
|
||||
* strbuf_tohex(data, len);
|
||||
* the following invariants hold:
|
||||
* strbuf_count(sb) == c + len * 2
|
||||
* strbuf_len(sb) >= n
|
||||
* strbuf_len(sb) <= n + len * 2
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
strbuf strbuf_tohex(strbuf sb, const unsigned char *data, size_t len);
|
||||
|
||||
|
||||
/** Append a single character to the strbuf if there is space, and place a
|
||||
* terminating nul after it. Return a pointer to the strbuf so that
|
||||
* concatenations can be chained in a single line.
|
||||
|
@ -20,6 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "strbuf_helpers.h"
|
||||
#include <poll.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
strbuf strbuf_append_poll_events(strbuf sb, short events)
|
||||
{
|
||||
@ -88,3 +90,22 @@ strbuf strbuf_append_shell_quotemeta(strbuf sb, const char *word)
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
strbuf strbuf_append_exit_status(strbuf sb, int status)
|
||||
{
|
||||
if (WIFEXITED(status))
|
||||
strbuf_sprintf(sb, "exited normally with status %u", WEXITSTATUS(status));
|
||||
else if (WIFSIGNALED(status)) {
|
||||
strbuf_sprintf(sb, "terminated by signal %u (%s)", WTERMSIG(status), strsignal(WTERMSIG(status)));
|
||||
#ifdef WCOREDUMP
|
||||
if (WCOREDUMP(status))
|
||||
strbuf_puts(sb, " and dumped core");
|
||||
#endif
|
||||
} else if (WIFSTOPPED(status))
|
||||
strbuf_sprintf(sb, "stopped by signal %u (%s)", WSTOPSIG(status), strsignal(WSTOPSIG(status)));
|
||||
#ifdef WIFCONTINUED
|
||||
else if (WIFCONTINUED(status))
|
||||
strbuf_sprintf(sb, "continued by signal %u (SIGCONT)", SIGCONT);
|
||||
#endif
|
||||
return sb;
|
||||
}
|
||||
|
@ -32,4 +32,10 @@ strbuf strbuf_append_poll_events(strbuf sb, short events);
|
||||
*/
|
||||
strbuf strbuf_append_shell_quotemeta(strbuf sb, const char *word);
|
||||
|
||||
/* Append a textual description of a process exit status as produced by wait(2)
|
||||
* and waitpid(2).
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
strbuf strbuf_append_exit_status(strbuf sb, int status);
|
||||
|
||||
#endif //__STRBUF_HELPERS_H__
|
||||
|
@ -941,7 +941,7 @@ _tfw_assert_stdxxx_is() {
|
||||
'') ln -f "$_tfw_tmp/$qual" "$_tfw_tmp/content";;
|
||||
*) sed -n -e "${_tfw_opt_line}p" "$_tfw_tmp/$qual" >"$_tfw_tmp/content";;
|
||||
esac
|
||||
local message="${_tfw_message:-${_tfw_opt_line:+line $_tfw_opt_line of }$qual of ($executed) is $*}"
|
||||
local message="${_tfw_message:-${_tfw_opt_line:+line $_tfw_opt_line of }$qual of ($executed) is $(_tfw_shellarg "$@")}"
|
||||
echo -n "$@" >$_tfw_tmp/stdxxx_is.tmp
|
||||
if ! cmp --quiet $_tfw_tmp/stdxxx_is.tmp "$_tfw_tmp/content"; then
|
||||
_tfw_failmsg "assertion failed: $message"
|
||||
|
412
tests/dnahelper
412
tests/dnahelper
@ -25,6 +25,7 @@ setup() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
setup_dnahelper
|
||||
start_servald_instances +A
|
||||
}
|
||||
|
||||
teardown() {
|
||||
@ -36,69 +37,366 @@ teardown() {
|
||||
# Called by start_servald_instances immediately before starting the server
|
||||
# process in each instance.
|
||||
configure_servald_server() {
|
||||
executeOk_servald config set dna.helper "$TFWTMP/dnahelper"
|
||||
executeOk_servald config set log.show_pid on
|
||||
executeOk_servald config set log.show_time on
|
||||
executeOk_servald config set debug.dnahelper on
|
||||
executeOk_servald config set dna.helper.executable "$dnahelper"
|
||||
}
|
||||
|
||||
setup_dnahelper() {
|
||||
cat >"$TFWTMP/dnahelper" <<EOF
|
||||
#!/usr/bin/env python
|
||||
# Sample DNA Helper application for testing
|
||||
|
||||
import sys;
|
||||
|
||||
def main():
|
||||
print "STARTED"
|
||||
while True:
|
||||
line = sys.stdin.readline().strip()
|
||||
if line == "":
|
||||
# EOF detection is broken :(
|
||||
break
|
||||
s = line.split('|')
|
||||
if len(s) != 3:
|
||||
print "ERROR"
|
||||
continue
|
||||
(token, number, xxx) = s
|
||||
|
||||
if number == "12345":
|
||||
# Multiple results (SID/VoMP results)
|
||||
print "%s|sid:%s|%s|%s|" % (token, token, number, "Agent A. Smith")
|
||||
print "%s|sid:%s|%s|%s|" % (token, token, number, "Agent B. Smith")
|
||||
if number == "5551234":
|
||||
# Single result, SIP URI
|
||||
print "%s|sip://5551234@10.1.2.3|%s|%s|" % (token, number, "Will Smith")
|
||||
if number == "5551001":
|
||||
# Empty URI field
|
||||
print "%s||%s|%s|" % (token, number, "Empty URI")
|
||||
if number == "5551002":
|
||||
# Empty DID field
|
||||
print "%s|sip://123@1.2.3.4||%s|" % (token, "Empty DID")
|
||||
if number == "5551003":
|
||||
# Empty CALLERID field
|
||||
print "%s|sip://empty-callerid@1.2.3.4|%s||" % (token, number)
|
||||
if number == "5551004":
|
||||
# Excessively long callerid
|
||||
print "%s|sip://long-callerid@1.2.3.4|%s|askjdhfkjashdfkljahsdflkjhasdljkfhasldjkfhaslkjdfhalskdjfhklajsdhflkajsdhflkjasdhflkjashdflkjashdflkjahsdflkjahsdfjklhasdljkfhasjkdfhakljsdfhklajsdhflkjashdfljkashdflkjashdf|" % (token, number)
|
||||
if number == "5551005":
|
||||
# Excessively long DID
|
||||
print "%s|sip://long-did@1.2.3.4|askjdhfkjashdfkljahsdflkjhasdljkfhasldjkfhaslkjdfhalskdjfhklajsdhflkajsdhflkjasdhflkjashdflkjashdflkjahsdflkjahsdfjklhasdljkfhasjkdfhakljsdfhklajsdhflkjashdfljkashdflkjashdf|%s|" % (token, "Agent Smith")
|
||||
if number == "5551006":
|
||||
# Excessively long URI
|
||||
print "%s|sip://askjdhfkjashdfkljahsdflkjhasdljkfhasldjkfhaslkjdfhalskdjfhklajsdhflkajsdhflkjasdhflkjashdflkjashdflkjahsdflkjahsdfjklhasdljkfhasjkdfhakljsdfhklajsdhflkjashdfljkashdflkjashdfasdjfkjahsdfjkhasdfkjlhasjldkfhajksdhflkjasdhfkljashdfkljahsdfkljhasdfkljhasdlkjfhasdlkjfhaslkjdfhakljsdhfklajshdfkljashdfljkashdflkjashdflkjahsdfkjlahsdflkjhasdfljkhasdkfjlhaslkdjfhaslkjdfhaklsjdfhaklsjdhflkajsdhflkjasdhflkjashdfljkashdfkljashdflkjashdflkjashdflkjashdflkjashdflkjashdfljkahsdflkjahsdfjklahsdfljkahsdflkjhasdflkjhasdjkfhaskjdlfhaslkjdfhaskljdfhasljkdfhalskdfhalkjsdhflkjasdhflkjahsdflkjahsdflkjahsdflkjhasdflkjahsdflkjahsdflkjahsdfkljashdflkajshdflkajsdhflaksjdfhalksjdfhlasdkjfh|%s|%s|" % (token, number, "Agent Smith")
|
||||
if number == "5551007":
|
||||
# Incorrect token
|
||||
print "cheeseburger|sip://incorrect-token@1.2.3.4|%s||" % (token, number)
|
||||
|
||||
print "DONE"
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
export SID_JOE_A=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEA
|
||||
export SID_JOE_B=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEB
|
||||
export SID_JOE_C=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEC
|
||||
export SID_JOE_D=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDED
|
||||
export SID_JOE_E=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEE
|
||||
export SID_JOE_F=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF
|
||||
export SID_ECCLES=1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDE0
|
||||
dnahelper="$TFWTMP/dnahelper"
|
||||
cat >"$dnahelper" <<'EOF'
|
||||
#!/bin/sh
|
||||
echo STARTED
|
||||
while read line
|
||||
do
|
||||
token="${line%%|*}"
|
||||
line="${line#*|}"
|
||||
did="${line%%|*}"
|
||||
line="${line#*|}"
|
||||
case "$token|$did|$line" in
|
||||
'|'*'|')
|
||||
echo "empty token" >&2
|
||||
;;
|
||||
*'||')
|
||||
echo "empty DID" >&2
|
||||
;;
|
||||
*'|00000|')
|
||||
# For verification during setup
|
||||
echo "$token|A|$did|B|"
|
||||
;;
|
||||
*'|00001|')
|
||||
# One valid reply
|
||||
echo "$token|sip://$SID_JOE_A@10.1.1.1|$did|Joe A. Bloggs|"
|
||||
;;
|
||||
*'|00002|')
|
||||
# Two valid replies
|
||||
echo "$token|sip://$SID_JOE_A@10.1.1.1|$did|Joe A. Bloggs|"
|
||||
sleep 0.1
|
||||
echo "$token|sip://$SID_JOE_B@10.1.1.1|$did|Joe B. Bloggs|"
|
||||
sleep 0.1
|
||||
;;
|
||||
*'|00003|')
|
||||
# Three valid replies
|
||||
echo "$token|sip://$SID_JOE_A@10.1.1.1|$did|Joe A. Bloggs|"
|
||||
sleep 0.1
|
||||
echo "$token|sip://$SID_JOE_B@10.1.1.1|$did|Joe B. Bloggs|"
|
||||
sleep 0.1
|
||||
echo "$token|sip://$SID_JOE_C@10.1.1.1|$did|Joe C. Bloggs|"
|
||||
sleep 0.1
|
||||
;;
|
||||
*'|00004|')
|
||||
# Empty URI
|
||||
echo "$token||$did|Eccles|"
|
||||
;;
|
||||
*'|000051|')
|
||||
# Malformed URI
|
||||
echo "$token|Bluebottle|$did|Eccles|"
|
||||
;;
|
||||
*'|000052|')
|
||||
# Malformed URI
|
||||
echo "$token|sip://Sea goon|$did|Eccles|"
|
||||
;;
|
||||
*'|000053|')
|
||||
# Malformed URI
|
||||
echo "$token|sip:|$did|Eccles|"
|
||||
;;
|
||||
*'|000061|')
|
||||
# Mismatched token
|
||||
echo "$SID_ECCLES|did://$SID_ECCLES/$did|$did|Eccles|"
|
||||
;;
|
||||
*'|000062|')
|
||||
# Empty token
|
||||
echo "|did://$SID_ECCLES/$did|$did|Eccles|"
|
||||
;;
|
||||
*'|000063|')
|
||||
# Invalid token (not a SID)
|
||||
echo "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEX|did://$SID_ECCLES/$did|$did|Eccles|"
|
||||
;;
|
||||
*'|000064|')
|
||||
# Long token
|
||||
echo "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF0|did://$SID_ECCLES/$did|$did|Eccles|"
|
||||
;;
|
||||
*'|000065|')
|
||||
# Short token
|
||||
echo "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDE|did://$SID_ECCLES/$did|$did|Eccles|"
|
||||
;;
|
||||
*'|000071|')
|
||||
# Mismatched DID
|
||||
echo "$token|sip://$SID_ECCLES/$did|99999|Eccles|"
|
||||
;;
|
||||
*'|000072|')
|
||||
# Empty DID
|
||||
echo "$token|sip://$SID_ECCLES/$did||Eccles|"
|
||||
;;
|
||||
*'|000073|')
|
||||
# Invalid DID
|
||||
echo "$token|sip://$SID_ECCLES/$did|9999X|Eccles|"
|
||||
;;
|
||||
*'|000074|')
|
||||
# Long DID
|
||||
echo "$token|sip://$SID_ECCLES/$did|123456789012345678901234567890123|Eccles|"
|
||||
;;
|
||||
*'|000075|')
|
||||
# Short DID
|
||||
echo "$token|sip://$SID_ECCLES/$did|9999|Eccles|"
|
||||
;;
|
||||
*'|000081|')
|
||||
# Malformed reply, missing final delimiter
|
||||
echo "$token|sip://$SID_ECCLES/$did|9999|Eccles"
|
||||
;;
|
||||
*'|000082|')
|
||||
# Malformed reply, long name
|
||||
echo "$token|sip://$SID_ECCLES/$did|9999|Abcd efgh ijkl mnop qrst uvwx yzab cdef ghij klmn opqr stuv wxyz abcd efgh ijkl|"
|
||||
;;
|
||||
*'|000083|')
|
||||
# Malformed reply, empty line
|
||||
echo
|
||||
;;
|
||||
*'|000084|')
|
||||
# Malformed reply, missing \n (which swallows the following DONE line)
|
||||
echo -n "$token|sip://$SID_JOE_A@10.1.1.1|$did|Joe A. Bloggs|"
|
||||
;;
|
||||
*'|000085|')
|
||||
# Malformed reply, line too long
|
||||
for i in 1 2 3 4 5 6 7 8 9 0; do
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
echo -n 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
|
||||
done
|
||||
echo
|
||||
;;
|
||||
*'|00009|')
|
||||
# Take too long to respond
|
||||
sleep 2
|
||||
echo "$token|sip://$SID_JOE_D@10.1.1.1|$did|Joe D. Bloggs|"
|
||||
;;
|
||||
*'|00010|')
|
||||
# Spurious output after DONE
|
||||
echo "$token|sip://$SID_JOE_E@10.1.1.1|$did|Joe E. Bloggs|"
|
||||
echo DONE
|
||||
echo "$token|sip://$SID_JOE_F@10.1.1.1|$did|Joe F. Bloggs|"
|
||||
;;
|
||||
*'|00011|')
|
||||
# Die unexpectedly
|
||||
echo "goodbye cruel world" >&2
|
||||
exit 42
|
||||
;;
|
||||
*'|'*'|')
|
||||
echo "token=$token did=$did line=$line" >&2
|
||||
;;
|
||||
*)
|
||||
echo "garbage line" >&2
|
||||
;;
|
||||
esac
|
||||
echo DONE
|
||||
done
|
||||
EOF
|
||||
chmod 0755 "$dnahelper"
|
||||
executeOk "$dnahelper" <<EOF
|
||||
ToKeN|00000|
|
||||
EOF
|
||||
assertStdoutIs -e "STARTED\nToKeN|A|00000|B|\nDONE\n"
|
||||
}
|
||||
|
||||
doc_MultiServer="Start three servald servers with dna helper"
|
||||
test_MultiServer() {
|
||||
start_servald_instances +A +B +C
|
||||
doc_ExecError="Non-existent DNA helper executable"
|
||||
setup_ExecError() {
|
||||
setup_servald
|
||||
assert_no_servald_processes
|
||||
dnahelper=/non/existent
|
||||
assert [ ! -e "$dnahelper" ]
|
||||
start_servald_instances +A
|
||||
}
|
||||
test_ExecError() {
|
||||
executeOk_servald dna lookup 12345
|
||||
}
|
||||
|
||||
doc_ReplyOk1="DNA helper returns one valid reply"
|
||||
test_ReplyOk1() {
|
||||
executeOk_servald dna lookup 00001
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
||||
}
|
||||
|
||||
doc_ReplyOk2="DNA helper returns two valid replies"
|
||||
test_ReplyOk2() {
|
||||
executeOk_servald dna lookup 00002
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00002:Joe A. Bloggs\nsip://$SID_JOE_B@10.1.1.1:00002:Joe B. Bloggs\n"
|
||||
}
|
||||
|
||||
doc_ReplyOk3="DNA helper returns three valid replies"
|
||||
test_ReplyOk3() {
|
||||
executeOk_servald dna lookup 00003
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00003:Joe A. Bloggs\nsip://$SID_JOE_B@10.1.1.1:00003:Joe B. Bloggs\nsip://$SID_JOE_C@10.1.1.1:00003:Joe C. Bloggs\n"
|
||||
}
|
||||
|
||||
doc_UriEmpty="DNA helper returns empty URI"
|
||||
test_UriEmpty() {
|
||||
executeOk_servald dna lookup 00004
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty URI'
|
||||
}
|
||||
|
||||
doc_UriInvalid1="DNA helper returns invalid URI, missing scheme"
|
||||
test_UriInvalid1() {
|
||||
executeOk_servald dna lookup 000051
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*Bluebottle.*invalid URI'
|
||||
}
|
||||
|
||||
doc_UriInvalid2="DNA helper returns invalid URI, invalid char"
|
||||
test_UriInvalid2() {
|
||||
executeOk_servald dna lookup 000052
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip://Sea goon.*invalid URI'
|
||||
}
|
||||
|
||||
doc_UriInvalid3="DNA helper returns invalid URI, empty hierarchical part"
|
||||
test_UriInvalid3() {
|
||||
executeOk_servald dna lookup 000053
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*sip:.*invalid URI'
|
||||
}
|
||||
|
||||
doc_TokenMismatch="DNA helper returns mismatched token"
|
||||
test_TokenMismatch() {
|
||||
executeOk_servald dna lookup 000061
|
||||
assertStdoutIs ""
|
||||
assertGrep --matches=0 "$LOGA" 'ERROR:.*DNAHELPER'
|
||||
}
|
||||
|
||||
doc_TokenEmpty="DNA helper returns empty token"
|
||||
test_TokenEmpty() {
|
||||
executeOk_servald dna lookup 000062
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty token'
|
||||
}
|
||||
|
||||
doc_TokenInvalid="DNA helper returns invalid token"
|
||||
test_TokenInvalid() {
|
||||
executeOk_servald dna lookup 000063
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
||||
}
|
||||
|
||||
doc_TokenInvalidLong="DNA helper returns invalid token, too long"
|
||||
test_TokenInvalidLong() {
|
||||
executeOk_servald dna lookup 000064
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||
}
|
||||
|
||||
doc_TokenInvalidShort="DNA helper returns invalid token, too short"
|
||||
test_TokenInvalidShort() {
|
||||
executeOk_servald dna lookup 000065
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid token'
|
||||
}
|
||||
|
||||
doc_DidMismatch="DNA helper returns mismatched DID"
|
||||
test_DidMismatch() {
|
||||
executeOk_servald dna lookup 000071
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*mismatched DID'
|
||||
}
|
||||
|
||||
doc_DidEmpty="DNA helper returns empty DID"
|
||||
test_DidEmpty() {
|
||||
executeOk_servald dna lookup 000072
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*empty DID'
|
||||
}
|
||||
|
||||
doc_DidInvalid="DNA helper returns invalid DID"
|
||||
test_DidInvalid() {
|
||||
executeOk_servald dna lookup 000073
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
||||
}
|
||||
|
||||
doc_DidInvalidLong="DNA helper returns invalid DID, too long"
|
||||
test_DidInvalidLong() {
|
||||
executeOk_servald dna lookup 000074
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||
}
|
||||
|
||||
doc_DidInvalidShort="DNA helper returns invalid DID, too short"
|
||||
test_DidInvalidShort() {
|
||||
executeOk_servald dna lookup 000075
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*invalid DID'
|
||||
}
|
||||
|
||||
doc_ReplyInvalidMissingDelim="DNA helper returns invalid reply, missing delimiter"
|
||||
test_ReplyInvalidMissingDelim() {
|
||||
executeOk_servald dna lookup 000081
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||
}
|
||||
|
||||
doc_ReplyInvalidLongName="DNA helper returns invalid reply, name too long"
|
||||
test_ReplyInvalidLongName() {
|
||||
executeOk_servald dna lookup 000082
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*invalid'
|
||||
}
|
||||
|
||||
doc_ReplyInvalidEmpty="DNA helper returns invalid reply, empty line"
|
||||
test_ReplyInvalidEmpty() {
|
||||
executeOk_servald dna lookup 000083
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply "\\n" invalid'
|
||||
}
|
||||
|
||||
doc_ReplyInvalidMissingNewline="DNA helper returns invalid reply, missing newline"
|
||||
test_ReplyInvalidMissingNewline() {
|
||||
executeOk_servald dna lookup 000084
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply.*spurious'
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
||||
}
|
||||
|
||||
doc_HelperTimeout="DNA helper process takes too long to reply and is restarted"
|
||||
test_HelperTimeout() {
|
||||
executeOk_servald dna lookup 00009
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*reply timeout'
|
||||
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*terminated by signal 15'
|
||||
executeOk_servald dna lookup 00001
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
||||
}
|
||||
|
||||
doc_ReplySpurious="DNA helper spurious output after DONE is ignored"
|
||||
test_ReplySpurious() {
|
||||
executeOk_servald dna lookup 00010
|
||||
assertStdoutIs -e "sip://$SID_JOE_E@10.1.1.1:00010:Joe E. Bloggs\n"
|
||||
assertGrep "$LOGA" 'WARN:.*DNAHELPER.*spurious output'
|
||||
executeOk_servald dna lookup 00001
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
||||
}
|
||||
|
||||
doc_HelperDies="DNA helper process dies unexpectedly and is restarted"
|
||||
test_HelperDies() {
|
||||
executeOk_servald dna lookup 00011
|
||||
assertStdoutIs ""
|
||||
assertGrep "$LOGA" 'INFO:.*DNAHELPER.*process.*exited normally with status 42'
|
||||
assertGrep "$LOGA" 'ERROR:.*DNAHELPER.*"goodbye cruel world\\n"'
|
||||
executeOk_servald dna lookup 00001
|
||||
assertStdoutIs -e "sip://$SID_JOE_A@10.1.1.1:00001:Joe A. Bloggs\n"
|
||||
}
|
||||
|
||||
runTests "$@"
|
||||
|
Loading…
x
Reference in New Issue
Block a user