mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1947 lines
39 KiB
1947 lines
39 KiB
/**
|
|
* $Id$
|
|
*
|
|
* XLOG module
|
|
*
|
|
* Copyright (C) 2001-2003 FhG Fokus
|
|
*
|
|
* This file is part of ser, a free SIP server.
|
|
*
|
|
* ser is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* For a license to use the ser software under conditions
|
|
* other than those described here, or to purchase support for this
|
|
* software, please contact iptel.org by e-mail at the following addresses:
|
|
* info@iptel.org
|
|
*
|
|
* ser is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/* History:
|
|
* --------
|
|
* 2004-10-20 - added header name specifier (ramona)
|
|
* 2005-07-04 - added color printing support via escape sequesnces
|
|
* contributed by Ingo Wolfsberger (ramona)
|
|
* 2005-12-23 - parts from private branch merged (mma)
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "../../dprint.h"
|
|
#include "../../mem/mem.h"
|
|
#include "../../mem/shm_mem.h"
|
|
#include "../../ut.h"
|
|
#include "../../trim.h"
|
|
#include "../../dset.h"
|
|
#include "../../resolve.h"
|
|
#include "../../qvalue.h"
|
|
#include "../../usr_avp.h"
|
|
|
|
#include "../../parser/parse_from.h"
|
|
#include "../../parser/parse_uri.h"
|
|
#include "../../parser/parse_hname2.h"
|
|
#include "../../parser/parse_refer_to.h"
|
|
|
|
#include "xp_lib.h"
|
|
#include <arpa/inet.h> // inet_ntop
|
|
|
|
#include "../../select.h"
|
|
|
|
static str str_null = STR_STATIC_INIT("<null>");
|
|
static str str_empty = STR_STATIC_INIT("");
|
|
static str str_per = STR_STATIC_INIT("%");
|
|
static str str_hostname, str_domainname, str_fullname, str_ipaddr;
|
|
|
|
enum xl_host_t {
|
|
XL_HOST_NULL,
|
|
XL_HOST_NAME,
|
|
XL_HOST_DOMAIN,
|
|
XL_HOST_FULL,
|
|
XL_HOST_IPADDR
|
|
};
|
|
|
|
int msg_id = 0;
|
|
time_t msg_tm = 0;
|
|
int cld_pid = 0;
|
|
|
|
#define XLOG_FIELD_DELIM ", "
|
|
#define XLOG_FIELD_DELIM_LEN (sizeof(XLOG_FIELD_DELIM) - 1)
|
|
|
|
#define UNIQUE_ID_LEN 16
|
|
static char UNIQUE_ID[UNIQUE_ID_LEN];
|
|
|
|
#define LOCAL_BUF_SIZE 511
|
|
static char local_buf[LOCAL_BUF_SIZE+1];
|
|
|
|
str* xl_get_nulstr()
|
|
{
|
|
return &str_null;
|
|
}
|
|
|
|
static int xl_get_null(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = str_null.s;
|
|
res->len = str_null.len;
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_empty(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = str_empty.s;
|
|
res->len = str_empty.len;
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_percent(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = str_per.s;
|
|
res->len = str_per.len;
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_pid(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(cld_pid == 0)
|
|
cld_pid = (int)getpid();
|
|
ch = int2str_base_0pad(cld_pid, &l, hi, hi==10?0:8);
|
|
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_times(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg_id != msg->id || msg_tm==0)
|
|
{
|
|
msg_tm = time(NULL);
|
|
msg_id = msg->id;
|
|
}
|
|
ch = int2str_base_0pad(msg_tm, &l, hi, hi==10?0:8);
|
|
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
static int xl_get_timef(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
if(msg_id != msg->id || msg_tm==0)
|
|
{
|
|
msg_tm = time(NULL);
|
|
msg_id = msg->id;
|
|
}
|
|
|
|
ch = ctime(&msg_tm);
|
|
|
|
res->s = ch;
|
|
res->len = strlen(ch)-1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_msgid(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
ch = int2str_base_0pad(msg->id, &l, hi, hi==10?0:8);
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_method(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REQUEST)
|
|
{
|
|
res->s = msg->first_line.u.request.method.s;
|
|
res->len = msg->first_line.u.request.method.len;
|
|
}
|
|
else
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_status(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REPLY)
|
|
{
|
|
res->s = msg->first_line.u.reply.status.s;
|
|
res->len = msg->first_line.u.reply.status.len;
|
|
}
|
|
else
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_reason(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REPLY)
|
|
{
|
|
res->s = msg->first_line.u.reply.reason.s;
|
|
res->len = msg->first_line.u.reply.reason.len;
|
|
}
|
|
else
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_ruri(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REPLY) /* REPLY doesnt have a ruri */
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
if(msg->parsed_uri_ok==0 /* R-URI not parsed*/ && parse_sip_msg_uri(msg)<0)
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_ruri: ERROR while parsing the R-URI\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
if (msg->new_uri.s!=NULL)
|
|
{
|
|
res->s = msg->new_uri.s;
|
|
res->len = msg->new_uri.len;
|
|
} else {
|
|
res->s = msg->first_line.u.request.uri.s;
|
|
res->len = msg->first_line.u.request.uri.len;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_contact(struct sip_msg* msg, str* res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->contact==NULL && parse_headers(msg, HDR_CONTACT_F, 0)==-1)
|
|
{
|
|
DBG("XLOG: xl_get_contact: no contact header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
if(!msg->contact || !msg->contact->body.s || msg->contact->body.len<=0)
|
|
{
|
|
DBG("XLOG: xl_get_contact: no contact header!\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
res->s = msg->contact->body.s;
|
|
res->len = msg->contact->body.len;
|
|
|
|
|
|
// res->s = ((struct to_body*)msg->contact->parsed)->uri.s;
|
|
// res->len = ((struct to_body*)msg->contact->parsed)->uri.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int xl_get_from(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(parse_from_header(msg)==-1)
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_from: ERROR cannot parse FROM header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
if(msg->from==NULL || get_from(msg)==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = get_from(msg)->uri.s;
|
|
res->len = get_from(msg)->uri.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_from_tag(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(parse_from_header(msg)==-1)
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_from: ERROR cannot parse FROM header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
|
|
if(msg->from==NULL || get_from(msg)==NULL
|
|
|| get_from(msg)->tag_value.s==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = get_from(msg)->tag_value.s;
|
|
res->len = get_from(msg)->tag_value.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int xl_get_to(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->to==NULL && parse_headers(msg, HDR_TO_F, 0)==-1)
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_to: ERROR cannot parse TO header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
if(msg->to==NULL || get_to(msg)==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = get_to(msg)->uri.s;
|
|
res->len = get_to(msg)->uri.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_to_tag(struct sip_msg* msg, str* res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->to==NULL && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
|
|
(msg->to==NULL)) )
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_to: ERROR cannot parse TO header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
if (get_to(msg)->tag_value.len <= 0)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = get_to(msg)->tag_value.s;
|
|
res->len = get_to(msg)->tag_value.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_cseq(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) ||
|
|
(msg->cseq==NULL)) )
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_cseq: ERROR cannot parse CSEQ header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
res->s = get_cseq(msg)->number.s;
|
|
res->len = get_cseq(msg)->number.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_msg_buf(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = msg->buf;
|
|
res->len = msg->len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_msg_len(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
ch = int2str(msg->len, &l);
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_flags(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
ch = int2str(msg->flags, &l);
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_callid(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->callid==NULL && ((parse_headers(msg, HDR_CALLID_F, 0)==-1) ||
|
|
(msg->callid==NULL)) )
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_callid: ERROR cannot parse Call-Id header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
res->s = msg->callid->body.s;
|
|
res->len = msg->callid->body.len;
|
|
trim(res);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_srcip(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = ip_addr2a(&msg->rcv.src_ip);
|
|
res->len = strlen(res->s);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_srcport(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int l = 0;
|
|
char *ch = NULL;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
ch = int2str(msg->rcv.src_port, &l);
|
|
res->s = ch;
|
|
res->len = l;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_rcvip(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->rcv.bind_address==NULL
|
|
|| msg->rcv.bind_address->address_str.s==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = msg->rcv.bind_address->address_str.s;
|
|
res->len = msg->rcv.bind_address->address_str.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_rcvport(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->rcv.bind_address==NULL
|
|
|| msg->rcv.bind_address->port_no_str.s==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = msg->rcv.bind_address->port_no_str.s;
|
|
res->len = msg->rcv.bind_address->port_no_str.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_useragent(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
if(msg->user_agent==NULL && ((parse_headers(msg, HDR_USERAGENT_F, 0)==-1)
|
|
|| (msg->user_agent==NULL)))
|
|
{
|
|
DBG("XLOG: xl_get_useragent: User-Agent header not found\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
res->s = msg->user_agent->body.s;
|
|
res->len = msg->user_agent->body.len;
|
|
trim(res);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_refer_to(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(parse_refer_to_header(msg)==-1)
|
|
{
|
|
LOG(L_ERR, "XLOG: xl_get_refer_to: ERROR cannot parse Refer-To header\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
if(msg->refer_to==NULL || get_refer_to(msg)==NULL)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->s = get_refer_to(msg)->uri.s;
|
|
res->len = get_refer_to(msg)->uri.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_dset(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
res->s = print_dset(msg, &res->len);
|
|
|
|
if ((res->s) == NULL) return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
res->len -= CRLF_LEN;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define COL_BUF 10
|
|
|
|
#define append_sstring(p, end, str) \
|
|
do{\
|
|
if ((p)+(sizeof(str)-1)<=(end)){\
|
|
memcpy((p), str, sizeof(str)-1); \
|
|
(p)+=sizeof(str)-1; \
|
|
}else{ \
|
|
/* overflow */ \
|
|
LOG(L_ERR, "XLOG: append_sstring overflow\n"); \
|
|
goto error;\
|
|
} \
|
|
} while(0)
|
|
|
|
static int xl_get_color(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
static char color[COL_BUF];
|
|
char* p;
|
|
char* end;
|
|
|
|
p = color;
|
|
end = p + COL_BUF;
|
|
|
|
/* excape sequenz */
|
|
append_sstring(p, end, "\033[");
|
|
|
|
if(hp->s[0]!='_')
|
|
{
|
|
if (islower((unsigned char)hp->s[0]))
|
|
{
|
|
/* normal font */
|
|
append_sstring(p, end, "0;");
|
|
} else {
|
|
/* bold font */
|
|
append_sstring(p, end, "1;");
|
|
hp->s[0] += 32;
|
|
}
|
|
}
|
|
|
|
/* foreground */
|
|
switch(hp->s[0])
|
|
{
|
|
case 'x':
|
|
append_sstring(p, end, "39;");
|
|
break;
|
|
case 's':
|
|
append_sstring(p, end, "30;");
|
|
break;
|
|
case 'r':
|
|
append_sstring(p, end, "31;");
|
|
break;
|
|
case 'g':
|
|
append_sstring(p, end, "32;");
|
|
break;
|
|
case 'y':
|
|
append_sstring(p, end, "33;");
|
|
break;
|
|
case 'b':
|
|
append_sstring(p, end, "34;");
|
|
break;
|
|
case 'p':
|
|
append_sstring(p, end, "35;");
|
|
break;
|
|
case 'c':
|
|
append_sstring(p, end, "36;");
|
|
break;
|
|
case 'w':
|
|
append_sstring(p, end, "37;");
|
|
break;
|
|
default:
|
|
LOG(L_ERR, "XLOG: exit foreground\n");
|
|
return xl_get_empty(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
/* background */
|
|
switch(hp->s[1])
|
|
{
|
|
case 'x':
|
|
append_sstring(p, end, "49");
|
|
break;
|
|
case 's':
|
|
append_sstring(p, end, "40");
|
|
break;
|
|
case 'r':
|
|
append_sstring(p, end, "41");
|
|
break;
|
|
case 'g':
|
|
append_sstring(p, end, "42");
|
|
break;
|
|
case 'y':
|
|
append_sstring(p, end, "43");
|
|
break;
|
|
case 'b':
|
|
append_sstring(p, end, "44");
|
|
break;
|
|
case 'p':
|
|
append_sstring(p, end, "45");
|
|
break;
|
|
case 'c':
|
|
append_sstring(p, end, "46");
|
|
break;
|
|
case 'w':
|
|
append_sstring(p, end, "47");
|
|
break;
|
|
default:
|
|
LOG(L_ERR, "XLOG: exit background\n");
|
|
return xl_get_empty(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
/* end */
|
|
append_sstring(p, end, "m");
|
|
|
|
res->s = color;
|
|
res->len = p-color;
|
|
return 0;
|
|
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
static int xl_get_branch(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
str branch;
|
|
qvalue_t q;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REPLY)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
|
|
init_branch_iterator();
|
|
branch.s = next_branch(&branch.len, &q, 0, 0, 0, 0, 0, 0, 0);
|
|
if (!branch.s) {
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
res->s = branch.s;
|
|
res->len = branch.len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define Q_PARAM ">;q="
|
|
#define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
|
|
|
|
static int xl_get_branches(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
str uri;
|
|
qvalue_t q;
|
|
int len, cnt, i;
|
|
unsigned int qlen;
|
|
char *p, *qbuf;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(msg->first_line.type == SIP_REPLY)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
cnt = len = 0;
|
|
|
|
init_branch_iterator();
|
|
while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
|
|
{
|
|
cnt++;
|
|
len += uri.len;
|
|
if (q != Q_UNSPECIFIED)
|
|
{
|
|
len += 1 + Q_PARAM_LEN + len_q(q);
|
|
}
|
|
}
|
|
|
|
if (cnt == 0)
|
|
return xl_get_empty(msg, res, hp, hi, hf);
|
|
|
|
len += (cnt - 1) * XLOG_FIELD_DELIM_LEN;
|
|
|
|
if (len + 1 > LOCAL_BUF_SIZE)
|
|
{
|
|
LOG(L_ERR, "ERROR:xl_get_branches: local buffer length exceeded\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
i = 0;
|
|
p = local_buf;
|
|
|
|
init_branch_iterator();
|
|
while ((uri.s = next_branch(&uri.len, &q, 0, 0, 0, 0, 0, 0, 0)))
|
|
{
|
|
if (i)
|
|
{
|
|
memcpy(p, XLOG_FIELD_DELIM, XLOG_FIELD_DELIM_LEN);
|
|
p += XLOG_FIELD_DELIM_LEN;
|
|
}
|
|
|
|
if (q != Q_UNSPECIFIED)
|
|
{
|
|
*p++ = '<';
|
|
}
|
|
|
|
memcpy(p, uri.s, uri.len);
|
|
p += uri.len;
|
|
if (q != Q_UNSPECIFIED)
|
|
{
|
|
memcpy(p, Q_PARAM, Q_PARAM_LEN);
|
|
p += Q_PARAM_LEN;
|
|
|
|
qbuf = q2str(q, &qlen);
|
|
memcpy(p, qbuf, qlen);
|
|
p += qlen;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
res->s = &(local_buf[0]);
|
|
res->len = len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_nexthop(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
*res=*GET_NEXT_HOP(msg);
|
|
return 0;
|
|
}
|
|
|
|
#define XLOG_PRINT_ALL -2
|
|
#define XLOG_PRINT_LAST -1
|
|
|
|
static int xl_get_header(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
struct hdr_field *hdrf, *hdrf0;
|
|
char *p;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
if(hp==NULL || hp->len==0)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
hdrf0 = NULL;
|
|
p = local_buf;
|
|
|
|
/* we need to be sure we have parsed all headers */
|
|
parse_headers(msg, HDR_EOH_F, 0);
|
|
for (hdrf=msg->headers; hdrf; hdrf=hdrf->next)
|
|
{
|
|
if(hp->s==NULL)
|
|
{
|
|
if (hp->len!=hdrf->type)
|
|
continue;
|
|
} else {
|
|
if (hdrf->name.len!=hp->len)
|
|
continue;
|
|
if (strncasecmp(hdrf->name.s, hp->s, hdrf->name.len)!=0)
|
|
continue;
|
|
}
|
|
|
|
hdrf0 = hdrf;
|
|
if(hi==XLOG_PRINT_ALL)
|
|
{
|
|
if(p!=local_buf)
|
|
{
|
|
if(p-local_buf+XLOG_FIELD_DELIM_LEN+1>LOCAL_BUF_SIZE)
|
|
{
|
|
LOG(L_ERR,
|
|
"ERROR:xl_get_header: local buffer length exceeded\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
memcpy(p, XLOG_FIELD_DELIM, XLOG_FIELD_DELIM_LEN);
|
|
p += XLOG_FIELD_DELIM_LEN;
|
|
}
|
|
|
|
if(p-local_buf+hdrf0->body.len+1>LOCAL_BUF_SIZE)
|
|
{
|
|
LOG(L_ERR,
|
|
"ERROR:xl_get_header: local buffer length exceeded!\n");
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
memcpy(p, hdrf0->body.s, hdrf0->body.len);
|
|
p += hdrf0->body.len;
|
|
continue;
|
|
}
|
|
|
|
if(hi==0)
|
|
goto done;
|
|
if(hi>0)
|
|
hi--;
|
|
}
|
|
|
|
done:
|
|
if(hi==XLOG_PRINT_ALL)
|
|
{
|
|
*p = 0;
|
|
res->s = local_buf;
|
|
res->len = p - local_buf;
|
|
return 0;
|
|
}
|
|
|
|
if(hdrf0==NULL || hi>0)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
res->s = hdrf0->body.s;
|
|
res->len = hdrf0->body.len;
|
|
trim(res);
|
|
return 0;
|
|
}
|
|
|
|
static int inc_hex(char* c)
|
|
{
|
|
switch (*c) {
|
|
case '9':
|
|
*c='a';
|
|
return 0;
|
|
case 'f':
|
|
*c='0';
|
|
return 1;
|
|
default:
|
|
(*c)++;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int xl_get_unique(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int i;
|
|
|
|
for (i=UNIQUE_ID_LEN-1; i && inc_hex(&UNIQUE_ID[i--]););
|
|
res->s = &UNIQUE_ID[0];
|
|
res->len = UNIQUE_ID_LEN;
|
|
return 0;
|
|
}
|
|
|
|
static int xl_get_host(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
switch (hi) {
|
|
case XL_HOST_NAME:
|
|
*res = str_hostname;
|
|
return 0;
|
|
case XL_HOST_DOMAIN:
|
|
*res = str_domainname;
|
|
return 0;
|
|
case XL_HOST_FULL:
|
|
*res = str_fullname;
|
|
return 0;
|
|
case XL_HOST_IPADDR:
|
|
*res = str_ipaddr;
|
|
return 0;
|
|
default:
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
}
|
|
|
|
static int xl_get_select(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int i;
|
|
if ((i=run_select(res, (select_t*)hp->s, msg))==1)
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
|
|
return i;
|
|
}
|
|
|
|
static void xl_free_select(str *hp)
|
|
{
|
|
if (hp && hp->s)
|
|
free_select((select_t*)hp->s);
|
|
}
|
|
|
|
/* shared memory version of xl_free_select() */
|
|
static void xl_shm_free_select(str *hp)
|
|
{
|
|
if (hp && hp->s)
|
|
shm_free_select((select_t*)hp->s);
|
|
}
|
|
|
|
static int xl_get_avp(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
int_str name, val;
|
|
struct usr_avp *avp, *lavp;
|
|
struct search_state st;
|
|
|
|
if(msg==NULL || res==NULL || hp==NULL)
|
|
return -1;
|
|
|
|
name.s=*hp;
|
|
if (0){
|
|
lavp=NULL;
|
|
for(avp=search_first_avp(AVP_NAME_STR, name, NULL, &st); avp; avp=search_next_avp(&st, NULL)) {
|
|
lavp=avp;
|
|
if (hi>0)
|
|
hi--;
|
|
else if (hi==0)
|
|
break;
|
|
}
|
|
|
|
if (lavp && (hi<=0)) {
|
|
get_avp_val(lavp, &val);
|
|
*res=val.s;
|
|
return 0;
|
|
}
|
|
}
|
|
if ((avp=search_avp_by_index(hf, name, &val, hi))) {
|
|
if (avp->flags & AVP_VAL_STR) {
|
|
*res=val.s;
|
|
} else {
|
|
res->s=int2str(val.n, &res->len);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return xl_get_null(msg, res, hp, hi, hf);
|
|
}
|
|
|
|
/* print special characters, like \r, \n, \t,... */
|
|
static int xl_get_special(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
static char c;
|
|
|
|
if(msg==NULL || res==NULL)
|
|
return -1;
|
|
|
|
c = (char)hi;
|
|
res->s = &c;
|
|
res->len = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* copy the string withing this range */
|
|
static int range_from = -1;
|
|
static int range_to = -1;
|
|
|
|
/* get the range of the string that follows */
|
|
static int xl_get_range(struct sip_msg *msg, str *res, str *hp, int hi, int hf)
|
|
{
|
|
range_from = hi;
|
|
range_to = hf;
|
|
|
|
res->s = NULL;
|
|
res->len = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int _xl_elog_free_all(xl_elog_p log, int shm)
|
|
{
|
|
xl_elog_p t;
|
|
while(log)
|
|
{
|
|
t = log;
|
|
log = log->next;
|
|
if (t->free_f)
|
|
(*t->free_f)(&(t->hparam));
|
|
if (shm)
|
|
shm_free(t);
|
|
else
|
|
pkg_free(t);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Parse an xl-formatted string pointed by s.
|
|
* el points to the resulted linked list that is allocated
|
|
* in shared memory when shm==1 otherwise in pkg memory.
|
|
* If parse_cb is not NULL then regular expression back references
|
|
* are passed to the parse_cb function that is supposed to farther parse
|
|
* the back reference and fill in the xl_elog_t structure.
|
|
*
|
|
* Return value:
|
|
* 0: success
|
|
* -1: error
|
|
*/
|
|
static int _xl_parse_format(char *s, xl_elog_p *el, int shm, xl_parse_cb parse_cb)
|
|
{
|
|
char *p, c;
|
|
int n = 0;
|
|
xl_elog_p e, e0;
|
|
struct hdr_field hdr;
|
|
str name;
|
|
int avp_flags, avp_index;
|
|
int_str avp_name;
|
|
select_t *sel;
|
|
int *range;
|
|
|
|
if(s==NULL || el==NULL)
|
|
return -1;
|
|
|
|
DBG("XLOG: xl_parse_format: parsing [%s]\n", s);
|
|
|
|
p = s;
|
|
*el = NULL;
|
|
e = e0 = NULL;
|
|
range = NULL;
|
|
|
|
while(*p)
|
|
{
|
|
e0 = e;
|
|
if (shm)
|
|
e = shm_malloc(sizeof(xl_elog_t));
|
|
else
|
|
e = pkg_malloc(sizeof(xl_elog_t));
|
|
if(!e)
|
|
goto error;
|
|
memset(e, 0, sizeof(xl_elog_t));
|
|
n++;
|
|
if(*el == NULL)
|
|
*el = e;
|
|
if(e0)
|
|
e0->next = e;
|
|
|
|
e->text.s = p;
|
|
while(*p && *p!='%' && *p!='\\' && !range)
|
|
p++;
|
|
|
|
e->text.len = p - e->text.s;
|
|
if(*p == '\0')
|
|
break;
|
|
|
|
if ((*p == '\\') && !range) {
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case '\\':
|
|
e->itf = xl_get_special;
|
|
e->hindex = '\\';
|
|
break;
|
|
case 'r':
|
|
e->itf = xl_get_special;
|
|
e->hindex = '\r';
|
|
break;
|
|
case 'n':
|
|
e->itf = xl_get_special;
|
|
e->hindex = '\n';
|
|
break;
|
|
case 't':
|
|
e->itf = xl_get_special;
|
|
e->hindex = '\t';
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
/* Regular expression back reference found */
|
|
if (!parse_cb) {
|
|
/* There is no callback function, hence the
|
|
* result will be written as it is. */
|
|
e->itf = xl_get_special;
|
|
e->hindex = *p;
|
|
break;
|
|
}
|
|
name.s = p;
|
|
/* eat all the numeric characters */
|
|
while ((*(p+1) >= '0') && (*(p+1) <= '9'))
|
|
p++;
|
|
name.len = p - name.s + 1;
|
|
if (parse_cb(&name, shm, e)) {
|
|
ERR("xprint: xl_parse_format: failed to parse '%.*s'\n",
|
|
name.len, name.s);
|
|
goto error;
|
|
}
|
|
break;
|
|
default:
|
|
/* not a special character, it will be just
|
|
written to the result as it is */
|
|
e->itf = xl_get_special;
|
|
e->hindex = *p;
|
|
}
|
|
goto cont;
|
|
}
|
|
|
|
if (range)
|
|
range = NULL;
|
|
else
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'b':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'r':
|
|
e->itf = xl_get_branch;
|
|
break;
|
|
case 'R':
|
|
e->itf = xl_get_branches;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'c':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'i':
|
|
e->itf = xl_get_callid;
|
|
break;
|
|
case 's':
|
|
e->itf = xl_get_cseq;
|
|
break;
|
|
case 't':
|
|
e->itf = xl_get_contact;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'C':
|
|
p++;
|
|
e->hparam.s = p;
|
|
|
|
/* foreground */
|
|
switch(*p)
|
|
{
|
|
case 'x':
|
|
case 's': case 'r': case 'g':
|
|
case 'y': case 'b': case 'p':
|
|
case 'c': case 'w': case 'S':
|
|
case 'R': case 'G': case 'Y':
|
|
case 'B': case 'P': case 'C':
|
|
case 'W':
|
|
break;
|
|
default:
|
|
e->itf = xl_get_empty;
|
|
goto error;
|
|
}
|
|
p++;
|
|
|
|
/* background */
|
|
switch(*p)
|
|
{
|
|
case 'x':
|
|
case 's': case 'r': case 'g':
|
|
case 'y': case 'b': case 'p':
|
|
case 'c': case 'w':
|
|
break;
|
|
default:
|
|
e->itf = xl_get_empty;
|
|
goto error;
|
|
}
|
|
|
|
/* end */
|
|
e->hparam.len = 2;
|
|
e->itf = xl_get_color;
|
|
break;
|
|
case 'd':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 's':
|
|
e->itf = xl_get_dset;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'f':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'u':
|
|
e->itf = xl_get_from;
|
|
break;
|
|
case 't':
|
|
e->itf = xl_get_from_tag;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'H':
|
|
p++;
|
|
e->itf = xl_get_host;
|
|
switch(*p)
|
|
{
|
|
case 'n':
|
|
e->hindex = XL_HOST_NAME;
|
|
break;
|
|
case 'd':
|
|
e->hindex = XL_HOST_DOMAIN;
|
|
break;
|
|
case 'f':
|
|
e->hindex = XL_HOST_FULL;
|
|
break;
|
|
case 'i':
|
|
e->hindex = XL_HOST_IPADDR;
|
|
break;
|
|
default:
|
|
e->hindex = XL_HOST_NULL;
|
|
break;
|
|
}
|
|
break;
|
|
case 'm':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'b':
|
|
e->itf = xl_get_msg_buf;
|
|
break;
|
|
case 'f':
|
|
e->itf = xl_get_flags;
|
|
break;
|
|
case 'i':
|
|
e->itf = xl_get_msgid;
|
|
e->hindex = 10;
|
|
break;
|
|
case 'l':
|
|
e->itf = xl_get_msg_len;
|
|
break;
|
|
case 'x':
|
|
e->itf = xl_get_msgid;
|
|
e->hindex = 16;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'n':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'h':
|
|
e->itf = xl_get_nexthop;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'p':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'p':
|
|
e->itf = xl_get_pid;
|
|
e->hindex = 10;
|
|
break;
|
|
case 'x':
|
|
e->itf = xl_get_pid;
|
|
e->hindex = 16;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'r':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'm':
|
|
e->itf = xl_get_method;
|
|
break;
|
|
case 'u':
|
|
e->itf = xl_get_ruri;
|
|
break;
|
|
case 's':
|
|
e->itf = xl_get_status;
|
|
break;
|
|
case 'r':
|
|
e->itf = xl_get_reason;
|
|
break;
|
|
case 't':
|
|
e->itf = xl_get_refer_to;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'R':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'i':
|
|
e->itf = xl_get_rcvip;
|
|
break;
|
|
case 'p':
|
|
e->itf = xl_get_rcvport;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 's':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'i':
|
|
e->itf = xl_get_srcip;
|
|
break;
|
|
case 'p':
|
|
e->itf = xl_get_srcport;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 't':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'u':
|
|
e->itf = xl_get_to;
|
|
break;
|
|
case 't':
|
|
e->itf = xl_get_to_tag;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'T':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 's':
|
|
e->itf = xl_get_times;
|
|
e->hindex = 10;
|
|
break;
|
|
case 'f':
|
|
e->itf = xl_get_timef;
|
|
break;
|
|
case 'x':
|
|
e->itf = xl_get_times;
|
|
e->hindex = 16;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case 'u':
|
|
p++;
|
|
switch(*p)
|
|
{
|
|
case 'a':
|
|
e->itf = xl_get_useragent;
|
|
break;
|
|
case 'q':
|
|
e->itf = xl_get_unique;
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
break;
|
|
case '{':
|
|
p++;
|
|
/* we expect a letter */
|
|
if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z'))
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] pos [%d]\n", s, (int)(p-s));
|
|
goto error;
|
|
}
|
|
e->hparam.s = p;
|
|
while(*p && *p!='}' && *p!='[')
|
|
p++;
|
|
if(*p == '\0')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting '}' after position [%d]\n", s,
|
|
(int)(e->hparam.s-s));
|
|
goto error;
|
|
}
|
|
|
|
e->hparam.len = p - e->hparam.s;
|
|
/* check if we have index */
|
|
if(*p == '[')
|
|
{
|
|
p++;
|
|
if(*p=='-')
|
|
{
|
|
p++;
|
|
if(*p!='1')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error"
|
|
" parsing format [%s] -- only -1 is accepted"
|
|
" as a negative index\n", s);
|
|
goto error;
|
|
}
|
|
e->hindex = XLOG_PRINT_LAST;
|
|
p++;
|
|
} else if (*p=='*') {
|
|
e->hindex = XLOG_PRINT_ALL;
|
|
p++;
|
|
} else {
|
|
while(*p>='0' && *p<='9')
|
|
{
|
|
e->hindex = e->hindex * 10 + *p - '0';
|
|
p++;
|
|
}
|
|
}
|
|
if(*p != ']')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting ']' after position [%d]\n", s,
|
|
(int)(e->hparam.s - s + e->hparam.len));
|
|
goto error;
|
|
}
|
|
p++;
|
|
}
|
|
if(*p != '}')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting '}' after position [%d]!\n", s,
|
|
(int)(e->hparam.s-s));
|
|
goto error;
|
|
}
|
|
|
|
DBG("xprint: xl_parse_format: header name [%.*s] index [%d]\n",
|
|
e->hparam.len, e->hparam.s, e->hindex);
|
|
|
|
/* optimize for known headers -- fake header name */
|
|
c = e->hparam.s[e->hparam.len];
|
|
e->hparam.s[e->hparam.len] = ':';
|
|
e->hparam.len++;
|
|
/* ugly hack for compact header names -- !!fake length!!
|
|
* -- parse_hname2 expects name buffer length >= 4
|
|
*/
|
|
if (parse_hname2(e->hparam.s,
|
|
e->hparam.s + ((e->hparam.len<4)?4:e->hparam.len),
|
|
&hdr)==0)
|
|
{
|
|
LOG(L_ERR,"xprint: xl_parse_format: strange error\n");
|
|
goto error;
|
|
}
|
|
e->hparam.len--;
|
|
e->hparam.s[e->hparam.len] = c;
|
|
if (hdr.type!=HDR_OTHER_T && hdr.type!=HDR_ERROR_T)
|
|
{
|
|
LOG(L_INFO,"INFO:xprint: xl_parse_format: using "
|
|
"hdr type (%d) instead of <%.*s>\n",
|
|
hdr.type, e->hparam.len, e->hparam.s);
|
|
e->hparam.len = hdr.type;
|
|
e->hparam.s = NULL;
|
|
}
|
|
e->itf = xl_get_header;
|
|
break;
|
|
case '<':
|
|
p++;
|
|
/* we expect a letter */
|
|
if((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z'))
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] pos [%d]\n", s, (int)(p-s));
|
|
goto error;
|
|
}
|
|
e->hparam.s = p;
|
|
while(*p && *p!='>' && *p!='[')
|
|
p++;
|
|
if(*p == '\0')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting '>' after position [%d]\n", s,
|
|
(int)(e->hparam.s-s));
|
|
goto error;
|
|
}
|
|
|
|
e->hparam.len = p - e->hparam.s;
|
|
/* check if we have index */
|
|
if(*p == '[')
|
|
{
|
|
p++;
|
|
if(*p=='-')
|
|
{
|
|
p++;
|
|
if(*p!='1')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error"
|
|
" parsing format [%s] -- only -1 is accepted"
|
|
" as a negative index\n", s);
|
|
goto error;
|
|
}
|
|
e->hindex = -1;
|
|
p++;
|
|
}
|
|
else
|
|
{
|
|
while(*p>='0' && *p<='9')
|
|
{
|
|
e->hindex = e->hindex * 10 + *p - '0';
|
|
p++;
|
|
}
|
|
}
|
|
if(*p != ']')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting ']' after position [%d]\n", s,
|
|
(int)(e->hparam.s - s + e->hparam.len));
|
|
goto error;
|
|
}
|
|
p++;
|
|
}
|
|
if(*p != '>')
|
|
{
|
|
LOG(L_ERR, "xprint: xl_parse_format: error parsing format"
|
|
" [%s] expecting '>' after position [%d]!\n", s,
|
|
(int)(e->hparam.s-s));
|
|
goto error;
|
|
}
|
|
|
|
DBG("xprint: xl_parse_format: AVP [%.*s] index [%d]\n",
|
|
e->hparam.len, e->hparam.s, e->hindex);
|
|
|
|
e->itf = xl_get_avp;
|
|
break;
|
|
case '$':
|
|
p++;
|
|
name.s=p;
|
|
while ( (*p>='a' && *p<='z') || (*p>='A' && *p<='Z') || (*p>='0' && *p<='9') || (*p=='_') || (*p=='+') || (*p=='-') || (*p=='[') || (*p==']') || (*p=='.') ) p++;
|
|
name.len=p-name.s;
|
|
p--;
|
|
if (parse_avp_name(&name, &avp_flags, &avp_name, &avp_index) < 0) {
|
|
ERR("error while parsing AVP name\n");
|
|
goto error;
|
|
}
|
|
e->itf = xl_get_avp;
|
|
e->hflags=avp_flags;
|
|
e->hparam.s=name.s;
|
|
e->hparam.len=name.len;
|
|
e->hindex=avp_index;
|
|
DBG("flags %x name %.*s index %d\n", avp_flags, avp_name.s.len, avp_name.s.s, avp_index);
|
|
break;
|
|
case '@':
|
|
/* fill select structure and call resolve_select */
|
|
DBG("xprint: xl_parse_format: @\n");
|
|
if (shm)
|
|
n=shm_parse_select(&p, &sel);
|
|
else
|
|
n=parse_select(&p, &sel);
|
|
if (n<0) {
|
|
ERR("xprint: xl_parse_format: parse_select returned error\n");
|
|
goto error;
|
|
}
|
|
e->itf = xl_get_select;
|
|
e->hparam.s = (char*)sel;
|
|
e->free_f = (shm) ? xl_shm_free_select : xl_free_select;
|
|
p--;
|
|
break;
|
|
case '%':
|
|
e->itf = xl_get_percent;
|
|
break;
|
|
case ' ': /* enables spaceless terminating of avp, e.g. "blah%$avp% text goes on" */
|
|
case '|':
|
|
e->itf = xl_get_empty;
|
|
break;
|
|
case '[':
|
|
range = &e->hindex;
|
|
e->itf = xl_get_range;
|
|
while (1) {
|
|
p++;
|
|
if (((*p) >= '0') && ((*p) <= '9')) {
|
|
(*range) *= 10;
|
|
(*range) += (*p) - '0';
|
|
|
|
} else if ((*p) == '-') {
|
|
if (range == &e->hindex) {
|
|
range = &e->hflags;
|
|
} else {
|
|
ERR("xprint: xl_parse_format: syntax error in the range specification\n");
|
|
goto error;
|
|
}
|
|
|
|
} else if ((*p) == ']') {
|
|
if (range == &e->hindex) {
|
|
/* no range, only a single number */
|
|
e->hflags = e->hindex;
|
|
} else if (e->hflags == 0) {
|
|
/* only the left side is defined */
|
|
e->hflags = -1;
|
|
} else if (e->hindex > e->hflags) {
|
|
ERR("xprint: xl_parse_format: syntax error in the range specification\n");
|
|
goto error;
|
|
}
|
|
break;
|
|
|
|
} else {
|
|
ERR("xprint: xl_parse_format: syntax error in the range specification\n");
|
|
goto error;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
e->itf = xl_get_null;
|
|
}
|
|
|
|
cont:
|
|
if(*p == '\0')
|
|
break;
|
|
p++;
|
|
}
|
|
DBG("XLOG: xl_parse_format: format parsed OK: [%d] items\n", n);
|
|
|
|
return 0;
|
|
|
|
error:
|
|
_xl_elog_free_all(*el, shm);
|
|
*el = NULL;
|
|
return -1;
|
|
}
|
|
|
|
/* wrapper function for _xl_parse_format()
|
|
* pkg memory version
|
|
*/
|
|
int xl_parse_format(char *s, xl_elog_p *el)
|
|
{
|
|
return _xl_parse_format(s, el, 0 /* pkg mem */, NULL /* callback */);
|
|
}
|
|
|
|
/* wrapper function for _xl_parse_format()
|
|
* shm memory version
|
|
*/
|
|
int xl_shm_parse_format(char *s, xl_elog_p *el)
|
|
{
|
|
return _xl_parse_format(s, el, 1 /* shm mem */, NULL /* callback */);
|
|
}
|
|
|
|
/* wrapper function for _xl_parse_format()
|
|
* pkg memory version
|
|
*/
|
|
int xl_parse_format2(char *s, xl_elog_p *el, xl_parse_cb cb)
|
|
{
|
|
return _xl_parse_format(s, el, 0 /* pkg mem */, cb);
|
|
}
|
|
|
|
/* wrapper function for _xl_parse_format()
|
|
* shm memory version
|
|
*/
|
|
int xl_shm_parse_format2(char *s, xl_elog_p *el, xl_parse_cb cb)
|
|
{
|
|
return _xl_parse_format(s, el, 1 /* shm mem */, cb);
|
|
}
|
|
|
|
int xl_print_log(struct sip_msg* msg, xl_elog_p log, char *buf, int *len)
|
|
{
|
|
int n, h;
|
|
str tok;
|
|
xl_elog_p it;
|
|
char *cur;
|
|
|
|
if(msg==NULL || log==NULL || buf==NULL || len==NULL)
|
|
return -1;
|
|
|
|
if(*len <= 0)
|
|
return -1;
|
|
|
|
*buf = '\0';
|
|
cur = buf;
|
|
|
|
h = 0;
|
|
n = 0;
|
|
for (it=log; it; it=it->next)
|
|
{
|
|
/* put the text */
|
|
if(it->text.s && it->text.len>0)
|
|
{
|
|
if(n+it->text.len < *len)
|
|
{
|
|
memcpy(cur, it->text.s, it->text.len);
|
|
n += it->text.len;
|
|
cur += it->text.len;
|
|
}
|
|
else
|
|
goto overflow;
|
|
}
|
|
/* put the value of the specifier */
|
|
if(it->itf
|
|
/* && ((*it->itf != xl_get_color) || (log_stderr!=0)) */
|
|
&& !((*it->itf)(msg, &tok, &(it->hparam), it->hindex, it->hflags)))
|
|
{
|
|
if (*it->itf == xl_get_range)
|
|
continue;
|
|
|
|
/* cut the string to the required size */
|
|
if (range_to >= 0) {
|
|
if (range_to + 1 < tok.len)
|
|
tok.len = range_to + 1;
|
|
range_to = -1;
|
|
}
|
|
if (range_from > 0) {
|
|
if (range_from + 1 > tok.len) {
|
|
range_from = -1;
|
|
/* nothing to copy */
|
|
continue;
|
|
}
|
|
tok.s += range_from;
|
|
tok.len -= range_from;
|
|
range_from = -1;
|
|
}
|
|
|
|
if (tok.len == 0)
|
|
continue;
|
|
|
|
if(n+tok.len < *len)
|
|
{
|
|
memcpy(cur, tok.s, tok.len);
|
|
n += tok.len;
|
|
cur += tok.len;
|
|
|
|
/* check for color entries to reset later */
|
|
if (*it->itf == xl_get_color) {
|
|
h = 1;
|
|
}
|
|
}
|
|
else
|
|
goto overflow;
|
|
}
|
|
}
|
|
|
|
/* reset to default after entry */
|
|
if (h == 1)
|
|
{
|
|
h = sizeof("\033[0m")-1;
|
|
if (n+h < *len)
|
|
{
|
|
memcpy(cur, "\033[0m", h);
|
|
n += h;
|
|
cur += h;
|
|
} else {
|
|
goto overflow;
|
|
}
|
|
}
|
|
|
|
goto done;
|
|
|
|
overflow:
|
|
LOG(L_ERR,
|
|
"XLOG:xl_print_log: buffer overflow -- increase the buffer size...\n");
|
|
LOG(L_ERR, "Pos: %d, Add: %d, Len: %d, Buf:%.*s\n", n, tok.len, *len, n, buf);
|
|
return -1;
|
|
|
|
done:
|
|
DBG("XLOG: xl_print_log: final buffer length %d\n", n);
|
|
*cur = '\0';
|
|
*len = n;
|
|
return 0;
|
|
}
|
|
|
|
/* wrapper function for _xl_elog_free_all()
|
|
* pkg memory version
|
|
*/
|
|
int xl_elog_free_all(xl_elog_p log)
|
|
{
|
|
return _xl_elog_free_all(log, 0 /* pkg mem */);
|
|
}
|
|
|
|
/* wrapper function for _xl_elog_free_all()
|
|
* shm memory version
|
|
*/
|
|
int xl_elog_shm_free_all(xl_elog_p log)
|
|
{
|
|
return _xl_elog_free_all(log, 1 /* shm mem */);
|
|
}
|
|
|
|
int xl_bind(xl_api_t *xl_api)
|
|
{
|
|
xl_api->xprint = xl_print_log;
|
|
xl_api->xparse = xl_parse_format;
|
|
xl_api->shm_xparse = xl_shm_parse_format;
|
|
xl_api->xparse2 = xl_parse_format2;
|
|
xl_api->shm_xparse2 = xl_shm_parse_format2;
|
|
xl_api->xfree = xl_elog_free_all;
|
|
xl_api->shm_xfree = xl_elog_shm_free_all;
|
|
xl_api->xnulstr = xl_get_nulstr;
|
|
return 0;
|
|
}
|
|
|
|
int xl_mod_init()
|
|
{
|
|
#ifdef HOST_NAME_MAX
|
|
#define HOSTNAME_MAX HOST_NAME_MAX
|
|
#else
|
|
#define HOSTNAME_MAX 256
|
|
#endif
|
|
char *s, *d;
|
|
struct hostent *he;
|
|
int i;
|
|
|
|
s=(char*)pkg_malloc(HOSTNAME_MAX);
|
|
if (!s) return -1;
|
|
if (gethostname(s, HOSTNAME_MAX)<0) {
|
|
str_fullname.len = 0;
|
|
str_fullname.s = NULL;
|
|
str_hostname.len = 0;
|
|
str_hostname.s = NULL;
|
|
str_domainname.len = 0;
|
|
str_domainname.s = NULL;
|
|
} else {
|
|
str_fullname.len = strlen(s);
|
|
s = pkg_realloc(s, str_fullname.len+1); /* this will leave the ending \0 */
|
|
if (!s) { /* should never happen because decreasing size */
|
|
pkg_free(s);
|
|
return -1;
|
|
}
|
|
str_fullname.s = s;
|
|
|
|
d=strchr(s, '.');
|
|
if (d) {
|
|
str_hostname.len=d-s;
|
|
str_hostname.s=s;
|
|
str_domainname.len=str_fullname.len-str_hostname.len-1;
|
|
str_domainname.s=d+1;
|
|
} else {
|
|
str_hostname=str_fullname;
|
|
str_domainname.len=0;
|
|
str_domainname.s=NULL;
|
|
}
|
|
s=(char*)pkg_malloc(HOSTNAME_MAX);
|
|
if (!s) {
|
|
pkg_free(str_fullname.s);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
str_ipaddr.len=0;
|
|
str_ipaddr.s=NULL;
|
|
if (str_fullname.len) {
|
|
he=resolvehost(str_fullname.s);
|
|
if (he) {
|
|
if ((strlen(he->h_name)!=str_fullname.len) || strncmp(he->h_name, str_fullname.s, str_fullname.len)) {
|
|
LOG(L_WARN, "WARNING: xl_mod_init: DIFFERENT hostname '%.*s' and gethostbyname '%s'\n", str_fullname.len, ZSW(str_hostname.s), he->h_name);
|
|
}
|
|
|
|
if (he->h_addr_list) {
|
|
for (i=0; he->h_addr_list[i]; i++) {
|
|
if (inet_ntop(he->h_addrtype, he->h_addr_list[i], s, HOSTNAME_MAX)) {
|
|
if (str_ipaddr.len==0) {
|
|
str_ipaddr.len=strlen(s);
|
|
str_ipaddr.s=(char*)pkg_malloc(str_ipaddr.len);
|
|
if (str_ipaddr.s) {
|
|
memcpy(str_ipaddr.s, s, str_ipaddr.len);
|
|
} else {
|
|
str_ipaddr.len=0;
|
|
LOG(L_ERR, "ERROR: xl_mod_init: No memory left for str_ipaddr\n");
|
|
}
|
|
} else if (strncmp(str_ipaddr.s, s, str_ipaddr.len)!=0) {
|
|
LOG(L_WARN, "WARNING: xl_mod_init: more IP %s not used\n", s);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
LOG(L_WARN, "WARNING: xl_mod_init: can't resolve hostname's address\n");
|
|
}
|
|
|
|
}
|
|
}
|
|
pkg_free(s);
|
|
|
|
DBG("Hostname: %.*s\n", str_hostname.len, ZSW(str_hostname.s));
|
|
DBG("Domainname: %.*s\n", str_domainname.len, ZSW(str_domainname.s));
|
|
DBG("Fullname: %.*s\n", str_fullname.len, ZSW(str_fullname.s));
|
|
DBG("IPaddr: %.*s\n", str_ipaddr.len, ZSW(str_ipaddr.s));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int xl_child_init(int rank)
|
|
{
|
|
int i, x, rb, cb;
|
|
|
|
for (i=RAND_MAX, rb=0; i; rb++, i>>=1);
|
|
|
|
cb=x=0; /* x asiignment to make gcc happy */
|
|
for (i=0; i<UNIQUE_ID_LEN; i++) {
|
|
if (!cb) {
|
|
cb=rb;
|
|
x=rand();
|
|
}
|
|
UNIQUE_ID[i]=fourbits2char[x&0x0F];
|
|
x>>=rb;
|
|
cb-=rb;
|
|
}
|
|
|
|
return 0;
|
|
}
|