void worker_schedulePacket(Packet* packet) { /* get our thread-private worker */ Worker* worker = _worker_getPrivate(); if(slave_isKilled(worker->slave)) { /* the simulation is over, don't bother */ return; } in_addr_t srcIP = packet_getSourceIP(packet); in_addr_t dstIP = packet_getDestinationIP(packet); Address* srcAddress = dns_resolveIPToAddress(worker_getDNS(), (guint32) srcIP); Address* dstAddress = dns_resolveIPToAddress(worker_getDNS(), (guint32) dstIP); if(!srcAddress || !dstAddress) { error("unable to schedule packet because of null addresses"); return; } /* check if network reliability forces us to 'drop' the packet */ gdouble reliability = topology_getReliability(worker_getTopology(), srcAddress, dstAddress); Random* random = host_getRandom(worker_getCurrentHost()); gdouble chance = random_nextDouble(random); /* don't drop control packets with length 0, otherwise congestion * control has problems responding to packet loss */ if(chance <= reliability || packet_getPayloadLength(packet) == 0) { /* the sender's packet will make it through, find latency */ gdouble latency = topology_getLatency(worker_getTopology(), srcAddress, dstAddress); SimulationTime delay = (SimulationTime) ceil(latency * SIMTIME_ONE_MILLISECOND); PacketArrivedEvent* event = packetarrived_new(packet); worker_scheduleEvent((Event*)event, delay, (GQuark)address_getID(dstAddress)); packet_addDeliveryStatus(packet, PDS_INET_SENT); } else { packet_addDeliveryStatus(packet, PDS_INET_DROPPED); } }
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); }