core: Make sure that responses to requests received on a WebSocket are sent on existi...
[sip-router] / forward.c
index 4b58f71..89fe18f 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -124,6 +124,8 @@ static int sock_inet = -1;
 static int sock_inet6 = -1;
 #endif /* USE_IPV6 */
 
+static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg);
+
 struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
 {
        int* temp_sock;
@@ -131,6 +133,10 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
        union sockaddr_union from; 
        struct socket_info* si;
        struct ip_addr ip;
+       union sockaddr_union uncon;
+
+       memset(&uncon, 0, sizeof(union sockaddr_union));
+       uncon.sin.sin_family = AF_UNSPEC;
 
        if (unlikely(proto!=PROTO_UDP)) {
                LOG(L_CRIT, "BUG: get_out_socket can only be called for UDP\n");
@@ -167,6 +173,14 @@ retry:
                return 0;
        }
        }
+
+       if( !mhomed_sock_cache_disabled ){
+               /* some Linux kernel versions (all?) along with other UNIXes don't re-bound the sock if already bound */
+               /* to un-bound a socket set sin_family to AF_UNSPEC and zero out the rest*/
+               if (unlikely(connect(*temp_sock, &uncon.s, sockaddru_len(uncon)) < 0))
+                               mhomed_sock_cache_disabled = 1;
+       }
+
        if (unlikely(connect(*temp_sock, &to->s, sockaddru_len(*to))==-1)) {
                if (unlikely(errno==EISCONN && !mhomed_sock_cache_disabled)){
                        /*  no multiple connects support on the same socket */
@@ -234,26 +248,36 @@ struct socket_info* get_send_socket2(struct socket_info* force_send_socket,
                                                                                enum ss_mismatch* mismatch)
 {
        struct socket_info* send_sock;
+       struct socket_info* orig;
        
        if (likely(mismatch)) *mismatch=0;
        /* check if send interface is not forced */
        if (unlikely(force_send_socket)){
                if (unlikely(force_send_socket->proto!=proto)){
+                       orig=force_send_socket;
                        force_send_socket=find_si(&(force_send_socket->address),
                                                                                        force_send_socket->port_no,
                                                                                        proto);
                        if (unlikely(force_send_socket == 0)){
                                if (likely(mismatch)) *mismatch=SS_MISMATCH_ADDR;
                                LOG(L_WARN, "WARNING: get_send_socket: "
-                                               "protocol/port mismatch\n");
+                                               "protocol/port mismatch (forced %s:%s:%d,"
+                                               " to %s:%s)\n",
+                                               proto2a(orig->proto), ip_addr2a(&orig->address),
+                                               orig->port_no,
+                                               proto2a(proto), su2a(to, sizeof(*to)));
                                goto not_forced;
                        }
                        if (likely(mismatch)) *mismatch=SS_MISMATCH_PROTO;
                }
                if (unlikely(force_send_socket->address.af!=to->s.sa_family)){
-                       DBG("get_send_socket: force_send_socket of different af (dst %d,"
-                                       " forced %d)\n",
-                                       to->s.sa_family, force_send_socket->address.af);
+                       DBG("get_send_socket: force_send_socket of different af"
+                                       " (dst %d - %s:%s forced %d -%s:%s:%d)\n",
+                                       to->s.sa_family, proto2a(proto), su2a(to, sizeof(*to)),
+                                       force_send_socket->address.af,
+                                       proto2a(force_send_socket->proto),
+                                       ip_addr2a(&force_send_socket->address),
+                                       force_send_socket->port_no);
                        if (likely(mismatch)) *mismatch=SS_MISMATCH_AF;
                        goto not_forced;
                }
@@ -268,7 +292,11 @@ struct socket_info* get_send_socket2(struct socket_info* force_send_socket,
                else{
                        if (!(force_send_socket->flags & SI_IS_MCAST))
                                LOG(L_WARN, "WARNING: get_send_socket: not listening"
-                                                        " on the requested socket, no fork mode?\n");
+                                                        " on the requested socket (%s:%s:%d),"
+                                                        " no fork mode?\n",
+                                                       proto2a(force_send_socket->proto),
+                                                       ip_addr2a(&force_send_socket->address),
+                                                       force_send_socket->port_no);
                        else if (likely(mismatch)) *mismatch=SS_MISMATCH_MCAST;
                }
        };
@@ -279,7 +307,9 @@ not_forced:
                        return send_sock; /* found or error*/
                else if (send_sock->socket==-1){
                        LOG(L_WARN, "WARNING: get_send_socket: not listening on the"
-                                       " requested socket, no fork mode?\n");
+                                       " requested socket (%s:%s:%d), no fork mode?\n",
+                                       proto2a(send_sock->proto), ip_addr2a(&send_sock->address),
+                                       send_sock->port_no);
                        /* continue: try to use some socket */
                }
        }
