gboolean socket_getSocketName(Socket* socket, in_addr_t* ip, in_port_t* port) { MAGIC_ASSERT(socket); /* boundAddress could be 0 (INADDR_NONE), so just check port */ if(!socket_isBound(socket)) { return FALSE; } if(ip) { *ip = socket->boundAddress; } if(port) { *port = socket->boundPort; } return TRUE; }
gint host_listenForPeer(Host* host, gint handle, gint backlog) { MAGIC_ASSERT(host); Descriptor* descriptor = host_lookupDescriptor(host, handle); if(descriptor == NULL) { warning("descriptor handle '%i' not found", handle); return EBADF; } DescriptorStatus status = descriptor_getStatus(descriptor); if(status & DS_CLOSED) { warning("descriptor handle '%i' not a valid open descriptor", handle); return EBADF; } DescriptorType type = descriptor_getType(descriptor); if(type != DT_TCPSOCKET) { warning("wrong type for descriptor handle '%i'", handle); return EOPNOTSUPP; } Socket* socket = (Socket*) descriptor; TCP* tcp = (TCP*) descriptor; if(!socket_isBound(socket)) { /* implicit bind */ in_addr_t bindAddress = htonl(INADDR_ANY); in_port_t bindPort = _host_getRandomFreePort(host, bindAddress, type); if(!bindPort) { return EADDRNOTAVAIL; } _host_associateInterface(host, socket, bindAddress, bindPort); } tcp_enterServerMode(tcp, backlog); return 0; }
gint host_connectToPeer(Host* host, gint handle, const struct sockaddr* address) { MAGIC_ASSERT(host); sa_family_t family = 0; in_addr_t peerIP = 0; in_port_t peerPort = 0; if(address->sa_family == AF_INET) { struct sockaddr_in* saddr = (struct sockaddr_in*) address; family = saddr->sin_family; peerIP = saddr->sin_addr.s_addr; peerPort = saddr->sin_port; } else if (address->sa_family == AF_UNIX) { struct sockaddr_un* saddr = (struct sockaddr_un*) address; family = saddr->sun_family; gchar* sockpath = saddr->sun_path; peerIP = htonl(INADDR_LOOPBACK); gpointer val = g_hash_table_lookup(host->unixPathToPortMap, sockpath); if(val) { peerPort = (in_port_t)GPOINTER_TO_UINT(val); } } in_addr_t loIP = htonl(INADDR_LOOPBACK); /* make sure we will be able to route this later */ if(peerIP != loIP) { Address* myAddress = networkinterface_getAddress(host->defaultInterface); Address* peerAddress = dns_resolveIPToAddress(worker_getDNS(), peerIP); if(!peerAddress || !topology_isRoutable(worker_getTopology(), myAddress, peerAddress)) { /* can't route it - there is no node with this address */ gchar* peerAddressString = address_ipToNewString(peerIP); warning("attempting to connect to address '%s:%u' for which no host exists", peerAddressString, ntohs(peerPort)); g_free(peerAddressString); return ECONNREFUSED; } } Descriptor* descriptor = host_lookupDescriptor(host, handle); if(descriptor == NULL) { warning("descriptor handle '%i' not found", handle); return EBADF; } DescriptorStatus status = descriptor_getStatus(descriptor); if(status & DS_CLOSED) { warning("descriptor handle '%i' not a valid open descriptor", handle); return EBADF; } DescriptorType type = descriptor_getType(descriptor); if(type != DT_TCPSOCKET && type != DT_UDPSOCKET) { warning("wrong type for descriptor handle '%i'", handle); return ENOTSOCK; } Socket* socket = (Socket*) descriptor; if(!socket_isFamilySupported(socket, family)) { return EAFNOSUPPORT; } if(type == DT_TCPSOCKET) { gint error = tcp_getConnectError((TCP*)socket); if(error) { return error; } } if (address->sa_family == AF_UNIX) { struct sockaddr_un* saddr = (struct sockaddr_un*) address; socket_setUnixPath(socket, saddr->sun_path, FALSE); } if(!socket_isBound(socket)) { /* do an implicit bind to a random port. * use default interface unless the remote peer is on loopback */ in_addr_t defaultIP = networkinterface_getIPAddress(host->defaultInterface); in_addr_t bindAddress = loIP == peerIP ? loIP : defaultIP; in_port_t bindPort = _host_getRandomFreePort(host, bindAddress, type); if(!bindPort) { return EADDRNOTAVAIL; } _host_associateInterface(host, socket, bindAddress, bindPort); } return socket_connectToPeer(socket, peerIP, peerPort, family); }
gint host_bindToInterface(Host* host, gint handle, const struct sockaddr* address) { MAGIC_ASSERT(host); in_addr_t bindAddress = 0; in_port_t bindPort = 0; if(address->sa_family == AF_INET) { struct sockaddr_in* saddr = (struct sockaddr_in*) address; bindAddress = saddr->sin_addr.s_addr; bindPort = saddr->sin_port; } else if (address->sa_family == AF_UNIX) { struct sockaddr_un* saddr = (struct sockaddr_un*) address; /* cant bind twice to the same unix path */ if(g_hash_table_lookup(host->unixPathToPortMap, saddr->sun_path)) { return EADDRINUSE; } bindAddress = htonl(INADDR_LOOPBACK); bindPort = 0; /* choose a random free port below */ } Descriptor* descriptor = host_lookupDescriptor(host, handle); if(descriptor == NULL) { warning("descriptor handle '%i' not found", handle); return EBADF; } DescriptorStatus status = descriptor_getStatus(descriptor); if(status & DS_CLOSED) { warning("descriptor handle '%i' not a valid open descriptor", handle); return EBADF; } DescriptorType type = descriptor_getType(descriptor); if(type != DT_TCPSOCKET && type != DT_UDPSOCKET) { warning("wrong type for descriptor handle '%i'", handle); return ENOTSOCK; } /* make sure we have an interface at that address */ if(!_host_doesInterfaceExist(host, bindAddress)) { return EADDRNOTAVAIL; } Socket* socket = (Socket*) descriptor; /* make sure socket is not bound */ if(socket_isBound(socket)) { warning("socket already bound to requested address"); return EINVAL; } /* make sure we have a proper port */ if(bindPort == 0) { /* we know it will be available */ bindPort = _host_getRandomFreePort(host, bindAddress, type); if(!bindPort) { return EADDRNOTAVAIL; } } else { /* make sure their port is available at that address for this protocol. */ if(!_host_isInterfaceAvailable(host, bindAddress, type, bindPort)) { return EADDRINUSE; } } /* bind port and set associations */ _host_associateInterface(host, socket, bindAddress, bindPort); if (address->sa_family == AF_UNIX) { struct sockaddr_un* saddr = (struct sockaddr_un*) address; gchar* sockpath = g_strndup(saddr->sun_path, 108); /* UNIX_PATH_MAX=108 */ socket_setUnixPath(socket, sockpath, TRUE); g_hash_table_replace(host->unixPathToPortMap, sockpath, GUINT_TO_POINTER(bindPort)); } return 0; }