... | ... |
@@ -241,7 +241,7 @@ int do_action(struct action* a, struct sip_msg* msg) |
241 | 241 |
p->tx_bytes+=msg->len; |
242 | 242 |
if (a->type==SEND_T){ |
243 | 243 |
/*udp*/ |
244 |
- send_sock=get_send_socket(to, PROTO_UDP); |
|
244 |
+ send_sock=get_send_socket(msg, to, PROTO_UDP); |
|
245 | 245 |
if (send_sock!=0){ |
246 | 246 |
ret=udp_send(send_sock, msg->buf, msg->len, to); |
247 | 247 |
}else{ |
... | ... |
@@ -45,6 +45,7 @@ |
45 | 45 |
* 2003-10-21 check_self updated to handle proto (andrei) |
46 | 46 |
* 2003-10-24 converted to the new socket_info lists (andrei) |
47 | 47 |
* 2004-10-10 modified check_self to use grep_sock_info (andrei) |
48 |
+ * 2004-11-08 added force_send_socket support in get_send_socket (andrei) |
|
48 | 49 |
*/ |
49 | 50 |
|
50 | 51 |
|
... | ... |
@@ -79,6 +80,8 @@ |
79 | 80 |
#include <dmalloc.h> |
80 | 81 |
#endif |
81 | 82 |
|
83 |
+ |
|
84 |
+ |
|
82 | 85 |
/* return a socket_info_pointer to the sending socket; as opposed to |
83 | 86 |
* get_send_socket, which returns process's default socket, get_out_socket |
84 | 87 |
* attempts to determine the outbound interface which will be used; |
... | ... |
@@ -153,11 +156,29 @@ found: |
153 | 156 |
|
154 | 157 |
|
155 | 158 |
/* returns a socket_info pointer to the sending socket or 0 on error |
156 |
- * params: destination socket_union pointer |
|
159 |
+ * params: sip msg (can be null), destination socket_union pointer, protocol |
|
160 |
+ * if msg!=null and msg->force_send_socket, the force_send_socket will be |
|
161 |
+ * used |
|
157 | 162 |
*/ |
158 |
-struct socket_info* get_send_socket(union sockaddr_union* to, int proto) |
|
163 |
+struct socket_info* get_send_socket(struct sip_msg *msg, |
|
164 |
+ union sockaddr_union* to, int proto) |
|
159 | 165 |
{ |
160 | 166 |
struct socket_info* send_sock; |
167 |
+ |
|
168 |
+ /* check if send interface is not forced */ |
|
169 |
+ if (msg && msg->force_send_socket){ |
|
170 |
+ if (msg->force_send_socket->proto!=proto){ |
|
171 |
+ DBG("get_send_socket: force_send_socket of different proto" |
|
172 |
+ " (%d)!\n", proto); |
|
173 |
+ msg->force_send_socket=find_si(&(msg->force_send_socket->address), |
|
174 |
+ msg->force_send_socket->port_no, |
|
175 |
+ proto); |
|
176 |
+ } |
|
177 |
+ if (msg->force_send_socket) |
|
178 |
+ return msg->force_send_socket; |
|
179 |
+ else |
|
180 |
+ LOG(L_WARN, "WARNING: get_send_socket: protocol/port mismatch\n"); |
|
181 |
+ }; |
|
161 | 182 |
|
162 | 183 |
if (mhomed && proto==PROTO_UDP) return get_out_socket(to, proto); |
163 | 184 |
|
... | ... |
@@ -278,7 +299,7 @@ int forward_request( struct sip_msg* msg, struct proxy_l * p, int proto) |
278 | 299 |
p->tx_bytes+=len; |
279 | 300 |
|
280 | 301 |
|
281 |
- send_sock=get_send_socket(to, proto); |
|
302 |
+ send_sock=get_send_socket(msg, to, proto); |
|
282 | 303 |
if (send_sock==0){ |
283 | 304 |
LOG(L_ERR, "forward_req: ERROR: cannot forward to af %d, proto %d " |
284 | 305 |
"no corresponding listening socket\n", to->s.sa_family, proto); |
... | ... |
@@ -53,7 +53,9 @@ |
53 | 53 |
#endif |
54 | 54 |
|
55 | 55 |
|
56 |
-struct socket_info* get_send_socket(union sockaddr_union* su, int proto); |
|
56 |
+ |
|
57 |
+struct socket_info* get_send_socket(struct sip_msg* msg, |
|
58 |
+ union sockaddr_union* su, int proto); |
|
57 | 59 |
struct socket_info* get_out_socket(union sockaddr_union* to, int proto); |
58 | 60 |
int check_self(str* host, unsigned short port, unsigned short proto); |
59 | 61 |
int forward_request( struct sip_msg* msg, struct proxy_l* p, int proto); |
... | ... |
@@ -87,7 +89,7 @@ static inline int msg_send( struct socket_info* send_sock, int proto, |
87 | 89 |
{ |
88 | 90 |
|
89 | 91 |
if (proto==PROTO_UDP){ |
90 |
- if (send_sock==0) send_sock=get_send_socket(to, proto); |
|
92 |
+ if (send_sock==0) send_sock=get_send_socket(0, to, proto); |
|
91 | 93 |
if (send_sock==0){ |
92 | 94 |
LOG(L_ERR, "msg_send: ERROR: no sending socket found\n"); |
93 | 95 |
goto error; |
... | ... |
@@ -215,7 +215,7 @@ int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop, |
215 | 215 |
hostent2su( &to, &proxy->host, proxy->addr_idx, |
216 | 216 |
proxy->port ? proxy->port:SIP_PORT); |
217 | 217 |
|
218 |
- send_sock=get_send_socket( &to , proto); |
|
218 |
+ send_sock=get_send_socket( request, &to , proto); |
|
219 | 219 |
if (send_sock==0) { |
220 | 220 |
LOG(L_ERR, "ERROR: add_uac: can't fwd to af %d, proto %d " |
221 | 221 |
" (no corresponding listening socket)\n", |
... | ... |
@@ -933,7 +933,7 @@ int init_rb( struct retr_buf *rb, struct sip_msg *msg) |
933 | 933 |
*/ |
934 | 934 |
backup_mhomed=mhomed; |
935 | 935 |
mhomed=0; |
936 |
- send_sock=get_send_socket(&rb->dst.to, proto); |
|
936 |
+ send_sock=get_send_socket(msg, &rb->dst.to, proto); |
|
937 | 937 |
mhomed=backup_mhomed; |
938 | 938 |
if (send_sock==0) { |
939 | 939 |
LOG(L_ERR, "ERROR: init_rb: cannot fwd to af %d, proto %d " |
... | ... |
@@ -408,7 +408,7 @@ char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans, unsigned int branch |
408 | 408 |
|
409 | 409 |
|
410 | 410 |
/* via */ |
411 |
- send_sock = uri2sock(next_hop, &to_su, PROTO_NONE); |
|
411 |
+ send_sock = uri2sock(rpl, next_hop, &to_su, PROTO_NONE); |
|
412 | 412 |
if (!send_sock) { |
413 | 413 |
LOG(L_ERR, "build_dlg_ack: no socket found\n"); |
414 | 414 |
goto error; |
... | ... |
@@ -309,7 +309,8 @@ static char *build_local_ack(struct sip_msg* rpl, struct cell *trans, int branch |
309 | 309 |
* The function is used to send a localy generated ACK to INVITE |
310 | 310 |
* (tm generates the ACK on behalf of application using UAC |
311 | 311 |
*/ |
312 |
-static int send_local_ack(str* next_hop, char* ack, int ack_len) |
|
312 |
+static int send_local_ack(struct sip_msg* msg, str* next_hop, |
|
313 |
+ char* ack, int ack_len) |
|
313 | 314 |
{ |
314 | 315 |
struct socket_info* send_sock; |
315 | 316 |
union sockaddr_union to_su; |
... | ... |
@@ -319,7 +320,7 @@ static int send_local_ack(str* next_hop, char* ack, int ack_len) |
319 | 320 |
return -1; |
320 | 321 |
} |
321 | 322 |
|
322 |
- send_sock = uri2sock(next_hop, &to_su, PROTO_NONE); |
|
323 |
+ send_sock = uri2sock(msg, next_hop, &to_su, PROTO_NONE); |
|
323 | 324 |
if (!send_sock) { |
324 | 325 |
LOG(L_ERR, "send_local_ack: no socket found\n"); |
325 | 326 |
return -1; |
... | ... |
@@ -480,6 +481,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg) |
480 | 481 |
static struct cell *backup_t; |
481 | 482 |
static unsigned int backup_msgid; |
482 | 483 |
static struct usr_avp **backup_list; |
484 |
+ static struct socket_info* backup_si; |
|
483 | 485 |
|
484 | 486 |
if (msg) { |
485 | 487 |
/* remember we are back in request processing, but process |
... | ... |
@@ -502,6 +504,9 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg) |
502 | 504 |
set_t(t); |
503 | 505 |
/* make available the avp list from transaction */ |
504 | 506 |
backup_list = set_avp_list( &t->user_avps ); |
507 |
+ /* set default send address to the saved value */ |
|
508 |
+ backup_si=bind_address; |
|
509 |
+ bind_address=t->uac[0].request.dst.send_sock; |
|
505 | 510 |
} else { |
506 | 511 |
/* restore original environment */ |
507 | 512 |
set_t(backup_t); |
... | ... |
@@ -509,6 +514,7 @@ static inline void faked_env( struct cell *t,struct sip_msg *msg) |
509 | 514 |
rmode=backup_mode; |
510 | 515 |
/* restore original avp list */ |
511 | 516 |
set_avp_list( backup_list ); |
517 |
+ bind_address=backup_si; |
|
512 | 518 |
} |
513 | 519 |
} |
514 | 520 |
|
... | ... |
@@ -1255,7 +1261,7 @@ int reply_received( struct sip_msg *p_msg ) |
1255 | 1261 |
} else if ((t->flags & T_IS_LOCAL_FLAG) && msg_status >= 200) { |
1256 | 1262 |
ack = build_local_ack(p_msg, t, branch, &ack_len, &next_hop); |
1257 | 1263 |
if (ack) { |
1258 |
- if (send_local_ack(&next_hop, ack, ack_len) < 0) { |
|
1264 |
+ if (send_local_ack(p_msg, &next_hop, ack, ack_len) < 0) { |
|
1259 | 1265 |
LOG(L_ERR, "Error while sending local ACK\n"); |
1260 | 1266 |
} |
1261 | 1267 |
shm_free(ack); |
... | ... |
@@ -185,7 +185,8 @@ int t_uac(str* method, str* headers, str* body, dlg_t* dialog, |
185 | 185 |
|
186 | 186 |
DBG("DEBUG:tm:t_uac: next_hop=<%.*s>\n",dialog->hooks.next_hop->len, |
187 | 187 |
dialog->hooks.next_hop->s); |
188 |
- send_sock = uri2sock(dialog->hooks.next_hop, &to_su, PROTO_NONE); |
|
188 |
+ /* it's a new message, so we will take the default socket */ |
|
189 |
+ send_sock = uri2sock(0, dialog->hooks.next_hop, &to_su, PROTO_NONE); |
|
189 | 190 |
if (!send_sock) { |
190 | 191 |
ret=ser_error; |
191 | 192 |
LOG(L_ERR, "t_uac: no socket found\n"); |
... | ... |
@@ -267,7 +267,7 @@ static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) |
267 | 267 |
if (!new) goto error; |
268 | 268 |
/* substitute */ |
269 | 269 |
if (!sock_name) { |
270 |
- send_sock=uri2sock( uri, &to_su, proto ); |
|
270 |
+ send_sock=uri2sock(0, uri, &to_su, proto ); |
|
271 | 271 |
if (!send_sock) { |
272 | 272 |
LOG(L_ERR, "ERROR: get_hfblock: send_sock failed\n"); |
273 | 273 |
goto error; |
... | ... |
@@ -294,7 +294,7 @@ static char *get_hfblock(str *uri, struct hdr_field *hf, int *l, int proto) |
294 | 294 |
if (!new_str(begin, frag_len, &last, &total_len)) goto error; |
295 | 295 |
/* substitute */ |
296 | 296 |
if (!sock_name) { |
297 |
- send_sock = uri2sock(uri, &to_su, proto); |
|
297 |
+ send_sock = uri2sock(0, uri, &to_su, proto); |
|
298 | 298 |
if (!send_sock) { |
299 | 299 |
LOG(L_ERR, "ERROR: get_hfblock: send_sock failed\n"); |
300 | 300 |
goto error; |
... | ... |
@@ -133,7 +133,8 @@ inline static struct proxy_l *uri2proxy( str *uri, int proto ) |
133 | 133 |
/* |
134 | 134 |
* Convert a URI into socket_info |
135 | 135 |
*/ |
136 |
-static inline struct socket_info *uri2sock(str *uri, union sockaddr_union *to_su, int proto) |
|
136 |
+static inline struct socket_info *uri2sock(struct sip_msg* msg, str *uri, |
|
137 |
+ union sockaddr_union *to_su, int proto) |
|
137 | 138 |
{ |
138 | 139 |
struct proxy_l *proxy; |
139 | 140 |
struct socket_info* send_sock; |
... | ... |
@@ -148,7 +149,7 @@ static inline struct socket_info *uri2sock(str *uri, union sockaddr_union *to_su |
148 | 149 |
hostent2su(to_su, &proxy->host, proxy->addr_idx, |
149 | 150 |
(proxy->port) ? proxy->port : SIP_PORT); |
150 | 151 |
/* we use proxy->proto since uri2proxy just set it correctly*/ |
151 |
- send_sock = get_send_socket(to_su, proxy->proto); |
|
152 |
+ send_sock = get_send_socket(msg, to_su, proxy->proto); |
|
152 | 153 |
if (!send_sock) { |
153 | 154 |
LOG(L_ERR, "ERROR: uri2sock: no corresponding socket for af %d\n", |
154 | 155 |
to_su->s.sa_family); |
... | ... |
@@ -91,7 +91,7 @@ char* get_hdr_field(char* buf, char* end, struct hdr_field* hdr) |
91 | 91 |
} |
92 | 92 |
|
93 | 93 |
/* eliminate leading whitespace */ |
94 |
- tmp=eat_lws_end(tmp, end); |
|
94 |
+ /* tmp=eat_lws_end(tmp, end); not allowed anyway --andrei */ |
|
95 | 95 |
if (tmp>=end) { |
96 | 96 |
LOG(L_ERR, "ERROR: get_hdr_field: HF empty\n"); |
97 | 97 |
goto error; |
... | ... |
@@ -36,6 +36,7 @@ |
36 | 36 |
* 2003-04-11 updated the sip_uri structure (lots of fields added) (andrei) |
37 | 37 |
* 2003-04-12 added msg_flags to sip_msg (andrei) |
38 | 38 |
* 2003-11-02 added diversion header field to sip_msg (jh) |
39 |
+ * 2004-11-08 added force_send_socket (andrei) |
|
39 | 40 |
*/ |
40 | 41 |
|
41 | 42 |
|
... | ... |
@@ -237,6 +238,8 @@ struct sip_msg { |
237 | 238 |
flag_t flags; |
238 | 239 |
str set_global_address; |
239 | 240 |
str set_global_port; |
241 |
+ struct socket_info* force_send_socket; /* force sending on this socket, |
|
242 |
+ if ser */ |
|
240 | 243 |
}; |
241 | 244 |
|
242 | 245 |
/* pointer to a fakes message which was never received ; |
... | ... |
@@ -33,6 +33,7 @@ |
33 | 33 |
* -------- |
34 | 34 |
* 2003-10-22 created by andrei |
35 | 35 |
* 2004-10-10 added grep_sock_info (andrei) |
36 |
+ * 2004-11-08 added find_si (andrei) |
|
36 | 37 |
*/ |
37 | 38 |
|
38 | 39 |
|
... | ... |
@@ -205,7 +206,6 @@ struct socket_info* grep_sock_info(str* host, unsigned short port, |
205 | 206 |
#ifdef USE_IPV6 |
206 | 207 |
struct ip_addr* ip6; |
207 | 208 |
#endif |
208 |
- |
|
209 | 209 |
h_len=host->len; |
210 | 210 |
hname=host->s; |
211 | 211 |
#ifdef USE_IPV6 |
... | ... |
@@ -279,6 +279,53 @@ found: |
279 | 279 |
|
280 | 280 |
|
281 | 281 |
|
282 |
+/* checks if the proto: ip:port is one of the address we listen on |
|
283 |
+ * and returns the corresponding socket_info structure. |
|
284 |
+ * (same as grep_socket_info, but use ip addr instead) |
|
285 |
+ * if port==0, the port number is ignored |
|
286 |
+ * if proto==0 (PROTO_NONE) the protocol is ignored |
|
287 |
+ * returns 0 if not found |
|
288 |
+ * WARNING: uses str2ip6 so it will overwrite any previous |
|
289 |
+ * unsaved result of this function (static buffer) |
|
290 |
+ */ |
|
291 |
+struct socket_info* find_si(struct ip_addr* ip, unsigned short port, |
|
292 |
+ unsigned short proto) |
|
293 |
+{ |
|
294 |
+ struct socket_info* si; |
|
295 |
+ struct socket_info** list; |
|
296 |
+ unsigned short c_proto; |
|
297 |
+ |
|
298 |
+ c_proto=proto?proto:PROTO_UDP; |
|
299 |
+ do{ |
|
300 |
+ /* get the proper sock_list */ |
|
301 |
+ if (c_proto==PROTO_NONE) |
|
302 |
+ list=&udp_listen; |
|
303 |
+ else |
|
304 |
+ list=get_sock_info_list(c_proto); |
|
305 |
+ |
|
306 |
+ if (list==0){ |
|
307 |
+ LOG(L_WARN, "WARNING: grep_sock_info: " |
|
308 |
+ "unknown proto %d\n", c_proto); |
|
309 |
+ goto not_found; /* false */ |
|
310 |
+ } |
|
311 |
+ for (si=*list; si; si=si->next){ |
|
312 |
+ if (port) { |
|
313 |
+ if (si->port_no!=port) { |
|
314 |
+ continue; |
|
315 |
+ } |
|
316 |
+ } |
|
317 |
+ if (ip_addr_cmp(ip, &si->address)) |
|
318 |
+ goto found; |
|
319 |
+ } |
|
320 |
+ }while( (proto==0) && (c_proto=next_proto(c_proto)) ); |
|
321 |
+not_found: |
|
322 |
+ return 0; |
|
323 |
+found: |
|
324 |
+ return si; |
|
325 |
+} |
|
326 |
+ |
|
327 |
+ |
|
328 |
+ |
|
282 | 329 |
/* adds a new sock_info structure to the corresponding list |
283 | 330 |
* return 0 on success, -1 on error */ |
284 | 331 |
int new_sock2list(char* name, unsigned short port, unsigned short proto, |
... | ... |
@@ -59,6 +59,8 @@ void print_aliases(); |
59 | 59 |
|
60 | 60 |
struct socket_info* grep_sock_info(str* host, unsigned short port, |
61 | 61 |
unsigned short proto); |
62 |
+struct socket_info* find_si(struct ip_addr* ip, unsigned short port, |
|
63 |
+ unsigned short proto); |
|
62 | 64 |
|
63 | 65 |
/* helper function: |
64 | 66 |
* returns next protocol, if the last one is reached return 0 |
... | ... |
@@ -51,6 +51,7 @@ |
51 | 51 |
* 2003-11-17 handle_new_connect & tcp_connect will close the |
52 | 52 |
* new socket if tcpconn_new return 0 (e.g. out of mem) (andrei) |
53 | 53 |
* 2003-11-28 tcp_blocking_write & tcp_blocking_connect added (andrei) |
54 |
+ * 2004-11-08 dropped find_tcp_si and replaced with find_si (andrei) |
|
54 | 55 |
*/ |
55 | 56 |
|
56 | 57 |
|
... | ... |
@@ -368,22 +369,6 @@ error: |
368 | 369 |
|
369 | 370 |
|
370 | 371 |
|
371 |
- |
|
372 |
-struct socket_info* find_tcp_si(union sockaddr_union* s) |
|
373 |
-{ |
|
374 |
- struct ip_addr ip; |
|
375 |
- struct socket_info* si; |
|
376 |
- |
|
377 |
- su2ip_addr(&ip, s); |
|
378 |
- for (si=tcp_listen; si; si=si->next) |
|
379 |
- if (ip_addr_cmp(&ip, &si->address)){ |
|
380 |
- /* found it, we use first match */ |
|
381 |
- return si; |
|
382 |
- } |
|
383 |
- return 0; /* no match */ |
|
384 |
-} |
|
385 |
- |
|
386 |
- |
|
387 | 372 |
struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type) |
388 | 373 |
{ |
389 | 374 |
int s; |
... | ... |
@@ -391,6 +376,7 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type) |
391 | 376 |
union sockaddr_union my_name; |
392 | 377 |
socklen_t my_name_len; |
393 | 378 |
struct tcp_connection* con; |
379 |
+ struct ip_addr ip; |
|
394 | 380 |
|
395 | 381 |
s=socket(AF2PF(server->s.sa_family), SOCK_STREAM, 0); |
396 | 382 |
if (s==-1){ |
... | ... |
@@ -412,12 +398,13 @@ struct tcp_connection* tcpconn_connect(union sockaddr_union* server, int type) |
412 | 398 |
strerror(errno), errno); |
413 | 399 |
si=0; /* try to go on */ |
414 | 400 |
} |
401 |
+ su2ip_addr(&ip, &my_name); |
|
415 | 402 |
#ifdef USE_TLS |
416 | 403 |
if (type==PROTO_TLS) |
417 |
- si=find_tls_si(&my_name); |
|
404 |
+ si=find_si(&ip, 0, PROTO_TLS); |
|
418 | 405 |
else |
419 | 406 |
#endif |
420 |
- si=find_tcp_si(&my_name); |
|
407 |
+ si=find_si(&ip, 0, PROTO_TCP); |
|
421 | 408 |
|
422 | 409 |
if (si==0){ |
423 | 410 |
LOG(L_ERR, "ERROR: tcp_connect: could not find corresponding" |