static void _networkinterface_dropInboundPacket(NetworkInterface* interface, Packet* packet) { MAGIC_ASSERT(interface); /* drop incoming packet that traversed the network link from source */ if(networkinterface_getIPAddress(interface) == packet_getSourceIP(packet)) { /* packet is on our own interface, so event destination is our node */ PacketDroppedEvent* event = packetdropped_new(packet); worker_scheduleEvent((Event*)event, 1, 0); } else { /* let the network schedule the event with appropriate delays */ network_scheduleRetransmit(interface->network, packet); } }
static void _networkinterface_scheduleNextSend(NetworkInterface* interface) { /* the next packet needs to be sent according to bandwidth limitations. * we need to spend time sending it before sending the next. */ SimulationTime batchTime = worker_getConfig()->interfaceBatchTime; /* loop until we find a socket that has something to send */ while(interface->sendNanosecondsConsumed <= batchTime) { gint socketHandle = -1; /* choose which packet to send next based on our queuing discipline */ Packet* packet; switch(interface->qdisc) { case NIQ_RR: { packet = _networkinterface_selectRoundRobin(interface, &socketHandle); break; } case NIQ_FIFO: default: { packet = _networkinterface_selectFirstInFirstOut(interface, &socketHandle); break; } } if(!packet) { break; } packet_addDeliveryStatus(packet, PDS_SND_INTERFACE_SENT); /* now actually send the packet somewhere */ if(networkinterface_getIPAddress(interface) == packet_getDestinationIP(packet)) { /* packet will arrive on our own interface */ PacketArrivedEvent* event = packetarrived_new(packet); /* event destination is our node */ worker_scheduleEvent((Event*)event, 1, 0); } else { /* let the worker schedule with appropriate delays */ worker_schedulePacket(packet); } /* successfully sent, calculate how long it took to 'send' this packet */ guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet); interface->sendNanosecondsConsumed += (length * interface->timePerByteUp); tracker_addOutputBytes(host_getTracker(worker_getCurrentHost()),(guint64)length, socketHandle); _networkinterface_pcapWritePacket(interface, packet); /* sending side is done with its ref */ packet_unref(packet); } /* * we need to call back and try to send more, even if we didnt consume all * of our batch time, because we might have more packets to send then. */ SimulationTime sendTime = (SimulationTime) floor(interface->sendNanosecondsConsumed); if(sendTime >= SIMTIME_ONE_NANOSECOND) { /* we are 'sending' the packets */ interface->flags |= NIF_SENDING; /* call back when the packets are 'sent' */ InterfaceSentEvent* event = interfacesent_new(interface); /* event destination is our node */ worker_scheduleEvent((Event*)event, sendTime, 0); } }
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; }
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); }
// TODO replace this with address object functions in_addr_t host_getDefaultIP(Host* host) { MAGIC_ASSERT(host); return networkinterface_getIPAddress(host->defaultInterface); }