diff options
Diffstat (limited to 'daemon/misc.c')
-rw-r--r-- | daemon/misc.c | 835 |
1 files changed, 423 insertions, 412 deletions
diff --git a/daemon/misc.c b/daemon/misc.c index 8e361be..f48d801 100644 --- a/daemon/misc.c +++ b/daemon/misc.c @@ -20,60 +20,71 @@ extern pthread_mutex_t g_mutex; const char kMsgDelimiter[] = ": "; #define MAX_MSGLEN 128 -void ha_messagex(int level, const char* msg, ...) +static void vmessage(const ha_request_t* rq, int level, int err, + const char* msg, va_list ap) { - va_list ap; - va_start(ap, msg); + size_t len; + char* m; + int e = errno; + int x; - ASSERT(msg); + if(g_daemonized) + { + if(level >= LOG_DEBUG) + return; + } + else + { + if(g_debuglevel < level) + return; + } + + ASSERT(msg); - /* Either to syslog or stderr */ - if(g_daemonized) - { - if(level < LOG_DEBUG) - vsyslog(level, msg, ap); - } + len = strlen(msg) + 20 + MAX_MSGLEN; + m = (char*)alloca(len); - else - { - if(g_debuglevel >= level) - vwarnx(msg, ap); - } + if(m) + { + if(rq) + snprintf(m, len, "%06X: %s%s", rq->id, msg, err ? ": " : ""); + else + snprintf(m, len, "%s%s", msg, err ? ": " : ""); - va_end(ap); + if(err) + { + /* TODO: strerror_r doesn't want to work for us + strerror_r(e, m + strlen(m), MAX_MSGLEN); */ + strncat(m, strerror(e), len); + } + + m[len - 1] = 0; + msg = m; + } + + /* Either to syslog or stderr */ + if(g_daemonized) + vsyslog(level, msg, ap); + else + vwarnx(msg, ap); } -void ha_message(int level, const char* msg, ...) +void ha_messagex(const ha_request_t* rq, int level, const char* msg, ...) { - va_list ap; - va_start(ap, msg); - - ASSERT(msg); + va_list ap; - /* Either to syslog or stderr */ - if(g_daemonized) - { - if(level < LOG_DEBUG) - { - char* m = (char*)alloca(strlen(msg) + MAX_MSGLEN + sizeof(kMsgDelimiter)); + va_start(ap, msg); + vmessage(rq, level, 0, msg, ap); + va_end(ap); +} - if(m) - { - strcpy(m, msg); - strcat(m, kMsgDelimiter); - strerror_r(errno, m + strlen(m), MAX_MSGLEN); - } +void ha_message(const ha_request_t* rq, int level, const char* msg, ...) +{ + va_list ap; - vsyslog(LOG_ERR, m ? m : msg, ap); - } - } - else - { - if(g_debuglevel >= level) - vwarn(msg, ap); - } - - va_end(ap); + va_start(ap, msg); + vmessage(rq, level, 1, msg, ap); + va_end(ap); } @@ -81,67 +92,67 @@ void ha_message(int level, const char* msg, ...) * Header Functionality */ -const ha_header_t* ha_findheader(const ha_request_t* req, const char* name) +const ha_header_t* ha_findheader(const ha_request_t* rq, const char* name) { - int i; + int i; - ASSERT(req && name); + ASSERT(rq && name); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(req->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - if(strcasecmp(req->headers[i].name, name) == 0) - return &(req->headers[i]); + if(rq->req_headers[i].name) + { + if(strcasecmp(rq->req_headers[i].name, name) == 0) + return &(rq->req_headers[i]); + } } - } - return NULL; + return NULL; } -const char* ha_getheader(const ha_request_t* req, const char* name, const char* prefix) +const char* ha_getheader(const ha_request_t* rq, const char* name, const char* prefix) { - int i, l; + int i, l; - ASSERT(req && name); + ASSERT(rq && name); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(req->headers[i].name) + for(i = 0; i < HA_MAX_HEADERS; i++) { - if(strcasecmp(req->headers[i].name, name) == 0) - { - if(!prefix) - return req->headers[i].data; + if(rq->req_headers[i].name) + { + if(strcasecmp(rq->req_headers[i].name, name) == 0) + { + if(!prefix) + return rq->req_headers[i].data; - l = strlen(prefix); + l = strlen(prefix); - if(strncasecmp(prefix, req->headers[i].data, l) == 0) - return req->headers[i].data + l; - } + if(strncasecmp(prefix, rq->req_headers[i].data, l) == 0) + return rq->req_headers[i].data + l; + } + } } - } - return NULL; + return NULL; } -void ha_addheader(ha_response_t* resp, const char* name, const char* data) +void ha_addheader(ha_request_t* rq, const char* name, const char* data) { - int i = 0; + int i = 0; - ASSERT(resp && name && data); + ASSERT(rq && name && data); - for(i = 0; i < HA_MAX_HEADERS; i++) - { - if(!(resp->headers[i].name)) + for(i = 0; i < HA_MAX_HEADERS; i++) { - resp->headers[i].name = name; - resp->headers[i].data = data; - return; + if(!(rq->resp_headers[i].name)) + { + rq->resp_headers[i].name = name; + rq->resp_headers[i].data = data; + return; + } } - } - ha_messagex(LOG_WARNING, "too many headers in response. discarding '%s'", name); + ha_messagex(rq, LOG_WARNING, "too many headers in response. discarding '%s'", name); } @@ -151,51 +162,51 @@ void ha_addheader(ha_response_t* resp, const char* name, const char* data) void ha_lock(pthread_mutex_t* mtx) { - int r; + int r; #ifdef _DEBUG - int wait = 0; + int wait = 0; #endif - if(!mtx) - mtx = &g_mutex; + if(!mtx) + mtx = &g_mutex; #ifdef _DEBUG - r = pthread_mutex_trylock(mtx); - if(r == EBUSY) - { - wait = 1; - ha_message(LOG_DEBUG, "thread will block: %d", pthread_self()); - r = pthread_mutex_lock(mtx); - } + r = pthread_mutex_trylock(mtx); + if(r == EBUSY) + { + wait = 1; + ha_message(NULL, LOG_DEBUG, "thread will block: %d", pthread_self()); + r = pthread_mutex_lock(mtx); + } #else - r = pthread_mutex_lock(mtx); + r = pthread_mutex_lock(mtx); #endif - if(r != 0) - { - errno = r; - ha_message(LOG_CRIT, "threading problem. couldn't lock mutex"); - } + if(r != 0) + { + errno = r; + ha_message(NULL, LOG_CRIT, "threading problem. couldn't lock mutex"); + } #ifdef _DEBUG - else if(wait) - { - ha_message(LOG_DEBUG, "thread unblocked: %d", pthread_self()); - } + else if(wait) + { + ha_message(NULL, LOG_DEBUG, "thread unblocked: %d", pthread_self()); + } #endif } void ha_unlock(pthread_mutex_t* mtx) { - int r = pthread_mutex_unlock(mtx ? mtx : &g_mutex); - if(r != 0) - { - errno = r; - ha_message(LOG_CRIT, "threading problem. couldn't unlock mutex"); - } + int r = pthread_mutex_unlock(mtx ? mtx : &g_mutex); + if(r != 0) + { + errno = r; + ha_message(NULL, LOG_CRIT, "threading problem. couldn't unlock mutex"); + } } @@ -205,51 +216,51 @@ void ha_unlock(pthread_mutex_t* mtx) int ha_confbool(const char* name, const char* conf, int* value) { - ASSERT(name && value); - - if(conf == NULL || - conf[0] == 0 || - strcasecmp(conf, "0") == 0 || - strcasecmp(conf, "no") == 0 || - strcasecmp(conf, "false") == 0 || - strcasecmp(conf, "f") == 0 || - strcasecmp(conf, "off") == 0) - { - *value = 0; - return HA_OK; - } - - if(strcasecmp(conf, "1") == 0 || - strcasecmp(conf, "yes") == 0 || - strcasecmp(conf, "true") == 0 || - strcasecmp(conf, "t") == 0 || - strcasecmp(conf, "on") == 0) - { - *value = 1; - return HA_OK; - } + ASSERT(name && value); + + if(conf == NULL || + conf[0] == 0 || + strcasecmp(conf, "0") == 0 || + strcasecmp(conf, "no") == 0 || + strcasecmp(conf, "false") == 0 || + strcasecmp(conf, "f") == 0 || + strcasecmp(conf, "off") == 0) + { + *value = 0; + return HA_OK; + } - ha_messagex(LOG_ERR, "invalid configuration value '%s': must be 'on' or 'off'.", name); - return HA_FAILED; + if(strcasecmp(conf, "1") == 0 || + strcasecmp(conf, "yes") == 0 || + strcasecmp(conf, "true") == 0 || + strcasecmp(conf, "t") == 0 || + strcasecmp(conf, "on") == 0) + { + *value = 1; + return HA_OK; + } + + ha_messagex(NULL, LOG_ERR, "invalid configuration value '%s': must be 'on' or 'off'.", name); + return HA_FAILED; } int ha_confint(const char* name, const char* conf, int min, int max, int* value) { - char* p; + char* p; - ASSERT(name && conf && value); - ASSERT(min <= max); + ASSERT(name && conf && value); + ASSERT(min <= max); - errno = 0; - *value = strtol(conf, &p, 10); + errno = 0; + *value = strtol(conf, &p, 10); - if(*p || errno == ERANGE || (*value < min) || (*value > max)) - { - ha_messagex(LOG_ERR, "invalid configuration value '%s': must be a number between %d and %d", name, min, max); - return HA_FAILED; - } + if(*p || errno == ERANGE || (*value < min) || (*value > max)) + { + ha_messagex(NULL, LOG_ERR, "invalid configuration value '%s': must be a number between %d and %d", name, min, max); + return HA_FAILED; + } - return HA_OK; + return HA_OK; } @@ -259,366 +270,366 @@ int ha_confint(const char* name, const char* conf, int min, int max, int* value) char* ha_uriformat(ha_buffer_t* buf, const ha_uri_t* uri) { - ASSERT(buf && uri); + ASSERT(buf && uri); - /* This creates a new block */ - ha_bufcpy(buf, ""); + /* This creates a new block */ + ha_bufcpy(buf, ""); + + if(uri->host) + { + const char* l = ""; + const char* r = ""; - if(uri->host) - { - const char* l = ""; - const char* r = ""; + ha_bufmcat(buf, uri->scheme ? uri->scheme : "http", + "://", NULL); - ha_bufmcat(buf, uri->scheme ? uri->scheme : "http", - "://", NULL); + if(uri->user) + { + ha_bufjoin(buf); + ha_bufmcat(buf, uri->user, + uri->pw ? ":" : "", + uri->pw ? uri->pw : "", + "@", NULL); + } - if(uri->user) + if(strchr(uri->host, ':')) /* v6 ip */ + { + l = "["; + r = "]"; + } + + ha_bufjoin(buf); + ha_bufmcat(buf, l, uri->host, r, NULL); + } + + if(uri->path) { - ha_bufjoin(buf); - ha_bufmcat(buf, uri->user, - uri->pw ? ":" : "", - uri->pw ? uri->pw : "", - "@", NULL); + ha_bufjoin(buf); + ha_bufmcat(buf, "/", uri->path); } - if(strchr(uri->host, ':')) /* v6 ip */ + if(uri->query) { - l = "["; - r = "]"; + ha_bufjoin(buf); + ha_bufmcat(buf, "?", uri->query); } - ha_bufjoin(buf); - ha_bufmcat(buf, l, uri->host, r, NULL); - } - - if(uri->path) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "/", uri->path); - } - - if(uri->query) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "?", uri->query); - } - - if(uri->fragment) - { - ha_bufjoin(buf); - ha_bufmcat(buf, "#", uri->fragment); - } - - return ha_bufdata(buf); + if(uri->fragment) + { + ha_bufjoin(buf); + ha_bufmcat(buf, "#", uri->fragment); + } + + return ha_bufdata(buf); } int ha_uriparse(ha_buffer_t* buf, const char* suri, ha_uri_t* uri) { - char* s; - char* s1; - char* hostinfo; - char* endstr; - char* str; - int port; - int v6_offset1 = 0; - - ASSERT(buf && suri && uri); + char* s; + char* s1; + char* hostinfo; + char* endstr; + char* str; + int port; + int v6_offset1 = 0; - /* TODO: We need to http decode the uri */ + ASSERT(buf && suri && uri); - /* Copy the memory */ - str = ha_bufcpy(buf, suri); + /* TODO: We need to http decode the uri */ - if(!str) - return HA_CRITERROR; + /* Copy the memory */ + str = ha_bufcpy(buf, suri); - /* Initialize the structure */ - memset(uri, 0, sizeof(*uri)); + if(!str) + return HA_CRITERROR; - /* - * We assume the processor has a branch predictor like most -- - * it assumes forward branches are untaken and backwards are taken. That's - * the reason for the gotos. -djg - */ - - if(str[0] == '/') - { -deal_with_path: - *str == 0; - ++str; + /* Initialize the structure */ + memset(uri, 0, sizeof(*uri)); /* - * we expect uri to point to first character of path ... remember - * that the path could be empty -- http://foobar?query for example + * We assume the processor has a branch predictor like most -- + * it assumes forward branches are untaken and backwards are taken. That's + * the reason for the gotos. -djg */ - s = str; - while(*s && *s != '?' && *s != '#') - ++s; - - if(s != str) - uri->path = str; - if(*s == 0) - return HA_OK; - - if(*s == '?') + if(str[0] == '/') { - *s = 0; - ++s; - uri->query = s; +deal_with_path: + *str == 0; + ++str; - s1 = strchr(s, '#'); - if(s1) - { - *s1 = 0; - ++s1; - uri->fragment = s1; - } + /* + * we expect uri to point to first character of path ... remember + * that the path could be empty -- http://foobar?query for example + */ + s = str; + while(*s && *s != '?' && *s != '#') + ++s; - return HA_OK; - } + if(s != str) + uri->path = str; - *s = 0; - ++s; + if(*s == 0) + return HA_OK; - /* otherwise it's a fragment */ - uri->fragment = s; - return HA_OK; - } + if(*s == '?') + { + *s = 0; + ++s; + uri->query = s; + + s1 = strchr(s, '#'); + if(s1) + { + *s1 = 0; + ++s1; + uri->fragment = s1; + } + + return HA_OK; + } + + *s = 0; + ++s; - /* find the scheme: */ - s = str; + /* otherwise it's a fragment */ + uri->fragment = s; + return HA_OK; + } - while(*s && *s != ':' && *s != '/' && *s != '?' && *s != '#') - s++; + /* find the scheme: */ + s = str; - /* scheme must be non-empty and followed by :// */ - if(s == str || s[0] != ':' || s[1] != '/' || s[2] != '/') - goto deal_with_path; /* backwards predicted taken! */ + while(*s && *s != ':' && *s != '/' && *s != '?' && *s != '#') + s++; - uri->scheme = str; - *s = 0; - s += 3; + /* scheme must be non-empty and followed by :// */ + if(s == str || s[0] != ':' || s[1] != '/' || s[2] != '/') + goto deal_with_path; /* backwards predicted taken! */ - hostinfo = s; + uri->scheme = str; + *s = 0; + s += 3; - while(*s && *s != '/' && *s != '?' && *s != '#') - ++s; + hostinfo = s; - str = s; /* whatever follows hostinfo is start of uri */ + while(*s && *s != '/' && *s != '?' && *s != '#') + ++s; - /* - * If there's a username:password@host:port, the @ we want is the last @... - * too bad there's no memrchr()... For the C purists, note that hostinfo - * is definately not the first character of the original uri so therefore - * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. - */ - do - { - --s; - } - while(s >= hostinfo && *s != '@'); + str = s; /* whatever follows hostinfo is start of uri */ - if(s < hostinfo) - { - /* again we want the common case to be fall through */ -deal_with_host: /* - * We expect hostinfo to point to the first character of - * the hostname. If there's a port it is the first colon, - * except with IPv6. + * If there's a username:password@host:port, the @ we want is the last @... + * too bad there's no memrchr()... For the C purists, note that hostinfo + * is definately not the first character of the original uri so therefore + * &hostinfo[-1] < &hostinfo[0] ... and this loop is valid C. */ - if(*hostinfo == '[') + do { - v6_offset1 = 1; - - s = str; - for(;;) - { --s; + } + while(s >= hostinfo && *s != '@'); - if(s < hostinfo) + if(s < hostinfo) + { + /* again we want the common case to be fall through */ +deal_with_host: + /* + * We expect hostinfo to point to the first character of + * the hostname. If there's a port it is the first colon, + * except with IPv6. + */ + if(*hostinfo == '[') { - s = NULL; /* no port */ - break; + v6_offset1 = 1; + + s = str; + for(;;) + { + --s; + + if(s < hostinfo) + { + s = NULL; /* no port */ + break; + } + + else if(*s == ']') + { + *s = 0; + s = NULL; /* no port */; + break; + } + + else if(*s == ':') + { + *s = 0; + ++s; /* found a port */ + break; + } + } } - else if(*s == ']') + else { - *s = 0; - s = NULL; /* no port */; - break; + s = memchr(hostinfo, ':', str - hostinfo); + if(s) + { + *s = 0; + ++s; + } } - else if(*s == ':') + uri->host = hostinfo + v6_offset1; + + if(s == NULL) { - *s = 0; - ++s; /* found a port */ - break; + /* we expect the common case to have no port */ + goto deal_with_path; } - } - } - else - { - s = memchr(hostinfo, ':', str - hostinfo); - if(s) - { - *s = 0; - ++s; - } + if(str != s) + { + port = strtol(s, &endstr, 10); + uri->port = port; + if(*endstr != '\0') + return HA_FAILED; + } + + goto deal_with_path; } - uri->host = hostinfo + v6_offset1; + /* Remove the @ symbol */ + *s = 0; - if(s == NULL) + /* first colon delimits username:password */ + s1 = memchr(hostinfo, ':', s - hostinfo); + if(s1) { - /* we expect the common case to have no port */ - goto deal_with_path; - } + *s1 = 0; + ++s1; - if(str != s) + uri->user = hostinfo; + uri->pw = s1; + } + else { - port = strtol(s, &endstr, 10); - uri->port = port; - if(*endstr != '\0') - return HA_FAILED; + str = hostinfo; } - goto deal_with_path; - } - - /* Remove the @ symbol */ - *s = 0; - - /* first colon delimits username:password */ - s1 = memchr(hostinfo, ':', s - hostinfo); - if(s1) - { - *s1 = 0; - ++s1; - - uri->user = hostinfo; - uri->pw = s1; - } - else - { - str = hostinfo; - } - - hostinfo = s + 1; - goto deal_with_host; + hostinfo = s + 1; + goto deal_with_host; } -int uri_cmp_part_s(const char* s1, const char* s2, const char* def, int cs) +static int uri_cmp_part_s(const char* s1, const char* s2, const char* def, int cs) { - if(def) - { - if(s1 && strcmp(def, s1) == 0) - s1 = NULL; - if(s2 && strcmp(def, s2) == 0) - s2 = NULL; - } - - if(!s1 && !s2) - return 0; + if(def) + { + if(s1 && strcmp(def, s1) == 0) + s1 = NULL; + if(s2 && strcmp(def, s2) == 0) + s2 = NULL; + } + + if(!s1 && !s2) + return 0; - if(!s1) - return -1; + if(!s1) + return -1; - if(!s2) - return 1; + if(!s2) + return 1; - return cs ? strcasecmp(s1, s2) : strcmp(s1, s2); + return cs ? strcasecmp(s1, s2) : strcmp(s1, s2); } -int uri_cmp_part_n(int n1, int n2, int def) +static int uri_cmp_part_n(int n1, int n2, int def) { - if(def) - { - if(n1 == def) - n1 = 0; - if(n2 == def) - n2 = 0; - } - - if(n1 == n2) - return 0; + if(def) + { + if(n1 == def) + n1 = 0; + if(n2 == def) + n2 = 0; + } + + if(n1 == n2) + return 0; - else if(n1 < n2) - return -1; + else if(n1 < n2) + return -1; - else if(n2 > n1) - return 1; + else if(n2 > n1) + return 1; - /* Not reached */ - ASSERT(0); + /* Not reached */ + ASSERT(0); } int ha_uricmp(ha_uri_t* one, ha_uri_t* two) { - int r; + int r; - ASSERT(one && two); + ASSERT(one && two); - /* We don't compare user or password */ + /* We don't compare user or password */ - /* The scheme */ - if((r = uri_cmp_part_s(one->scheme, two->scheme, "http", 0)) != 0 || - (r = uri_cmp_part_s(one->host, two->host, NULL, 1)) != 0 != 0 || - (r = uri_cmp_part_n(one->port, two->port, 80)) != 0 || - (r = uri_cmp_part_s(one->path, two->path, NULL, 0)) != 0 || - (r = uri_cmp_part_s(one->query, two->query, NULL, 0)) != 0 || - (r = uri_cmp_part_s(one->fragment, two->fragment, NULL, 0))) - return r; + /* The scheme */ + if((r = uri_cmp_part_s(one->scheme, two->scheme, "http", 0)) != 0 || + (r = uri_cmp_part_s(one->host, two->host, NULL, 1)) != 0 != 0 || + (r = uri_cmp_part_n(one->port, two->port, 80)) != 0 || + (r = uri_cmp_part_s(one->path, two->path, NULL, 0)) != 0 || + (r = uri_cmp_part_s(one->query, two->query, NULL, 0)) != 0 || + (r = uri_cmp_part_s(one->fragment, two->fragment, NULL, 0))) + return r; - return 0; + return 0; } int ha_genrandom(unsigned char* data, size_t len) { - int r, dd; - - ASSERT(data && len > 0); - - dd = open("/dev/urandom", O_RDONLY); - if(dd == -1) - { - ha_message(LOG_ERR, "couldn't open /dev/urandom"); - return HA_FAILED; - } + int r, dd; - for(;;) - { - r = read(dd, data, len); + ASSERT(data && len > 0); - if(r == -1) + dd = open("/dev/urandom", O_RDONLY); + if(dd == -1) { - switch(errno) - { - case EINTR: - case EAGAIN: - continue; - - default: - ha_message(LOG_ERR, "couldn't read random bytes from /dev/urandom"); - break; - } - - break; + ha_message(NULL, LOG_ERR, "couldn't open /dev/urandom"); + return HA_FAILED; } - else if(r >= 0) + for(;;) { - if(r >= len) - break; + r = read(dd, data, len); + + if(r == -1) + { + switch(errno) + { + case EINTR: + case EAGAIN: + continue; + + default: + ha_message(NULL, LOG_ERR, "couldn't read random bytes from /dev/urandom"); + break; + }; + + break; + } - len -= r; - data += r; + else if(r >= 0) + { + if(r >= len) + break; + + len -= r; + data += r; + } } - } - close(dd); - return r == -1 ? HA_FAILED : HA_OK; + close(dd); + return r == -1 ? HA_FAILED : HA_OK; } |