mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-25 21:40:06 +00:00
Add lots of profiling to assist in debugging
- made some debug output conditional. - make it possible to debug slip decoding without getting swamped by other output. - Improve reporting of unnamed schedule() calls. - always collect performance statistics, and report on any excess use (>1sec in every 3), even if debug.timing is not enabled. - include file size information in Rhizome transfer messages. - reduce output when debug.rhizome_rx is set.
This commit is contained in:
parent
80168e3530
commit
f465f3a9ee
@ -657,6 +657,7 @@ int app_dna_lookup(const struct cli_parsed *parsed, void *context)
|
||||
|
||||
int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
{
|
||||
IN();
|
||||
if (config.debug.verbose)
|
||||
DEBUG_cli_parsed(parsed);
|
||||
/* Process optional arguments */
|
||||
@ -680,7 +681,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
status=server_probe(&pid);
|
||||
if (status!=SERVER_NOTRUNNING) {
|
||||
WHY("Tried to stop stuck servald process, but attempt failed.");
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
}
|
||||
WHY("Killed stuck servald process, so will try to start");
|
||||
pid=-1;
|
||||
@ -702,23 +703,23 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
int foregroundP = parsed->argc >= 2 && !strcasecmp(parsed->args[1], "foreground");
|
||||
if (cli_arg(parsed, "instance path", &instancepath, cli_absolute_path, NULL) == -1
|
||||
|| cli_arg(parsed, "exec path", &execpath, cli_absolute_path, NULL) == -1)
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
if (instancepath != NULL)
|
||||
serval_setinstancepath(instancepath);
|
||||
if (execpath == NULL) {
|
||||
#ifdef HAVE_JNI_H
|
||||
if (jni_env)
|
||||
return WHY("Must supply <exec path> argument when invoked via JNI");
|
||||
RETURN(WHY("Must supply <exec path> argument when invoked via JNI"));
|
||||
#endif
|
||||
if ((tmp = malloc(PATH_MAX)) == NULL)
|
||||
return WHY("Out of memory");
|
||||
if (get_self_executable_path(tmp, PATH_MAX) == -1)
|
||||
return WHY("unable to determine own executable name");
|
||||
RETURN(WHY("unable to determine own executable name"));
|
||||
execpath = tmp;
|
||||
}
|
||||
/* Create the instance directory if it does not yet exist */
|
||||
if (create_serval_instance_dir() == -1)
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
/* Now that we know our instance path, we can ask for the default set of
|
||||
network interfaces that we will take interest in. */
|
||||
if (config.interfaces.ac == 0)
|
||||
@ -726,7 +727,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
if (pid == -1)
|
||||
pid = server_pid();
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
int ret = -1;
|
||||
// If the pidfile identifies this process, it probably means we are re-spawning after a SEGV, so
|
||||
// go ahead and do the fork/exec.
|
||||
@ -741,17 +742,17 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
/* Start the Serval process. All server settings will be read by the server process from the
|
||||
instance directory when it starts up. */
|
||||
if (server_remove_stopfile() == -1)
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
overlayMode = 1;
|
||||
if (foregroundP)
|
||||
return server(NULL);
|
||||
RETURN(server(NULL));
|
||||
const char *dir = getenv("SERVALD_SERVER_CHDIR");
|
||||
if (!dir)
|
||||
dir = config.server.chdir;
|
||||
switch (cpid = fork()) {
|
||||
case -1:
|
||||
/* Main process. Fork failed. There is no child process. */
|
||||
return WHY_perror("fork");
|
||||
RETURN(WHY_perror("fork"));
|
||||
case 0: {
|
||||
/* Child process. Fork then exit, to disconnect daemon from parent process, so that
|
||||
when daemon exits it does not live on as a zombie. N.B. Do not return from within this
|
||||
@ -800,9 +801,9 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
sleep_ms(200); // 5 Hz
|
||||
} while ((pid = server_pid()) == 0 && gettime_ms() < timeout);
|
||||
if (pid == -1)
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
if (pid == 0)
|
||||
return WHY("Server process did not start");
|
||||
RETURN(WHY("Server process did not start"));
|
||||
ret = 0;
|
||||
}
|
||||
cli_puts("instancepath");
|
||||
@ -826,7 +827,7 @@ int app_server_start(const struct cli_parsed *parsed, void *context)
|
||||
sleep_ms(milliseconds);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
RETURN(ret);
|
||||
}
|
||||
|
||||
int app_server_stop(const struct cli_parsed *parsed, void *context)
|
||||
|
@ -203,6 +203,7 @@ ATOM(char, packetrx, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, packetradio, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, rejecteddata, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, slip, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, slipdecode, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, packetconstruction, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, rhizome, 0, cf_opt_char_boolean,, "")
|
||||
ATOM(char, rhizome_tx, 0, cf_opt_char_boolean,, "")
|
||||
|
18
fdqueue.c
18
fdqueue.c
@ -92,7 +92,6 @@ int _schedule(struct __sourceloc __whence, struct sched_ent *alarm)
|
||||
__whence.function,__whence.file,__whence.line);
|
||||
if (!alarm->stats)
|
||||
WARNF("schedule() called from %s() %s:%d without supplying an alarm name",
|
||||
alloca_alarm_name(alarm),
|
||||
__whence.function,__whence.file,__whence.line);
|
||||
|
||||
struct sched_ent *node = next_alarm, *last = NULL;
|
||||
@ -159,6 +158,9 @@ int _watch(struct __sourceloc __whence, struct sched_ent *alarm)
|
||||
{
|
||||
if (config.debug.io)
|
||||
DEBUGF("watch(alarm=%s)", alloca_alarm_name(alarm));
|
||||
if (!alarm->stats)
|
||||
WARNF("watch() called from %s() %s:%d without supplying an alarm name",
|
||||
__whence.function,__whence.file,__whence.line);
|
||||
|
||||
if (!alarm->function)
|
||||
return WHY("Can't watch if you haven't set the function pointer");
|
||||
@ -208,9 +210,13 @@ int _unwatch(struct __sourceloc __whence, struct sched_ent *alarm)
|
||||
|
||||
static void call_alarm(struct sched_ent *alarm, int revents)
|
||||
{
|
||||
IN();
|
||||
struct call_stats call_stats;
|
||||
call_stats.totals = alarm->stats;
|
||||
|
||||
if (config.debug.io) DEBUGF("Calling alarm/callback %p ('%s')",
|
||||
alarm, alloca_alarm_name(alarm));
|
||||
|
||||
if (call_stats.totals)
|
||||
fd_func_enter(__HERE__, &call_stats);
|
||||
|
||||
@ -219,16 +225,21 @@ static void call_alarm(struct sched_ent *alarm, int revents)
|
||||
|
||||
if (call_stats.totals)
|
||||
fd_func_exit(__HERE__, &call_stats);
|
||||
|
||||
if (config.debug.io) DEBUGF("Alarm %p returned",alarm);
|
||||
|
||||
OUT();
|
||||
}
|
||||
|
||||
int fd_poll()
|
||||
{
|
||||
IN();
|
||||
int i, r=0;
|
||||
int ms=60000;
|
||||
time_ms_t now = gettime_ms();
|
||||
|
||||
if (!next_alarm && !next_deadline && fdcount==0)
|
||||
return 0;
|
||||
RETURN(0);
|
||||
|
||||
/* move alarms that have elapsed to the deadline queue */
|
||||
while (next_alarm!=NULL&&next_alarm->alarm <=now){
|
||||
@ -258,6 +269,7 @@ int fd_poll()
|
||||
else
|
||||
usleep(ms*1000);
|
||||
}else{
|
||||
if (config.debug.io) DEBUGF("poll(X,%d,%d)",fdcount,ms);
|
||||
r = poll(fds, fdcount, ms);
|
||||
if (config.debug.io) {
|
||||
strbuf b = strbuf_alloca(1024);
|
||||
@ -298,5 +310,5 @@ int fd_poll()
|
||||
set_block(fds[i].fd);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
RETURN(1);
|
||||
}
|
||||
|
10
overlay.c
10
overlay.c
@ -79,6 +79,8 @@ keyring_file *keyring=NULL;
|
||||
|
||||
int overlayServerMode()
|
||||
{
|
||||
IN();
|
||||
|
||||
/* In overlay mode we need to listen to all of our sockets, and also to
|
||||
send periodic traffic. This means we need to */
|
||||
INFO("Running in overlay mode.");
|
||||
@ -152,15 +154,13 @@ schedule(&_sched_##X); }
|
||||
/* Periodically advertise bundles */
|
||||
SCHEDULE(overlay_rhizome_advertise, 1000, 10000);
|
||||
|
||||
/* Show CPU usage stats periodically */
|
||||
if (config.debug.timing){
|
||||
SCHEDULE(fd_periodicstats, 3000, 500);
|
||||
}
|
||||
/* Calculate (and possibly show) CPU usage stats periodically */
|
||||
SCHEDULE(fd_periodicstats, 3000, 500);
|
||||
|
||||
#undef SCHEDULE
|
||||
|
||||
/* Check for activitiy and respond to it */
|
||||
while(fd_poll());
|
||||
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
@ -627,9 +627,10 @@ static void interface_read_stream(struct overlay_interface *interface){
|
||||
|
||||
struct slip_decode_state *state=&interface->slip_decode_state;
|
||||
|
||||
if (config.debug.slip)
|
||||
dump("RX bytes",&state->src[state->src_offset],
|
||||
state->src_size-state->src_offset);
|
||||
if (config.debug.slip) {
|
||||
dump("RX bytes",&state->src[state->src_offset],
|
||||
state->src_size-state->src_offset);
|
||||
}
|
||||
|
||||
state->src=buffer;
|
||||
state->src_size=nread;
|
||||
|
@ -316,8 +316,9 @@ overlay_stuff_packet(struct outgoing_packet *packet, overlay_txqueue *queue, tim
|
||||
// TODO stop when the packet is nearly full?
|
||||
while(frame){
|
||||
if (frame->enqueued_at + queue->latencyTarget < now){
|
||||
DEBUGF("Dropping frame type %x for %s due to expiry timeout",
|
||||
frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
|
||||
if (config.debug.rejecteddata)
|
||||
DEBUGF("Dropping frame type %x for %s due to expiry timeout",
|
||||
frame->type, frame->destination?alloca_tohex_sid(frame->destination->sid):"All");
|
||||
frame = overlay_queue_remove(queue, frame);
|
||||
continue;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
|
||||
struct profile_total *stats_head=NULL;
|
||||
struct call_stats *current_call=NULL;
|
||||
@ -148,17 +149,31 @@ int fd_showstats()
|
||||
stats = stats->_next;
|
||||
}
|
||||
|
||||
INFOF("servald time usage stats:");
|
||||
stats = stats_head;
|
||||
while(stats!=NULL){
|
||||
/* Get total time spent doing everything */
|
||||
if (stats->calls)
|
||||
fd_showstat(&total,stats);
|
||||
stats = stats->_next;
|
||||
// Report any functions that take too much time
|
||||
if (!config.debug.timing)
|
||||
{
|
||||
stats = stats_head;
|
||||
while(stats!=NULL){
|
||||
/* If a function spends more than 1 second in any
|
||||
notionally 3 second period, then dob on it */
|
||||
if (stats->total_time>1000
|
||||
&&strcmp(stats->name,"Idle (in poll)"))
|
||||
fd_showstat(&total,stats);
|
||||
stats = stats->_next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
INFOF("servald time usage stats:");
|
||||
stats = stats_head;
|
||||
while(stats!=NULL){
|
||||
/* Get total time spent doing everything */
|
||||
if (stats->calls)
|
||||
fd_showstat(&total,stats);
|
||||
stats = stats->_next;
|
||||
}
|
||||
fd_showstat(&total,&total);
|
||||
}
|
||||
|
||||
fd_showstat(&total,&total);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1115,11 +1115,11 @@ cleanup:
|
||||
int64_t rhizome_database_create_blob_for(const char *hashhex,int64_t fileLength,
|
||||
int priority)
|
||||
{
|
||||
|
||||
IN();
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
|
||||
if (sqlite_exec_void_retry(&retry, "BEGIN TRANSACTION;") != SQLITE_OK)
|
||||
return WHY("Failed to begin transaction");
|
||||
RETURN(WHY("Failed to begin transaction"));
|
||||
|
||||
/* INSERT INTO FILES(id as text, data blob, length integer, highestpriority integer).
|
||||
BUT, we have to do this incrementally so that we can handle blobs larger than available memory.
|
||||
@ -1155,7 +1155,7 @@ int64_t rhizome_database_create_blob_for(const char *hashhex,int64_t fileLength,
|
||||
insert_row_fail:
|
||||
WHYF("Failed to insert row for fileid=%s", hashhex);
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;");
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
}
|
||||
|
||||
/* Get rowid for inserted row, so that we can modify the blob */
|
||||
@ -1164,10 +1164,10 @@ insert_row_fail:
|
||||
ret = sqlite_exec_void_retry(&retry, "COMMIT;");
|
||||
if (ret!=SQLITE_OK){
|
||||
sqlite_exec_void_retry(&retry, "ROLLBACK;");
|
||||
return WHYF("Failed to commit transaction");
|
||||
RETURN(WHYF("Failed to commit transaction"));
|
||||
}
|
||||
DEBUGF("Got rowid %lld for %s", rowid, hashhex);
|
||||
return rowid;
|
||||
RETURN(rowid);
|
||||
}
|
||||
|
||||
void rhizome_bytes_to_hex_upper(unsigned const char *in, char *out, int byteCount)
|
||||
|
@ -524,6 +524,7 @@ static int rhizome_import_received_bundle(struct rhizome_manifest *m)
|
||||
|
||||
static int schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
{
|
||||
IN();
|
||||
int sock = -1;
|
||||
/* TODO Don't forget to implement resume */
|
||||
/* TODO We should stream file straight into the database */
|
||||
@ -601,7 +602,7 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
slot->alarm.alarm = gettime_ms() + RHIZOME_IDLE_TIMEOUT;
|
||||
slot->alarm.deadline = slot->alarm.alarm + RHIZOME_IDLE_TIMEOUT;
|
||||
schedule(&slot->alarm);
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
bail_http:
|
||||
@ -609,7 +610,7 @@ static int schedule_fetch(struct rhizome_fetch_slot *slot)
|
||||
the connection/attempt to fetch via HTTP failed. */
|
||||
slot->state=RHIZOME_FETCH_RXFILEMDP;
|
||||
rhizome_fetch_switch_to_mdp(slot);
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
/* Start fetching a bundle's payload ready for importing.
|
||||
@ -675,12 +676,12 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct
|
||||
|
||||
if (config.debug.rhizome_rx)
|
||||
DEBUGF("Fetching bundle slot=%d bid=%s version=%lld size=%lld peerip=%s",
|
||||
slotno(slot),
|
||||
bid,
|
||||
m->version,
|
||||
m->fileLength,
|
||||
alloca_sockaddr(peerip)
|
||||
);
|
||||
slotno(slot),
|
||||
bid,
|
||||
m->version,
|
||||
m->fileLength,
|
||||
alloca_sockaddr(peerip)
|
||||
);
|
||||
|
||||
// If the payload is empty, no need to fetch, so import now.
|
||||
if (m->fileLength == 0) {
|
||||
@ -828,6 +829,7 @@ rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip,
|
||||
*/
|
||||
static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
|
||||
{
|
||||
IN();
|
||||
struct rhizome_fetch_queue *q;
|
||||
for (q = (struct rhizome_fetch_queue *) slot; q >= rhizome_fetch_queues; --q) {
|
||||
int i = 0;
|
||||
@ -836,11 +838,11 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
|
||||
int result = rhizome_fetch(slot, c->manifest, &c->peer_ipandport,c->peer_sid);
|
||||
switch (result) {
|
||||
case SLOTBUSY:
|
||||
return;
|
||||
OUT(); return;
|
||||
case STARTED:
|
||||
c->manifest = NULL;
|
||||
rhizome_fetch_unqueue(q, i);
|
||||
return;
|
||||
OUT(); return;
|
||||
case IMPORTED:
|
||||
case SAMEBUNDLE:
|
||||
case SAMEPAYLOAD:
|
||||
@ -858,6 +860,7 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
|
||||
}
|
||||
}
|
||||
}
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Called soon after any fetch candidate is queued, to start any queued fetches.
|
||||
@ -866,9 +869,11 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot)
|
||||
*/
|
||||
static void rhizome_start_next_queued_fetches(struct sched_ent *alarm)
|
||||
{
|
||||
IN();
|
||||
int i;
|
||||
for (i = 0; i < NQUEUES; ++i)
|
||||
rhizome_start_next_queued_fetch(&rhizome_fetch_queues[i].active);
|
||||
OUT();
|
||||
}
|
||||
|
||||
/* Search all fetch slots, including active downloads, for a matching manifest */
|
||||
@ -908,6 +913,9 @@ rhizome_manifest * rhizome_fetch_search(unsigned char *id, int prefix_length){
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
struct profile_total rsnqf_stats={.name="rhizome_start_next_queued_fetches"};
|
||||
struct profile_total rfmsc_stats={.name="rhizome_fetch_mdp_slot_callback"};
|
||||
|
||||
int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip,const unsigned char peersid[SID_SIZE])
|
||||
{
|
||||
IN();
|
||||
@ -1029,7 +1037,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock
|
||||
|
||||
if (!is_scheduled(&sched_activate)) {
|
||||
sched_activate.function = rhizome_start_next_queued_fetches;
|
||||
sched_activate.stats = NULL;
|
||||
sched_activate.stats = &rsnqf_stats;
|
||||
sched_activate.alarm = gettime_ms() + rhizome_fetch_delay_ms();
|
||||
sched_activate.deadline = sched_activate.alarm + 5000;
|
||||
schedule(&sched_activate);
|
||||
@ -1074,28 +1082,33 @@ static int rhizome_fetch_close(struct rhizome_fetch_slot *slot)
|
||||
|
||||
static void rhizome_fetch_mdp_slot_callback(struct sched_ent *alarm)
|
||||
{
|
||||
IN();
|
||||
struct rhizome_fetch_slot *slot=(struct rhizome_fetch_slot*)alarm;
|
||||
|
||||
if (slot->state!=5) {
|
||||
DEBUGF("Stale alarm triggered on idle/reclaimed slot. Ignoring");
|
||||
unschedule(alarm);
|
||||
OUT();
|
||||
return;
|
||||
}
|
||||
|
||||
long long now=gettime_ms();
|
||||
if (now-slot->last_write_time>slot->mdpIdleTimeout) {
|
||||
DEBUGF("MDP connection timed out: last RX %lldms ago",
|
||||
now-slot->last_write_time);
|
||||
DEBUGF("MDP connection timed out: last RX %lldms ago (read %d of %d bytes)",
|
||||
now-slot->last_write_time,
|
||||
slot->file_ofs,slot->file_len);
|
||||
rhizome_fetch_close(slot);
|
||||
OUT();
|
||||
return;
|
||||
}
|
||||
if (config.debug.rhizome_rx)
|
||||
DEBUGF("Timeout waiting for blocks. Resending request for slot=0x%p",
|
||||
slot);
|
||||
DEBUGF("Timeout: Resending request for slot=0x%p (%d of %d received)",
|
||||
slot,slot->file_ofs,slot->file_len);
|
||||
if (slot->bidP)
|
||||
rhizome_fetch_mdp_requestblocks(slot);
|
||||
else
|
||||
rhizome_fetch_mdp_requestmanifest(slot);
|
||||
OUT();
|
||||
}
|
||||
|
||||
static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
|
||||
@ -1138,6 +1151,7 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot)
|
||||
slot->mdpResponsesOutstanding=32; // TODO: set according to bitmap
|
||||
|
||||
unschedule(&slot->alarm);
|
||||
slot->alarm.stats=&rfmsc_stats;
|
||||
slot->alarm.function = rhizome_fetch_mdp_slot_callback;
|
||||
// 266ms @ 1mbit (WiFi broadcast speed) = 32x1024 byte packets.
|
||||
slot->alarm.alarm=gettime_ms()+266;
|
||||
@ -1205,7 +1219,8 @@ static int rhizome_fetch_switch_to_mdp(struct rhizome_fetch_slot *slot)
|
||||
}
|
||||
|
||||
if (config.debug.rhizome_rx)
|
||||
DEBUGF("Trying to switch to MDP for Rhizome fetch: slot=0x%p",slot);
|
||||
DEBUGF("Trying to switch to MDP for Rhizome fetch: slot=0x%p (%d bytes)",
|
||||
slot,slot->file_len);
|
||||
|
||||
/* close socket and stop watching it */
|
||||
if (slot->alarm.poll.fd>=0) {
|
||||
@ -1365,7 +1380,7 @@ int rhizome_write_content(struct rhizome_fetch_slot *slot, char *buffer, int byt
|
||||
if (config.debug.rhizome_rx) {
|
||||
DEBUGF("slot->blob_buffer_bytes=%d, slot->file_ofs=%d",
|
||||
slot->blob_buffer_bytes,slot->file_ofs);
|
||||
dump("buffer",buffer,bytes);
|
||||
// dump("buffer",buffer,bytes);
|
||||
}
|
||||
|
||||
if (!slot->blob_buffer_size) {
|
||||
|
7
server.c
7
server.c
@ -87,6 +87,7 @@ void server_save_argv(int argc, const char *const *argv)
|
||||
|
||||
int server(char *backing_file)
|
||||
{
|
||||
IN();
|
||||
/* For testing, it can be very helpful to delay the start of the server process, for example to
|
||||
* check that the start/stop logic is robust.
|
||||
*/
|
||||
@ -121,11 +122,11 @@ int server(char *backing_file)
|
||||
/* Record PID to advertise that the server is now running */
|
||||
char filename[1024];
|
||||
if (!FORM_SERVAL_INSTANCE_PATH(filename, PIDFILE_NAME))
|
||||
return -1;
|
||||
RETURN(-1);
|
||||
FILE *f=fopen(filename,"w");
|
||||
if (!f) {
|
||||
WHY_perror("fopen");
|
||||
return WHYF("Could not write to PID file %s", filename);
|
||||
RETURN(WHYF("Could not write to PID file %s", filename));
|
||||
}
|
||||
server_getpid = getpid();
|
||||
fprintf(f,"%d\n", server_getpid);
|
||||
@ -133,7 +134,7 @@ int server(char *backing_file)
|
||||
|
||||
overlayServerMode();
|
||||
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
/* Called periodically by the server process in its main loop.
|
||||
|
67
slip.c
67
slip.c
@ -193,22 +193,24 @@ int parse_rfd900_rssi(char *s)
|
||||
#define UPPER7_STATE_D7 15
|
||||
int upper7_decode(struct slip_decode_state *state,unsigned char byte)
|
||||
{
|
||||
if (0&&config.debug.slip)
|
||||
IN()
|
||||
if (config.debug.slipdecode)
|
||||
DEBUGF("state=%d, byte=0x%02x",state->state,byte);
|
||||
|
||||
// Parse out inline RSSI reports
|
||||
if (byte=='{') {
|
||||
state->state=UPPER7_STATE_L1;
|
||||
state->packet_length=0;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
} else if (byte=='}') {
|
||||
// End of packet marker -- report end of received packet to caller
|
||||
// for CRC verification etc.
|
||||
state->state=UPPER7_STATE_NOTINPACKET; return 1;
|
||||
state->state=UPPER7_STATE_NOTINPACKET; RETURN(1);
|
||||
} else if (byte>=' '&&byte<=0x7f) {
|
||||
if (state->rssi_len<0) state->rssi_len=0;
|
||||
if (state->rssi_len<RSSI_TEXT_SIZE)
|
||||
state->rssi_text[state->rssi_len++]=byte;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
} else if (byte=='\r'||byte=='\n') {
|
||||
if (state->rssi_len>=RSSI_TEXT_SIZE) state->rssi_len=RSSI_TEXT_SIZE-1;
|
||||
if (state->rssi_len<0) state->rssi_len=0;
|
||||
@ -220,17 +222,21 @@ int upper7_decode(struct slip_decode_state *state,unsigned char byte)
|
||||
// Non-data bytes (none currently used, but we need to catch them before
|
||||
// moving onto processing data bytes)
|
||||
if (byte<0x80) {
|
||||
switch (byte) {
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
// Data bytes and packet fields
|
||||
byte&=0x7f;
|
||||
if (state->packet_length>=OVERLAY_INTERFACE_RX_BUFFER_SIZE
|
||||
||(state->dst_offset+7)>=OVERLAY_INTERFACE_RX_BUFFER_SIZE
|
||||
||state->dst_offset<0)
|
||||
{
|
||||
WARNF("state->dst_offset=%d, ->packet_length=%d, ->state=%d",
|
||||
state->dst_offset,state->packet_length,state->state);
|
||||
}
|
||||
switch(state->state) {
|
||||
case UPPER7_STATE_NOTINPACKET: return 0;
|
||||
case UPPER7_STATE_L1: state->packet_length=byte<<7; state->state++; return 0;
|
||||
case UPPER7_STATE_NOTINPACKET: RETURN(0);
|
||||
case UPPER7_STATE_L1: state->packet_length=byte<<7; state->state++; RETURN(0);
|
||||
case UPPER7_STATE_L2: state->packet_length|=byte;
|
||||
// Make sure packet length can fit in RX buffer, including that we might
|
||||
// need upto 7 bytes extra temporary space due to blocking
|
||||
@ -242,57 +248,57 @@ int upper7_decode(struct slip_decode_state *state,unsigned char byte)
|
||||
DEBUGF("Ignoring jumbo packet of %d bytes",state->packet_length);
|
||||
state->state=UPPER7_STATE_NOTINPACKET;
|
||||
}
|
||||
return 0;
|
||||
case UPPER7_STATE_C1: state->crc=byte<<25; state->state++; return 0;
|
||||
case UPPER7_STATE_C2: state->crc|=byte<<(25-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C3: state->crc|=byte<<(25-7-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C4: state->crc|=byte<<(25-7-7-7); state->state++; return 0;
|
||||
case UPPER7_STATE_C5: state->crc|=byte<<0; state->state++; return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_C1: state->crc=byte<<25; state->state++; RETURN(0);
|
||||
case UPPER7_STATE_C2: state->crc|=byte<<(25-7); state->state++; RETURN(0);
|
||||
case UPPER7_STATE_C3: state->crc|=byte<<(25-7-7); state->state++; RETURN(0);
|
||||
case UPPER7_STATE_C4: state->crc|=byte<<(25-7-7-7); state->state++; RETURN(0);
|
||||
case UPPER7_STATE_C5: state->crc|=byte<<0; state->state++; RETURN(0);
|
||||
case UPPER7_STATE_D0:
|
||||
// Prevent buffer overruns
|
||||
if (state->dst_offset+7>OVERLAY_INTERFACE_RX_BUFFER_SIZE)
|
||||
state=UPPER7_STATE_NOTINPACKET;
|
||||
state->dst[state->dst_offset]=byte<<1;
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D1:
|
||||
state->dst[state->dst_offset+0]|=(byte>>6)&0x01;
|
||||
state->dst[state->dst_offset+1]=(byte<<2);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D2:
|
||||
state->dst[state->dst_offset+1]|=(byte>>5)&0x03;
|
||||
state->dst[state->dst_offset+2]=(byte<<3);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D3:
|
||||
state->dst[state->dst_offset+2]|=(byte>>4)&0x07;
|
||||
state->dst[state->dst_offset+3]=(byte<<4);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D4:
|
||||
state->dst[state->dst_offset+3]|=(byte>>3)&0x0f;
|
||||
state->dst[state->dst_offset+4]=(byte<<5);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D5:
|
||||
state->dst[state->dst_offset+4]|=(byte>>2)&0x1f;
|
||||
state->dst[state->dst_offset+5]=(byte<<6);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D6:
|
||||
state->dst[state->dst_offset+5]|=(byte>>1)&0x3f;
|
||||
state->dst[state->dst_offset+6]=(byte<<7);
|
||||
state->state++;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
case UPPER7_STATE_D7:
|
||||
state->dst[state->dst_offset+6]|=(byte>>0)&0x7f;
|
||||
state->dst_offset+=7;
|
||||
state->state=UPPER7_STATE_D0;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
default:
|
||||
state->state=UPPER7_STATE_NOTINPACKET;
|
||||
return 0;
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -387,13 +393,15 @@ int slip_decode(struct slip_decode_state *state)
|
||||
if (state->rssi_len<0) state->rssi_len=0;
|
||||
if (state->rssi_len>=RSSI_TEXT_SIZE) state->rssi_len=RSSI_TEXT_SIZE-1;
|
||||
state->rssi_text[state->rssi_len]=0;
|
||||
DEBUGF("RX state=%d, rssi_len=%d, rssi_text='%s'",
|
||||
state->state,state->rssi_len,state->rssi_text);
|
||||
DEBUGF("RX state=%d, rssi_len=%d, rssi_text='%s',src=%p, src_size=%d",
|
||||
state->state,state->rssi_len,state->rssi_text,
|
||||
state->src,state->src_size);
|
||||
}
|
||||
while(state->src_offset<state->src_size)
|
||||
while(state->src_offset<state->src_size) {
|
||||
if (upper7_decode(state,state->src[state->src_offset++])==1) {
|
||||
if (config.debug.slip)
|
||||
if (config.debug.slip) {
|
||||
dump("de-slipped packet",state->dst,state->packet_length);
|
||||
}
|
||||
|
||||
// Check that CRC matches
|
||||
uint32_t crc=Crc32_ComputeBuf( 0, state->dst, state->packet_length);
|
||||
@ -410,6 +418,7 @@ int slip_decode(struct slip_decode_state *state)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user