Beispiel #1
0
void parse_cmdline(int argc, char *argv[])
{
	int s, i;
	int failed = 0;
	
	while ((s = getopt(argc, argv, "c:fn:r:e:o:l:s:?h")) != -1) {
	switch (s) {
		case 'c':
			cfgfile = hstrdup(optarg);
			break;
		case 'f':
			fork_a_daemon = 1;
			break;
		case 'n':
			logname = hstrdup(optarg);
			break;
		case 'r':
			log_dir = hstrdup(optarg);
			break;
		case 'e':
			i = pick_loglevel(optarg, log_levelnames);
			if (i > -1)
				log_level = i;
			else {
				fprintf(stderr, "Log level unknown: \"%s\"\n", optarg);
				failed = 1;
			}
			break;
		case 'o':
			i = pick_loglevel(optarg, log_destnames);
			if (i > -1)
				log_dest = i;
			else {
				fprintf(stderr, "Log destination unknown: \"%s\"\n", optarg);
				failed = 1;
			}
			break;
		case 'l':
			sound_in_file = hstrdup(optarg);
			break;
		case 's':
			sound_out_file = hstrdup(optarg);
			break;
		case '?':
		case 'h':
			fprintf(stderr, "%s\n", VERSTR);
			failed = 1;
	}
	}
	
	if ((log_dest == L_FILE) && (!log_dir)) {
		fprintf(stderr, "Log destination set to 'file' but no log directory specified!\n");
		failed = 1;
	}
	
	if (failed) {
		fprintf(stderr," %s",HELPS);
		exit(failed);
	}
}
Beispiel #2
0
int do_uplink(struct uplink_config_t **lq, int argc, char **argv)
{
	struct uplink_config_t *l;
	int uplink_proto = 0;
	
	if (argc < 3)
		return -1;
	
	if (strcasecmp(argv[2], "json") == 0) {
		uplink_proto = UPLINK_JSON;
	} else {
		hlog(LOG_ERR, "Uplink: Unsupported uplink protocol '%s'\n", argv[2]);
		return -2;
	}
	
	l = hmalloc(sizeof(*l));

	l->proto = uplink_proto;
	l->name  = hstrdup(argv[1]);
	l->url = hstrdup(argv[3]);

	/* put in the list */
	l->next = *lq;
	if (l->next)
		l->next->prevp = &l->next;
	*lq = l;
	
	return 0;
}
Beispiel #3
0
time_t parse_interval(char *origs)
{
	time_t t = 0;
	int i;
	char *s, *np, *p, c;
	
	np = p = s = hstrdup(origs);
	
	while (*p) {
		if (!isdigit((int)*p)) {
			c = tolower(*p);
			*p = '\0';
			i = atoi(np);
			if (c == 's')
				t += i;
			else if (c == 'm')
				t += 60 * i;
			else if (c == 'h')
				t += 60 * 60 * i;
			else if (c == 'd')
				t += 24 * 60 * 60 * i;
			np = p + 1;
		}
		p++;
	}
	
	if (*np)
		t += atoi(np);
		
	hfree(s);
	return t;
}
Beispiel #4
0
struct cdata_t *cdata_alloc(const char *name)
{
    int e;
    struct cdata_t *cd;

    cd = hmalloc(sizeof(*cd));
    memset(cd, 0, sizeof(*cd));

    pthread_mutex_init(&cd->mt, NULL);
    cd->name = hstrdup(name);
    cd->last_index = -1; // no data inserted yet
    cd->is_gauge = 0;

    if ((e = pthread_mutex_lock(&counterdata_mt))) {
        hlog(LOG_CRIT, "cdata_allocate: failed to lock counterdata_mt: %s", strerror(e));
        exit(1);
    }

    cd->next = counterdata;
    if (counterdata)
        counterdata->prevp = &cd->next;
    counterdata = cd;
    cd->prevp = &counterdata;

    if ((e = pthread_mutex_unlock(&counterdata_mt))) {
        hlog(LOG_CRIT, "cdata_allocate: could not unlock counterdata_mt: %s", strerror(e));
        exit(1);
    }

    //hlog(LOG_DEBUG, "cdata: allocated: %s", cd->name);

    return cd;
}
Beispiel #5
0
/*
 * classify by file name extensions
 */
HContents
uriclass(HConnect *hc, char *name)
{
	HContents conts;
	Suffix *s;
	HContent *type, *enc;
	char *buf, *p;

	type = nil;
	enc = nil;
	if((p = strrchr(name, '/')) != nil)
		name = p + 1;
	buf = hstrdup(hc, name);
	while((p = strrchr(buf, '.')) != nil){
		for(s = suffixes; s; s = s->next){
			if(strcmp(p, s->suffix) == 0){
				if(s->generic != nil && type == nil)
					type = hmkcontent(hc, s->generic, s->specific, nil);
				if(s->encoding != nil && enc == nil)
					enc = hmkcontent(hc, s->encoding, nil, nil);
			}
		}
		*p = 0;
	}
	conts.type = type;
	conts.encoding = enc;
	return conts;
}
Beispiel #6
0
static char*
getword(HConnect *c)
{
	char *buf;
	int ch, n;

	while((ch = getc(c)) == ' ' || ch == '\t' || ch == '\r')
		;
	if(ch == '\n')
		return nil;
	n = 0;
	buf = halloc(c, 1);
	for(;;){
		switch(ch){
		case ' ':
		case '\t':
		case '\r':
		case '\n':
			buf[n] = '\0';
			return hstrdup(c, buf);
		}

		if(n < HMaxWord-1){
			buf = bingrow(&c->bin, buf, n, n + 1, 0);
			if(buf == nil)
				return nil;
			buf[n++] = ch;
		}
		ch = getc(c);
	}
}
Beispiel #7
0
static Strings
parseuri(HConnect *c, char *uri)
{
    Strings ss;
    char *urihost, *p;

    urihost = nil;
    if(uri[0] != '/') {
        if(cistrncmp(uri, "http://", 7) != 0) {
            ss.s1 = nil;
            ss.s2 = nil;
            return ss;
        }
        uri += 5;	/* skip http: */
    }

    /*
     * anything starting with // is a host name or number
     * hostnames consists of letters, digits, - and .
     * for now, just ignore any port given
     */
    if(uri[0] == '/' && uri[1] == '/') {
        urihost = uri + 2;
        p = strchr(urihost, '/');
        if(p == nil)
            uri = hstrdup(c, "/");
        else {
            uri = hstrdup(c, p);
            *p = '\0';
        }
        p = strchr(urihost, ':');
        if(p != nil)
            *p = '\0';
    }

    if(uri[0] != '/' || uri[1] == '/') {
        ss.s1 = nil;
        ss.s2 = nil;
        return ss;
    }

    ss.s1 = uri;
    ss.s2 = hlower(urihost);
    return ss;
}
Beispiel #8
0
int do_string(char **dest, int argc, char **argv)
{
	if (argc < 2)
		return -1;
	if (*dest)
		hfree(*dest);
	*dest = hstrdup(argv[1]);
	return 0;
}
Beispiel #9
0
/*
 *  to circumscribe the accessible files we have to eliminate ..'s
 *  and resolve all names from the root.
 */
