There are two design options how to rewrite replies too.
I think the easieast one is to create a reply processing
function in your module and rewrite replies from it.
(Look how for example TM module registers a reply processing
function.)
The other way around would be to hook yourself to transaction
management and do the rewrite from a TM callback.
I like the first method better, because it does not
require stateful processing.
-Jiri
At 10:25 PM 1/12/2003, Maxim Sobolev wrote:
I've almost done with add_rport() and
fix_nated_contact(), it sorta
works, but I've bumped to a problem, I have no good solution for.
My setup is as follows:
private public
[UA1]---[NAT]---[SER]---[UA2]
UA1 is Cisco ATA186
UA2 is eStara SoftPHONE
Since eStara doesn't support symmetric signalling, my config looks
like the following:
if (search("User-Agent: Cisco ATA.*") || search("Server: Cisco
ATA.*")) {
add_rport();
fix_nated_contact();
};
rewriteFromRoute();
[REGISTRATION STUFF STRIPPED]
if (method=="INVITE") {
addRecordRoute();
};
# forward to current uri now
if (!t_relay()) {
sl_reply_error();
};
Everything works just fine when I'm calling from UA1 to UA2, i.e.
from behind the NAT to the "outside world", however there are
some problems when I'm doing it in reverse direction. The problem
is that OK INVITE that the UA1 sends in reply to UA2's INVITE when
the user picks up the phone is not passed to my helper functions
and hence UA2 makes a wrong conclusion about where to send ACK and
BYE to.
Do you have any ideas on how to overcome this problem?
-Maxim
On Sun, Jan 12, 2003 at 08:23:37PM +0200, Maxim Sobolev wrote:
> On Sun, Jan 12, 2003 at 06:02:35PM +0100, Jan Janak wrote:
> > Hello,
> >
> > I will review the patch and let you know.
>
> Thanks! In the meantime, I've located and fixed several bugs in it,
> so that please don't hurry up applying it to the repository yet.
>
> -Maxim
>
> >
> > regards, Jan.
> >
> > On 11-01 06:50, Maxim Sobolev wrote:
> > > Thank you for the explanation! Attached please find first version
> > > of `rport' support for SER (we need it in the core engine), the
> > > module will follow probably tomorrow. Please note that the code
> > > is quite raw (6:20 am here ;) and I did not perform any seriuos
> > > tests yet.
> > >
> > > The code does the following:
> > >
> > > 1. Adds support for `rport' Via field parameter into the message
> > > parser;
> > >
> > > 2. Extends parser to allow valueless parameters as requred by
> > > the draft RFC. This will probably requre additional code
> > > review, as there may be places in the code where it is
> > > assumed that parameter value could not be a NULL pointer;
> > >
> > > 3. Fills in blank rport parameter if present before forwarding
> > > a request or replying to it;
> > >
> > > 4. Changes the code, so that if `rport' is present, then this
> > > port is used for connecting to that UA.
> > >
> > > Any comments, corrections or suggestions are highly appreciated!
> > >
> > > -Maxim
> > >
> > > On Sat, Jan 11, 2003 at 12:04:34AM +0100, Jiri Kuthan wrote:
> > > > that's correct.
> > > >
> > > > >1. Check that _m->somefield is NULL and call parse_headers()
with the
> > > > >appropriate HDR_FOO flag.
> > > >
> > > > yes. you can skip the first check, parse_headers will do it;
> > > > don't forget to handle errors if parse_headers returns -1
> > > > (most likely mem alloc failure)
> > > >
> > > > >2. Check that _m->somefield is non-NULL and return if false.
> > > >
> > > > yes, that means, that the header field is not in message.
> > > >
> > > > note too that some header fields may occur multiple times; in which
case
> > > > msg->hdr_foo points to the first occurence; if you wish to
> > > > process all of them, you need to traverse the list
> > > > msg->headers
> > > >
> > > > example from record-routing (XXX are my extra comments):
> > > >
> > > > int find_first_route(struct sip_msg* _m)
> > > > {
> > > > /* XXX don't look at _m->route ... parse_headers will do it
for you */
> > > > if (parse_headers(_m, HDR_ROUTE, 0) == -1) {
> > > > /* XXX -1 is some bad error, most likely lack of memory --
leave! */
> > > > LOG(L_ERR, "find_first_route(): Error while parsing
headers\n");
> > > > return -1;
> > > > } else {
> > > >
> > > > if (_m->route) {
> > > > return 0;
> > > > } else { /* XXX not found .... the header field is not there
*/
> > > > DBG("find_first_route(): No Route headers
found\n");
> > > > return 1;
> > > > }
> > > > }
> > > > }
> > > >
> > > >
> > > >
> > > > >3. Modify _m->somefield according to the type of that field.
> > > > >4. Using del_lump() mark original version of the header for
deletion and
> > > > >using insert_new_lump() indicate where modified version should be
placed
> > > > >before sending a message out.
> > > >
> > > > 3 is the same as 4, isn't it. you modify a header field by
creating
> > > > a delete lump refering the old value and an insert lump with the new
> > > > value. the new value must be created using pkg_malloc. the replace
> > > > action in textops module is a good example. (The lump lists, sort
> > > > of "diffs", is processed when later on the message is
printed and forwarded.)
> > > >
> > > > -Jiri
> >
> > > --- modules/sl/sl_funcs.c.orig Mon Oct 21 23:30:15 2002
> > > +++ modules/sl/sl_funcs.c Sat Jan 11 06:09:54 2003
> > > @@ -121,7 +121,7 @@
> > > to.sin_family = AF_INET; */
> > >
> > > if (reply_to_via) {
> > > - if (update_sock_struct_from_via( &(to), msg->via1
)==-1)
> > > + if (update_sock_struct_from_via( &(to), msg->via1,
msg)==-1)
> > > {
> > > LOG(L_ERR, "ERROR: sl_send_reply: "
> > > "cannot lookup reply dst: %s\n",
> > > --- modules/tm/t_lookup.c.orig Mon Oct 21 22:21:50 2002
> > > +++ modules/tm/t_lookup.c Sat Jan 11 06:09:54 2003
> > > @@ -717,7 +717,7 @@
> > > } else {
> > > via=msg->via1;
> > > /*init retrans buffer*/
> > > - if (update_sock_struct_from_via( &(rb->to),via )==-1) {
> > > + if (update_sock_struct_from_via( &(rb->to),via,msg )==-1)
{
> > > LOG(L_ERR, "ERROR: init_rb: cannot lookup reply dst:
%.*s\n",
> > > via->host.len, via->host.s );
> > > ser_error=E_BAD_VIA;
> > > --- parser/msg_parser.h.orig Wed Oct 23 18:12:20 2002
> > > +++ parser/msg_parser.h Sat Jan 11 06:15:11 2003
> > > @@ -118,6 +118,7 @@
> > > char* unparsed; /* here we stopped parsing*/
> > >
> > > struct ip_addr src_ip;
> > > + unsigned short src_port_no;
> > > struct ip_addr dst_ip;
> > >
> > > char* orig; /* original message copy */
> > > --- parser/parse_via.c.orig Thu Sep 19 15:23:55 2002
> > > +++ parser/parse_via.c Sat Jan 11 06:09:54 2003
> > > @@ -87,8 +87,10 @@
> > > MADDR1, MADDR2, MADDR3, MADDR4,
> > > RECEIVED1, RECEIVED2, RECEIVED3, RECEIVED4, RECEIVED5, RECEIVED6,
> > > RECEIVED7,
> > > + RPORT1, RPORT2, RPORT3,
> > > /* fin states (227-...)*/
> > > FIN_HIDDEN = 230, FIN_TTL, FIN_BRANCH, FIN_MADDR, FIN_RECEIVED,
> > > + FIN_RPORT,
> > > /*GEN_PARAM,
> > > PARAM_ERROR*/ /* declared in msg_parser.h*/
> > > };
> > > @@ -125,6 +127,7 @@
> > > case FIN_TTL:
> > > case FIN_MADDR:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > *tmp=0;
> > > param->type=state;
> > >
param->name.len=tmp-param->name.s;
> > > @@ -160,6 +163,7 @@
> > > case FIN_TTL:
> > > case FIN_MADDR:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > *tmp=0;
> > > param->type=state;
> > >
param->name.len=tmp-param->name.s;
> > > @@ -200,6 +204,7 @@
> > > case FIN_TTL:
> > > case FIN_MADDR:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > *tmp=0;
> > > param->type=state;
> > >
param->name.len=tmp-param->name.s;
> > > @@ -231,6 +236,7 @@
> > > case FIN_TTL:
> > > case FIN_MADDR:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > *tmp=0;
> > > param->type=state;
> > >
param->name.len=tmp-param->name.s;
> > > @@ -267,6 +273,7 @@
> > > case FIN_MADDR:
> > > case FIN_TTL:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > LOG(L_ERR, "ERROR:
parse_via: invalid char <%c> in"
> > > " state
%d\n", *tmp, state);
> > > goto error;
> > > @@ -296,6 +303,7 @@
> > > case FIN_MADDR:
> > > case FIN_TTL:
> > > case FIN_RECEIVED:
> > > + case FIN_RPORT:
> > > LOG(L_ERR, "ERROR:
parse_via_param: new via found"
> > >
"(',') when '=' expected (state %d=)\n",
> > > state);
> > > @@ -458,6 +466,9 @@
> > > case TTL1:
> > > state=TTL2;
> > > break;
> > > + case RPORT3:
> > > + state=FIN_RPORT;
> > > + break;
> > > case GEN_PARAM:
> > > break;
> > > case F_CR:
> > > @@ -545,6 +556,9 @@
> > > case BRANCH1:
> > > state=BRANCH2;
> > > break;
> > > + case RPORT2:
> > > + state=RPORT3;
> > > + break;
> > > case GEN_PARAM:
> > > break;
> > > case F_CR:
> > > @@ -619,7 +633,36 @@
> > > state=GEN_PARAM;
> > > }
> > > break;
> > > -
> > > + case 'p':
> > > + case 'P':
> > > + switch(state){
> > > + case RECEIVED1:
> > > + state=RPORT1;
> > > + break;
> > > + case F_CR:
> > > + case F_LF:
> > > + case F_CRLF:
> > > + state=END_OF_HEADER;
> > > + goto end_via;
> > > + default:
> > > + state=GEN_PARAM;
> > > + }
> > > + break;
> > > + case 'o':
> > > + case 'O':
> > > + switch(state){
> > > + case RPORT1:
> > > + state=RPORT2;
> > > + break;
> > > + case F_CR:
> > > + case F_LF:
> > > + case F_CRLF:
> > > + state=END_OF_HEADER;
> > > + goto end_via;
> > > + default:
> > > + state=GEN_PARAM;
> > > + }
> > > + break;
> > > default:
> > > switch(state){
> > > case F_PARAM:
> > > @@ -750,6 +793,11 @@
> > >
param->value.len=tmp-param->value.s;
> > > state=F_PARAM;
> > > goto endofvalue;
> > > + case F_VALUE:
> > > + *tmp=0;
> > > + param->value.len=0;
> > > + state=F_PARAM;
> > > + goto endofvalue;
> > > case P_STRING:
> > > break; /* what to do? */
> > > case F_LF:
> > > @@ -1681,6 +1729,8 @@
> > > vb->branch=param;
> > > else if
(param->type==PARAM_RECEIVED)
> > > vb->received=param;
> > > + else if
(param->type==PARAM_RPORT)
> > > + vb->rport=param;
> > > break;
> > > case P_PARAM:
> > > break;
> > > --- parser/parse_via.h.orig Mon Oct 21 18:46:27 2002
> > > +++ parser/parse_via.h Sat Jan 11 06:09:54 2003
> > > @@ -36,7 +36,7 @@
> > > */
> > > enum {
> > > PARAM_HIDDEN=230, PARAM_TTL, PARAM_BRANCH,
> > > - PARAM_MADDR, PARAM_RECEIVED, GEN_PARAM,
> > > + PARAM_MADDR, PARAM_RECEIVED, PARAM_RPORT, GEN_PARAM,
> > > PARAM_ERROR
> > > };
> > >
> > > @@ -70,6 +70,7 @@
> > > struct via_param* branch;
> > > str tid; /* transaction id, part of branch */
> > > struct via_param* received;
> > > + struct via_param* rport;
> > >
> > > struct via_body* next; /* pointer to next via body string if
> > > compact via or null */
> > > --- config.h.orig Mon Oct 21 22:21:50 2002
> > > +++ config.h Sat Jan 11 06:09:54 2003
> > > @@ -82,6 +82,9 @@
> > > #define RECEIVED ";received="
> > > #define RECEIVED_LEN 10
> > >
> > > +#define RPORT ";rport="
> > > +#define RPORT_LEN 7
> > > +
> > > #define SRV_PREFIX "_sip._udp."
> > > #define SRV_PREFIX_LEN 10
> > >
> > > @@ -112,6 +115,7 @@
> > > /* forwarding -- Via buffer dimensioning */
> > > #define MAX_VIA_LINE_SIZE 240
> > > #define MAX_RECEIVED_SIZE 57
> > > +#define MAX_RPORT_SIZE 13
> > >
> > > /* maximum number of branches per transaction */
> > > #define MAX_BRANCHES 4
> > > --- forward.h.orig Wed Oct 23 18:12:20 2002
> > > +++ forward.h Sat Jan 11 06:09:54 2003
> > > @@ -40,7 +40,7 @@
> > > int check_self(str* host, unsigned short port);
> > > int forward_request( struct sip_msg* msg, struct proxy_l* p);
> > > int update_sock_struct_from_via( union sockaddr_union* to,
> > > - struct via_body*
via );
> > > + struct via_body* via, struct sip_msg *msg );
> > > int update_sock_struct_from_ip( union sockaddr_union* to,
> > > struct sip_msg *msg );
> > > int forward_reply( struct sip_msg* msg);
> > > --- ip_addr.h.orig Mon Nov 4 19:05:32 2002
> > > +++ ip_addr.h Sat Jan 11 06:09:54 2003
> > > @@ -201,6 +201,21 @@
> > > }
> > > }
> > >
> > > +static inline unsigned int su2port_no(union sockaddr_union* su)
> > > +{
> > > + switch(su->s.sa_family){
> > > + case AF_INET:
> > > + return ntohs(su->sin.sin_port);
> > > +#ifdef USE_IPV6
> > > + case AF_INET6:
> > > + return ntohs(su->sin6.sin6_port);
> > > +#endif
> > > + default:
> > > + LOG(L_CRIT,"su2port_no: BUG: unknown
address family %d\n",
> > > + su->s.sa_family);
> > > + }
> > > + return 0;
> > > +}
> > >
> > > /* ip_addr2su -> the same as init_su*/
> > > #define ip_addr2su init_su
> > > --- msg_translator.c.orig Mon Oct 21 22:21:50 2002
> > > +++ msg_translator.c Sat Jan 11 06:09:54 2003
> > > @@ -145,9 +145,10 @@
> > > else
> > > foo=&(msg->first_line.u.request.uri);
> > > print_len=snprintf(buf+fix_len, MAX_WARNING_LEN-fix_len,
> > > - "pid=%d req_src_ip=%s in_uri=%.*s out_uri=%.*s
via_cnt%c=%d\"",
> > > + "pid=%d req_src_ip=%s req_src_port=%d in_uri=%.*s
out_uri=%.*s via_cnt%c=%d\"",
> > > my_pid(),
> > > ip_addr2a(&msg->src_ip),
> > > + msg->src_port_no,
> > > msg->first_line.u.request.uri.len,
msg->first_line.u.request.uri.s,
> > > foo->len, foo->s,
> > > msg->parsed_flag & HDR_EOH ? '=' : '>',
/* should be = */
> > > @@ -208,7 +209,26 @@
> > > return buf;
> > > }
> > >
> > > +char *rport_builder(struct sip_msg *msg, unsigned int *rport_len)
> > > +{
> > > + char *buf;
> > >
> > > + buf=pkg_malloc(sizeof(char)*MAX_RPORT_SIZE);
> > > + if (buf==0){
> > > + ser_error=E_OUT_OF_MEM;
> > > + LOG(L_ERR, "ERROR: rport_builder: out of memory\n");
> > > + return 0;
> > > + }
> > > + /*
> > > + * Don't need any sanity checks here, because
> > > + * msg->src_port_no is unsigned int, which means
> > > + * that it couldn't be more than 5 chars long in
> > > + * string representation.
> > > + */
> > > + *rport_len = snprintf(buf, MAX_RPORT_SIZE, "%s%u", RPORT,
msg->src_port_no);
> > > +
> > > + return buf;
> > > +}
> > >
> > > /* computes the "unpacked" len of a lump list,
> > > code moved from build_req_from_req */
> > > @@ -395,9 +415,10 @@
> > > unsigned int
*returned_len,
> > > struct
socket_info* send_sock)
> > > {
> > > - unsigned int len, new_len, received_len, uri_len, via_len;
> > > + unsigned int len, new_len, received_len, rport_len, uri_len, via_len;
> > > char* line_buf;
> > > char* received_buf;
> > > + char* rport_buf;
> > > char* new_buf;
> > > char* orig;
> > > char* buf;
> > > @@ -411,8 +432,10 @@
> > > buf=msg->buf;
> > > len=msg->len;
> > > received_len=0;
> > > + rport_len=0;
> > > new_buf=0;
> > > received_buf=0;
> > > + rport_buf=0;
> > >
> > >
> > > line_buf = via_builder( &via_len, send_sock,
> > > @@ -430,6 +453,11 @@
> > > if ((received_buf=received_builder(msg,&received_len))==0)
> > > goto error01; /* free also line_buf */
> > > }
> > > + /* check if rport needs to be updated */
> > > + if (msg->via1->rport &&
msg->via1->rport->value.s==0) {
> > > + if ((rport_buf=rport_builder(msg,&rport_len))==0)
> > > + goto error01; /* free also line_buf */
> > > + }
> > >
> > > /* add via header to the list */
> > > /* try to add it before msg. 1st via */
> > > @@ -459,6 +487,14 @@
> > > if (insert_new_lump_after(anchor, received_buf, received_len,
HDR_VIA)
> > > ==0 ) goto error02; /* free also line_buf */
> > > }
> > > + /* if rport needs to be updated do it */
> > > + if (rport_len){
> > > + offset = msg->via1->rport->value.s - buf - 1;
> > > + anchor=del_lump(&msg->add_rm, offset,
msg->via1->rport->size + 1, HDR_VIA);
> > > + if (anchor==0) goto error02; /* free also line_buf */
> > > + if (insert_new_lump_after(anchor, rport_buf, rport_len, HDR_VIA)
> > > + ==0 ) goto error02; /* free also line_buf */
> > > + }
> > >
> > > /* compute new msg len and fix overlapping zones*/
> > > new_len=len+lumps_len(msg->add_rm);
> > > @@ -507,6 +543,7 @@
> > > pkg_free(line_buf);
> > > error02:
> > > if (received_buf) pkg_free(received_buf);
> > > + if (rport_buf) pkg_free(rport_buf);
> > > error00:
> > > *returned_len=0;
> > > return 0;
> > > @@ -587,14 +624,18 @@
> > > int i;
> > > char backup;
> > > char *received_buf;
> > > + char *rport_buf;
> > > unsigned int received_len;
> > > + unsigned int rport_len;
> > > char *warning;
> > > unsigned int warning_len;
> > > int r;
> > > str to_tag;
> > >
> > > received_buf=0;
> > > + rport_buf=0;
> > > received_len=0;
> > > + rport_len=0;
> > > buf=0;
> > > /* make -Wall happy */
> > > warning=0;
> > > @@ -621,6 +662,15 @@
> > > goto error00;
> > > }
> > > }
> > > + /* check if rport needs to be updated */
> > > + if (msg->via1->rport &&
msg->via1->rport->value.s==0) {
> > > + if ((rport_buf=rport_builder(msg,&rport_len))==0) {
> > > + LOG(L_ERR, "ERROR: build_res_buf_from_sip_req:
"
> > > + "alas, rport_builder failed\n");
> > > + goto error00;
> > > + }
> > > + rport_len -= msg->via1->rport->size;
> > > + }
> > >
> > > /*computes the lenght of the new response buffer*/
> > > len = 0;
> > > @@ -641,7 +691,7 @@
> > >
len+=new_tag_len+5/*";tag="*/;
> > > }
> > > case HDR_VIA:
> > > - if (hdr==msg->h_via1) len += received_len;
> > > + if (hdr==msg->h_via1) len += received_len +
rport_len;
> > > case HDR_FROM:
> > > case HDR_CALLID:
> > > case HDR_CSEQ:
> > > @@ -716,10 +766,23 @@
> > > break;
> > > }
> > > case HDR_VIA:
> > > - append_str_trans( p, hdr->name.s ,
> > > + if (hdr==msg->h_via1 && rport_buf) {
> > > + append_str_trans( p, hdr->name.s ,
> > > + msg->via1->rport->name.s -
hdr->name.s - 1, msg);
> > > + append_str( p, rport_buf,
> > > + rport_len +
msg->via1->rport->size, msg);
> > > + append_str_trans( p,
msg->via1->rport->name.s +
> > > + msg->via1->rport->size,
> > > + hdr->body.s + hdr->body.len -
> > > + msg->via1->rport->name.s -
> > > + msg->via1->rport->size,
msg);
> > > + } else {
> > > + append_str_trans( p, hdr->name.s ,
> > > ((hdr->body.s+hdr->body.len
)-hdr->name.s ),msg);
> > > + }
> > > if (hdr==msg->h_via1 && received_buf)
> > > append_str( p, received_buf,
received_len, msg);
> > > +
> > > append_str( p, CRLF,CRLF_LEN,msg);
> > > break;
> > > case HDR_FROM:
> > > @@ -763,10 +826,12 @@
> > > needs to be deleted here
> > > */
> > > if (received_buf) pkg_free(received_buf);
> > > + if (rport_buf) pkg_free(rport_buf);
> > > return buf;
> > >
> > > error01:
> > > if (received_buf) pkg_free(received_buf);
> > > + if (rport_buf) pkg_free(rport_buf);
> > > error00:
> > > *returned_len=0;
> > > return 0;
> > > --- receive.c.orig Thu Oct 3 23:06:10 2002
> > > +++ receive.c Sat Jan 11 06:09:54 2003
> > > @@ -77,6 +77,7 @@
> > > useful as most of the work is done with scrath-pad; -jiri */
> > > buf[len]=0;
> > > su2ip_addr(&msg->src_ip, src_su);
> > > + msg->src_port_no=su2port_no(src_su);
> > > msg->dst_ip=bind_address->address; /* won't work if listening
on 0.0.0.0 */
> > > msg->id=msg_no;
> > > /* make a copy of the message */
> > > --- forward.c.orig Thu Oct 24 17:21:08 2002
> > > +++ forward.c Sat Jan 11 06:21:11 2003
> > > @@ -240,14 +240,21 @@
> > > int update_sock_struct_from_ip( union sockaddr_union* to,
> > > struct sip_msg *msg )
> > > {
> > > + unsigned short port_no;
> > >
> > > - init_su(to, &msg->src_ip,
> > > - (msg->via1->port)?htons(msg->via1->port):
htons(SIP_PORT) );
> > > + if (msg->src_port_no)
> > > + port_no = msg->src_port_no;
> > > + else if (msg->via1->port)
> > > + port_no = msg->via1->port;
> > > + else
> > > + port_no = SIP_PORT;
> > > +
> > > + init_su(to, &msg->src_ip, htons(port_no));
> > > return 1;
> > > }
> > >
> > > int update_sock_struct_from_via( union sockaddr_union* to,
> > > - struct via_body*
via )
> > > + struct via_body* via, struct sip_msg *msg )
> > > {
> > > struct hostent* he;
> > > char *host_copy;
> > > @@ -266,6 +273,11 @@
> > > name=&(via->host);
> > > port=via->port;
> > > }
> > > + if (via->rport && via->rport->value.s) {
> > > + port=atoi(via->rport->value.s);
> > > + } else if (via->rport && via->rport->value.s==0
&& !via->received) {
> > > + return update_sock_struct_from_ip( to, msg);
> > > + }
> > > /* we do now a malloc/memcpy because gethostbyname loves \0-terminated
> > > strings; -jiri
> > > but only if host is not null terminated
> > > @@ -353,7 +365,7 @@
> > > goto error;
> > > }
> > >
> > > - if (update_sock_struct_from_via( to, msg->via2 )==-1) goto error;
> > > + if (update_sock_struct_from_via( to, msg->via2, msg)==-1) goto error;
> > > send_sock=get_send_socket(to);
> > > if (send_sock==0){
> > > LOG(L_ERR, "forward_reply: ERROR: no sending socket
found\n");
> >
>
>
> _______________________________________________
> Serusers mailing list
> serusers(a)lists.iptel.org
>
http://lists.iptel.org/mailman/listinfo/serusers