void networkinterface_free(NetworkInterface* interface) { MAGIC_ASSERT(interface); /* unref all packets sitting in our input buffer */ while(interface->inBuffer && !g_queue_is_empty(interface->inBuffer)) { Packet* packet = g_queue_pop_head(interface->inBuffer); packet_unref(packet); } g_queue_free(interface->inBuffer); /* unref all sockets wanting to send */ while(interface->rrQueue && !g_queue_is_empty(interface->rrQueue)) { Socket* socket = g_queue_pop_head(interface->rrQueue); descriptor_unref(socket); } g_queue_free(interface->rrQueue); priorityqueue_free(interface->fifoQueue); g_hash_table_destroy(interface->boundSockets); dns_deregister(worker_getDNS(), interface->address); address_unref(interface->address); if(interface->pcapFile) { fclose(interface->pcapFile); } MAGIC_CLEAR(interface); g_free(interface); }
void tracker_updateSocketPeer(Tracker* tracker, gint handle, in_addr_t peerIP, in_port_t peerPort) { MAGIC_ASSERT(tracker); if(_tracker_getFlags(tracker) & TRACKER_FLAGS_SOCKET) { SocketStats* socket = g_hash_table_lookup(tracker->socketStats, &handle); if(socket) { socket->peerIP = peerIP; socket->peerPort = peerPort; GString* hostnameBuffer = g_string_new(NULL); if(peerIP == htonl(INADDR_LOOPBACK)) { g_string_printf(hostnameBuffer, "127.0.0.1"); } else if (peerIP == htonl(INADDR_ANY)) { g_string_printf(hostnameBuffer, "0.0.0.0"); } else { g_string_printf(hostnameBuffer, "%s", dns_resolveIPToName(worker_getDNS(), peerIP)); } /* free the old string if we already have one */ if(socket->peerHostname) { g_free(socket->peerHostname); } socket->peerHostname = g_string_free(hostnameBuffer, FALSE); } } }
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); }
Host* host_new(GQuark id, gchar* hostname, gchar* ipHint, gchar* geocodeHint, gchar* typeHint, guint64 requestedBWDownKiBps, guint64 requestedBWUpKiBps, guint cpuFrequency, gint cpuThreshold, gint cpuPrecision, guint nodeSeed, SimulationTime heartbeatInterval, GLogLevelFlags heartbeatLogLevel, gchar* heartbeatLogInfo, GLogLevelFlags logLevel, gboolean logPcap, gchar* pcapDir, gchar* qdisc, guint64 receiveBufferSize, gboolean autotuneReceiveBuffer, guint64 sendBufferSize, gboolean autotuneSendBuffer, guint64 interfaceReceiveLength) { Host* host = g_new0(Host, 1); MAGIC_INIT(host); host->id = id; host->name = g_strdup(hostname); host->random = random_new(nodeSeed); /* get unique virtual address identifiers for each network interface */ Address* loopbackAddress = dns_register(worker_getDNS(), host->id, host->name, "127.0.0.1"); Address* ethernetAddress = dns_register(worker_getDNS(), host->id, host->name, ipHint); /* connect to topology and get the default bandwidth */ guint64 bwDownKiBps = 0, bwUpKiBps = 0; topology_attach(worker_getTopology(), ethernetAddress, host->random, ipHint, geocodeHint, typeHint, &bwDownKiBps, &bwUpKiBps); /* prefer assigned bandwidth if available */ if(requestedBWDownKiBps) { bwDownKiBps = requestedBWDownKiBps; } if(requestedBWUpKiBps) { bwUpKiBps = requestedBWUpKiBps; } /* virtual addresses and interfaces for managing network I/O */ NetworkInterface* loopback = networkinterface_new(loopbackAddress, G_MAXUINT32, G_MAXUINT32, logPcap, pcapDir, qdisc, interfaceReceiveLength); NetworkInterface* ethernet = networkinterface_new(ethernetAddress, bwDownKiBps, bwUpKiBps, logPcap, pcapDir, qdisc, interfaceReceiveLength); host->interfaces = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) networkinterface_free); g_hash_table_replace(host->interfaces, GUINT_TO_POINTER((guint)networkinterface_getIPAddress(ethernet)), ethernet); g_hash_table_replace(host->interfaces, GUINT_TO_POINTER((guint)htonl(INADDR_LOOPBACK)), loopback); host->defaultInterface = ethernet; /* thread-level event communication with other nodes */ g_mutex_init(&(host->lock)); host->events = eventqueue_new(); host->availableDescriptors = g_queue_new(); host->descriptorHandleCounter = MIN_DESCRIPTOR; /* virtual descriptor management */ host->descriptors = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, descriptor_unref); host->receiveBufferSize = receiveBufferSize; host->sendBufferSize = sendBufferSize; host->autotuneReceiveBuffer = autotuneReceiveBuffer; host->autotuneSendBuffer = autotuneSendBuffer; host->shadowToOSHandleMap = g_hash_table_new(g_direct_hash, g_direct_equal); host->osToShadowHandleMap = g_hash_table_new(g_direct_hash, g_direct_equal); host->unixPathToPortMap = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); /* applications this node will run */ host->applications = g_queue_new(); host->cpu = cpu_new(cpuFrequency, cpuThreshold, cpuPrecision); host->tracker = tracker_new(heartbeatInterval, heartbeatLogLevel, heartbeatLogInfo); host->logLevel = logLevel; host->logPcap = logPcap; host->pcapDir = pcapDir; message("Created Host '%s', ip %s, " "%"G_GUINT64_FORMAT" bwUpKiBps, %"G_GUINT64_FORMAT" bwDownKiBps, %"G_GUINT64_FORMAT" initSockSendBufSize, %"G_GUINT64_FORMAT" initSockRecvBufSize, " "%u cpuFrequency, %i cpuThreshold, %i cpuPrecision, %u seed", g_quark_to_string(host->id), networkinterface_getIPName(host->defaultInterface), bwUpKiBps, bwDownKiBps, sendBufferSize, receiveBufferSize, cpuFrequency, cpuThreshold, cpuPrecision, nodeSeed); return host; }