@@ -289,6 +319,7 @@ not_forced:
         * eg: ipv4 -> ipv6 or ipv6 -> ipv4) */
        switch(proto){
 #ifdef USE_TCP
+               case PROTO_WS:
                case PROTO_TCP:
                /* on tcp just use the "main address", we don't really now the
                 * sending address (we can find it out, but we'll need also to see
@@ -358,7 +389,8 @@ not_forced:
                        }else send_sock=bind_address;
                        break;
                default:
-                       LOG(L_CRIT, "BUG: get_send_socket: unknown proto %d\n", proto);
+                       LOG(L_CRIT, "BUG: get_send_socket: unsupported proto %d (%s)\n",
+                                       proto, proto2a(proto));
        }
        return send_sock;
 }
@@ -368,6 +400,14 @@ static struct _check_self_func {
        struct _check_self_func *next;
 } *_check_self_func_list = NULL;
 
+/* check if _check_self_func_list is set
+ * - return 1 if yes, 0 if no
+ */
+int is_check_self_func_list_set(void)
+{
+       return (_check_self_func_list)?1:0;
+}
+
 /* register a function to be called when matching for myself
  * - return 0 on success, -1 on error
  * - f must have same prototype as check_self() and return same kind of values
@@ -514,8 +554,8 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
           value in there; better for performance
        */
        if (syn_branch ) {
-               *msg->add_to_branch_s='0';
-               msg->add_to_branch_len=1;
+               memcpy(msg->add_to_branch_s, "z9hG4bKcydzigwkX", 16);
+               msg->add_to_branch_len=16;
        } else {
                if (!char_msg_val( msg, md5 ))  { /* parses transaction key */
                        LOG(L_ERR, "ERROR: forward_request: char_msg_val failed\n");
@@ -603,8 +643,7 @@ int forward_request(struct sip_msg* msg, str* dst, unsigned short port,
                if (msg_send(send_info, buf, len)<0){
                        ret=ser_error=E_SEND;
 #ifdef USE_DST_BLACKLIST
-                       if (cfg_get(core, core_cfg, use_dst_blacklist))
-                               dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
+                       dst_blacklist_add(BLST_ERR_SEND, send_info, msg);
 #endif
 #ifdef USE_DNS_FAILOVER
                        continue; /* try another ip */
@@ -755,7 +794,7 @@ int forward_reply(struct sip_msg* msg)
                || (msg->via2==0) || (msg->via2->error!=PARSE_OK))
        {
                /* no second via => error */
-               LOG(L_ERR, "ERROR: forward_reply: no 2nd via found in reply\n");
+               LOG(L_DBG, "broken reply to forward - no 2nd via\n");
                goto error;
        }
 
@@ -766,7 +805,7 @@ int forward_reply(struct sip_msg* msg)
        }
 
        dst.proto=msg->via2->proto;
-       dst.send_flags=msg->fwd_send_flags | msg->rpl_send_flags;
+       SND_FLAGS_OR(&dst.send_flags, &msg->fwd_send_flags, &msg->rpl_send_flags);
        if (update_sock_struct_from_via( &dst.to, msg, msg->via2 )==-1) goto error;
 #ifdef USE_COMP
        dst.comp=msg->via2->comp_no;
@@ -801,6 +840,9 @@ int forward_reply(struct sip_msg* msg)
                                
        } 
 #endif
+
+       apply_force_send_socket(&dst, msg);
+
        if (msg_send(&dst, new_buf, new_len)<0)
        {
                STATS_RPL_FWD_DROP();
@@ -822,3 +864,10 @@ error:
        if (new_buf) pkg_free(new_buf);
        return -1;
 }
+
+static void apply_force_send_socket(struct dest_info* dst, struct sip_msg* msg)
+{
+       if (msg->force_send_socket != 0) {
+               dst->send_sock = get_send_socket(msg, &dst->to, dst->proto);
+       }
+}