static char*
abspath(HConnect *cc, char *origpath, char *curdir)
{
	char *p, *sp, *path, *work, *rpath;
	int len, n, c;

	if(curdir == nil)
		curdir = "/";
	if(origpath == nil)
		origpath = "";
	work = hstrdup(cc, origpath);
	path = work;

	/*
	 * remove any really special characters
	 */
	for(sp = "`;|"; *sp; sp++){
		p = strchr(path, *sp);
		if(p)
			*p = 0;
	}

	len = strlen(curdir) + strlen(path) + 2 + UTFmax;
	if(len < 10)
		len = 10;
	rpath = halloc(cc, len);
	if(*path == '/')
		rpath[0] = 0;
	else
		strcpy(rpath, curdir);
	n = strlen(rpath);

	while(path){
		p = strchr(path, '/');
		if(p)
			*p++ = 0;
		if(strcmp(path, "..") == 0){
			while(n > 1){
				n--;
				c = rpath[n];
				rpath[n] = 0;
				if(c == '/')
					break;
			}
		}else if(strcmp(path, ".") == 0){
			;
		}else if(n == 1)
			n += snprint(rpath+n, len-n, "%s", path);
		else
			n += snprint(rpath+n, len-n, "/%s", path);
		path = p;
	}

	if(strncmp(rpath, "/bin/", 5) == 0)
		strcpy(rpath, "/");
	return rpath;
}
Beispiel #10
0
void login_set_app_name(struct client_t *c, const char *app_name, const char *app_ver)
{
#ifndef FIXED_IOBUFS
	c->app_name = hstrdup(app_name);
#else
	strncpy(c->app_name, app_name, sizeof(c->app_name));
	c->app_name[sizeof(c->app_name)-1] = 0;
#endif
	sanitize_ascii_string(c->app_name);
			
#ifndef FIXED_IOBUFS
	c->app_version = hstrdup(app_ver);
#else
	strncpy(c->app_version, app_ver, sizeof(c->app_version));
	c->app_version[sizeof(c->app_version)-1] = 0;
#endif
	sanitize_ascii_string(c->app_version);
}
Beispiel #11
0
void
hintprint(HConnect *hc, Hio *hout, char *uri, int thresh, int havej)
{
	int i, j, pr, prefix, fd, siz, havei, newhint = 0, n;
	char *query, *sf, etag[32], *wurl;
	Dir *dir;
	Hint *h, *haveh;

	query = hstrdup(hc, uri);
	urlcanon(query);
	j = urllookup(hashstr(query));
	if(j < 0)
		return;
	query = strrchr(uri,'/');
	if(!query)
		return;  /* can't happen */
	prefix = query-uri+1;  /* = strlen(dirname)+1 */
	h = hints[j];
	for(i=0; i<nhint[j]; i++){
		if(havej > 0 && havej < URLmax){ /* exclude hints client has */
			haveh = hints[havej];
			for(havei=0; havei<nhint[havej]; havei++)
				if( haveh[havei].url == h[i].url)
					goto continuei;
		}
		sf = urlname[h[i].url];
		pr = h[i].prob;
		if(pr<thresh)
			break;
		n = strlen(webroot) + strlen(sf) + 1;
		wurl = halloc(hc, n);
		strcpy(wurl, webroot);
		strcat(wurl, sf);
		fd = open(wurl, OREAD);
		if(fd<0)
			continue;
		dir = dirfstat(fd);
		if(dir == nil){
			close(fd);
			continue;
		}
		close(fd);
		snprint(etag, sizeof(etag), "\"%lluxv%lx\"", dir->qid.path, dir->qid.vers);
		siz = (int)( log((double)dir->length) * RECIPLOG2 + 0.9999);
		free(dir);
		if(strncmp(uri,sf,prefix)==0 && strchr(sf+prefix,'/')==0 && sf[prefix]!=0)
			sf = sf+prefix;
		hprint(hout, "Fresh: %d,%s,%d,%s\r\n", pr, etag, siz, sf);
		newhint++;
continuei: ;
	}
	if(newhint)
		hprint(hout, "Fresh: have/%d\r\n", j);
}
Beispiel #12
0
static void listener_copy_filters(struct listen_t *l, struct listen_config_t *lc)
{
	int i;
	char filter_s[FILTER_S_SIZE] = "";
	int filter_s_l = 0;
	
	for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) {
		if (l->filters[i]) {
			hfree(l->filters[i]);
			l->filters[i] = NULL;
		}
		
		if (i < (sizeof(lc->filters)/sizeof(lc->filters[0]))) {
			if (!lc->filters[i])
				continue;
				
			l->filters[i] = hstrdup(lc->filters[i]);
			
			int len = strlen(l->filters[i]);
			if (filter_s_l + len + 2 < FILTER_S_SIZE) {
				if (filter_s_l)
					filter_s[filter_s_l++] = ' ';
				
				memcpy(filter_s + filter_s_l, l->filters[i], len);
				filter_s_l += len;
				filter_s[filter_s_l] = 0;
			}
		}
	}
	
	if (l->filter_s) {
		hfree(l->filter_s);
		l->filter_s = NULL;
	}
	
	if (filter_s_l == 0)
		return;
		
	sanitize_ascii_string(filter_s);
	l->filter_s = hstrdup(filter_s);
}
Beispiel #13
0
struct status_error_t *status_error_find(const char *err)
{
	struct status_error_t *e;
	
	for (e = status_errs; (e); e = e->next) {
		if (strcmp(e->err, err) == 0)
			return e;
	}
	
	e = hmalloc(sizeof(*e));
	e->err = hstrdup(err);
	e->next = status_errs;
	e->set = -1;
	status_errs = e;
	
	return e;
}
Beispiel #14
0
int open_log(char *name, int reopen)
{
    if (!reopen)
        rwl_wrlock(&log_file_lock);

    if (log_name)
        hfree(log_name);

    if (!(log_name = hstrdup(name))) {
        fprintf(stderr, "aprsc logger: out of memory!\n");
        exit(1);
    }

    if (log_basename)
        hfree(log_basename);

    log_basename = hmalloc(strlen(log_name) + 5);
    sprintf(log_basename, "%s.log", log_name);

    if (log_dest == L_SYSLOG)
        openlog(name, LOG_NDELAY|LOG_PID, log_facility);

    if (log_dest == L_FILE) {
        if (log_fname)
            hfree(log_fname);

        log_fname = hmalloc(strlen(log_dir) + strlen(log_basename) + 2);
        sprintf(log_fname, "%s/%s", log_dir, log_basename);

        log_file = open(log_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
        if (log_file < 0) {
            fprintf(stderr, "aprsc logger: Could not open %s: %s\n", log_fname, strerror(errno));
            exit(1);
        }
    }

    rwl_wrunlock(&log_file_lock);

    if (log_dest == L_FILE)
        hlog(LOG_DEBUG, "Log file %s %sopened on fd %d", log_fname, (reopen) ? "re" : "", log_file);

    return 0;
}
Beispiel #15
0
int close_log(int reopen)
{
    hlog(LOG_DEBUG, "close_log");

    char *s = NULL;
    if (log_name)
        s = hstrdup(log_name);

    rwl_wrlock(&log_file_lock);

    if (log_name) {
        hfree(log_name);
        log_name = NULL;
    }

    if (log_dest == L_SYSLOG) {
        closelog();
    } else if (log_dest == L_FILE) {
        if (log_file >= 0) {
            if (close(log_file))
                fprintf(stderr, "aprsc logger: Could not close log file %s: %s\n", log_fname, strerror(errno));
            log_file = -1;
        }
        if (log_fname) {
            hfree(log_fname);
            log_fname = NULL;
        }
    }

    if (reopen && s)
        open_log(s, 1);

    if (!reopen)
        rwl_wrunlock(&log_file_lock);

    if (s)
        hfree(s);

    return 0;
}
Beispiel #16
0
int accesslog_open(char *logd, int reopen)
{
    if (!reopen)
        rwl_wrlock(&accesslog_lock);

    if (accesslog_fname)
        hfree(accesslog_fname);

    if (accesslog_dir)
        hfree(accesslog_dir);

    accesslog_dir = hstrdup(logd);
    accesslog_fname = hmalloc(strlen(accesslog_dir) + strlen(accesslog_basename) + 2);
    sprintf(accesslog_fname, "%s/%s", accesslog_dir, accesslog_basename);

    accesslog_file = open(accesslog_fname, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP);
    if (accesslog_file < 0)
        hlog(LOG_CRIT, "Could not open %s: %s", accesslog_fname, strerror(errno));

    rwl_wrunlock(&accesslog_lock);

    return accesslog_file;
}
Beispiel #17
0
char *status_json_string(int no_cache, int periodical)
{
	char *out = NULL;
	int pe;
	
	/* if we have a very recent status JSON available, return it instead. */
	if (!no_cache) {
		if ((pe = pthread_mutex_lock(&status_json_mt))) {
			hlog(LOG_ERR, "status_json_string(): could not lock status_json_mt: %s", strerror(pe));
			return NULL;
		}
		if (status_json_cached && (status_json_cache_t == tick || status_json_cache_t == tick - 1)) {
			out = hstrdup(status_json_cached);
			if ((pe = pthread_mutex_unlock(&status_json_mt))) {
				hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe));
				hfree(out);
				return NULL;
			}
			return out;
		}
		if ((pe = pthread_mutex_unlock(&status_json_mt))) {
			hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe));
			return NULL;
		}
	}
	
	/* Ok, go and build the JSON tree */
	cJSON *root = cJSON_CreateObject();
	if (http_status_options)
		cJSON_AddStringToObject(root, "status_options", http_status_options);
	status_check_motd(root);
	
	cJSON *server = cJSON_CreateObject();
	cJSON_AddStringToObject(server, "server_id", serverid);
	cJSON_AddStringToObject(server, "admin", myadmin);
	cJSON_AddStringToObject(server, "email", myemail);
	cJSON_AddStringToObject(server, "software", PROGNAME);
	cJSON_AddStringToObject(server, "software_version", version_build);
	cJSON_AddStringToObject(server, "software_build_time", verstr_build_time);
	cJSON_AddStringToObject(server, "software_build_user", verstr_build_user);
	cJSON_AddStringToObject(server, "software_build_features", verstr_features);
	cJSON_AddNumberToObject(server, "uptime", tick - startup_tick);
	cJSON_AddNumberToObject(server, "tick_now", tick);
	cJSON_AddNumberToObject(server, "time_now", now);
	cJSON_AddNumberToObject(server, "time_started", startup_time);
	status_uname(server);
	cJSON_AddItemToObject(root, "server", server);
	
	cJSON *memory = cJSON_CreateObject();
