static gboolean inf_tcp_connection_addr_info(InfNativeSocket socket, gboolean local, InfIpAddress** address, guint* port, GError** error) { union { struct sockaddr in_generic; struct sockaddr_in in; struct sockaddr_in6 in6; } native_addr; socklen_t len; int res; int code; len = sizeof(native_addr); if(local == TRUE) res = getsockname(socket, &native_addr.in_generic, &len); else res = getpeername(socket, &native_addr.in_generic, &len); if(res == -1) { code = INF_NATIVE_SOCKET_LAST_ERROR; inf_native_socket_make_error(code, error); return FALSE; } switch(native_addr.in_generic.sa_family) { case AF_INET: if(address != NULL) *address = inf_ip_address_new_raw4(native_addr.in.sin_addr.s_addr); if(port != NULL) *port = ntohs(native_addr.in.sin_port); break; case AF_INET6: if(address != NULL) *address = inf_ip_address_new_raw6(native_addr.in6.sin6_addr.s6_addr); if(port != NULL) *port = ntohs(native_addr.in6.sin6_port); break; default: g_assert_not_reached(); break; } return TRUE; }
void Gobby::Server::open(unsigned int port, InfXmppConnectionSecurityPolicy security_policy, InfCertificateCredentials* creds, InfSaslContext* context, const char* sasl_mechanisms) { // If we can open one of tcp4 or tcp6 that's a success. InfdTcpServer* tcp4; InfdTcpServer* tcp6; // If the server is already open and we do not need to change the // port, then just change the credentials and SASL context without // doing anything else. if(is_open() && get_port() == port) { set_credentials(security_policy, creds); set_sasl_context(context, sasl_mechanisms); return; } static const guint8 ANY6_ADDR[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; InfIpAddress* any6 = inf_ip_address_new_raw6(ANY6_ADDR); tcp4 = INFD_TCP_SERVER(g_object_new( INFD_TYPE_TCP_SERVER, "io", m_io, "local-address", NULL, "local-port", port, NULL)); tcp6 = INFD_TCP_SERVER(g_object_new( INFD_TYPE_TCP_SERVER, "io", m_io, "local-address", any6, "local-port", port, NULL)); inf_ip_address_free(any6); if(!infd_tcp_server_open(tcp6, NULL)) { g_object_unref(tcp6); tcp6 = NULL; GError* error = NULL; if(!infd_tcp_server_open(tcp4, &error)) { g_object_unref(tcp4); const std::string message = error->message; g_error_free(error); throw std::runtime_error(message); } } else { if(!infd_tcp_server_open(tcp4, NULL)) { g_object_unref(tcp4); tcp4 = NULL; } } // We have the new server open, from this point on there is nothing // that can go wrong anymore. Therefore, close the old server and // take over the new one. if(is_open()) close(); InfXmppConnectionSecurityPolicy policy = INF_XMPP_CONNECTION_SECURITY_ONLY_UNSECURED; if(creds != NULL) policy = security_policy; if(tcp4) { m_xmpp4 = infd_xmpp_server_new( tcp4, security_policy, creds, context, sasl_mechanisms); g_object_unref(tcp4); } if(tcp6) { m_xmpp6 = infd_xmpp_server_new( tcp6, security_policy, creds, context, sasl_mechanisms); g_object_unref(tcp6); } if(m_pool) { if(m_xmpp4 != NULL) { infd_server_pool_add_server( m_pool, INFD_XML_SERVER(m_xmpp4)); infd_server_pool_add_local_publisher( m_pool, m_xmpp4, m_publisher); } if(m_xmpp6 != NULL) { infd_server_pool_add_server( m_pool, INFD_XML_SERVER(m_xmpp6)); infd_server_pool_add_local_publisher( m_pool, m_xmpp6, m_publisher); } } }