21 static volatile unsigned allocated_segments = 0;
22 static volatile unsigned active_segments = 0;
23 static volatile unsigned allocated_calls = 0;
24 static volatile unsigned allocated_maps = 0;
25 static volatile unsigned active_calls = 0;
26 static unsigned mapped_calls = 0;
31 static unsigned keysize = 177;
32 static condlock_t locking;
33 static mutex_t mapping;
37 static bool tobool(
const char *s)
55 static const char *ifaddr(
const char *addr,
const char *
id)
57 if(eq(
id,
"any") || eq(
id,
"world") || eq(
id,
"nat"))
64 cidr(acl, ifaddr(addr, id), id)
67 struct sockaddr_storage dest;
68 struct sockaddr_in in;
70 struct sockaddr_in6 in6;
75 unsigned bits = getMask();
81 shell::log(
DEBUG3,
"adding policy %s for %s",
id, addr);
83 if(eq(
id,
"world") || eq(
id,
"any") || eq(
id,
"nat")) {
84 if(eq(
id,
"nat") || eq(
id,
"any"))
91 Socket::store(&
iface, ifs.getAddr());
95 memset(&us.dest, 0,
sizeof(us.dest));
96 us.in.sin_family = Family;
99 us.in.sin_port = htons(1);
100 memcpy(&us.in.sin_addr, &Network,
sizeof(us.in.sin_addr));
101 lp = ((
unsigned char *)(&us.in.sin_addr)) +
sizeof(us.in.sin_addr) - 1;
107 us.in6.sin6_port = htons(1);
108 memcpy(&us.in6.sin6_addr, &Network,
sizeof(us.in6.sin6_addr));
109 lp = ((
unsigned char *)(&us.in6.sin6_addr)) +
sizeof(us.in6.sin6_addr) - 1;
117 Socket::query((
struct sockaddr *)&us.dest, buf,
sizeof(buf));
119 if(Socket::via((
struct sockaddr *)&
iface, (
struct sockaddr *)&us.dest))
122 else if(eq(
id,
"gateway")) {
124 Socket::query((
struct sockaddr *)&
iface, buf,
sizeof(buf));
128 else if(!is_member((
struct sockaddr *)&
iface)) {
148 sid.enlist(&hash[cid % keysize]);
165 void *stack::segment::operator
new(
size_t size)
172 void stack::segment::operator
delete(
void *obj)
179 void *stack::call::operator
new(
size_t size)
187 void stack::call::operator
delete(
void *obj)
210 thread->Conditional::lock();
212 thread->Conditional::signal();
213 thread->Conditional::unlock();
218 thread->Conditional::lock();
220 thread->Conditional::signal();
221 thread->Conditional::unlock();
226 shell::log(
DEBUG1,
"starting background thread");
227 timeout_t timeout, current;
228 Timer expiration = interval;
229 time_t then = 0, now;
239 Conditional::unlock();
240 shell::log(
DEBUG1,
"stopping background thread");
244 timeout = expiration.get();
245 if(!signalled && timeout) {
246 if(timeout > interval)
248 Conditional::wait(timeout);
250 timeout = expiration.get();
251 if(signalled || !timeout) {
254 Conditional::unlock();
257 linked_pointer<stack::call> cp =
stack::sip.begin();
261 if(current && current < timeout)
266 expiration = timeout;
270 Conditional::unlock();
278 shell::debug(9,
"registry cleanup; %d expired", released);
280 shell::debug(9,
"registry cleanup; no entries expired");
298 agent =
"sipwitch-" VERSION
"/eXosip";
302 localnames =
"localhost, localhost.localdomain";
311 LinkedObject::release();
321 ::remove(DEFAULT_VARPATH
"/log/sipdump.log");
342 log.open(
control::env(
"siplogs"), fsys::GROUP_PRIVATE, fsys::APPEND);
345 log.write(text, tlen);
346 log.write(
"---\n\n", 5);
405 if(--cr->
count == 0) {
406 shell::debug(4,
"clearing call %08x:%u\n",
416 shell::debug(4,
"clearing call %08x:%u session %08x:%u\n",
422 s->delist(&hash[s->
cid % keysize]);
443 assert(s != NULL && s->
parent != NULL);
444 Mutex::protect(s->
parent);
446 Mutex::release(s->
parent);
454 Mutex::protect(s->
parent);
456 Mutex::release(s->
parent);
474 else if(cr->
target == source)
478 if(!header || !header->
hvalue)
494 target->
tid = sevent->
tid;
511 else if(cr->
target == source)
526 snprintf(type,
sizeof(type),
"%s/%s", ct->
type, ct->
subtype);
528 snprintf(type,
sizeof(type),
"%s", ct->
type);
538 linked_pointer<segment> sp = cr->
segments.begin();
560 linked_pointer<segment> sp;
572 if(!sp->sid.closed) {
573 if(&(sp->sid) == cr->
source)
577 sp->sid.closed =
true;
580 if(sp->sid.cid > 0) {
584 sp->sid.delist(&hash[sp->sid.cid % keysize]);
603 String::set(map->
state,
sizeof(map->
state),
"-");
606 map->enlist(&freemaps);
618 freemaps = map->getNext();
620 else if(allocated_maps < mapped_calls)
621 map =
sip(allocated_maps++);
626 String::set(map->
state,
sizeof(map->
state),
"iinit");
638 assert(iface != NULL && dest != NULL);
640 Socket::via(iface, dest);
641 switch(iface->sa_family) {
643 ((
struct sockaddr_in*)(iface))->sin_port = htons(
sip_port);
647 ((
struct sockaddr_in6*)(iface))->sin6_port = htons(
sip_port);
679 sp =
new segment(context, cr, cid, did, tid);
691 linked_pointer<session> sp;
694 sp = hash[cid % keysize];
727 shell::log(
DEBUG1,
"starting sip stack v%d; %d maps", ver, mapped_calls);
731 shell::log(shell::FAIL,
"calls could not be mapped");
739 memset(&ctx, 0,
sizeof(ctx));
752 if ((ctx_error = eXosip_set_tls_ctx(&ctx)) !=
TLS_OK)
753 shell::log(shell::FAIL,
754 "sip set tls credentials failed %i", ctx_error);
780 #if defined(EXOSIP2_OPTION_SEND_101) && !defined(EXOSIP_API4)
788 shell::log(shell::FAIL,
"cannot listen port %u for udp",
sip_port);
790 shell::log(shell::NOTIFY,
"listening port %u for udp",
sip_port);
798 shell::log(shell::FAIL,
"cannot listen port %u for tcp",
sip_port);
799 shell::log(shell::NOTIFY,
"listening port %u for tcp",
sip_port);
808 shell::log(shell::FAIL,
"cannot listen port %u for tls",
sip_port + 1);
809 shell::log(shell::NOTIFY,
"listening port %u for tls",
sip_port + 1);
822 shell::log(
DEBUG1,
"stopping sip stack");
826 MappedMemory::release();
833 shell::log(shell::INFO,
"checking tcp context...");
838 shell::log(shell::INFO,
"checking udp context...");
843 shell::log(shell::INFO,
"checking tls context...");
854 linked_pointer<call> cp;
855 fprintf(fp,
"SIP:\n");
857 fprintf(fp,
" mapped calls: %d\n", mapped_calls);
858 fprintf(fp,
" active calls: %d\n", active_calls);
859 fprintf(fp,
" active sessions: %d\n", active_segments);
860 fprintf(fp,
" allocated calls: %d\n", allocated_calls);
861 fprintf(fp,
" allocated sessions: %d\n", allocated_segments);
873 const char *new_proxy = NULL;
875 linked_pointer<service::keynode> sp = cfg->
getList(
"stack");
876 linked_pointer<service::keynode> tp = cfg->
getList(
"timers");
878 const char *localhosts =
"localhost, localhost.localdomain";
880 unsigned cfna_value = 0;
881 unsigned ring_value = 0;
882 unsigned reset_value = 0;
885 if(!gethostname(buf,
sizeof(buf))) {
886 String::add(buf,
sizeof(buf),
", localhost, localhost.localdomainb");
894 value = sp->getPointer();
900 else if(eq(key,
"timing"))
902 else if(eq(key,
"incoming"))
904 else if(eq(key,
"outgoing"))
906 else if(eq(key,
"trace") || eq(key,
"dumping"))
909 keysize = atoi(value);
914 if(strchr(value,
':') != NULL)
917 if(eq(value,
":::") || eq(value,
"::0") || eq(value,
"::*") || eq(value,
"*") || eq(value,
"0.0.0.0") || !*value)
920 value = strdup(value);
923 else if(eq(key,
"send101") && !
is_configured() && tobool(value))
933 else if(eq(key,
"restricted")) {
934 if(eq(value,
"none"))
939 else if(eq(key,
"localnames"))
940 localhosts = cfg->dup(value);
941 else if(eq(key,
"trusted")) {
942 if(eq(value,
"none"))
947 else if(eq(key,
"system"))
949 else if(eq(key,
"anon"))
951 else if(eq(key,
"contact"))
953 else if(eq(key,
"published") || eq(key,
"public"))
955 else if(eq(key,
"peering") || eq(key,
"gateway"))
957 else if(eq(key,
"proxy") || eq(key,
"outbound"))
958 new_proxy = cfg->dup(value);
964 mapped_calls = atoi(value);
978 if(eq(value,
"tcp") || eq(value,
"tls"))
989 value = tp->getPointer();
992 ring_value = atoi(value);
993 else if(eq(key,
"cfna"))
994 cfna_value = atoi(value);
995 else if(eq(key,
"reset"))
996 reset_value = atoi(value);
997 else if(eq(key,
"invite"))
1009 if(ring_value && ring_value < 100)
1011 else if(ring_value >= 100)
1014 if(cfna_value && cfna_value < 1000)
1016 else if(cfna_value >= 1000)
1019 if(reset_value && reset_value < 100)
1021 else if(reset_value >= 100)
1041 assert(addr != NULL);
1042 assert(buf != NULL);
1043 assert(user == NULL || *user != 0);
1053 String::set(buf, size,
"sips:");
1055 String::set(buf, size,
"sip:");
1061 String::add(buf, size, user);
1063 String::add(buf, size,
"@[");
1065 String::add(buf, size,
"@");
1068 String::add(buf, size,
"[");
1072 snprintf(pbuf,
sizeof(pbuf),
"]:%u",
sip_port);
1074 snprintf(pbuf,
sizeof(pbuf),
":%u",
sip_port);
1075 String::add(buf, size, pbuf);
1081 assert(addr != NULL);
1082 assert(buf != NULL);
1083 assert(user == NULL || *user != 0);
1089 const char *defaddr = NULL;
1100 switch(addr->address.sa_family) {
1102 port = ntohs(addr->ipv4.sin_port);
1107 port = ntohs(addr->ipv6.sin6_port);
1117 String::set(buf, size,
"sips:");
1119 String::set(buf, size,
"sip:");
1122 String::add(buf, size, user);
1124 String::add(buf, size,
"@[");
1126 String::add(buf, size,
"@");
1129 String::add(buf, size,
"[");
1132 String::add(buf,
sizeof(buf), defaddr);
1137 Socket::query((
struct sockaddr *)addr, buf + len, size - len);
1139 snprintf(pbuf,
sizeof(pbuf),
"]:%u", port);
1141 snprintf(pbuf,
sizeof(pbuf),
":%u", port);
1142 String::add(buf, size, pbuf);
1148 assert(addr != NULL && *addr != 0);
1152 const char *svc =
"sip";
1156 sp = strchr(addr,
'<');
1160 if(!strnicmp(addr,
"sip:", 4))
1162 else if(!strnicmp(addr,
"sips:", 5))
1165 if(strchr(addr,
'@'))
1166 addr = strchr(addr,
'@') + 1;
1170 String::set(buffer,
sizeof(buffer), ++addr);
1172 ep = strchr(buffer,
'>');
1177 ep = strchr(buffer,
']');
1185 String::set(buffer,
sizeof(buffer), addr);
1187 ep = (
char *)strchr(buffer,
'>');
1191 ep = strchr(buffer,
':');
1199 ep = (
char *)strchr(svc,
';');
1205 ap->add(buffer, svc, family);
1207 ap =
new Socket::address(family, buffer, svc);
1209 if(ap && !ap->getList()) {
1226 if(String::equal(call->
diverting,
"all")) {
1227 snprintf(touri,
sizeof(touri),
"<%s>;reason=unconditional", route);
1230 else if(String::equal(call->
diverting,
"na")) {
1231 snprintf(touri,
sizeof(touri),
"<%s>;reason=no-answer", route);
1234 else if(String::equal(call->
diverting,
"busy")) {
1235 snprintf(touri,
sizeof(touri),
"<%s>;reason=user-busy", route);
1238 else if(String::equal(call->
diverting,
"dnd")) {
1239 snprintf(touri,
sizeof(touri),
"<%s>;reason=do-not-disturb", route);
1242 else if(String::equal(call->
diverting,
"away")) {
1243 snprintf(touri,
sizeof(touri),
"<%s>;reason=away", route);
1250 assert(s != NULL && s->
parent != NULL);
1251 assert(uri_target != NULL);
1255 linked_pointer<stack::segment> sp = call->
segments.begin();
1264 unsigned icount = 0;
1267 struct sockaddr_storage peering;
1269 const char *schema = NULL;
1283 if(eq(uri_target,
"tcp:", 4)) {
1287 else if(eq(uri_target,
"udp:", 4)) {
1293 snprintf(rewrite,
sizeof(rewrite),
"%s:%s", schema, uri_target);
1294 uri_target = rewrite;
1300 String::set(network,
sizeof(network),
"*");
1301 uri::userid(uri_target, username,
sizeof(username));
1305 memcpy(&peering, &subnet->
iface,
sizeof(
struct sockaddr_storage));
1306 String::set(network,
sizeof(network), subnet->
getId());
1319 snprintf(touri,
sizeof(touri),
"<%s>", uri_target);
1324 shell::log(shell::ERR,
"cannot invite %s; build failed", uri_target);
1333 if(digest && s->
reg) {
1334 char *authbuf =
new char[1024];
1335 stringbuf<64> response;
1340 snprintf(authbuf, 1024,
"%s:%s", invite->
sip_method, req);
1341 Random::uuid(nounce);
1343 digest_t auth(
"md5");
1349 snprintf(authbuf, 1024,
"%s:%s:%s", digest, *once, *response);
1353 snprintf(authbuf, 1024,
1354 "Digest username=\"%s\""
1369 snprintf(expheader,
sizeof(expheader),
"%ld", (
long)(call->
expires - now));
1377 shell::log(shell::ERR,
"cannot assign media proxy for %s", uri_target);
1386 snprintf(seqid,
sizeof(seqid),
"%08x-%d", s->
sequence, s->
cid);
1393 shell::log(shell::ERR,
"invite failed for %s", uri_target);
1400 String::set(invited->
display,
sizeof(invited->
display), username);
1401 snprintf(invited->
from,
sizeof(invited->
from),
"<%s>", uri_target);
1402 String::set(invited->
network,
sizeof(invited->
network), network);
1407 shell::debug(3,
"inviting %s\n", uri_target);
1413 unsigned invited = cr->
invited;
1434 fwd = user.
keys->getChild(
"forwarding");
1440 if((!target || !*target) && (String::equal(forwarding,
"away") || String::equal(forwarding,
"dnd")))
1443 if(!target || !*target)
1448 if(strchr(target,
'@'))
1455 shell::debug(3,
"call forward <%s> to %s", forwarding, target);
1471 if(!String::equal(target,
"sip:", 4) && !String::equal(target,
"sips:", 5))
1472 snprintf(buffer,
sizeof(buffer),
"%s:%s",
getScheme(), target);
1474 String::set(buffer,
sizeof(buffer), target);
1477 shell::debug(3,
"call forward <%s> to %s", forwarding, target);
1494 assert(s != NULL && s->
parent != NULL);
1497 linked_pointer<registry::target> tp = rr->
source.
internal.targets;
1500 linked_pointer<stack::segment> sp = call->
segments.begin();
1511 unsigned icount = 0;
1528 if(tp->expires && tp->expires < now + 1)
1531 switch(tp->status) {
1543 snprintf(touri,
sizeof(touri),
"\"%s\" <%s;user=phone>", call->
dialed, route);
1545 else if(call->
phone)
1546 snprintf(touri,
sizeof(touri),
"<%s;user=phone>", tp->contact);
1548 snprintf(touri,
sizeof(touri),
"<%s>", tp->contact);
1552 String::add(route,
sizeof(route),
";lr>");
1556 shell::log(shell::ERR,
"cannot invite %s; build failed", route);
1564 String::add(route,
sizeof(route),
";user=phone");
1565 snprintf(touri,
sizeof(touri),
"\"%s\" <%s>", call->
dialed, route);
1579 snprintf(expheader,
sizeof(expheader),
"%ld", (
long)(call->
expires - now));
1586 shell::log(shell::ERR,
"no media proxy available for %s", route);
1595 snprintf(seqid,
sizeof(seqid),
"%08x-%d", s->
sequence, s->
cid);
1596 stack::sipAddress((
struct sockaddr_internet *)&tp->peering, route, seqid,
sizeof(route));
1603 shell::log(shell::ERR,
"invite failed for %s", route);
1609 String::set(invited->
network,
sizeof(invited->
network), tp->network);
1610 invited->
peering = tp->peering;
1623 snprintf(invited->
from,
sizeof(invited->
from),
1626 snprintf(invited->
from,
sizeof(invited->
from),
1629 snprintf(invited->
from,
sizeof(invited->
from),
1637 shell::debug(3,
"routing to %s\n", route);
1640 shell::debug(3,
"inviting %s\n", route);
static void lock(context_t ctx)
Structure for SIP Message (REQUEST and RESPONSE).
char * subtype
Sub-Type of attachement.
static void call_reference(context_t ctx, call_t cid, void *route)
static void close(session *s)
int osip_uri_to_str(const osip_uri_t *url, char **dest)
Get a string representation of a url element.
char network[MAX_NETWORK_SIZE]
static void getInterface(struct sockaddr *iface, const struct sockaddr *dest)
static bool forward(stack::call *cr)
static void identity(const struct sockaddr *address, char *buffer, const char *user, size_t size)
static void divert(stack::call *cr, voip::msg_t msg)
static bool userid(const char *sipuri, char *buffer, size_t size)
static void unlock(context_t ctx)
static String path(const char *id)
Get a string from a server environment variable.
static voip::context_t udp_context
static const char * getDomain(void)
static Socket::address * getAddress(const char *uri, Socket::address *addr=NULL)
const char *volatile trusted
Pointer to a provisioned user xml subtree.
static voip::context_t tls_context
static unsigned getEntries(void)
char identity[MAX_URI_SIZE]
static session * create(voip::context_t context, voip::call_t cid, voip::did_t did, voip::tid_t tid)
static void automatic(void)
static void destroy(session *s)
void osip_trace_initialize_syslog(osip_trace_level_t level, char *ident)
Structure for event description.
const char *volatile published
struct sockaddr_storage peering
void reload(service *cfg)
static stack::subnet * getPolicy(const struct sockaddr *addr)
static char * sipPublish(struct sockaddr_internet *addr, char *buf, const char *user=NULL, size_t size=MAX_URI_SIZE)
void osip_to_free(osip_to_t *header)
Free a To element.
keynode * getList(const char *path)
static session * access(voip::call_t cid)
static unsigned cleanup(time_t period)
Structure for holding Body.
static int getDialog(session *session)
char sysident[MAX_IDENT_SIZE]
segment(voip::context_t context, call *cr, voip::call_t cid, voip::did_t did=-1, voip::tid_t tid=0)
static void post(cdr *cdr)
Post cdr record to callbacks through the cdr thread queue.
char * type
Type of attachement.
char from[MAX_URI_SIZE+MAX_DISPLAY_SIZE]
int osip_message_header_get_byname(const osip_message_t *sip, const char *hname, int pos, osip_header_t **dest)
Find an "unknown" header.
static void publish(const char *addr)
Set and publish public "appearing" address of the server.
osip_content_type_t * content_type
Content-Type header.
union sipwitch::MappedRegistry::@6 source
static voip::context_t tcp_context
void closingLocked(session *s)
static call_t send_invite_request(context_t ctx, msg_t msg)
Definition of the Content-Type header.
static void send_dialog_message(context_t ctx, did_t did, msg_t msg)
static const char * sip_iface
#define EXOSIP_OPT_UDP_LEARN_PORT
int *: specific re-usage of "rport"
static bool make_dialog_info(context_t ctx, did_t did, msg_t *msg)
static unsigned allocate(void)
void setContact(const char *text)
static void disjoin(call *cr)
static const char * getScheme(void)
static void shutdown(void)
int osip_message_set_to(osip_message_t *sip, const char *hvalue)
Set the To header.
char forward[MAX_USERID_SIZE]
char dh_param[1024]
absolute path to a file necessary for diffie hellman key exchange
static void clear(session *s)
const char *volatile restricted
static void enableDumping(void)
static void create(timeout_t interval)
struct sockaddr_storage iface
static background * thread
static void detach(session *s)
static const char * getRealm(void)
enum sipwitch::stack::session::@10 state
timeout_t getTimeout(void)
char random_file[1024]
absolute path to a file with random(!) data
osip_uri_t * req_uri
Request-Uri (SIP request only)
char subject[MAX_URI_SIZE]
static void published(struct sockaddr_storage *peer)
subnet(cidr::policy **acl, const char *rule, const char *name)
Representation of an active call record.
int eXosip_set_option(struct eXosip_t *excontext, int opt, const void *value)
Set eXosip options.
struct sipwitch::MappedRegistry::@6::@8 internal
static void release(stack::subnet *access)
osip_message_t * request
request within current transaction
static bool listen(context_t ctx, int proto=IPPROTO_UDP, const char *iface=NULL, unsigned port=5060, bool tls=false)
static bool is_configured(void)
static void siplog(voip::msg_t msg)
static void attach(msg_t msg, const char *type, const char *body)
static void refer(session *session, voip::event_t sevent)
static void server_supports(voip::msg_t msg, const char *txt)
static const char * sip_tlskey
static const char * sip_domain
static void incUse(mapped *rr, stats::stat_t stat)
static void release_call(context_t ctx, call_t cid, did_t did)
static const char * sip_tlsdh
char dialed[MAX_IDENT_SIZE]
structure to describe the whole TLS-context for eXosip consists of a certificate, a corresponding pri...
static void detach(mapped *m)
static const char * sip_tlsca
int osip_message_to_str(osip_message_t *sip, char **dest, size_t *message_length)
Get a string representation of a osip_message_t element.
static void wait(unsigned count)
eXosip_tls_credentials_t server
credential of the server
static void send_answer_response(context_t ctx, tid_t tid, int status, msg_t msg=NULL)
static void infomsg(session *session, voip::event_t sevent)
char netname[MAX_NETWORK_SIZE]
static const char * getDigest(void)
static void getProvision(const char *id, usernode &user)
static void free_message_request(context_t ctx, voip::msg_t msg)
voip::context_t route(const char *uri, char *buf, size_t size)
#define EXOSIP_OPT_UDP_KEEP_ALIVE
int *: interval for keep alive packets (UDP, TCP, TLS, DTLS)
static void disableDumping(void)
static char * sipAddress(struct sockaddr_internet *addr, char *buf, const char *user=NULL, size_t size=MAX_URI_SIZE)
static void clearDumping(void)
static voip::context_t out_context
static void option(context_t ctx, int opt, const void *value)
static const char * sip_tlsdev
void terminateLocked(void)
static const char * sip_tlscert
static bool make_dialog_refer(context_t ctx, did_t did, const char *to, msg_t *msg)
const char *volatile localnames
static mapped * access(const char *id)
char * body
buffer containing data
System configuration instance and service functions.
static unsigned short sip_port
static void publish(const char *uri, char *buffer, const char *user, size_t size)
char display[MAX_DISPLAY_SIZE]
Interface class for call detail records.
char root_ca_cert[1024]
absolute path to the file with known rootCAs
int tid
unique id for transactions (to be used for answers)
static void decUse(mapped *rr, stats::stat_t stat)
int osip_message_get_body(const osip_message_t *sip, int pos, osip_body_t **dest)
Get one body header.
char * sip_method
METHOD (SIP request only)
yippieh, everything is fine :)
static bool make_invite_request(context_t ctx, const char *to, const char *from, const char *subject, msg_t *msg, const char *route=NULL)
#define SIP_SERVICE_UNAVAILABLE
static void setDialog(session *session, voip::did_t did)
background(timeout_t sync)
static int inviteRemote(stack::session *session, const char *uri, const char *digest=NULL)
char request[MAX_URI_SIZE]
static int inviteLocal(stack::session *session, registry::mapped *rr, destination_t dest)
static const char * getValue(keynode *base, const char *id)
static const char * sip_tlspwd
static void server_allows(voip::msg_t msg)
char divert[MAX_USERID_SIZE]
static MappedCall * get(void)
static const char * env(const char *id)
Return the value of a server environment variable.
static void header(msg_t msg, const char *key, const char *value)
treemap< char * > keynode
Definition of a xml node.
static void create(context_t *ctx, const char *agent, int family=AF_INET)