#ifndef _FOR_VALGRIND_
	struct cellstatus_t cellst;
	historydb_cell_stats(&cellst), 
	cJSON_AddNumberToObject(memory, "historydb_cells_used", historydb_cellgauge);
	cJSON_AddNumberToObject(memory, "historydb_cells_free", cellst.freecount);
	cJSON_AddNumberToObject(memory, "historydb_used_bytes", historydb_cellgauge*cellst.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "historydb_allocated_bytes", (long)cellst.blocks * (long)cellst.block_size);
	cJSON_AddNumberToObject(memory, "historydb_block_size", (long)cellst.block_size);
	cJSON_AddNumberToObject(memory, "historydb_blocks", (long)cellst.blocks);
	cJSON_AddNumberToObject(memory, "historydb_blocks_max", (long)cellst.blocks_max);
	cJSON_AddNumberToObject(memory, "historydb_cell_size", cellst.cellsize);
	cJSON_AddNumberToObject(memory, "historydb_cell_size_aligned", cellst.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "historydb_cell_align", cellst.alignment);
	
	dupecheck_cell_stats(&cellst), 
	cJSON_AddNumberToObject(memory, "dupecheck_cells_used", dupecheck_cellgauge);
	cJSON_AddNumberToObject(memory, "dupecheck_cells_free", cellst.freecount);
	cJSON_AddNumberToObject(memory, "dupecheck_used_bytes", dupecheck_cellgauge*cellst.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "dupecheck_allocated_bytes", (long)cellst.blocks * (long)cellst.block_size);
	cJSON_AddNumberToObject(memory, "dupecheck_block_size", (long)cellst.block_size);
	cJSON_AddNumberToObject(memory, "dupecheck_blocks", (long)cellst.blocks);
	cJSON_AddNumberToObject(memory, "dupecheck_blocks_max", (long)cellst.blocks_max);
	cJSON_AddNumberToObject(memory, "dupecheck_cell_size", cellst.cellsize);
	cJSON_AddNumberToObject(memory, "dupecheck_cell_size_aligned", cellst.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "dupecheck_cell_align", cellst.alignment);
	
	struct cellstatus_t cellst_filter, cellst_filter_wx, cellst_filter_entrycall;
	filter_cell_stats(&cellst_filter, &cellst_filter_entrycall, &cellst_filter_wx),
	cJSON_AddNumberToObject(memory, "filter_cells_used", filter_cellgauge);
	cJSON_AddNumberToObject(memory, "filter_cells_free", cellst_filter.freecount);
	cJSON_AddNumberToObject(memory, "filter_used_bytes", filter_cellgauge*cellst_filter.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_allocated_bytes", (long)cellst_filter.blocks * (long)cellst_filter.block_size);
	cJSON_AddNumberToObject(memory, "filter_block_size", (long)cellst_filter.block_size);
	cJSON_AddNumberToObject(memory, "filter_blocks", (long)cellst_filter.blocks);
	cJSON_AddNumberToObject(memory, "filter_blocks_max", (long)cellst_filter.blocks_max);
	cJSON_AddNumberToObject(memory, "filter_cell_size", cellst_filter.cellsize);
	cJSON_AddNumberToObject(memory, "filter_cell_size_aligned", cellst_filter.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_cell_align", cellst_filter.alignment);
	
	cJSON_AddNumberToObject(memory, "filter_wx_cells_used", filter_wx_cellgauge);
	cJSON_AddNumberToObject(memory, "filter_wx_cells_free", cellst_filter_wx.freecount);
	cJSON_AddNumberToObject(memory, "filter_wx_used_bytes", filter_wx_cellgauge*cellst_filter_wx.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_wx_allocated_bytes", (long)cellst_filter_wx.blocks * (long)cellst_filter_wx.block_size);
	cJSON_AddNumberToObject(memory, "filter_wx_block_size", (long)cellst_filter_wx.block_size);
	cJSON_AddNumberToObject(memory, "filter_wx_blocks", (long)cellst_filter_wx.blocks);
	cJSON_AddNumberToObject(memory, "filter_wx_blocks_max", (long)cellst_filter_wx.blocks_max);
	cJSON_AddNumberToObject(memory, "filter_wx_cell_size", cellst_filter_wx.cellsize);
	cJSON_AddNumberToObject(memory, "filter_wx_cell_size_aligned", cellst_filter_wx.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_wx_cell_align", cellst_filter_wx.alignment);
	
	cJSON_AddNumberToObject(memory, "filter_entrycall_cells_used", filter_entrycall_cellgauge);
	cJSON_AddNumberToObject(memory, "filter_entrycall_cells_free", cellst_filter_entrycall.freecount);
	cJSON_AddNumberToObject(memory, "filter_entrycall_used_bytes", filter_entrycall_cellgauge*cellst_filter_entrycall.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_entrycall_allocated_bytes", (long)cellst_filter_entrycall.blocks * (long)cellst_filter_entrycall.block_size);
	cJSON_AddNumberToObject(memory, "filter_entrycall_block_size", (long)cellst_filter_entrycall.block_size);
	cJSON_AddNumberToObject(memory, "filter_entrycall_blocks", (long)cellst_filter_entrycall.blocks);
	cJSON_AddNumberToObject(memory, "filter_entrycall_blocks_max", (long)cellst_filter_entrycall.blocks_max);
	cJSON_AddNumberToObject(memory, "filter_entrycall_cell_size", cellst_filter_entrycall.cellsize);
	cJSON_AddNumberToObject(memory, "filter_entrycall_cell_size_aligned", cellst_filter_entrycall.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "filter_entrycall_cell_align", cellst_filter_entrycall.alignment);
	
	struct cellstatus_t cellst_pbuf_small, cellst_pbuf_medium, cellst_pbuf_large;
	incoming_cell_stats(&cellst_pbuf_small, &cellst_pbuf_medium, &cellst_pbuf_large);
	cJSON_AddNumberToObject(memory, "pbuf_small_cells_used", cellst_pbuf_small.cellcount - cellst_pbuf_small.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_small_cells_free", cellst_pbuf_small.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_small_cells_alloc", cellst_pbuf_small.cellcount);
	cJSON_AddNumberToObject(memory, "pbuf_small_used_bytes", (cellst_pbuf_small.cellcount - cellst_pbuf_small.freecount)*cellst_pbuf_small.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_small_allocated_bytes", (long)cellst_pbuf_small.blocks * (long)cellst_pbuf_small.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_small_block_size", (long)cellst_pbuf_small.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_small_blocks", (long)cellst_pbuf_small.blocks);
	cJSON_AddNumberToObject(memory, "pbuf_small_blocks_max", (long)cellst_pbuf_small.blocks_max);
	cJSON_AddNumberToObject(memory, "pbuf_small_cell_size", cellst_pbuf_small.cellsize);
	cJSON_AddNumberToObject(memory, "pbuf_small_cell_size_aligned", cellst_pbuf_small.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_small_cell_align", cellst_pbuf_small.alignment);
	
	cJSON_AddNumberToObject(memory, "pbuf_medium_cells_used", cellst_pbuf_medium.cellcount - cellst_pbuf_medium.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_medium_cells_free", cellst_pbuf_medium.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_medium_cells_alloc", cellst_pbuf_medium.cellcount);
	cJSON_AddNumberToObject(memory, "pbuf_medium_used_bytes", (cellst_pbuf_medium.cellcount - cellst_pbuf_medium.freecount)*cellst_pbuf_medium.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_medium_allocated_bytes", (long)cellst_pbuf_medium.blocks * (long)cellst_pbuf_medium.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_medium_block_size", (long)cellst_pbuf_medium.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_medium_blocks", (long)cellst_pbuf_medium.blocks);
	cJSON_AddNumberToObject(memory, "pbuf_medium_blocks_max", (long)cellst_pbuf_medium.blocks_max);
	cJSON_AddNumberToObject(memory, "pbuf_medium_cell_size", cellst_pbuf_medium.cellsize);
	cJSON_AddNumberToObject(memory, "pbuf_medium_cell_size_aligned", cellst_pbuf_medium.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_medium_cell_align", cellst_pbuf_medium.alignment);
	
	cJSON_AddNumberToObject(memory, "pbuf_large_cells_used", cellst_pbuf_large.cellcount - cellst_pbuf_large.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_large_cells_free", cellst_pbuf_large.freecount);
	cJSON_AddNumberToObject(memory, "pbuf_large_cells_alloc", cellst_pbuf_large.cellcount);
	cJSON_AddNumberToObject(memory, "pbuf_large_used_bytes", (cellst_pbuf_large.cellcount - cellst_pbuf_large.freecount)*cellst_pbuf_large.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_large_allocated_bytes", (long)cellst_pbuf_large.blocks * (long)cellst_pbuf_large.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_large_block_size", (long)cellst_pbuf_large.block_size);
	cJSON_AddNumberToObject(memory, "pbuf_large_blocks", (long)cellst_pbuf_large.blocks);
	cJSON_AddNumberToObject(memory, "pbuf_large_blocks_max", (long)cellst_pbuf_large.blocks_max);
	cJSON_AddNumberToObject(memory, "pbuf_large_cell_size", cellst_pbuf_large.cellsize);
	cJSON_AddNumberToObject(memory, "pbuf_large_cell_size_aligned", cellst_pbuf_large.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "pbuf_large_cell_align", cellst_pbuf_large.alignment);
	
	struct cellstatus_t cellst_client_heard;
	client_heard_cell_stats(&cellst_client_heard);
	cJSON_AddNumberToObject(memory, "client_heard_cells_used", cellst_client_heard.cellcount - cellst_client_heard.freecount);
	cJSON_AddNumberToObject(memory, "client_heard_cells_free", cellst_client_heard.freecount);
	cJSON_AddNumberToObject(memory, "client_heard_cells_alloc", cellst_client_heard.cellcount);
	cJSON_AddNumberToObject(memory, "client_heard_used_bytes", (cellst_client_heard.cellcount - cellst_client_heard.freecount)*cellst_client_heard.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "client_heard_allocated_bytes", (long)cellst_client_heard.blocks * (long)cellst_client_heard.block_size);
	cJSON_AddNumberToObject(memory, "client_heard_block_size", (long)cellst_client_heard.block_size);
	cJSON_AddNumberToObject(memory, "client_heard_blocks", (long)cellst_client_heard.blocks);
	cJSON_AddNumberToObject(memory, "client_heard_blocks_max", (long)cellst_client_heard.blocks_max);
	cJSON_AddNumberToObject(memory, "client_heard_cell_size", cellst_client_heard.cellsize);
	cJSON_AddNumberToObject(memory, "client_heard_cell_size_aligned", cellst_client_heard.cellsize_aligned);
	cJSON_AddNumberToObject(memory, "client_heard_cell_align", cellst_client_heard.alignment);
#endif
	
	cJSON_AddItemToObject(root, "memory", memory);
	
	cJSON *historydb = cJSON_CreateObject();
	cJSON_AddNumberToObject(historydb, "inserts", historydb_inserts);
	cJSON_AddNumberToObject(historydb, "lookups", historydb_lookups);
	cJSON_AddNumberToObject(historydb, "hashmatches", historydb_hashmatches);
	cJSON_AddNumberToObject(historydb, "keymatches", historydb_keymatches);
	cJSON_AddNumberToObject(historydb, "noposcount", historydb_noposcount);
	cJSON_AddNumberToObject(historydb, "cleaned", historydb_cleanup_cleaned);
	cJSON_AddItemToObject(root, "historydb", historydb);
	
	cJSON *dupecheck = cJSON_CreateObject();
	cJSON_AddNumberToObject(dupecheck, "dupes_dropped", dupecheck_dupecount);
	cJSON_AddNumberToObject(dupecheck, "uniques_out", dupecheck_outcount);
	cJSON_AddItemToObject(root, "dupecheck", dupecheck);
	
	cJSON *dupe_vars = cJSON_CreateObject();
	cJSON_AddNumberToObject(dupe_vars, "exact", dupecheck_dupetypes[0]);
	cJSON_AddNumberToObject(dupe_vars, "space_trim", dupecheck_dupetypes[DTYPE_SPACE_TRIM]);
	cJSON_AddNumberToObject(dupe_vars, "8bit_strip", dupecheck_dupetypes[DTYPE_STRIP_8BIT]);
	cJSON_AddNumberToObject(dupe_vars, "8bit_clear", dupecheck_dupetypes[DTYPE_CLEAR_8BIT]);
	cJSON_AddNumberToObject(dupe_vars, "8bit_spaced", dupecheck_dupetypes[DTYPE_SPACED_8BIT]);
	cJSON_AddNumberToObject(dupe_vars, "low_strip", dupecheck_dupetypes[DTYPE_LOWDATA_STRIP]);
	cJSON_AddNumberToObject(dupe_vars, "low_spaced", dupecheck_dupetypes[DTYPE_LOWDATA_SPACED]);
	cJSON_AddNumberToObject(dupe_vars, "del_strip", dupecheck_dupetypes[DTYPE_DEL_STRIP]);
	cJSON_AddNumberToObject(dupe_vars, "del_spaced", dupecheck_dupetypes[DTYPE_DEL_SPACED]);
	cJSON_AddItemToObject(dupecheck, "variations", dupe_vars);
	
	cJSON *json_totals = cJSON_CreateObject();
	cJSON *json_listeners = cJSON_CreateArray();
	accept_listener_status(json_listeners, json_totals);
	cJSON_AddItemToObject(root, "totals", json_totals);
	cJSON_AddItemToObject(root, "listeners", json_listeners);
	
	cJSON *json_clients = cJSON_CreateArray();
	cJSON *json_uplinks = cJSON_CreateArray();
	cJSON *json_peers = cJSON_CreateArray();
	cJSON *json_workers = cJSON_CreateArray();
	worker_client_list(json_workers, json_clients, json_uplinks, json_peers, json_totals, memory);
	cJSON_AddItemToObject(root, "workers", json_workers);
	cJSON_AddItemToObject(root, "uplinks", json_uplinks);
	cJSON_AddItemToObject(root, "peers", json_peers);
	cJSON_AddItemToObject(root, "clients", json_clients);
	
	/* if this is a periodical per-minute dump, collect historical data */
	if (periodical) {
		cJSON *ct, *cv;
		struct cdata_list_t *cl;
		for (cl = cdata_list; (cl); cl = cl->next) {
			ct = cJSON_GetObjectItem(root, cl->tree);
			if (!ct)
				continue;
				
			cv = cJSON_GetObjectItem(ct, cl->name);
			
			/* cJSON's cv->valueint is just an integer, which will overflow
			 * too quickly. So, let's take the more expensive valuedouble.
			 */
			if (cl->gauge)
				cdata_gauge_sample(cl->cd, (cv) ? cv->valuedouble : -1);
			else
				cdata_counter_sample(cl->cd, (cv) ? cv->valuedouble : -1);
		}
	}
	
	cJSON_AddNumberToObject(json_totals, "tcp_bytes_rx_rate", cdata_get_last_value("totals.tcp_bytes_rx") / CDATA_INTERVAL);
	cJSON_AddNumberToObject(json_totals, "tcp_bytes_tx_rate", cdata_get_last_value("totals.tcp_bytes_tx") / CDATA_INTERVAL);
	cJSON_AddNumberToObject(json_totals, "udp_bytes_rx_rate", cdata_get_last_value("totals.udp_bytes_rx") / CDATA_INTERVAL);
	cJSON_AddNumberToObject(json_totals, "udp_bytes_tx_rate", cdata_get_last_value("totals.udp_bytes_tx") / CDATA_INTERVAL);
	cJSON_AddNumberToObject(json_totals, "bytes_rx_rate", (cdata_get_last_value("totals.tcp_bytes_rx") + cdata_get_last_value("totals.udp_bytes_rx")) / CDATA_INTERVAL);
	cJSON_AddNumberToObject(json_totals, "bytes_tx_rate", (cdata_get_last_value("totals.tcp_bytes_tx") + cdata_get_last_value("totals.udp_bytes_tx")) / CDATA_INTERVAL);
	
	cJSON *json_rx_errs = cJSON_CreateStringArray(inerr_labels, INERR_BUCKETS);
	cJSON_AddItemToObject(root, "rx_errs", json_rx_errs);
	
	cJSON_AddItemToObject(root, "alarms", status_error_json());
	
	/* the tree is built, print it out to a malloc'ed string */
	out = cJSON_Print(root);
	cJSON_Delete(root);
	
	/* cache it */
	if ((pe = pthread_mutex_lock(&status_json_mt))) {
		hlog(LOG_ERR, "status_json_string(): could not lock status_json_mt: %s", strerror(pe));
                                return NULL;
	}
	if (status_json_cached)
		hfree(status_json_cached);
		
	status_json_cached = hstrdup(out);
	status_json_cache_t = tick;
	
	if ((pe = pthread_mutex_unlock(&status_json_mt))) {
		hlog(LOG_ERR, "status_json_string(): could not unlock status_json_mt: %s", strerror(pe));
		return NULL;
	}
	
	return out;
}
Beispiel #18
0
static int accept_liveupgrade_single(cJSON *client, int *rxerr_map, int rxerr_map_len)
{
	cJSON *fd, *listener_id, *username, *time_connect, *tick_connect;
	cJSON *state;
	cJSON *addr_loc;
	cJSON *udp_port;
	cJSON *app_name, *app_version;
	cJSON *verified;
	cJSON *obuf_q;
	cJSON *bytes_rx, *bytes_tx;
	cJSON *pkts_rx, *pkts_tx, *pkts_ign;
	cJSON *rx_errs;
	cJSON *filter;
	cJSON *ibuf, *obuf;
	cJSON *client_heard;
	cJSON *lat, *lng;
	unsigned addr_len;
	union sockaddr_u sa;
	char *argv[256];
	int i, argc;
	const char *username_s = "unknown";
	
	/* get username first, so we can log it later */
	username = accept_liveupgrade_cJSON_get(client, "username", cJSON_String, username_s);
	if (username)
		username_s = username->valuestring;
	
	fd = accept_liveupgrade_cJSON_get(client, "fd", cJSON_Number, username_s);
	int fd_i = -1;
	if (fd)
		fd_i = fd->valueint;
		
	if (fd_i < 0) {
		hlog(LOG_INFO, "Live upgrade: Client '%s' has negative fd %d, ignoring (corepeer?)", username_s, fd_i);
		return -1;
	}
	
	listener_id = accept_liveupgrade_cJSON_get(client, "listener_id", cJSON_Number, username_s);
	state = accept_liveupgrade_cJSON_get(client, "state", cJSON_String, username_s);
	time_connect = accept_liveupgrade_cJSON_get(client, "t_connect", cJSON_Number, username_s);
	addr_loc = accept_liveupgrade_cJSON_get(client, "addr_loc", cJSON_String, username_s);
	app_name = accept_liveupgrade_cJSON_get(client, "app_name", cJSON_String, username_s);
	app_version = accept_liveupgrade_cJSON_get(client, "app_version", cJSON_String, username_s);
	verified = accept_liveupgrade_cJSON_get(client, "verified", cJSON_Number, username_s);
	obuf_q = accept_liveupgrade_cJSON_get(client, "obuf_q", cJSON_Number, username_s);
	bytes_rx = accept_liveupgrade_cJSON_get(client, "bytes_rx", cJSON_Number, username_s);
	bytes_tx = accept_liveupgrade_cJSON_get(client, "bytes_tx", cJSON_Number, username_s);
	pkts_rx = accept_liveupgrade_cJSON_get(client, "pkts_rx", cJSON_Number, username_s);
	pkts_tx = accept_liveupgrade_cJSON_get(client, "pkts_tx", cJSON_Number, username_s);
	pkts_ign = accept_liveupgrade_cJSON_get(client, "pkts_ign", cJSON_Number, username_s);
	rx_errs = accept_liveupgrade_cJSON_get(client, "rx_errs", cJSON_Array, username_s);
	filter = accept_liveupgrade_cJSON_get(client, "filter", cJSON_String, username_s);
	
	/* optional */
	tick_connect = cJSON_GetObjectItem(client, "t_connect_tick");
	udp_port = cJSON_GetObjectItem(client, "udp_port");
	ibuf = cJSON_GetObjectItem(client, "ibuf");
	obuf = cJSON_GetObjectItem(client, "obuf");
	client_heard = cJSON_GetObjectItem(client, "client_heard");
	lat = cJSON_GetObjectItem(client, "lat");
	lng = cJSON_GetObjectItem(client, "lng");
	
	if (!(
		(fd)
		&& (listener_id)
		&& (state)
		&& (username)
		&& (time_connect)
		&& (addr_loc)
		&& (app_name)
		&& (app_version)
		&& (verified)
		&& (obuf_q)
		&& (bytes_rx)
		&& (bytes_tx)
		&& (pkts_rx)
		&& (pkts_tx)
		&& (pkts_ign)
		&& (rx_errs)
		&& (filter)
		)) {
			hlog(LOG_ERR, "Live upgrade: Fields missing from client JSON, discarding client fd %d", fd_i);
			if (fd_i >= 0)
				close(fd_i);
			return -1;
	}
	
	hlog(LOG_DEBUG, "Old client on fd %d: %s", fd->valueint, username->valuestring);
	
	/* fetch peer address from the fd instead of parsing it from text */
	addr_len = sizeof(sa);
	if (getpeername(fd->valueint, &sa.sa, &addr_len) != 0) {
		/* Sometimes clients disconnect during upgrade, especially on slow RPi servers... */
		if (errno == ENOTCONN)
			hlog(LOG_INFO, "Live upgrade: Client %s on fd %d has disconnected during upgrade (%s)",
				username->valuestring, fd->valueint, strerror(errno));
		else
			hlog(LOG_ERR, "Live upgrade: getpeername client fd %d failed: %s", fd->valueint, strerror(errno));
		close(fd->valueint);
		return -1;
	}
	
	/* convert client address to string */
	char *client_addr_s = strsockaddr( &sa.sa, addr_len );
	
	/* find the right listener for this client, for configuration and accounting */
	struct listen_t *l = liveupgrade_find_listener(listener_id->valueint);
	if (!l) {
		hlog(LOG_INFO, "Live upgrade: Listener has been removed for fd %d (%s - local %s): disconnecting %s",
			fd->valueint, client_addr_s, addr_loc->valuestring, username->valuestring);
		close(fd->valueint);
		hfree(client_addr_s);
		return -1;
	}
	
	struct client_t *c = accept_client_for_listener(l, fd->valueint, client_addr_s, &sa, addr_len);
	if (!c) {
		hlog(LOG_ERR, "Live upgrade - client_alloc returned NULL, too many clients. Denied client %s on fd %d from %s",
			username->valuestring, fd->valueint, client_addr_s);
		close(fd->valueint);
		hfree(client_addr_s);
		return -1;
	}
	
	hfree(client_addr_s);
	
	if (strcmp(state->valuestring, "connected") == 0) {
		c->state   = CSTATE_CONNECTED;
		c->handler_line_in = &incoming_handler;
		strncpy(c->username, username->valuestring, sizeof(c->username));
		c->username[sizeof(c->username)-1] = 0;
		c->username_len = strlen(c->username);
	} else if (strcmp(state->valuestring, "login") == 0) {
		c->state   = CSTATE_LOGIN;
		c->handler_line_in = &login_handler;
	} else {
		hlog(LOG_ERR, "Live upgrade: Client %s is in invalid state '%s' (fd %d)", l->addr_s, state->valuestring, l->fd);
		goto err;
	}
	/* distribute keepalive intervals for the existing old clients
	 * but send them rather sooner than later */
	// coverity[dont_call]  // squelch warning: not security sensitive use of random(): load distribution
	c->keepalive = tick + (random() % (keepalive_interval/2));
	/* distribute cleanup intervals over the next 2 minutes */
	// coverity[dont_call]  // squelch warning: not security sensitive use of random(): load distribution
	c->cleanup = tick + (random() % 120);
	
	c->connect_time = time_connect->valueint;
	/* live upgrade / backward compatibility: upgrading from <= 1.8.2 requires the 'else' path' */
	if (tick_connect && tick_connect->type == cJSON_Number)
		c->connect_tick = tick_connect->valueint;
	else /* convert to monotonic time */
		c->connect_tick = tick - (now - c->connect_time);
	
	c->validated = verified->valueint;
	c->localaccount.rxbytes = bytes_rx->valuedouble;
	c->localaccount.txbytes = bytes_tx->valuedouble;
	c->localaccount.rxpackets = pkts_rx->valuedouble;
	c->localaccount.txpackets = pkts_tx->valuedouble;
	c->localaccount.rxdrops = pkts_ign->valuedouble;
	
	login_set_app_name(c, app_name->valuestring, app_version->valuestring);
	
	// handle client's filter setting
	if (c->flags & CLFLAGS_USERFILTEROK && (filter) && (filter->valuestring) && *(filter->valuestring)) {
		// archive a copy of the filters, for status display
		strncpy(c->filter_s, filter->valuestring, FILTER_S_SIZE);
		c->filter_s[FILTER_S_SIZE-1] = 0;
		sanitize_ascii_string(c->filter_s);
		
		char *f = hstrdup(filter->valuestring);
		argc = parse_args(argv, f);
		for (i = 0; i < argc; ++i) {
			filter_parse(c, argv[i], 1);
		}
		hfree(f);
	}
	
	// set up UDP downstream if necessary
	if (udp_port && udp_port->type == cJSON_Number && udp_port->valueint > 1024 && udp_port->valueint < 65536) {
		if (login_setup_udp_feed(c, udp_port->valueint) != 0) {
			hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, c->username);
		}
	}
	
	// fill up ibuf
	if (ibuf && ibuf->type == cJSON_String && ibuf->valuestring) {
		int l = hex_decode(c->ibuf, c->ibuf_size, ibuf->valuestring);
		if (l < 0) {
			hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode ibuf: %s", c->addr_rem, c->username, ibuf->valuestring);
		} else {
			c->ibuf_end = l;
			hlog(LOG_DEBUG, "Live upgrade: Decoded ibuf %d bytes: '%.*s'", l, l, c->ibuf);
			hlog(LOG_DEBUG, "Hex: %s", ibuf->valuestring);
		}
	}
	
	// fill up obuf
	if (obuf && obuf->type == cJSON_String && obuf->valuestring) {
		int l = hex_decode(c->obuf, c->obuf_size, obuf->valuestring);
		if (l < 0) {
			hlog(LOG_ERR, "Live upgrade: %s/%s: Failed to decode obuf: %s", c->addr_rem, c->username, obuf->valuestring);
		} else {
			c->obuf_start = 0;
			c->obuf_end = l;
			hlog(LOG_DEBUG, "Live upgrade: Decoded obuf %d bytes: '%.*s'", l, l, c->obuf);
			hlog(LOG_DEBUG, "Hex: %s", obuf->valuestring);
		}
	}
	
	/* load list of stations heard by this client, to immediately support
	 * messaging
	 */
	if (client_heard && client_heard->type == cJSON_Array)
		client_heard_json_load(c, client_heard);
	
	/* load rxerrs counters, with error name string mapping to support
	 * adding/reordering of error counters
	 */
	if (rx_errs && rx_errs->type == cJSON_Array && rxerr_map && rxerr_map_len > 0)
		accept_rx_err_load(c, rx_errs, rxerr_map, rxerr_map_len);
	
	/* set client lat/lon, if they're given
	 */
	if (lat && lng && lat->type == cJSON_Number && lng->type == cJSON_Number) {
		c->loc_known = 1;
		c->lat = lat->valuedouble;
		c->lng = lng->valuedouble;
	}
	
	hlog(LOG_DEBUG, "%s - Accepted live upgrade client on fd %d from %s", c->addr_loc, c->fd, c->addr_rem);
	
	/* set client socket options, return -1 on serious errors */
	if (set_client_sockopt(c) != 0)
		goto err;
	
	/* Add the client to the client list. */
	int old_fd = clientlist_add(c);
	if (c->validated && old_fd != -1) {
		/* TODO: If old connection is SSL validated, and this one is not, do not disconnect it. */
		hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, c->username);
		shutdown(old_fd, SHUT_RDWR);
	}
	
	/* ok, found it... lock the new client queue and pass the client */
	if (pass_client_to_worker(pick_next_worker(), c))
		goto err;
	
	return 0;
	
err:
	close(c->fd);
	inbound_connects_account(0, c->portaccount); /* something failed, remove this from accounts.. */
	client_free(c);
	return -1;
}
Beispiel #19
0
static int open_listener(struct listen_config_t *lc)
{
	struct listen_t *l;
	int i;
	
	l = listener_alloc();
	l->id = lc->id;
	l->hidden = lc->hidden;
	l->corepeer = lc->corepeer;
	l->client_flags = lc->client_flags;
	l->clients_max = lc->clients_max;
	
	l->portaccount = port_accounter_alloc();
	
	/* Pick first of the AIs for this listen definition */
	l->addr_s = strsockaddr( lc->ai->ai_addr, lc->ai->ai_addrlen );
	l->name   = hstrdup(lc->name);
	l->portnum = lc->portnum;
	l->ai_protocol = lc->ai->ai_protocol;
	l->listener_id = keyhash(l->addr_s, strlen(l->addr_s), 0);
	l->listener_id = keyhash(&lc->ai->ai_socktype, sizeof(lc->ai->ai_socktype), l->listener_id);
	l->listener_id = keyhash(&lc->ai->ai_protocol, sizeof(lc->ai->ai_protocol), l->listener_id);
	hlog(LOG_DEBUG, "Opening listener %d/%d '%s': %s", lc->id, l->listener_id, lc->name, l->addr_s);
	
	if (lc->ai->ai_socktype == SOCK_DGRAM &&
	    lc->ai->ai_protocol == IPPROTO_UDP) {
		/* UDP listenting is not quite same as TCP listening.. */
		i = open_udp_listener(l, lc->ai);
	} else if (lc->ai->ai_socktype == SOCK_STREAM && lc->ai->ai_protocol == IPPROTO_TCP) {
		/* TCP listenting... */
		i = open_tcp_listener(l, lc->ai, "TCP");
#ifdef USE_SCTP
	} else if (lc->ai->ai_socktype == SOCK_STREAM &&
		   lc->ai->ai_protocol == IPPROTO_SCTP) {
		i = open_tcp_listener(l, lc->ai, "SCTP");
		if (i >= 0)
			i = sctp_set_listen_params(l);
#endif
	} else {
		hlog(LOG_ERR, "Unsupported listener protocol for '%s'", l->name);
		listener_free(l);
		return -1;
	}
	
	if (i < 0) {
		hlog(LOG_DEBUG, "... failed");
		listener_free(l);
		return -1;
	}
	
	hlog(LOG_DEBUG, "... ok, bound");
	
	/* Set up an SSL context if necessary */
#ifdef USE_SSL
	if (lc->keyfile && lc->certfile) {
		l->ssl = ssl_alloc();
		
		if (ssl_create(l->ssl, (void *)l)) {
			hlog(LOG_ERR, "Failed to create SSL context for '%s*': %s", lc->name, l->addr_s);
			listener_free(l);
			return -1;
		}
		
		if (ssl_certificate(l->ssl, lc->certfile, lc->keyfile)) {
			hlog(LOG_ERR, "Failed to load SSL key and certificates for '%s*': %s", lc->name, l->addr_s);
			listener_free(l);
			return -1;
		}
		
		/* optional client cert validation */
		if (lc->cafile) {
			if (ssl_ca_certificate(l->ssl, lc->cafile, 2)) {
				hlog(LOG_ERR, "Failed to load trusted SSL CA certificates for '%s*': %s", lc->name, l->addr_s);
				listener_free(l);
				return -1;
			}
		}
		
		hlog(LOG_INFO, "SSL initialized for '%s': %s%s", lc->name, l->addr_s, (lc->cafile) ? " (client validation enabled)" : "");
	}
#endif
	
	/* Copy access lists */
	if (lc->acl)
		l->acl = acl_dup(lc->acl);
	
	/* Copy filter definitions */
	listener_copy_filters(l, lc);
	
	hlog(LOG_DEBUG, "... adding %s to listened sockets", l->addr_s);
	// put (first) in the list of listening sockets
	l->next = listen_list;
	l->prevp = &listen_list;
	if (listen_list)
		listen_list->prevp = &l->next;
	listen_list = l;
	
	return 0;
}
Beispiel #20
0
int login_handler(struct worker_t *self, struct client_t *c, int l4proto, char *s, int len)
{
	int argc;
	char *argv[256];
	int i, rc;
	
	/* make it null-terminated for our string processing */
	char *e = s + len;
	*e = 0;
	hlog(LOG_DEBUG, "%s: login string: '%s' (%d)", c->addr_rem, s, len);
	
	/* parse to arguments */
	if ((argc = parse_args_noshell(argv, s)) == 0 || *argv[0] == '#')
		return 0;
	
	if (argc < 2) {
		hlog(LOG_WARNING, "%s: Invalid login string, too few arguments: '%s'", c->addr_rem, s);
		rc = client_printf(self, c, "# Invalid login string, too few arguments\r\n");
		goto failed_login;
	}
	
	if (strcasecmp(argv[0], "user") != 0) {
		if (strcasecmp(argv[0], "GET") == 0)
			c->failed_cmds = 10; /* bail out right away for a HTTP client */
		
		c->failed_cmds++;
		hlog(LOG_WARNING, "%s: Invalid login string, no 'user': '******'", c->addr_rem, s);
		rc = client_printf(self, c, "# Invalid login command\r\n");
		goto failed_login;
	}
	
	char *username = argv[1];
	
	/* limit username length */
	if (strlen(username) > CALLSIGNLEN_MAX) {
		hlog(LOG_WARNING, "%s: Invalid login string, too long 'user' username: '******'", c->addr_rem, c->username);
		username[CALLSIGNLEN_MAX] = 0;
		rc = client_printf(self, c, "# Invalid username format\r\n");
		goto failed_login;
	}
	
#ifndef FIXED_IOBUFS
	c->username = hstrdup(username);
#else
	strncpy(c->username, username, sizeof(c->username));
	c->username[sizeof(c->username)-1] = 0;
#endif
	c->username_len = strlen(c->username);
	
	/* check the username against a static list of disallowed usernames */
	for (i = 0; (disallow_login_usernames[i]); i++) {
		if (strcasecmp(c->username, disallow_login_usernames[i]) == 0) {
			hlog(LOG_WARNING, "%s: Login by user '%s' not allowed", c->addr_rem, c->username);
			rc = client_printf(self, c, "# Login by user not allowed\r\n");
			goto failed_login;
		}
	}
	
	/* make sure the callsign is OK on the APRS-IS */
	if (check_invalid_q_callsign(c->username, c->username_len)) {
		hlog(LOG_WARNING, "%s: Invalid login string, invalid 'user': '******'", c->addr_rem, c->username);
		rc = client_printf(self, c, "# Invalid username format\r\n");
		goto failed_login;
	}
	
	int given_passcode = -1;
	
	for (i = 2; i < argc; i++) {
		if (strcasecmp(argv[i], "pass") == 0) {
			if (++i >= argc) {
				hlog(LOG_WARNING, "%s/%s: No passcode after pass command", c->addr_rem, username);
				break;
			}
			
			given_passcode = atoi(argv[i]);
			if (given_passcode >= 0)
				if (given_passcode == aprs_passcode(c->username))
					c->validated = 1;
		} else if (strcasecmp(argv[i], "vers") == 0) {
			/* Collect application name and version separately.
			 * Some clients only give out application name but
			 * no version. If those same applications do try to
			 * use filter or udp, the filter/udp keyword will end
			 * up as the version number. So good luck with that.
			 */
			 
			if (i+1 >= argc) {
				hlog(LOG_INFO, "%s/%s: No application name after 'vers' in login", c->addr_rem, username);
				break;
			}
			
			login_set_app_name(c, argv[i+1], (i+2 < argc) ? argv[i+2] : "");
			i += 2;

		} else if (strcasecmp(argv[i], "udp") == 0) {
			if (++i >= argc) {
				hlog(LOG_WARNING, "%s/%s: Missing UDP port number after UDP command", c->addr_rem, username);
				break;
			}
			
			int udp_port = atoi(argv[i]);
			if (udp_port < 1024 || udp_port > 65535) {
				hlog(LOG_WARNING, "%s/%s: UDP port number %s is out of range", c->addr_rem, username, argv[i]);
				break;
			}

			if (login_setup_udp_feed(c, udp_port) != 0) {
				/* Sorry, no UDP service for this port.. */
				hlog(LOG_DEBUG, "%s/%s: Requested UDP on client port with no UDP configured", c->addr_rem, username);
				rc = client_printf(self, c, "# No UDP service available on this port\r\n");
				if (rc < -2)
					return rc; // client got destroyed
					
			}

		} else if (strstr(argv[i], "filter")) {
                        /* Follows javaaprssrvr's example - any command having 'filter' in the
                         * end is OK.
                         */
			if (!(c->flags & CLFLAGS_USERFILTEROK)) {
				rc = client_printf(self, c, "# No user-specified filters on this port\r\n");
				if (rc < -2)
                        		return rc; // client got destroyed
				break;
			}
			
			/* copy the null-separated filter arguments back to a space-separated
			 * string, for the status page to show
			 */
			char *fp = c->filter_s;
			char *fe = c->filter_s + FILTER_S_SIZE;
			int f_non_first = 0;
			
			while (++i < argc) {
				int l = strlen(argv[i]);
				if (fp + l + 2 < fe) {
					if (f_non_first) {
						*fp++ = ' ';
					}
					memcpy(fp, argv[i], l);
					fp += l;
					*fp = 0;
					
					f_non_first = 1;	
				}
				
				/* parse filters in argv[i] */
				rc = filter_parse(c, argv[i], 1);
				if (rc) {
					rc = client_printf( self, c, "# Parse errors on filter spec: '%s'\r\n", argv[i]);
					if (rc < -2)
						return rc; // The client probably got destroyed!
				}
			}
		}
	}
	
	/* ok, login succeeded, switch handler */
	c->handler = &incoming_handler; /* handler of all incoming APRS-IS data during a connection */
	
	rc = client_printf( self, c, "# logresp %s %s, server %s\r\n",
			    username,
			    (c->validated) ? "verified" : "unverified",
			    serverid );
	if (rc < -2)
		return rc; // The client probably got destroyed!

	c->keepalive = now + keepalive_interval/2 + random() % keepalive_interval;
	c->state = CSTATE_CONNECTED;
	
	hlog(LOG_DEBUG, "%s: login '%s'%s%s%s%s%s%s%s%s",
	     c->addr_rem, username,
	     (c->validated) ? " pass_ok" : "",
	     (!c->validated && given_passcode >= 0) ? " pass_invalid" : "",
	     (given_passcode < 0) ? " pass_none" : "",
	     (c->udp_port) ? " UDP" : "",
	     (c->app_name) ? " app " : "",
	     (c->app_name) ? c->app_name : "",
	     (c->app_version) ? " ver " : "",
	     (c->app_version) ? c->app_version : ""
	);
	
	/* Add the client to the client list.
	 *
	 * If the client logged in with a valid passcode, check if there are
	 * other validated clients logged in with the same username.
	 * If one is found, it needs to be disconnected.
	 *
	 * The lookup is done while holding the write lock to the clientlist,
	 * instead of a separate lookup call, so that two clients logging in
	 * at exactly the same time won't make it.
	 */
	 
	int old_fd = clientlist_add(c);
	if (c->validated && old_fd != -1) {
		hlog(LOG_INFO, "fd %d: Disconnecting duplicate validated client with username '%s'", old_fd, username);
		/* The other client may be on another thread, so cannot client_close() it.
		 * There is a small potential race here, if the old client disconnected and
		 * the fd was recycled for another client right after the clientlist check.
		 */
		shutdown(old_fd, SHUT_RDWR);
	}
	
	return 0;

failed_login:
	
	/* if we already lost the client, just return */
	if (rc < -2)
		return rc;
	
	c->failed_cmds++;
	if (c->failed_cmds >= 3) {
		client_close(self, c, CLIERR_LOGIN_RETRIES);
		return -3;
	}
	
	return rc;
}
Beispiel #21
0
/*
 * parse the next request line
 * returns:
 *	1 ok
 *	0 eof
 *	-1 error
 */
int
hparsereq(HConnect *c, int timeout)
{
	Strings ss;
	char *vs, *v, *search, *uri, *origuri, *extra;

	if(c->bin != nil){
		hfail(c, HInternal);
		return -1;
	}

	/*
	 * serve requests until a magic request.
	 * later requests have to come quickly.
	 * only works for http/1.1 or later.
	 */
	if(timeout)
		alarm(timeout);
	if(hgethead(c, 0) < 0)
		return -1;
	if(timeout)
		alarm(0);
	c->reqtime = time(nil);
	c->req.meth = getword(c);
	if(c->req.meth == nil){
		hfail(c, HSyntax);
		return -1;
	}
	uri = getword(c);
	if(uri == nil || strlen(uri) == 0){
		hfail(c, HSyntax);
		return -1;
	}
	v = getword(c);
	if(v == nil){
		if(strcmp(c->req.meth, "GET") != 0){
			hfail(c, HUnimp, c->req.meth);
			return -1;
		}
		c->req.vermaj = 0;
		c->req.vermin = 9;
	}else{
		vs = v;
		if(strncmp(vs, "HTTP/", 5) != 0){
			hfail(c, HUnkVers, vs);
			return -1;
		}
		vs += 5;
		c->req.vermaj = strtoul(vs, &vs, 10);
		if(*vs != '.' || c->req.vermaj != 1){
			hfail(c, HUnkVers, vs);
			return -1;
		}
		vs++;
		c->req.vermin = strtoul(vs, &vs, 10);
		if(*vs != '\0'){
			hfail(c, HUnkVers, vs);
			return -1;
		}

		extra = getword(c);
		if(extra != nil){
			hfail(c, HSyntax);
			return -1;
		}
	}

	/*
	 * the fragment is not supposed to be sent
	 * strip it 'cause some clients send it
	 */
	origuri = uri;
	uri = strchr(origuri, '#');
	if(uri != nil)
		*uri = 0;

	/*
	 * http/1.1 requires the server to accept absolute
	 * or relative uri's.  convert to relative with an absolute path
	 */
	if(http11(c)){
		ss = parseuri(c, origuri);
		uri = ss.s1;
		c->req.urihost = ss.s2;
		if(uri == nil){
			hfail(c, HBadReq, uri);
			return -1;
		}
		origuri = uri;
	}

	/*
	 * munge uri for search, protection, and magic
	 */
	ss = stripsearch(origuri);
	origuri = ss.s1;
	search = ss.s2;
	uri = hurlunesc(c, origuri);
	uri = abspath(c, uri, "/");
	if(uri == nil || uri[0] == '\0'){
		hfail(c, HNotFound, "no object specified");
		return -1;
	}

	c->req.uri = uri;
	c->req.search = search;
	if(search)
		c->req.searchpairs = hparsequery(c, hstrdup(c, search));

	return 1;
}
Beispiel #22
0
static void peerip_clients_config(void)
{
	struct client_t *c;
	struct peerip_config_t *pe;
	struct client_udp_t *udpclient;
	char *s;
	union sockaddr_u sa; /* large enough for also IPv6 address */
	socklen_t addr_len = sizeof(sa);
	
	for (pe = peerip_config; (pe); pe = pe->next) {
		hlog(LOG_DEBUG, "Setting up UDP peer %s (%s)", pe->name, pe->host);
		udpclient = client_udp_find(udppeers, pe->af, pe->local_port);
		
		if (!udpclient) {
			hlog(LOG_ERR, "Failed to find UDP socket on port %d for peer %s (%s)", pe->local_port, pe->name, pe->host);
			continue;
		}

		c = client_alloc();
		if (!c) {
			hlog(LOG_ERR, "peerip_clients_config: client_alloc returned NULL");
			abort();
		}
		c->fd = -1; // Right, this client will never have a socket of it's own.
		c->ai_protocol = IPPROTO_UDP;
		c->portnum = pe->local_port; // local port
		c->state = CSTATE_COREPEER;
		c->validated = VALIDATED_WEAK;
		c->flags = CLFLAGS_UPLINKPORT;
		c->handler_line_in = &incoming_handler;
		memcpy((void *)&c->udpaddr.sa, (void *)pe->ai->ai_addr, pe->ai->ai_addrlen);
		c->udpaddrlen = pe->ai->ai_addrlen;
		c->udp_port = pe->remote_port; // remote port
		c->addr = c->udpaddr;
		c->udpclient = udpclient;
		//c->portaccount = l->portaccount;
		c->keepalive = tick + keepalive_interval;
		c->last_read = tick; /* not simulated time */
		
		inbound_connects_account(3, c->udpclient->portaccount); /* "3" = udp, not listening..  */
		
		/* set up peer serverid to username */
		strncpy(c->username, pe->serverid, sizeof(c->username));
		c->username[sizeof(c->username)-1] = 0;
		c->username_len = strlen(c->username);
		
		/* convert client address to string */
		s = strsockaddr( &c->udpaddr.sa, c->udpaddrlen );
		
		/* text format of client's IP address + port */
		strncpy(c->addr_rem, s, sizeof(c->addr_rem));
		c->addr_rem[sizeof(c->addr_rem)-1] = 0;
		hfree(s);
		
		/* hex format of client's IP address + port */
		s = hexsockaddr( &c->udpaddr.sa, c->udpaddrlen );
		
		strncpy(c->addr_hex, s, sizeof(c->addr_hex));
		c->addr_hex[sizeof(c->addr_hex)-1] = 0;
		hfree(s);

		/* text format of servers' connected IP address + port */
		addr_len = sizeof(sa);
		if (getsockname(c->udpclient->fd, &sa.sa, &addr_len) == 0) { /* Fails very rarely.. */
			/* present my socket end address as a malloced string... */
			s = strsockaddr( &sa.sa, addr_len );
		} else {
			hlog(LOG_ERR, "Peer config: getsockname on udpclient->fd failed: %s", strerror(errno));
			s = hstrdup( "um" ); /* Server's bound IP address.. TODO: what? */
		}
		strncpy(c->addr_loc, s, sizeof(c->addr_loc));
		c->addr_loc[sizeof(c->addr_loc)-1] = 0;
		hfree(s);

		/* pass the client to the first worker thread */
		if (pass_client_to_worker(worker_threads, c)) {
			hlog(LOG_ERR, "Failed to pass UDP peer %s (%s) to worker", pe->name, pe->host);
			client_free(c);
		}
	}
}
Beispiel #23
0
struct client_t *accept_client_for_listener(struct listen_t *l, int fd, char *addr_s, union sockaddr_u *sa, unsigned addr_len)
{
	struct client_t *c;
	char *s;
	int i;
	union sockaddr_u sa_loc; /* local address */
	socklen_t addr_len_loc = sizeof(sa_loc);
	
	c = client_alloc();
	if (!c)
		return NULL;
		
	c->fd    = fd;
	c->listener_id = l->listener_id;
	c->addr  = *sa;
	c->ai_protocol = l->ai_protocol;
	c->portnum = l->portnum;
	c->hidden  = l->hidden;
	c->flags   = l->client_flags;
	c->udpclient = client_udp_find(udpclients, sa->sa.sa_family, l->portnum);
	c->portaccount = l->portaccount;
	c->last_read = tick; /* not simulated time */
	inbound_connects_account(1, c->portaccount); /* account all ports + port-specifics */
	
	/* text format of client's IP address + port */
	strncpy(c->addr_rem, addr_s, sizeof(c->addr_rem));
	c->addr_rem[sizeof(c->addr_rem)-1] = 0;

	/* hex format of client's IP address + port */
	s = hexsockaddr( &sa->sa, addr_len );
	strncpy(c->addr_hex, s, sizeof(c->addr_hex));
	c->addr_hex[sizeof(c->addr_hex)-1] = 0;
	hfree(s);

	/* text format of servers' connected IP address + port */
	if (getsockname(fd, &sa_loc.sa, &addr_len_loc) == 0) { /* Fails very rarely.. */
		if (addr_len_loc > sizeof(sa_loc))
			hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s truncated local address of %d to %d bytes", c->addr_rem, addr_len_loc, sizeof(sa_loc));
		/* present my socket end address as a malloced string... */
		s = strsockaddr( &sa_loc.sa, addr_len_loc );
	} else {
		s = hstrdup( l->addr_s ); /* Server's bound IP address */
		hlog(LOG_ERR, "accept_client_for_listener: getsockname for client %s failed: %s (using '%s' instead)", c->addr_rem, strerror(errno), s);
	}
	strncpy(c->addr_loc, s, sizeof(c->addr_loc));
	c->addr_loc[sizeof(c->addr_loc)-1] = 0;
	hfree(s);

	/* apply predefined filters */
	for (i = 0; i < (sizeof(l->filters)/sizeof(l->filters[0])); ++i) {
		if (l->filters[i]) {
			if (filter_parse(c, l->filters[i], 0) < 0) { /* system filters */
				hlog(LOG_ERR, "Bad system filter definition: %s", l->filters[i]);
			}
		}
	}
	if (l->filter_s) {
		strncpy(c->filter_s, l->filter_s, sizeof(c->filter_s));
		c->filter_s[FILTER_S_SIZE-1] = 0;
	}
	
	return c;
}
Beispiel #24
0
int read_cfgfile(char *f, struct cfgcmd *cmds)
{
	FILE *fp;
	FILE *tmp_file;
	char line[CFGLINE_LEN];
	int ret, n = 0;
	char *conf_home_folder;
	char *conf_home_folder_name;

	tmp_file = fopen("/etc/gnuais.conf","r");	
	if(tmp_file != NULL){
		hlog(LOG_WARNING, "gnuais does not use the configuration file /etc/gnuais.conf anymore. It is now in your home directory as .config/gnuais/config. /etc/gnuais.conf should be deleted to avoid confusion");
		fclose(tmp_file);
	}
	fp = fopen(f, "r");
    if(fp == NULL){
		conf_home_folder_name = hstrdup(getenv("HOME"));	
		conf_home_folder_name = str_append(conf_home_folder_name,"/.config");
		ret = mkdir(conf_home_folder_name, 0777); 
		conf_home_folder_name = str_append(conf_home_folder_name,"/gnuais");
		conf_home_folder = hstrdup(conf_home_folder_name);
		conf_home_folder = str_append(conf_home_folder,"/config");
		fp = fopen(conf_home_folder,"r");
		if(fp == NULL){
			hlog(LOG_INFO,"Creating directory: ~/.config/gnuais/");
			ret = mkdir(conf_home_folder_name, 0777); 
			if(ret != 0){
				hlog(LOG_INFO,"~/.config/gnuais/ already exists");
			}
			tmp_file = fopen("/etc/gnuais.conf","r");	
			ret = 0;
			if(tmp_file == NULL){
				tmp_file = fopen("/usr/local/share/doc/gnuais/gnuais.conf-example","r");	
				if(tmp_file == NULL){
					tmp_file = fopen("/usr/share/doc/gnuais/gnuais.conf-example","r");	
					if(tmp_file == NULL){
						hlog(LOG_ERR,"No gnuais.conf-example found to be copied to ~/.config/gnuais/config");
					}
					else {
						hlog(LOG_NOTICE, "Using gnuais.conf-example as a starting point for ~/.config/gnuais/config...");
						ret = cpfile(conf_home_folder,"/usr/share/doc/gnuais/gnuais.conf-example");
						if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file to the home folder");
						else hlog(LOG_NOTICE, "DONE creating configuration file (~/.config/gnuais/config). You should edit this file manually!");
					}
				}
				else {
					hlog(LOG_NOTICE, "Using gnuais.conf-example as a starting point for ~/.config/gnuais/config...");
					ret = cpfile(conf_home_folder,"/usr/local/share/doc/gnuais/gnuais.conf-example");
					if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file to the home folder");
					else hlog(LOG_NOTICE, "DONE creating configuration file (~/.config/gnuais/config). You should edit this file manually!");
				}
			}
			else {
				hlog(LOG_WARNING, "/etc/gnuais.conf found, but no ~/.config/gnuais/config found.");
				hlog(LOG_WARNING, "It will be copied to your home directory (~/.config/gnuais/config)...");
				ret = cpfile(conf_home_folder,"/etc/gnuais.conf");
				if(ret == -1) hlog(LOG_ERR, "Could not copy configuration file from /etc/gnuais.conf to your home directory");
				else hlog(LOG_NOTICE, "DONE");
			}
			if(ret != -1) {
				fp = fopen(conf_home_folder,"r");
				if(fp == NULL){
					hlog(LOG_ERR, "Could not open configuration file after copying it to the home directory");
				}
			}
		}
		hfree(conf_home_folder_name);
		hfree(conf_home_folder);
	}
    if(fp == NULL){
		hlog(LOG_ERR, "No configuration file found! Running with the default configuration. You should create a file ~/.config/gnuais/config. There should be an example to use in the source archive called gnuais.conf-example");
	}
	else {
		while (fgets(line, CFGLINE_LEN, fp) != NULL) {
			n++;
			ret = cmdparse(cmds, line);
			if (ret < 0) {
				fprintf(stderr, "Problem in %s at line %d: %s\n", f, n, line);
				fclose(fp);
				return 2;
			}
		}
		fclose(fp);
	}
	
	return 0;
}
Beispiel #25
0
int read_config(void)
{
	int failed = 0;
	char *s;
	
	if (read_cfgfile(cfgfile, cfg_cmds))
		return -1;
	
	/* these parameters will only be used when reading the configuration
	 * for the first time.
	 */
	if(log_dir){	/* Check if logdir passed from command line. In that case config file parameter should be ignored*/
		logdir = hstrdup(log_dir);	
	}
	else if(!logdir) { /* Using current directory as default if not given neither in config file or command line */
		if(log_dest == L_FILE)
			hlog(LOG_WARNING, "Config: logdir not defined. Using . as log directory");
		logdir = hstrdup(".");
	}

	/* mycall is only applied when running for the first time. */
	if (!mycall) {
		mycall = hstrdup("NOCALLDEFINED"); 
		hlog(LOG_WARNING, "Config: mycall is not defined - using: %s.",mycall);
		//failed = 1;
	} else if (!valid_aprsis_call(mycall)) {
		hlog(LOG_CRIT, "Config: mycall '%s' is not valid.", mycall);
		failed = 1;
	}
	
	if (!myemail) {
		myemail = hstrdup("notdefined@notdefined"); 
		hlog(LOG_WARNING, "Config: myemail is not defined - using: %s.",myemail);
		//failed = 1;
	}
	
	if (!sound_in_file && !sound_device) {
		sound_device = def_sound_device;
		hlog(LOG_WARNING, "Config: SoundDevice is not defined - using: %s", sound_device);
	}
	
	if (sound_in_file && sound_device) {
		if (sound_device != def_sound_device)
			hfree(sound_device);
		sound_device = NULL;
	}
	
	/* put in the new uplink config */
	free_uplink_config(&uplink_config);
	uplink_config = new_uplink_config;
	if (uplink_config)
		uplink_config->prevp = &uplink_config;
	new_uplink_config = NULL;

	if (failed)
		return -1;
	
	if (!pidfile) {
		s = hmalloc(strlen(logdir) + 1 + strlen(logname) + 3 + 2);
		sprintf(s, "%s/%s.pid", logdir, logname);
		
		pidfile = s;
	}
	
	return 0;
}