Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 172440) +++ channels/chan_sip.c (working copy) @@ -1158,7 +1158,8 @@ /*! \brief The SIP socket definition */ struct sip_socket { enum sip_transport type; /*!< UDP, TCP or TLS */ - int fd; /*!< Filed descriptor, the actual socket */ + int fd; /*!< File descriptor, the actual socket */ + int *io_id; uint16_t port; struct ast_tcptls_session_instance *tcptls_session; /* If tcp or tls, a socket manager */ }; @@ -4265,6 +4266,9 @@ peer->socket.tcptls_session = NULL; } + if (peer->socket.fd > -1 && peer->socket.fd != sipsock && peer->socket.fd != sip_tcp_desc.accept_fd && peer->socket.fd != sip_tls_desc.accept_fd) { + ast_io_remove(io, peer->socket.io_id); + } ast_string_field_free_memory(peer); } @@ -20608,7 +20612,7 @@ } req.len = res; - req.socket.fd = sipsock; + req.socket.fd = fd; req.socket.type = SIP_TRANSPORT_UDP; req.socket.tcptls_session = NULL; req.socket.port = bindaddr.sin_port; @@ -22390,6 +22394,59 @@ if (!peer->socket.type) /*!< The first transport listed should be used for outgoing */ peer->socket.type = peer->transports; } + } else if (!strcasecmp(v->name, "udpbindaddr") && !ast_strlen_zero(v->value)) { + struct sockaddr_in sin, oldsin; + char *colonptr; + int sockfd; + const int reuseFlag = 1; + if ((colonptr = strchr(v->value, ':'))) { + *colonptr++ = '\0'; + sscanf(colonptr, "%hd", &peer->socket.port); + } + inet_aton(v->value, &sin.sin_addr); + sin.sin_port = peer->socket.port ? peer->socket.port : STANDARD_SIP_PORT; + + /* Is this the same info (no change required)? */ + if (peer->socket.fd > -1) { + socklen_t oldsin_len = sizeof(oldsin); + getsockname(peer->socket.fd, (struct sockaddr *) &oldsin, &oldsin_len); + if (oldsin.sin_addr.s_addr == sin.sin_addr.s_addr && oldsin.sin_port == sin.sin_port) { + continue; + } + } + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + ast_log(LOG_WARNING, "Unable to create SIP socket for peer %s: %s\n", name, strerror(errno)); + continue; + } + + setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (const char*)&reuseFlag, + sizeof reuseFlag); + + ast_enable_packet_fragmentation(sipsock); + + if (bind(sockfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + ast_log(LOG_WARNING, "Failed to bind to %s:%d: %s\n", + ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), + strerror(errno)); + close(sockfd); + sipsock = -1; + } else { + ast_verb(2, "SIP Listening on %s:%d\n", + ast_inet_ntoa(bindaddr.sin_addr), ntohs(bindaddr.sin_port)); + ast_netsock_set_qos(sipsock, global_tos_sip, global_cos_sip, "SIP"); + } + + /* Previously listening (on reload)? */ + if (peer->socket.fd > -1) { + int oldfd = peer->socket.fd; + peer->socket.fd = sockfd; + peer->socket.io_id = ast_io_change(io, peer->socket.io_id, sockfd, sipsock_read, AST_IO_IN, NULL); + close(oldfd); + } else { + peer->socket.io_id = ast_io_add(io, sockfd, sipsock_read, AST_IO_IN, NULL); + } } else if (realtime && !strcasecmp(v->name, "regseconds")) { ast_get_time_t(v->value, ®seconds, 0, NULL); } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) {