sdp_util.c

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <stdio.h>
00003 #include <string.h>
00004 #include <unistd.h>
00005 #include <errno.h>
00006 #include <sys/un.h>
00007 #include <sys/poll.h>
00008 #include <sys/uio.h>
00009 #include <sys/types.h>
00010 #include <sys/socket.h>
00011 #include <arpa/inet.h>
00012 
00013 
00014 #include "../../timer.h"
00015 #include "../../dprint.h"
00016 #include "../../mem/mem.h"
00017 #include "../../str.h"
00018 #include "../../trim.h"
00019 #include "../../parser/msg_parser.h"
00020 #include "../../parser/parser_f.h"
00021 #include "../../parser/parse_from.h"
00022 #include "../../parser/parse_uri.h"
00023 #include "../../parser/contact/parse_contact.h"
00024 #include "../../data_lump.h"
00025 #include "sdp_util.h"
00026 #include "mod.h"
00027 #include "nat_helper.h"
00028 #include "sip.h"
00029 
00030 extern int pcscf_nat_enable;
00031 extern struct rtpp_head rtpp_list;
00032 extern int rtpp_node_count ;
00033 extern char *rtpproxy_sock ; /* list */
00034 extern int rtpproxy_enable; 
00035 extern int rtpproxy_disable_tout ;
00036 extern int rtpproxy_retr ;
00037 extern int rtpproxy_tout ; 
00038 unsigned int myseqn ;
00039 
00040 static str sup_ptypes[] = {
00041     {.s = "udp", .len = 3},
00042     {.s = "udptl", .len = 5},
00043     {.s = "rtp/avp", .len = 7},
00044     {.s = NULL, .len = 0}
00045 };
00046 
00047 extern network_t nets_1918[];
00048 
00049 
00050 int check_content_type(struct sip_msg *msg)
00051 {
00052     static unsigned int appl[16] = {
00053         0x6c707061/*appl*/,0x6c707041/*Appl*/,0x6c705061/*aPpl*/,
00054         0x6c705041/*APpl*/,0x6c507061/*apPl*/,0x6c507041/*ApPl*/,
00055         0x6c505061/*aPPl*/,0x6c505041/*APPl*/,0x4c707061/*appL*/,
00056         0x4c707041/*AppL*/,0x4c705061/*aPpL*/,0x4c705041/*APpL*/,
00057         0x4c507061/*apPL*/,0x4c507041/*ApPL*/,0x4c505061/*aPPL*/,
00058         0x4c505041/*APPL*/};
00059     static unsigned int icat[16] = {
00060         0x74616369/*icat*/,0x74616349/*Icat*/,0x74614369/*iCat*/,
00061         0x74614349/*ICat*/,0x74416369/*icAt*/,0x74416349/*IcAt*/,
00062         0x74414369/*iCAt*/,0x74414349/*ICAt*/,0x54616369/*icaT*/,
00063         0x54616349/*IcaT*/,0x54614369/*iCaT*/,0x54614349/*ICaT*/,
00064         0x54416369/*icAT*/,0x54416349/*IcAT*/,0x54414369/*iCAT*/,
00065         0x54414349/*ICAT*/};
00066     static unsigned int ion_[8] = {
00067         0x006e6f69/*ion_*/,0x006e6f49/*Ion_*/,0x006e4f69/*iOn_*/,
00068         0x006e4f49/*IOn_*/,0x004e6f69/*ioN_*/,0x004e6f49/*IoN_*/,
00069         0x004e4f69/*iON_*/,0x004e4f49/*ION_*/};
00070     static unsigned int sdp_[8] = {
00071         0x00706473/*sdp_*/,0x00706453/*Sdp_*/,0x00704473/*sDp_*/,
00072         0x00704453/*SDp_*/,0x00506473/*sdP_*/,0x00506453/*SdP_*/,
00073         0x00504473/*sDP_*/,0x00504453/*SDP_*/};
00074     str           str_type;
00075     unsigned int  x;
00076     char          *p;
00077 
00078     if (!msg->content_type){
00079         if (parse_headers(msg, HDR_CONTENTTYPE_F, 0)<0){
00080             LOG(L_ERR,"ERR:"M_NAME":check_content_type: error parsing headers\n");
00081             return 1;   
00082         }
00083     }
00084     if (!msg->content_type)
00085     {
00086         LOG(L_WARN,"WARNING: check_content_type: Content-TYPE header absent!"
00087             "let's assume the content is text/plain ;-)\n");
00088         return 1;
00089     }
00090 
00091     trim_len(str_type.len,str_type.s,msg->content_type->body);
00092     p = str_type.s;
00093     advance(p,4,str_type,error_1);
00094     x = READ(p-4);
00095     if (!one_of_16(x,appl))
00096         goto other;
00097     advance(p,4,str_type,error_1);
00098     x = READ(p-4);
00099     if (!one_of_16(x,icat))
00100         goto other;
00101     advance(p,3,str_type,error_1);
00102     x = READ(p-3) & 0x00ffffff;
00103     if (!one_of_8(x,ion_))
00104         goto other;
00105 
00106     /* skip spaces and tabs if any */
00107     while (*p==' ' || *p=='\t')
00108         advance(p,1,str_type,error_1);
00109     if (*p!='/')
00110     {
00111         LOG(L_ERR, "ERROR:check_content_type: parse error:"
00112             "no / found after primary type\n");
00113         goto error;
00114     }
00115     advance(p,1,str_type,error_1);
00116     while ((*p==' ' || *p=='\t') && p+1<str_type.s+str_type.len)
00117         advance(p,1,str_type,error_1);
00118 
00119     advance(p,3,str_type,error_1);
00120     x = READ(p-3) & 0x00ffffff;
00121     if (!one_of_8(x,sdp_))
00122         goto other;
00123 
00124     if (*p==';'||*p==' '||*p=='\t'||*p=='\n'||*p=='\r'||*p==0) {
00125         DBG("DEBUG:check_content_type: type <%.*s> found valid\n",
00126             (int)(p-str_type.s), str_type.s);
00127         return 1;
00128     } else {
00129         LOG(L_ERR,"ERROR:check_content_type: bad end for type!\n");
00130         return -1;
00131     }
00132 
00133 error_1:
00134     LOG(L_ERR,"ERROR:check_content_type: parse error: body ended :-(!\n");
00135 error:
00136     return -1;
00137 other:
00138     LOG(L_ERR,"ERROR:check_content_type: invalid type for a message\n");
00139     return -1;
00140 }
00141 
00142 int extract_body(struct sip_msg *msg, str *body )
00143 {
00144     
00145     body->s = get_body(msg);
00146     if (body->s==0) {
00147         LOG(L_ERR, "ERROR: extract_body: failed to get the message body\n");
00148         goto error;
00149     }
00150     body->len = msg->len -(int)(body->s-msg->buf);
00151     if (body->len==0) {
00152         LOG(L_ERR, "ERROR: extract_body: message body has length zero\n");
00153         goto error;
00154     }
00155     
00156     /* no need for parse_headers(msg, EOH), get_body will 
00157      * parse everything */
00158     /*is the content type correct?*/
00159     if (check_content_type(msg)==-1)
00160     {
00161         LOG(L_ERR,"ERROR: extract_body: content type mismatching\n");
00162         goto error;
00163     }
00164     
00165     /*DBG("DEBUG:extract_body:=|%.*s|\n",body->len,body->s);*/
00166 
00167     return 1;
00168 error:
00169     return -1;
00170 }
00171 
00172 
00173 
00174 static int isnulladdr(str *sx, int pf)
00175 {
00176     char *cp;
00177 
00178     if (pf == AF_INET6) {
00179         for(cp = sx->s; cp < sx->s + sx->len; cp++)
00180             if (*cp != '0' && *cp != ':')
00181                 return 0;
00182         return 1;
00183     }
00184     return (sx->len == 7 && memcmp("0.0.0.0", sx->s, 7) == 0);
00185 }
00186 
00187 static int extract_mediaport(str *body, str *mediaport)
00188 {
00189     char *cp, *cp1;
00190     int len, i;
00191     str ptype;
00192 
00193     cp1 = NULL;
00194     for (cp = body->s; (len = body->s + body->len - cp) > 0;) {
00195         cp1 = ser_memmem(cp, "m=", len, 2);
00196         if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
00197             break;
00198         cp = cp1 + 2;
00199     }
00200     if (cp1 == NULL) {
00201         LOG(L_ERR, "ERROR: extract_mediaport: no `m=' in SDP\n");
00202         return -1;
00203     }
00204     mediaport->s = cp1 + 2; /* skip `m=' */
00205     mediaport->len = eat_line(mediaport->s, body->s + body->len -
00206       mediaport->s) - mediaport->s;
00207     trim_len(mediaport->len, mediaport->s, *mediaport);
00208 
00209     /* Skip media supertype and spaces after it */
00210     cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
00211     mediaport->len -= cp - mediaport->s;
00212     if (mediaport->len <= 0 || cp == mediaport->s) {
00213         LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n");
00214         return -1;
00215     }
00216     mediaport->s = cp;
00217     cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len);
00218     mediaport->len -= cp - mediaport->s;
00219     if (mediaport->len <= 0 || cp == mediaport->s) {
00220         LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n");
00221         return -1;
00222     }
00223     /* Extract port */
00224     mediaport->s = cp;
00225     cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
00226     ptype.len = mediaport->len - (cp - mediaport->s);
00227     if (ptype.len <= 0 || cp == mediaport->s) {
00228         LOG(L_ERR, "ERROR: extract_mediaport: no port in `m='\n");
00229         return -1;
00230     }
00231     ptype.s = cp;
00232     mediaport->len = cp - mediaport->s;
00233     /* Skip spaces after port */
00234     cp = eat_space_end(ptype.s, ptype.s + ptype.len);
00235     ptype.len -= cp - ptype.s;
00236     if (ptype.len <= 0 || cp == ptype.s) {
00237         LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n");
00238         return -1;
00239     }
00240     /* Extract protocol type */
00241     ptype.s = cp;
00242     cp = eat_token_end(ptype.s, ptype.s + ptype.len);
00243     if (cp == ptype.s) {
00244         LOG(L_ERR, "ERROR: extract_mediaport: no protocol type in `m='\n");
00245         return -1;
00246     }
00247     ptype.len = cp - ptype.s;
00248 
00249     for (i = 0; sup_ptypes[i].s != NULL; i++)
00250         if (ptype.len == sup_ptypes[i].len &&
00251             strncasecmp(ptype.s, sup_ptypes[i].s, ptype.len) == 0)
00252             return 0;
00253     /* Unproxyable protocol type. Generally it isn't error. */
00254     return -1;
00255 }
00256 
00257 
00258 static int extract_mediaip(str *body, str *mediaip, int *pf)
00259 {
00260     char *cp, *cp1;
00261     int len, nextisip;
00262 
00263     cp1 = NULL;
00264     for (cp = body->s; (len = body->s + body->len - cp) > 0;) {
00265         cp1 = ser_memmem(cp, "c=", len, 2);
00266         if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
00267             break;
00268         cp = cp1 + 2;
00269     }
00270     if (cp1 == NULL) {
00271         LOG(L_ERR, "ERROR: extract_mediaip: no `c=' in SDP\n");
00272         return -1;
00273     }
00274     mediaip->s = cp1 + 2;
00275     mediaip->len = eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s;
00276     trim_len(mediaip->len, mediaip->s, *mediaip);
00277 
00278     nextisip = 0;
00279     for (cp = mediaip->s; cp < mediaip->s + mediaip->len;) {
00280         len = eat_token_end(cp, mediaip->s + mediaip->len) - cp;
00281         if (nextisip == 1) {
00282             mediaip->s = cp;
00283             mediaip->len = len;
00284             nextisip++;
00285             break;
00286         }
00287         if (len == 3 && memcmp(cp, "IP", 2) == 0) {
00288             switch (cp[2]) {
00289             case '4':
00290                 nextisip = 1;
00291                 *pf = AF_INET;
00292                 break;
00293 
00294             case '6':
00295                 nextisip = 1;
00296                 *pf = AF_INET6;
00297                 break;
00298 
00299             default:
00300                 break;
00301             }
00302         }
00303         cp = eat_space_end(cp + len, mediaip->s + mediaip->len);
00304     }
00305     if (nextisip != 2 || mediaip->len == 0) {
00306         LOG(L_ERR, "ERROR: extract_mediaip: "
00307             "no `IP[4|6]' in `c=' field\n");
00308         return -1;
00309     }
00310     return 1;
00311 }
00312 
00313 
00314 
00315 //static int sdp_1918(struct sip_msg* msg)
00316 //{
00317 //  str body, ip;
00318 //  int pf;
00319 //
00320 //  if (extract_body(msg, &body) == -1) {
00321 //      LOG(L_ERR,"ERROR: sdp_1918: cannot extract body from msg!\n");
00322 //      return 0;
00323 //  }
00324 //  if (extract_mediaip(&body, &ip, &pf) == -1) {
00325 //      LOG(L_ERR, "ERROR: sdp_1918: can't extract media IP from the SDP\n");
00326 //      return 0;
00327 //  }
00328 //  if (pf != AF_INET || isnulladdr(&ip, pf))
00329 //      return 0;
00330 //
00331 //  return (is1918addr(&ip) == 1) ? 1 : 0;
00332 //}
00333 
00334 static int alter_mediaip(struct sip_msg *msg, str *body, str *oldip, int oldpf,
00335             str *newip, int newpf, int preserve)
00336 {
00337     char *buf;
00338     int offset;
00339     struct lump* anchor;
00340     str omip, nip, oip;
00341 
00342     /* check that updating mediaip is really necessary */
00343     if (oldpf == newpf && isnulladdr(oldip, oldpf))
00344         return 0;
00345     if (newip->len == oldip->len && memcmp(newip->s, oldip->s, newip->len) == 0)
00346         return 0;
00347 
00348     /*
00349      * Since rewriting the same info twice will mess SDP up,
00350      * apply simple anti foot shooting measure - put flag on
00351      * messages that have been altered and check it when
00352      * another request comes.
00353      */
00354 #if 0
00355     /* disabled:
00356      *  - alter_mediaip is called twice if 2 c= lines are present
00357      *    in the sdp (and we want to allow it)
00358      *  - the message flags are propagated in the on_reply_route
00359      *  => if we set the flags for the request they will be seen for the
00360      *    reply too, but we don't want that
00361      *  --andrei
00362      */
00363     if (msg->msg_flags & FL_SDP_IP_AFS) {
00364         LOG(L_ERR, "ERROR: alter_mediaip: you can't rewrite the same "
00365           "SDP twice, check your config!\n");
00366         return -1;
00367     }
00368 #endif
00369 
00370     if (preserve != 0) {
00371         anchor = anchor_lump(msg, body->s + body->len - msg->buf  , 0, 0);
00372         if (anchor == NULL) 
00373         {
00374             LOG(L_ERR, "ERROR: alter_mediaip: anchor_lump failed\n");
00375             return -1;
00376         }
00377         if (oldpf == AF_INET6) 
00378         {
00379             omip.s = AOLDMEDIP6 ;
00380             omip.len = AOLDMEDIP6_LEN;
00381         } else {
00382             omip.s = AOLDMEDIP;
00383             omip.len = AOLDMEDIP_LEN;
00384         }
00385         buf = pkg_malloc(omip.len + oldip->len + CRLF_LEN);
00386         if (buf == NULL) 
00387         {
00388             LOG(L_ERR, "ERROR: alter_mediaip: out of memory\n");
00389             return -1;
00390         }
00391         memcpy(buf, omip.s, omip.len);
00392         memcpy(buf + omip.len, oldip->s, oldip->len);
00393         memcpy(buf + omip.len + oldip->len, CRLF, CRLF_LEN);
00394         if (insert_new_lump_after(anchor, buf,
00395             omip.len + oldip->len + CRLF_LEN, 0) == NULL) {
00396             LOG(L_ERR, "ERROR: alter_mediaip: insert_new_lump_after failed\n");
00397             pkg_free(buf);
00398             return -1;
00399         }
00400     }
00401 
00402     if (oldpf == newpf) {
00403         nip.len = newip->len;
00404         nip.s = pkg_malloc(nip.len);
00405         if (nip.s == NULL) {
00406             LOG(L_ERR, "ERROR: alter_mediaip: out of memory\n");
00407             return -1;
00408         }
00409         memcpy(nip.s, newip->s, newip->len);
00410     } else {
00411         nip.len = newip->len + 2;
00412         nip.s = pkg_malloc(nip.len);
00413         if (nip.s == NULL) {
00414             LOG(L_ERR, "ERROR: alter_mediaip: out of memory\n");
00415             return -1;
00416         }
00417         memcpy(nip.s + 2, newip->s, newip->len);
00418         nip.s[0] = (newpf == AF_INET6) ? '6' : '4';
00419         nip.s[1] = ' ';
00420     }
00421 
00422     oip = *oldip;
00423     if (oldpf != newpf) {
00424         do {
00425             oip.s--;
00426             oip.len++;
00427         } while (*oip.s != '6' && *oip.s != '4');
00428     }
00429     offset = oip.s - msg->buf;
00430     anchor = del_lump(msg, offset, oip.len, 0);
00431     if (anchor == NULL) {
00432         LOG(L_ERR, "ERROR: alter_mediaip: del_lump failed\n");
00433         pkg_free(nip.s);
00434         return -1;
00435     }
00436 
00437 #if 0
00438     msg->msg_flags |= FL_SDP_IP_AFS;
00439 #endif
00440 
00441     if (insert_new_lump_after(anchor, nip.s, nip.len, 0) == 0) {
00442         LOG(L_ERR, "ERROR: alter_mediaip: insert_new_lump_after failed\n");
00443         pkg_free(nip.s);
00444         return -1;
00445     }
00446     return 0;
00447 }
00448 
00449 
00450 
00451 
00452 static int alter_mediaport(struct sip_msg *msg, str *body, str *oldport, str *newport,
00453   int preserve)
00454 {
00455     char *buf;
00456     int offset;
00457     struct lump* anchor;
00458 
00459     /* check that updating mediaport is really necessary */
00460     if (newport->len == oldport->len &&
00461         memcmp(newport->s, oldport->s, newport->len) == 0)
00462         return 0;
00463 
00464     /*
00465      * Since rewriting the same info twice will mess SDP up,
00466      * apply simple anti foot shooting measure - put flag on
00467      * messages that have been altered and check it when
00468      * another request comes.
00469      */
00470 #if 0
00471     /* disabled: - it propagates to the reply and we don't want this
00472      *  -- andrei */
00473     if (msg->msg_flags & FL_SDP_PORT_AFS) {
00474         LOG(L_ERR, "ERROR: alter_mediaip: you can't rewrite the same "
00475           "SDP twice, check your config!\n");
00476         return -1;
00477     }
00478 #endif
00479 
00480     if (preserve != 0) {
00481         anchor = anchor_lump(msg, body->s + body->len - msg->buf, 0, 0);
00482         if (anchor == NULL) {
00483             LOG(L_ERR, "ERROR: alter_mediaport: anchor_lump failed\n");
00484             return -1;
00485         }
00486         buf = pkg_malloc(AOLDMEDPRT_LEN + oldport->len + CRLF_LEN);
00487         if (buf == NULL) {
00488             LOG(L_ERR, "ERROR: alter_mediaport: out of memory\n");
00489             return -1;
00490         }
00491         memcpy(buf, AOLDMEDPRT, AOLDMEDPRT_LEN);
00492         memcpy(buf + AOLDMEDPRT_LEN, oldport->s, oldport->len);
00493         memcpy(buf + AOLDMEDPRT_LEN + oldport->len, CRLF, CRLF_LEN);
00494         if (insert_new_lump_after(anchor, buf,
00495             AOLDMEDPRT_LEN + oldport->len + CRLF_LEN, 0) == NULL) {
00496             LOG(L_ERR, "ERROR: alter_mediaport: insert_new_lump_after failed\n");
00497             pkg_free(buf);
00498             return -1;
00499         }
00500     }
00501 
00502     buf = pkg_malloc(newport->len);
00503     if (buf == NULL) {
00504         LOG(L_ERR, "ERROR: alter_mediaport: out of memory\n");
00505         return -1;
00506     }
00507     offset = oldport->s - msg->buf;
00508     anchor = del_lump(msg, offset, oldport->len, 0);
00509     if (anchor == NULL) {
00510         LOG(L_ERR, "ERROR: alter_mediaport: del_lump failed\n");
00511         pkg_free(buf);
00512         return -1;
00513     }
00514     memcpy(buf, newport->s, newport->len);
00515     if (insert_new_lump_after(anchor, buf, newport->len, 0) == 0) {
00516         LOG(L_ERR, "ERROR: alter_mediaport: insert_new_lump_after failed\n");
00517         pkg_free(buf);
00518         return -1;
00519     }
00520 
00521 #if 0
00522     msg->msg_flags |= FL_SDP_PORT_AFS;
00523 #endif
00524     return 0;
00525 }
00526 
00527 static char * find_sdp_line(char* p, char* plimit, char linechar)
00528 {
00529     static char linehead[3] = "x=";
00530     char *cp, *cp1;
00531     linehead[0] = linechar;
00532     /* Iterate thru body */
00533     cp = p;
00534     for (;;) {
00535         if (cp >= plimit)
00536             return NULL;
00537         cp1 = ser_memmem(cp, linehead, plimit-cp, 2);
00538         if (cp1 == NULL)
00539             return NULL;
00540         /*
00541          * As it is body, we assume it has previous line and we can
00542          * lookup previous character.
00543          */
00544         if (cp1[-1] == '\n' || cp1[-1] == '\r')
00545             return cp1;
00546         /*
00547          * Having such data, but not at line beginning.
00548          * Skip them and reiterate. ser_memmem() will find next
00549          * occurence.
00550          */
00551         if (plimit - cp1 < 2)
00552             return NULL;
00553         cp = cp1 + 2;
00554     }
00555     /*UNREACHED*/
00556     return NULL;
00557 }
00558 
00559 static char * find_next_sdp_line(char* p, char* plimit, char linechar, char* defptr)
00560 {
00561     char *t;
00562     if (p >= plimit || plimit - p < 3)
00563         return defptr;
00564     t = find_sdp_line(p + 2, plimit, linechar);
00565     return t ? t : defptr;
00566 }
00567 
00568 static inline int rfc1918address(str *address)
00569 {
00570     struct in_addr inaddr;
00571     uint32_t netaddr;
00572     int i, result;
00573     char c;
00574 
00575     c = address->s[address->len];
00576     address->s[address->len] = 0;
00577 
00578     result = inet_aton(address->s, &inaddr);
00579 
00580     address->s[address->len] = c;
00581 
00582     if (result==0)
00583         return -1; /* invalid address to test */
00584 
00585     netaddr = ntohl(inaddr.s_addr);
00586 
00587     for (i=0; nets_1918[i].cnetaddr!=NULL; i++) {
00588         if ((netaddr & nets_1918[i].mask)==nets_1918[i].netaddr) {
00589             return 1;
00590         }
00591     }
00592 
00593     return 0;
00594 }
00595 
00596 
00597 
00598 
00599 static inline int get_to_tag(struct sip_msg* _m, str* _tag)
00600 {
00601     if (!_m->to) {
00602         LOG(L_ERR, "get_to_tag(): To header field missing\n");
00603         return -1;
00604     }
00605 
00606     if (get_to(_m)->tag_value.len) {
00607         _tag->s = get_to(_m)->tag_value.s;
00608         _tag->len = get_to(_m)->tag_value.len;
00609     } else {
00610         _tag->s = 0; /* fixes gcc 4.0 warnings */
00611         _tag->len = 0;
00612     }
00613 
00614     return 0;
00615 }
00616 
00617 /*
00618  * Extract tag from From header field of a request
00619  */
00620 static inline int get_from_tag(struct sip_msg* _m, str* _tag)
00621 {
00622 
00623     if (parse_from_header(_m) == -1) {
00624         LOG(L_ERR, "get_from_tag(): Error while parsing From header\n");
00625         return -1;
00626     }
00627 
00628     if (get_from(_m)->tag_value.len) {
00629         _tag->s = get_from(_m)->tag_value.s;
00630         _tag->len = get_from(_m)->tag_value.len;
00631     } else {
00632         _tag->len = 0;
00633     }
00634 
00635     return 0;
00636 }
00637 
00638 static inline int get_callid(struct sip_msg* _m, str* _cid)
00639 {
00640 
00641     if ((parse_headers(_m, HDR_CALLID_F, 0) == -1)) {
00642         LOG(L_ERR, "get_callid(): parse_headers() failed\n");
00643         return -1;
00644     }
00645 
00646     if (_m->callid == NULL) {
00647         LOG(L_ERR, "get_callid(): Call-ID not found\n");
00648         return -1;
00649     }
00650 
00651     _cid->s = _m->callid->body.s;
00652     _cid->len = _m->callid->body.len;
00653     trim(_cid);
00654     return 0;
00655 }
00656 
00657 static char * gencookie()
00658 {
00659     static char cook[34];
00660 
00661     sprintf(cook, "%d_%u ", (int)getpid(), myseqn);
00662     myseqn++;
00663     return cook;
00664 }
00665 
00666 static char * send_rtpp_command(struct rtpp_node *node, struct iovec *v, int vcnt)
00667 {
00668     struct sockaddr_un addr;
00669     int fd, len, i;
00670     char *cp;
00671     static char buf[256];
00672     struct pollfd fds[1];
00673 
00674     len = 0;
00675     cp = buf;
00676     if (node->rn_umode == 0) {
00677         memset(&addr, 0, sizeof(addr));
00678         addr.sun_family = AF_LOCAL;
00679         strncpy(addr.sun_path, node->rn_address,
00680             sizeof(addr.sun_path) - 1);
00681 #ifdef HAVE_SOCKADDR_SA_LEN
00682         addr.sun_len = strlen(addr.sun_path);
00683 #endif
00684 
00685         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
00686         if (fd < 0) {
00687             LOG(L_ERR, "ERROR: send_rtpp_command: can't create socket\n");
00688             goto badproxy;
00689         }
00690         if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00691             close(fd);
00692             LOG(L_ERR, "ERROR: send_rtpp_command: can't connect to RTP proxy\n");
00693             goto badproxy;
00694         }
00695 
00696         do {
00697             len = writev(fd, v + 1, vcnt - 1);
00698         } while (len == -1 && errno == EINTR);
00699         if (len <= 0) {
00700             close(fd);
00701             LOG(L_ERR, "ERROR: send_rtpp_command: can't send command to a RTP proxy\n");
00702             goto badproxy;
00703         }
00704         do {
00705             len = read(fd, buf, sizeof(buf) - 1);
00706         } while (len == -1 && errno == EINTR);
00707         close(fd);
00708         if (len <= 0) {
00709             LOG(L_ERR, "ERROR: send_rtpp_command: can't read reply from a RTP proxy\n");
00710             goto badproxy;
00711         }
00712     } else {
00713         fds[0].fd = node->rn_fd;
00714         fds[0].events = POLLIN;
00715         fds[0].revents = 0;
00716         /* Drain input buffer */
00717         while ((poll(fds, 1, 0) == 1) &&
00718             ((fds[0].revents & POLLIN) != 0)) {
00719             recv(node->rn_fd, buf, sizeof(buf) - 1, 0);
00720             fds[0].revents = 0;
00721         }
00722         v[0].iov_base = gencookie();
00723         v[0].iov_len = strlen(v[0].iov_base);
00724         for (i = 0; i < rtpproxy_retr; i++) {
00725             do {
00726                 len = writev(node->rn_fd, v, vcnt);
00727             } while (len == -1 && (errno == EINTR || errno == ENOBUFS));
00728             if (len <= 0) {
00729                 LOG(L_ERR, "ERROR: send_rtpp_command: "
00730                     "can't send command to a RTP proxy\n");
00731                 goto badproxy;
00732             }
00733             while ((poll(fds, 1, rtpproxy_tout * 1000) == 1) &&
00734                 (fds[0].revents & POLLIN) != 0) {
00735                 do {
00736                     len = recv(node->rn_fd, buf, sizeof(buf) - 1, 0);
00737                 } while (len == -1 && errno == EINTR);
00738                 if (len <= 0) {
00739                     LOG(L_ERR, "ERROR: send_rtpp_command: "
00740                         "can't read reply from a RTP proxy\n");
00741                     goto badproxy;
00742                 }
00743                 if (len >= (v[0].iov_len - 1) &&
00744                     memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) {
00745                     len -= (v[0].iov_len - 1);
00746                     cp += (v[0].iov_len - 1);
00747                     if (len != 0) {
00748                         len--;
00749                         cp++;
00750                     }
00751                     goto out;
00752                 }
00753                 fds[0].revents = 0;
00754             }
00755         }
00756         if (i == rtpproxy_retr) {
00757             LOG(L_ERR, "ERROR: send_rtpp_command: "
00758                 "timeout waiting reply from a RTP proxy\n");
00759             goto badproxy;
00760         }
00761     }
00762 
00763 out:
00764     cp[len] = '\0';
00765     return cp;
00766 badproxy:
00767     LOG(L_ERR, "send_rtpp_command(): proxy <%s> does not responding, disable it\n", node->rn_url);
00768     node->rn_disabled = 1;
00769     node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;
00770     return NULL;
00771 }
00772 
00773 
00774 int rtpp_test(struct rtpp_node *node, int isdisabled, int force)
00775 {
00776     int rtpp_ver;
00777     char *cp;
00778     struct iovec v[2] = {{NULL, 0}, {"V", 1}};
00779     struct iovec vf[4] = {{NULL, 0}, {"VF", 2}, {" ", 1},
00780         {REQ_CPROTOVER, 8}};
00781 
00782     if (force == 0) {
00783         if (isdisabled == 0)
00784             return 0;
00785         if (node->rn_recheck_ticks > get_ticks())
00786             return 1;
00787     }
00788     do {
00789         cp = send_rtpp_command(node, v, 2);
00790         if (cp == NULL) {
00791             LOG(L_WARN,"WARNING: rtpp_test: can't get version of "
00792                 "the RTP proxy\n");
00793             break;
00794         }
00795         rtpp_ver = atoi(cp);
00796         if (rtpp_ver != SUP_CPROTOVER) {
00797             LOG(L_WARN, "WARNING: rtpp_test: unsupported "
00798                 "version of RTP proxy <%s> found: %d supported, "
00799                 "%d present\n", node->rn_url,
00800                 SUP_CPROTOVER, rtpp_ver);
00801             break;
00802         }
00803         cp = send_rtpp_command(node, vf, 4);
00804         if (cp == NULL) {
00805             LOG(L_WARN,"WARNING: rtpp_test: RTP proxy went down during "
00806                 "version query\n");
00807             break;
00808         }
00809         if (cp[0] == 'E' || atoi(cp) != 1) {
00810             LOG(L_WARN, "WARNING: rtpp_test: of RTP proxy <%s>"
00811                 "doesn't support required protocol version %s\n",
00812                 node->rn_url, REQ_CPROTOVER);
00813             break;
00814         }
00815         LOG(L_INFO, "rtpp_test: RTP proxy <%s> found, support for "
00816             "it %senabled\n",
00817             node->rn_url, force == 0 ? "re-" : "");
00818         return 0;
00819     } while(0);
00820     LOG(L_WARN, "WARNING: rtpp_test: support for RTP proxy <%s>"
00821         "has been disabled%s\n", node->rn_url,
00822         rtpproxy_disable_tout < 0 ? "" : " temporarily");
00823     if (rtpproxy_disable_tout >= 0)
00824         node->rn_recheck_ticks = get_ticks() + rtpproxy_disable_tout;
00825 
00826     return 1;
00827 }
00828 
00829 static struct rtpp_node * select_rtpp_node(str callid, int do_test, int node_idx) 
00830 {
00831     unsigned sum, sumcut, weight_sum;
00832     struct rtpp_node* node;
00833     int was_forced;
00834 
00835     /* Most popular case: 1 proxy, nothing to calculate */
00836     if (rtpp_node_count == 1) {
00837         if (node_idx > 0) {
00838             LOG(L_ERR, "ERROR: select_rtpp_node: node index out or range\n");
00839             return NULL;
00840         }
00841         node = rtpp_list.rn_first;
00842         if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
00843             /* Try to enable if it's time to try. */
00844             node->rn_disabled = rtpp_test(node, 1, 0);
00845         }
00846         return node->rn_disabled ? NULL : node;
00847     }
00848 
00849     if (node_idx != -1) {
00850         for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
00851             if (node_idx > 0) {
00852                 node_idx--;
00853                 continue;
00854             }
00855             if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
00856                 /* Try to enable if it's time to try. */
00857                 node->rn_disabled = rtpp_test(node, 1, 0);
00858             }
00859             return node->rn_disabled ? NULL : node;
00860         }
00861         LOG(L_ERR, "ERROR: select_rtpp_node: node index out or range\n");
00862         return NULL;
00863     }
00864 
00865     /* XXX Use quick-and-dirty hashing algo */
00866     for(sum = 0; callid.len > 0; callid.len--)
00867         sum += callid.s[callid.len - 1];
00868     sum &= 0xff;
00869 
00870     was_forced = 0;
00871 retry:
00872     weight_sum = 0;
00873     for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
00874         if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) {
00875             /* Try to enable if it's time to try. */
00876             node->rn_disabled = rtpp_test(node, 1, 0);
00877         }
00878         if (!node->rn_disabled)
00879             weight_sum += node->rn_weight;
00880     }
00881     if (weight_sum == 0) {
00882         /* No proxies? Force all to be redetected, if not yet */
00883         if (was_forced)
00884             return NULL;
00885         was_forced = 1;
00886         for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
00887             node->rn_disabled = rtpp_test(node, 1, 1);
00888         }
00889         goto retry;
00890     }
00891     sumcut = sum % weight_sum;
00892     /*
00893      * sumcut here lays from 0 to weight_sum-1.
00894      * Scan proxy list and decrease until appropriate proxy is found.
00895      */
00896     for (node = rtpp_list.rn_first; node != NULL; node = node->rn_next) {
00897         if (node->rn_disabled)
00898             continue;
00899         if (sumcut < node->rn_weight)
00900             goto found;
00901         sumcut -= node->rn_weight;
00902     }
00903     /* No node list */
00904     return NULL;
00905 found:
00906     if (do_test) {
00907         node->rn_disabled = rtpp_test(node, node->rn_disabled, 0);
00908         if (node->rn_disabled)
00909             goto retry;
00910     }
00911     return node;
00912 }
00913 
00914 
00915 static int
00916 force_rtp_proxy2_f(struct sip_msg* msg, char* str1, char* str2,int had_sdp_in_invite)
00917 {
00918     str body, body1, oldport, oldip, newport, newip;
00919     str callid, from_tag, to_tag, tmp;
00920     int create, port, len, asymmetric, flookup, argc, proxied, real;
00921     int oidx, pf=0, pf1, force, node_idx;
00922     char opts[16];
00923     char *cp, *cp1;
00924     char  *cpend, *next;
00925     char **ap, *argv[10];
00926     struct lump* anchor;
00927     struct rtpp_node *node;
00928     struct iovec v[14] = {
00929         {NULL, 0},  /* command */
00930         {NULL, 0},  /* options */
00931         {" ", 1},   /* separator */
00932         {NULL, 0},  /* callid */
00933         {" ", 1},   /* separator */
00934         {NULL, 7},  /* newip */
00935         {" ", 1},   /* separator */
00936         {NULL, 1},  /* oldport */
00937         {" ", 1},   /* separator */
00938         {NULL, 0},  /* from_tag */
00939         {";", 1},   /* separator */
00940         {NULL, 0},  /* medianum */
00941         {" ", 1},   /* separator */
00942         {NULL, 0}   /* to_tag */
00943     };
00944     char *v1p, *v2p, *c1p, *c2p, *m1p, *m2p, *bodylimit;
00945     char medianum_buf[20];
00946     int medianum, media_multi;
00947     str medianum_str, tmpstr1;
00948     int c1p_altered;
00949 
00950     v[1].iov_base=opts;
00951     asymmetric = flookup = force = real = 0;
00952     oidx = 1;
00953     node_idx = -1;
00954     for (cp = str1; *cp != '\0'; cp++) {
00955         switch (*cp) {
00956         case ' ':
00957         case '\t':
00958             break;
00959 
00960         case 'a':
00961         case 'A':
00962             opts[oidx++] = 'A';
00963             asymmetric = 1;
00964             real = 1;
00965             break;
00966 
00967         case 'i':
00968         case 'I':
00969             opts[oidx++] = 'I';
00970             break;
00971 
00972         case 'e':
00973         case 'E':
00974             opts[oidx++] = 'E';
00975             break;
00976 
00977         case 'l':
00978         case 'L':
00979             flookup = 1;
00980             break;
00981 
00982         case 'f':
00983         case 'F':
00984             force = 1;
00985             break;
00986 
00987         case 'r':
00988         case 'R':
00989             real = 1;
00990             break;
00991 
00992         case 'n':
00993         case 'N':
00994             cp++;
00995             for (len = 0; isdigit(cp[len]); len++)
00996                 continue;
00997             if (len == 0) {
00998                 LOG(L_ERR, "ERROR: force_rtp_proxy2: non-negative integer"
00999                     "should follow N option\n");
01000                 return -1;
01001             }
01002             node_idx = strtoul(cp, NULL, 10);
01003             cp += len - 1;
01004             break;
01005 
01006         default:
01007             LOG(L_ERR, "ERROR: force_rtp_proxy2: unknown option `%c'\n", *cp);
01008             return -1;
01009         }
01010     }
01011 
01012     if (msg->first_line.type == SIP_REQUEST &&
01013         msg->first_line.u.request.method_value == METHOD_INVITE) {
01014         create = 1;
01015     } else if (msg->first_line.type == SIP_REPLY) {
01016         if (had_sdp_in_invite) create = 0;
01017         else create = 1; // this was actually the first SDP, so we need to create it;
01018     } else if (msg->first_line.type == SIP_REQUEST &&
01019         msg->first_line.u.request.method_value == METHOD_ACK) {
01020         create = 0;
01021     } else {
01022         return -1;
01023     }
01024     /* extract_body will also parse all the headers in the message as
01025      * a side effect => don't move get_callid/get_to_tag in front of it
01026      * -- andrei */
01027     if (extract_body(msg, &body) == -1) {
01028         LOG(L_ERR, "ERROR: force_rtp_proxy2: can't extract body "
01029             "from the message\n");
01030         return -1;
01031     }
01032     if (get_callid(msg, &callid) == -1 || callid.len == 0) {
01033         LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get Call-Id field\n");
01034         return -1;
01035     }
01036     if (get_to_tag(msg, &to_tag) == -1) {
01037         LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get To tag\n");
01038         return -1;
01039     }
01040     if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
01041         LOG(L_ERR, "ERROR: force_rtp_proxy2: can't get From tag\n");
01042         return -1;
01043     }
01044     if (flookup != 0) {
01045         if (create == 0 || to_tag.len == 0)
01046             return -1;
01047         create = 0;
01048         tmp = from_tag;
01049         from_tag = to_tag;
01050         to_tag = tmp;
01051     }
01052     proxied = 0;
01053     for (cp = body.s; (len = body.s + body.len - cp) >= ANORTPPROXY_LEN;) {
01054         cp1 = ser_memmem(cp, ANORTPPROXY, len, ANORTPPROXY_LEN);
01055         if (cp1 == NULL)
01056             break;
01057         if (cp1[-1] == '\n' || cp1[-1] == '\r') {
01058             proxied = 1;
01059             break;
01060         }
01061         cp = cp1 + ANORTPPROXY_LEN;
01062     }
01063     if (proxied != 0 && force == 0)
01064         return -1;
01065     /*
01066      * Parsing of SDP body.
01067      * It can contain a few session descriptions (each starts with
01068      * v-line), and each session may contain a few media descriptions
01069      * (each starts with m-line).
01070      * We have to change ports in m-lines, and also change IP addresses in
01071      * c-lines which can be placed either in session header (fallback for
01072      * all medias) or media description.
01073      * Ports should be allocated for any media. IPs all should be changed
01074      * to the same value (RTP proxy IP), so we can change all c-lines
01075      * unconditionally.
01076      */
01077     bodylimit = body.s + body.len;
01078     v1p = find_sdp_line(body.s, bodylimit, 'v');
01079     if (v1p == NULL) {
01080         LOG(L_ERR, "ERROR: force_rtp_proxy2: no sessions in SDP\n");
01081         return -1;
01082     }
01083     v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
01084     media_multi = (v2p != bodylimit);
01085     v2p = v1p;
01086     medianum = 0;
01087     for(;;) {
01088         /* Per-session iteration. */
01089         v1p = v2p;
01090         if (v1p == NULL || v1p >= bodylimit)
01091             break; /* No sessions left */
01092         v2p = find_next_sdp_line(v1p, bodylimit, 'v', bodylimit);
01093         /* v2p is text limit for session parsing. */
01094         m1p = find_sdp_line(v1p, v2p, 'm');
01095         /* Have this session media description? */
01096         if (m1p == NULL) {
01097             LOG(L_ERR, "ERROR: force_rtp_proxy2: no m= in session\n");
01098             return -1;
01099         }
01100         /*
01101          * Find c1p only between session begin and first media.
01102          * c1p will give common c= for all medias.
01103          */
01104         c1p = find_sdp_line(v1p, m1p, 'c');
01105         c1p_altered = 0;
01106         /* Have session. Iterate media descriptions in session */
01107         m2p = m1p;
01108         for (;;) {
01109             m1p = m2p;
01110             if (m1p == NULL || m1p >= v2p)
01111                 break;
01112             m2p = find_next_sdp_line(m1p, v2p, 'm', v2p);
01113             /* c2p will point to per-media "c=" */
01114             c2p = find_sdp_line(m1p, m2p, 'c');
01115             /* Extract address and port */
01116             tmpstr1.s = c2p ? c2p : c1p;
01117             if (tmpstr1.s == NULL) {
01118                 /* No "c=" */
01119                 LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
01120                     " find media IP in the message\n");
01121                 return -1;
01122             }
01123             tmpstr1.len = v2p - tmpstr1.s; /* limit is session limit text */
01124             if (extract_mediaip(&tmpstr1, &oldip, &pf) == -1) {
01125                 LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
01126                     " extract media IP from the message\n");
01127                 return -1;
01128             }
01129             tmpstr1.s = m1p;
01130             tmpstr1.len = m2p - m1p;
01131             if (extract_mediaport(&tmpstr1, &oldport) == -1) {
01132                 LOG(L_ERR, "ERROR: force_rtp_proxy2: can't"
01133                     " extract media port from the message\n");
01134                 return -1;
01135             }
01136             ++medianum;
01137             if (asymmetric != 0 || real != 0) {
01138                 newip = oldip;
01139             } else {
01140                 newip.s = ip_addr2a(&msg->rcv.src_ip);
01141                 newip.len = strlen(newip.s);
01142             }
01143             /* XXX must compare address families in all addresses */
01144             if (pf == AF_INET6) {
01145                 opts[oidx] = '6';
01146                 oidx++;
01147             }
01148             snprintf(medianum_buf, sizeof medianum_buf, "%d", medianum);
01149             medianum_str.s = medianum_buf;
01150             medianum_str.len = strlen(medianum_buf);
01151             opts[0] = (create == 0) ? 'L' : 'U';
01152             v[1].iov_len = oidx;
01153             STR2IOVEC(callid, v[3]);
01154             STR2IOVEC(newip, v[5]);
01155             STR2IOVEC(oldport, v[7]);
01156             STR2IOVEC(from_tag, v[9]);
01157             if (1 || media_multi) /* XXX netch: can't choose now*/
01158             {
01159                 STR2IOVEC(medianum_str, v[11]);
01160             } else {
01161                 v[10].iov_len = v[11].iov_len = 0;
01162             }
01163             STR2IOVEC(to_tag, v[13]);
01164             do {
01165                 node = select_rtpp_node(callid, 1, node_idx);
01166                 if (!node) {
01167                     LOG(L_ERR, "ERROR: force_rtp_proxy2: no available proxies\n");
01168                     return -1;
01169                 }
01170                 cp = send_rtpp_command(node, v, (to_tag.len > 0) ? 14 : 12);
01171             } while (cp == NULL);
01172             /* Parse proxy reply to <argc,argv> */
01173             argc = 0;
01174             memset(argv, 0, sizeof(argv));
01175             cpend=cp+strlen(cp);
01176             next=eat_token_end(cp, cpend);
01177             for (ap = argv; cp<cpend; cp=next+1, next=eat_token_end(cp, cpend)){
01178                 *next=0;
01179                 if (*cp != '\0') {
01180                     *ap=cp;
01181                     argc++;
01182                     if ((char*)++ap >= ((char*)argv+sizeof(argv)))
01183                         break;
01184                 }
01185             }
01186             if (argc < 1) {
01187                 LOG(L_ERR, "force_rtp_proxy2: no reply from rtp proxy\n");
01188                 return -1;
01189             }
01190             port = atoi(argv[0]);
01191             if (port <= 0 || port > 65535) {
01192                 LOG(L_ERR, "force_rtp_proxy2: incorrect port in reply from rtp proxy\n");
01193                 return -1;
01194             }
01195 
01196             pf1 = (argc >= 3 && argv[2][0] == '6') ? AF_INET6 : AF_INET;
01197 
01198             if (isnulladdr(&oldip, pf)) {
01199                 if (pf1 == AF_INET6) {
01200                     newip.s = "::";
01201                     newip.len = 2;
01202                 } else {
01203                     newip.s = "0.0.0.0";
01204                     newip.len = 7;
01205                 }
01206             } else {
01207                 newip.s = (argc < 2) ? str2 : argv[1];
01208                 newip.len = strlen(newip.s);
01209             }
01210             newport.s = int2str(port, &newport.len); /* beware static buffer */
01211             /* Alter port. */
01212             body1.s = m1p;
01213             body1.len = bodylimit - body1.s;
01214             if (alter_mediaport(msg, &body1, &oldport, &newport, 0) == -1)
01215                 return -1;
01216             /*
01217              * Alter IP. Don't alter IP common for the session
01218              * more than once.
01219              */
01220             if (c2p != NULL || !c1p_altered) {
01221                 body1.s = c2p ? c2p : c1p;
01222                 body1.len = bodylimit - body1.s;
01223                 if (alter_mediaip(msg, &body1, &oldip, pf, &newip, pf1, 0) == -1)
01224                     return -1;
01225                 if (!c2p)
01226                     c1p_altered = 1;
01227             }
01228         } /* Iterate medias in session */
01229     } /* Iterate sessions */
01230 
01231     if (proxied == 0) {
01232         cp = pkg_malloc(ANORTPPROXY_LEN * sizeof(char));
01233         if (cp == NULL) {
01234             LOG(L_ERR, "ERROR: force_rtp_proxy2: out of memory\n");
01235             return -1;
01236         }
01237         anchor = anchor_lump(msg, body.s + body.len - msg->buf, 0, 0);
01238         if (anchor == NULL) {
01239             LOG(L_ERR, "ERROR: force_rtp_proxy2: anchor_lump failed\n");
01240             pkg_free(cp);
01241             return -1;
01242         }
01243         memcpy(cp, ANORTPPROXY, ANORTPPROXY_LEN);
01244         if (insert_new_lump_after(anchor, cp, ANORTPPROXY_LEN, 0) == NULL) {
01245             LOG(L_ERR, "ERROR: force_rtp_proxy2: insert_new_lump_after failed\n");
01246             pkg_free(cp);
01247             return -1;
01248         }
01249     }
01250 
01251     return 1;
01252 }
01253 static int unforce_rtp_proxy_f(struct sip_msg* msg, int node_idx)
01254 {
01255     str callid, from_tag, to_tag;
01256     struct rtpp_node *node;
01257     struct iovec v[1 + 4 + 3] = {{NULL, 0}, {"D", 1}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}, {" ", 1}, {NULL, 0}};
01258                         /* 1 */   /* 2 */   /* 3 */    /* 4 */   /* 5 */    /* 6 */   /* 1 */
01259     if (get_callid(msg, &callid) == -1 || callid.len == 0) {
01260         LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get Call-Id field\n");
01261         return -1;
01262     }
01263     if (get_to_tag(msg, &to_tag) == -1) {
01264         LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get To tag\n");
01265         return -1;
01266     }
01267     if (get_from_tag(msg, &from_tag) == -1 || from_tag.len == 0) {
01268         LOG(L_ERR, "ERROR: unforce_rtp_proxy: can't get From tag\n");
01269         return -1;
01270     }
01271     STR2IOVEC(callid, v[3]);
01272     STR2IOVEC(from_tag, v[5]);
01273     STR2IOVEC(to_tag, v[7]);
01274     node = select_rtpp_node(callid, 1, node_idx);
01275     if (!node) {
01276         LOG(L_ERR, "ERROR: unforce_rtp_proxy: no available proxies\n");
01277         return -1;
01278     }
01279     send_rtpp_command(node, v, (to_tag.len > 0) ? 8 : 6);
01280 
01281     return 1;
01282 }
01283 
01284 
01285 /* initialization of rtp_proxy module */