- ipv6 support (-DUSE_IPV6)
[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 "config.h"
17 #include "parser/msg_parser.h"
18 #include "route.h"
19 #include "dprint.h"
20 #include "udp_server.h"
21 #include "globals.h"
22 #include "data_lump.h"
23 #include "ut.h"
24 #include "mem/mem.h"
25 #include "msg_translator.h"
26 #include "sr_module.h"
27 #include "stats.h"
28 #include "ip_addr.h"
29 #include "resolve.h"
30
31 #ifdef DEBUG_DMALLOC
32 #include <dmalloc.h>
33 #endif
34
35
36
37 int forward_request( struct sip_msg* msg, struct proxy_l * p)
38 {
39         unsigned int len;
40         char* buf;
41         union sockaddr_union* to;
42
43         to=0;
44         buf = build_req_buf_from_sip_req( msg, &len);
45         if (!buf){
46                 LOG(L_ERR, "ERROR: forward_reply: building failed\n");
47                 goto error;
48         }
49
50         to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
51         if (to==0){
52                 LOG(L_ERR, "ERROR: forward_request: out of memory\n");
53                 goto error;
54         }
55
56          /* send it! */
57         DBG("Sending:\n%s.\n", buf);
58         DBG("orig. len=%d, new_len=%d\n", msg->len, len );
59
60         /* if error try next ip address if possible */
61         if (p->ok==0){
62                 if (p->host.h_addr_list[p->addr_idx+1])
63                         p->addr_idx++;
64                 else p->addr_idx=0;
65                 p->ok=1;
66         }
67
68         hostent2su(to, &p->host, p->addr_idx, 
69                                 (p->port)?htons(p->port):htons(SIP_PORT));
70         p->tx++;
71         p->tx_bytes+=len;
72
73         if (udp_send( buf, len,  to, sizeof(union sockaddr_union))==-1){
74                         p->errors++;
75                         p->ok=0;
76                         STATS_TX_DROPS;
77                         goto error;
78         }
79         /* sent requests stats */
80         else STATS_TX_REQUEST(  msg->first_line.u.request.method_value );
81         pkg_free(buf);
82         free(to);
83         /* received_buf & line_buf will be freed in receiv_msg by free_lump_list*/
84         return 0;
85 error:
86         if (buf) pkg_free(buf);
87         if (to) free(to);
88         return -1;
89 }
90
91
92 int update_sock_struct_from_via( union sockaddr_union* to,  
93                                                                  struct via_body* via )
94 {
95         int err;
96         struct hostent* he;
97         unsigned int ip;
98         char *host_copy;
99
100
101 #ifdef DNS_IP_HACK
102         ip=str2ip((unsigned char*)via->host.s,via->host.len,&err);
103         if (err==0){
104                 to->sin.sin_family=AF_INET;
105                 to->sin.sin_port=(via->port)?htons(via->port): htons(SIP_PORT);
106                 memcpy(&to->sin.sin_addr, (char*)&ip, 4);
107         }else
108 #endif
109         {
110                 /* we do now a malloc/memcpy because gethostbyname loves \0-terminated 
111                    strings; -jiri 
112                    but only if host is not null terminated
113                    (host.s[len] will always be ok for a via)
114            BTW: when is via->host.s non null terminated? tm copy?
115                    - andrei 
116                 */
117                 if (via->host.s[via->host.len]){
118                         if (!(host_copy=pkg_malloc( via->host.len+1 ))) {
119                                 LOG(L_NOTICE, "ERROR: update_sock_struct_from_via: not enough memory\n");
120                                 return -1;
121                         }
122                         memcpy(host_copy, via->host.s, via->host.len );
123                         host_copy[via->host.len]=0;
124                         he=resolvehost(host_copy);
125                         pkg_free( host_copy );
126                 }else{
127                         he=resolvehost(via->host.s);
128                 }
129
130                 if (he==0){
131                         LOG(L_NOTICE, "ERROR:forward_reply:gethostbyname(%s) failure\n",
132                                         via->host.s);
133                         return -1;
134                 }
135                 hostent2su(to, he, 0, (via->port)?htons(via->port): htons(SIP_PORT));
136         }
137         return 1;
138 }
139
140
141 /* removes first via & sends msg to the second */
142 int forward_reply(struct sip_msg* msg)
143 {
144         int  r;
145         char* new_buf;
146         union sockaddr_union* to;
147         unsigned int new_len;
148         struct sr_module *mod;
149         
150         to=0;
151         new_buf=0;
152         /*check if first via host = us */
153         if (check_via){
154                 for (r=0; r<addresses_no; r++)
155                         if(strcmp(msg->via1->host.s, names[r])==0) break;
156                 if (r==addresses_no){
157                         LOG(L_NOTICE, "ERROR: forward_reply: host in first via!=me :"
158                                         " %s\n", msg->via1->host.s);
159                         /* send error msg back? */
160                         goto error;
161                 }
162         }
163
164         /* quick hack, slower for mutliple modules*/
165         for (mod=modules;mod;mod=mod->next){
166                 if ((mod->exports) && (mod->exports->response_f)){
167                         DBG("forward_reply: found module %s, passing reply to it\n",
168                                         mod->exports->name);
169                         if (mod->exports->response_f(msg)==0) goto skip;
170                 }
171         }
172         
173         /* we have to forward the reply stateless, so we need second via -bogdan*/
174         if ((msg->via2==0) || (msg->via2->error!=VIA_PARSE_OK))
175         {
176                 /* no second via => error */
177                 LOG(L_ERR, "ERROR: forward_msg: no 2nd via found in reply\n");
178                 goto error;
179         }
180
181         to=(union sockaddr_union*)malloc(sizeof(union sockaddr_union));
182         if (to==0){
183                 LOG(L_ERR, "ERROR: forward_reply: out of memory\n");
184                 goto error;
185         }
186
187         new_buf = build_res_buf_from_sip_res( msg, &new_len);
188         if (!new_buf){
189                 LOG(L_ERR, "ERROR: forward_reply: building failed\n");
190                 goto error;
191         }
192
193         if (update_sock_struct_from_via( to, msg->via2 )==-1) goto error;
194
195         if (udp_send(new_buf,new_len,  to,
196                                 sizeof(union sockaddr_union))==-1)
197         {
198                 STATS_TX_DROPS;
199                 goto error;
200         } else {
201 #ifdef STATS
202                 int j = msg->first_line.u.reply.statuscode/100;
203                 STATS_TX_RESPONSE(  j );
204 #endif
205         }
206
207         DBG(" reply forwarded to %s:%d\n",msg->via2->host.s,
208                 (unsigned short) msg->via2->port);
209
210         pkg_free(new_buf);
211         free(to);
212 skip:
213         return 0;
214 error:
215         if (new_buf) pkg_free(new_buf);
216         if (to) free(to);
217         return -1;
218 }