Unfinished dnahelper implementation

This commit is contained in:
Andrew Bettison 2012-07-18 19:16:30 +09:30
parent 117a3191ab
commit 5aac5a3854
7 changed files with 205 additions and 164 deletions

View File

@ -497,28 +497,28 @@ 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(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);
}
}
} else {
WHYF("Received malformed DNA reply: %s", alloca_toprint(160, rx.in.payload, rx.in.payload_length));
}
}
}
else WHYF("packettype=0x%x",rx.packetTypeAndFlags);
@ -1632,18 +1632,18 @@ int app_node_info(int argc, const char *const *argv, struct command_line_option
}
{
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(m2.in.payload, m2.in.payload_length, sidhex, did, name, uri) != -1) {
/* Got a good DNA reply, copy it into place */
bcopy(did,mdp.nodeinfo.did,32);
bcopy(name,mdp.nodeinfo.name,64);
mdp.nodeinfo.resolve_did=1;
break;
} else {
WHYF("Received malformed DNA reply: %s", alloca_toprint(160, m2.in.payload, m2.in.payload_length));
}
}
}

View File

@ -17,7 +17,11 @@ 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 "serval.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
/*
The challenge with making an interface for calling an external program to
@ -38,80 +42,58 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
main loop.
*/
static pid_t dna_helper_pid = -1;
static int dna_helper_stdin = -1;
static int dna_helper_stdout = -1;
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;
l=0;
/* Replies look like: TOKEN|URI|DID|CALLERID| */
maxlen=SID_SIZE*2+1;
for(i=0;l<maxlen&&i<count&&bytes[i]!='|';i++)
sidhex[l++]=bytes[i];
sidhex[l]=0;
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;
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); */
parseDnaReply(const unsigned char *bytes, int count,
char *sidhex, char *did, char *name, char *uri)
{
/* Replies look like: TOKEN|URI|DID|NAME| */
const unsigned char *b = bytes;
const unsigned char *e = bytes + count;
char *p, *q;
for (p = sidhex, q = sidhex + SID_STRLEN; b != e && *b != '|' && p != q; ++p, ++b)
*p = *b;
*p = '\0';
if (b == e || *b++ != '|')
return -1;
for (p = uri, q = uri + 511; b != e && *b != '|' && p != q; ++p, ++b)
*p = *b;
*p = '\0';
if (b == e || *b++ != '|')
return -1;
for (p = did, q = did + DID_MAXSIZE; b != e && *b != '|' && p != q; ++p, ++b)
*p = *b;
*p = '\0';
if (b == e || *b++ != '|')
return -1;
for (p = name, q = name + 63; b != e && *b != '|' && p != q; ++p, ++b)
*p = *b;
*p = '\0';
if (b == e || *b != '|')
return -1;
return 0;
}
void dna_helper_monitor(int fd)
{
return;
}
static struct sched_ent dna_helper_sched;
struct sched_ent dna_helper_sched;
void dna_helper_monitor(struct sched_ent *alarm);
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");
dna_helper_start(const char *command, const char *arg)
{
int stdin_fds[2], stdout_fds[2];
if (pipe(stdin_fds))
return WHY_perror("pipe");
if (pipe(stdout_fds)) {
close(stdin_fds[0]);
close(stdin_fds[1]);
return WHY_perror("pipe");
}
if ((pid = fork()) == 0) {
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);
@ -120,77 +102,111 @@ dna_helper_start(const char *command, const char *arg) {
if (dup2(stdout_fds[0], 2)) /* replace stderr */
exit(-1);
execl(command, command, arg, NULL);
DEBUG("execl() failed");
WHYF_perror("execl(%s, %s, %s, NULL)", command, command, arg ? arg : "NULL");
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;
}
break;
case -1:
/* fork failed */
WHY_perror("fork");
close(stdin_fds[0]);
close(stdin_fds[1]);
close(stdout_fds[0]);
close(stdout_fds[1]);
return -1;
default:
/* Parent, should put file descriptors into place for use */
INFOF("Started DNA helper, pid=%u: %s %s", dna_helper_pid, command, arg ? arg : "");
dna_helper_stdin = stdin_fds[0];
dna_helper_stdout = stdout_fds[1];
dna_helper_sched.function = dna_helper_monitor;
dna_helper_sched.context = NULL;
dna_helper_sched.poll.fd = dna_helper_stdout;
dna_helper_sched.poll.events = POLLIN;
dna_helper_sched.alarm = overlay_gettime_ms() + 1000;
dna_helper_sched.stats = NULL;
watch(&dna_helper_sched);
schedule(&dna_helper_sched);
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_harvest()
{
D;
if (dna_helper_pid > 0) {
int status;
pid_t pid = waitpid(dna_helper_pid, &status, WNOHANG);
if (pid == dna_helper_pid) {
strbuf b = strbuf_alloca(80);
INFOF("DNA helper pid=%u %s", pid, strbuf_str(strbuf_append_exit_status(b, status)));
unschedule(&dna_helper_sched);
unwatch(&dna_helper_sched);
dna_helper_pid = -1;
return 1;
} else if (pid == -1) {
return WHYF_perror("waitpid(%d, WNOHANG)", dna_helper_pid);
} else if (pid) {
return WHYF("waitpid(%d, WNOHANG) returned %d", dna_helper_pid, pid);
}
}
return 0;
}
if (dna_helper_stdin == -1) {
dna_helper = confValueGet("dna.helper", NULL);
if (!dna_helper || !dna_helper[0]) {
void dna_helper_monitor(struct sched_ent *alarm)
{
if (alarm != &dna_helper_sched) {
WHY("Alarm not for me");
return;
}
if (dna_helper_sched.poll.revents & POLLIN) {
unsigned char buffer[1024];
if (read_nonblock(dna_helper_sched.poll.fd, buffer, sizeof buffer) != -1) {
DEBUGF("Got DNA helper reply %s", alloca_toprint(160, buffer, sizeof buffer));
}
}
if (dna_helper_harvest() <= 0) {
dna_helper_sched.alarm = overlay_gettime_ms() + 1000;
schedule(alarm);
}
}
int
dna_helper_enqueue(char *did, unsigned char *requestorSid)
{
if (dna_helper_pid == 0)
return -1;
if (dna_helper_pid == -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_stdin to magic value of -2 so that we don't waste time
dna_helper_pid to magic value of 0 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;
INFO("No DNA helper configured");
dna_helper_pid = 0;
return -1;
}
/* Look for optional argument */
dna_helper_arg = confValueGet("dna.helperarg", NULL);
/* Okay, so we have a helper configured.
Run it */
if (dna_helper_start(dna_helper, dna_helper_arg) < 0) {
if (dna_helper_start(dna_helper_executable, dna_helper_arg1) < 0) {
/* Something broke, bail out */
DEBUG("Failed to start dna helper");
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");
char buffer[1024];
strbuf b = strbuf_local(buffer, sizeof buffer);
strbuf_sprintf(b, "%s|%s|\n", alloca_tohex_sid(requestorSid), did);
if (strbuf_overrun(b))
return WHY("DNA helper buffer overrun");
sigPipeFlag = 0;
write_str(dna_helper_stdin, buffer);
write_all(dna_helper_stdin, strbuf_str(b), strbuf_len(b));
if (sigPipeFlag) {
/* Assume broken pipe due to dead helper.
Next request will cause it to be restarted.
@ -200,14 +216,14 @@ dna_helper_enqueue(char *did, unsigned char *requestorSid) {
in quick succession so that we don't waste lots of time with a buggy or
suicidal helper.
*/
WARN("Got SIGPIPE from DNA helper");
close(dna_helper_stdin);
close(dna_helper_stdout);
dna_helper_stdin = -1;
dna_helper_stdout = -1;
DEBUG("Sigpipe encountered");
dna_helper_harvest();
return -1;
}
return 0;
}

View File

@ -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;
@ -539,14 +540,12 @@ int overlay_saw_mdp_frame(overlay_mdp_frame *mdp,long long now)
(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;
bcopy(packedSid, &mdpreply.out.src.sid[0], SID_SIZE);
/* build reply as TOKEN|URI|DID|NAME|<NUL> */
strbuf b = strbuf_local((char *)mdpreply.out.payload, sizeof mdpreply.out.payload);
const char *sidhex = alloca_tohex_sid(packedSid);
strbuf_sprintf(b, "%s|sid://%s/%s|%s|%s|", sidhex, sidhex, unpackedDid, unpackedDid, name);
mdpreply.out.payload_length = strbuf_len(b) + 1;
/* deliver reply */
overlay_mdp_dispatch(&mdpreply,0 /* system generated */,NULL,0);
kp++;

View File

@ -1554,8 +1554,7 @@ int server_probe(int *pid);
int dna_helper_enqueue(char *did, 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 unsigned char *bytes, int count, char *sidhex, char *did, char *name, char *uri);
extern int sigPipeFlag;
extern int sigIoFlag;
void sigPipeHandler(int signal);

View File

@ -19,6 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "strbuf_helpers.h"
#include <poll.h>
#include <string.h>
#include <sys/wait.h>
strbuf strbuf_append_poll_events(strbuf sb, short events)
{
@ -61,3 +63,20 @@ strbuf strbuf_append_poll_events(strbuf sb, short events)
strbuf_putc(sb, '0');
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)));
else if (WIFCONTINUED(status))
strbuf_sprintf(sb, "continued by signal %u (SIGCONT)", SIGCONT);
return sb;
}

View File

@ -27,4 +27,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
strbuf strbuf_append_poll_events(strbuf sb, short events);
/* 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__

View File

@ -24,7 +24,6 @@ source "${0%/*}/../testdefs.sh"
setup() {
setup_servald
assert_no_servald_processes
setup_dnahelper
}
teardown() {
@ -36,17 +35,18 @@ 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 dna.helper.executable "$TFWTMP/dnahelper"
}
setup_dnahelper() {
cat >"$TFWTMP/dnahelper" <<EOF
dnahelper="$TFWTMP/dnahelper"
cat >"$dnahelper" <<EOF
#!/usr/bin/env python
# Sample DNA Helper application for testing
import sys;
def main():
import sys
def main():
print "STARTED"
while True:
line = sys.stdin.readline().strip()
@ -58,7 +58,6 @@ def main():
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")
@ -68,37 +67,40 @@ def main():
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")
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")
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)
print "%s|sip://long-callerid@1.2.3.4|%s|%s|" % (token, 'x' * 200, number)
if number == "5551005":
# Excessively long DID
print "%s|sip://long-did@1.2.3.4|askjdhfkjashdfkljahsdflkjhasdljkfhasldjkfhaslkjdfhalskdjfhklajsdhflkajsdhflkjasdhflkjashdflkjashdflkjahsdflkjahsdfjklhasdljkfhasjkdfhakljsdfhklajsdhflkjashdfljkashdflkjashdf|%s|" % (token, "Agent Smith")
print "%s|sip://long-did@1.2.3.4|%s|%s|" % (token, 'x' * 200, "Agent Smith")
if number == "5551006":
# Excessively long URI
print "%s|sip://askjdhfkjashdfkljahsdflkjhasdljkfhasldjkfhaslkjdfhalskdjfhklajsdhflkajsdhflkjasdhflkjashdflkjashdflkjahsdflkjahsdfjklhasdljkfhasjkdfhakljsdfhklajsdhflkjashdfljkashdflkjashdfasdjfkjahsdfjkhasdfkjlhasjldkfhajksdhflkjasdhfkljashdfkljahsdfkljhasdfkljhasdlkjfhasdlkjfhaslkjdfhakljsdhfklajshdfkljashdfljkashdflkjashdflkjahsdfkjlahsdflkjhasdfljkhasdkfjlhaslkdjfhaslkjdfhaklsjdfhaklsjdhflkajsdhflkjasdhflkjashdfljkashdfkljashdflkjashdflkjashdflkjashdflkjashdflkjashdfljkahsdflkjahsdfjklahsdfljkahsdflkjhasdflkjhasdjkfhaskjdlfhaslkjdfhaskljdfhasljkdfhalskdfhalkjsdhflkjasdhflkjahsdflkjahsdflkjahsdflkjhasdflkjahsdflkjahsdflkjahsdfkljashdflkajshdflkajsdhflaksjdfhalksjdfhlasdkjfh|%s|%s|" % (token, number, "Agent Smith")
print "%s|sip://%s|%s|%s|" % (token, 'x' * 1000, number, "Agent Smith")
if number == "5551007":
# Incorrect token
print "cheeseburger|sip://incorrect-token@1.2.3.4|%s||" % (token, number)
print "cheeseburger|sip://incorrect-token@1.2.3.4|%s||" % (token, number)
print "DONE"
if __name__ == "__main__":
main()
EOF
chmod 0755 "$dnahelper"
}
doc_MultiServer="Start three servald servers with dna helper"
test_MultiServer() {
start_servald_instances +A +B +C
doc_Simple="Simple DNA helper test"
setup_Simple() {
setup
setup_dnahelper
start_servald_instances +A
}
test_Simple() {
executeOk_servald dna lookup 12345
}
runTests "$@"