bignag change -- lot of things primarily added in relationship with
[sip-router] / forward.c
1 /*
2  * $Id$
3  */
4
5
6 #include <string.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/types.h>
10 #include <sys/socket.h>
11 #include <netdb.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14
15 #include "forward.h"
16 #include "hash_func.h"
17 #include "config.h"
18 #include "parser/msg_parser.h"
19 #include "route.h"
20 #include "dprint.h"
21 #include "udp_server.h"
22 #include "globals.h"
23 #include "data_lump.h"
24 #include "ut.h"
25 #include "mem/mem.h"
26 #include "msg_translator.h"
27 #include "sr_module.h"
28 #include "stats.h"
29 #include "ip_addr.h"
30 #include "resolve.h"
31
32 #ifdef DEBUG_DMALLOC
33 #include <dmalloc.h>
34 #endif
35
36
37
38 /* returns a socket_info pointer to the sending socket or 0 on error
39  * params: destination socke_union pointer
40  */
41 struct socket_info* get_send_socket(union sockaddr_union* to)
42 {
43         struct socket_info* send_sock;
44         
45         send_sock=0;
46         /* check if we need to change the socket (different address families -
47          * eg: ipv4 -> ipv6 or ipv6 -> ipv4) */
48         if (to->s.sa_family!=bind_address->address.af){
49                 switch(to->s.sa_family){
50                         case AF_INET:   send_sock=sendipv4;
51                                                         break;
52 #ifdef USE_IPV6
53                         case AF_INET6:  send_sock=sendipv6;
54                                                         break;
55 #endif
56                         default:                LOG(L_ERR, "get_send_socket: BUG: don't know how"
57                                                                         " to forward to af %d\n", to->s.sa_family);
58                 }
59         }else send_sock=bind_address;
60         return send_sock;
61 }
62
63
64
65 int forward_request( struct sip_msg* msg, struct proxy_l * p)
66 {
67         unsigned int len;
68         char* buf;
69         union sockaddr_union* to;
70         struct socket_info* send_sock;
71         char md5[MD5_LEN];
72         
73         to=0;
74         buf=0;
75         
76         to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
77         if (to==0){
78                 ser_error=E_OUT_OF_MEM;
79                 LOG(L_ERR, "ERROR: forward_request: out of memory\n");
80                 goto error;
81         }
82         
83         
84         /* if error try next ip address if possible */
85         if (p->ok==0){
86                 if (p->host.h_addr_list[p->addr_idx+1])
87                         p->addr_idx++;
88                 else p->addr_idx=0;
89                 p->ok=1;
90         }
91         
92         hostent2su(to, &p->host, p->addr_idx, 
93                                 (p->port)?htons(p->port):htons(SIP_PORT));
94         p->tx++;
95         p->tx_bytes+=len;
96         
97
98         send_sock=get_send_socket(to);
99         if (send_sock==0){
100                 LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d "
101                                 "no coresponding listening socket\n", to->s.sa_family);
102                 ser_error=E_NO_SOCKET;
103                 goto error1;
104         }
105
106         /* calculate branch for outbound request;  if syn_branch is turned off,
107            calculate is from transaction key, i.e., as an md5 of From/To/CallID/
108            CSeq exactly the same way as TM does; good for reboot -- than messages
109            belonging to transaction lost due to reboot will still be forwarded
110            with the same branch parameter and will be match-able downstream
111
112        if it is turned on, we don't care about reboot; we simply put a simple
113            value in there; better for performance
114         */
115
116         if (syn_branch ) {
117                 *msg->add_to_branch_s='0';
118                 msg->add_to_branch_len=1;
119         } else {
120                 if (!char_msg_val( msg, md5 ))  { /* parses transaction key */
121                         LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
122                         goto error1;
123                 }
124                 msg->hash_index=hash( msg->callid->body, get_cseq(msg)->number);
125                 if (!branch_builder( msg->hash_index, 0, md5, 0 /* 0-th branch */,
126                                         msg->add_to_branch_s, &msg->add_to_branch_len )) {
127                         LOG(L_ERR, "ERROR: forward_request: branch_builder failed\n");
128                         goto error1;
129                 }
130         }
131
132         buf = build_req_buf_from_sip_req( msg, &len, send_sock);
133         if (!buf){
134                 LOG(L_ERR, "ERROR: forward_request: building failed\n");
135                 goto error1;
136         }
137          /* send it! */
138         DBG("Sending:\n%s.\n", buf);
139         DBG("orig. len=%d, new_len=%d\n", msg->len, len );
140         
141         if (udp_send(send_sock, buf, len,  to,
142                                                         sizeof(union sockaddr_union))==-1){
143                         ser_error=E_SEND;
144                         p->errors++;
145                         p->ok=0;
146                         STATS_TX_DROPS;
147                         goto error1;
148         }
149         /* sent requests stats */
150         else STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
151         pkg_free(buf);
152         free(to);
153         /* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
154         return 0;
155
156 error1:
157         free(to);
158 error:
159         if (buf) pkg_free(buf);
160         return -1;
161 }
162
163
164 int update_sock_struct_from_ip( union sockaddr_union* to,
165         struct sip_msg *msg )
166 {
167         to->sin.sin_port=(msg->via1->port)
168                 ?htons(msg->via1->port): htons(SIP_PORT);
169         to->sin.sin_family=msg->src_ip.af;
170         memcpy(&to->sin.sin_addr, &msg->src_ip.u, msg->src_ip.len);
171
172         return 1;
173 }
174
175 int update_sock_struct_from_via( union sockaddr_union* to,
176                                                                  struct via_body* via )
177 {
178         struct hostent* he;
179         char *host_copy;
180         str* name;
181         unsigned short port;
182
183
184 #ifdef DNS_IP_HACK
185         int err;
186         unsigned int ip;
187 #endif
188
189
190         if (via->received){
191                 DBG("update_sock_struct_from_via: using 'received'\n");
192                 name=&(via->received->value);
193                 /* making sure that we won't do SRV lookup on "received"
194                  * (possible if no DNS_IP_HACK is used)*/
195                 port=via->port?via->port:SIP_PORT; 
196         }else{
197                 DBG("update_sock_struct_from_via: using via host\n");
198                 name=&(via->host);
199                 port=via->port;
200         }
201 #ifdef DNS_IP_HACK
202         ip=str2ip((unsigned char*)name->s, name->len,&err);
203         if (err==0){
204                 to->sin.sin_family=AF_INET;
205                 to->sin.sin_port=(via->port)?htons(via->port): htons(SIP_PORT);
206                 memcpy(&to->sin.sin_addr, (char*)&ip, 4);
207         }else
208 #endif
209         {
210                 /* we do now a malloc/memcpy because gethostbyname loves \0-terminated 
211                    strings; -jiri 
212                    but only if host is not null terminated
213                    (host.s[len] will always be ok for a via)
214            BTW: when is via->host.s non null terminated? tm copy?
215                    - andrei 
216                         Yes -- it happened on generating a 408 by TM; -jiri
217                 */
218                 if (name->s[name->len]){
219                         host_copy=pkg_malloc( name->len+1 );
220                         if (!host_copy) {
221                                 LOG(L_NOTICE, "ERROR: update_sock_struct_from_via:"
222                                                                 " not enough memory\n");
223                                 return -1;
224                         }
225                         memcpy(host_copy, name->s, name->len );
226                         host_copy[name->len]=0;
227                         DBG("update_sock_struct_from_via: trying SRV lookup\n");
228                         he=sip_resolvehost(host_copy, &port);
229                         
230                         pkg_free( host_copy );
231                 }else{
232                         DBG("update_sock_struct_from_via: trying SRV lookup\n");
233                         he=sip_resolvehost(name->s, &port);
234                 }
235                 
236                 if (he==0){
237                         LOG(L_NOTICE, "ERROR:forward_reply:resolve_host(%s) failure\n",
238                                         name->s);
239                         return -1;
240                 }
241                 hostent2su(to, he, 0, htons(port));
242         }
243         return 1;
244 }
245
246
247 /* removes first via & sends msg to the second */
248 int forward_reply(struct sip_msg* msg)
249 {
250         int  r;
251         char* new_buf;
252         union sockaddr_union* to;
253         struct socket_info* send_sock;
254         unsigned int new_len;
255         struct sr_module *mod;
256         
257         to=0;
258         new_buf=0;
259         /*check if first via host = us */
260         if (check_via){
261                 for (r=0; r<sock_no; r++)
262                 {
263                         DBG("forward_reply - checking if via==us: %d==%d && "
264                                         " [%.*s] == [%.*s]\n", 
265                                         msg->via1->host.len,
266                                         sock_info[r].name.len,
267                                         msg->via1->host.len, msg->via1->host.s,
268                                         sock_info[r].name.len, sock_info[r].name.s
269                                 );
270                         if ( (msg->via1->host.len==sock_info[r].name.len) && 
271         #ifdef USE_IPV6
272                                         (strncasecmp(msg->via1->host.s, sock_info[r].name.s,
273                                                                  sock_info[r].name.len)==0) /*slower*/
274         #else
275                                         (memcmp(msg->via1->host.s, sock_info[r].name.s, 
276                                                                                 sock_info[r].name.len)==0)
277         #endif
278                                         )
279                                 break;
280                 }
281                 if (r==sock_no){
282                         LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me :"
283                                         " %.*s\n", msg->via1->host.len, msg->via1->host.s);
284                         /* send error msg back? */
285                         goto error;
286                 }
287         }
288         /* quick hack, slower for mutliple modules*/
289         for (mod=modules;mod;mod=mod->next){
290                 if ((mod->exports) && (mod->exports->response_f)){
291                         DBG("forward_reply: found module %s, passing reply to it\n",
292                                         mod->exports->name);
293                         if (mod->exports->response_f(msg)==0) goto skip;
294                 }
295         }
296
297         /* we have to forward the reply stateless, so we need second via -bogdan*/
298         if (parse_headers( msg, HDR_VIA2, 0 )==-1 
299                 || (msg->via2==0) || (msg->via2->error!=PARSE_OK))
300         {
301                 /* no second via => error */
302                 LOG(L_ERR, "ERROR: forward_msg: no 2nd via found in reply\n");
303                 goto error;
304         }
305
306         to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
307         if (to==0){
308                 LOG(L_ERR, "ERROR: forward_reply: out of memory\n");
309                 goto error;
310         }
311
312         new_buf = build_res_buf_from_sip_res( msg, &new_len);
313         if (!new_buf){
314                 LOG(L_ERR, "ERROR: forward_reply: building failed\n");
315                 goto error;
316         }
317
318         if (update_sock_struct_from_via( to, msg->via2 )==-1) goto error;
319         send_sock=get_send_socket(to);
320         if (send_sock==0){
321                 LOG(L_ERR, "forward_reply: ERROR: no sending socket found\n");
322                 goto error;
323         }
324
325         if (udp_send(send_sock, new_buf,new_len,  to,
326                                 sizeof(union sockaddr_union))==-1)
327         {
328                 STATS_TX_DROPS;
329                 goto error;
330         } else {
331 #ifdef STATS
332                 int j = msg->first_line.u.reply.statuscode/100;
333                 STATS_TX_RESPONSE(  j );
334 #endif
335         }
336
337         DBG(" reply forwarded to %s:%d\n",msg->via2->host.s,
338                 (unsigned short) msg->via2->port);
339
340         pkg_free(new_buf);
341         free(to);
342 skip:
343         return 0;
344 error:
345         if (new_buf) pkg_free(new_buf);
346         if (to) free(to);
347         return -1;
348 }