void host_addApplication(Host* host, GQuark pluginID, SimulationTime startTime, SimulationTime stopTime, gchar* arguments) { MAGIC_ASSERT(host); Process* application = process_new(pluginID, startTime, stopTime, arguments); g_queue_push_tail(host->applications, application); StartApplicationEvent* event = startapplication_new(application); worker_scheduleEvent((Event*)event, startTime, host->id); if(stopTime > startTime) { StopApplicationEvent* event = stopapplication_new(application); worker_scheduleEvent((Event*)event, stopTime, host->id); } }
static void _epoll_check(Epoll* epoll, EpollWatch* watch) { MAGIC_ASSERT(epoll); MAGIC_ASSERT(watch); /* check if we need to schedule a notification */ gboolean needsNotify = _epollwatch_needsNotify(watch); gboolean isScheduled = (epoll->flags & EF_SCHEDULED) ? TRUE : FALSE; gpointer watchKey = descriptor_getHandleReference(watch->descriptor); if(needsNotify) { /* we need to report an event to user */ g_hash_table_replace(epoll->reports, watchKey, watch); if(!isScheduled) { /* schedule a notification event for our node */ NotifyPluginEvent* event = notifyplugin_new(epoll->super.handle); SimulationTime delay = 1; worker_scheduleEvent((Event*)event, delay, 0); epoll->flags |= EF_SCHEDULED; } } else { /* no longer needs reporting */ g_hash_table_remove(epoll->reports, watchKey); } }
void tracker_heartbeat(Tracker* tracker) { MAGIC_ASSERT(tracker); /* prefer our level over the global config */ GLogLevelFlags level = tracker->loglevel; if(!level) { Worker* w = worker_getPrivate(); if(w->cached_engine) { Configuration* c = engine_getConfig(w->cached_engine); level = configuration_getHeartbeatLogLevel(c); } } /* prefer our interval over the global config */ SimulationTime interval = tracker->interval; if(!interval) { Worker* w = worker_getPrivate(); if(w->cached_engine) { Configuration* c = engine_getConfig(w->cached_engine); interval = configuration_getHearbeatInterval(c); } } guint seconds = (guint) (interval / SIMTIME_ONE_SECOND); double in = (double) (tracker->inputBytesLastInterval); double out = (double)(tracker->outputBytesLastInterval); double alloc = (double)(((double)tracker->allocatedBytesLastInterval) / 1024.0); double dealloc = (double)(((double)tracker->deallocatedBytesLastInterval) / 1024.0); double mem = (double)(((double)tracker->allocatedBytesTotal) / 1024.0); double cpuutil = (double)(((double)tracker->processingTimeLastInterval) / interval); double avedelayms = 0.0; if(tracker->numDelayedLastInterval > 0) { double delayms = (double) (((double)tracker->delayTimeLastInterval) / ((double)SIMTIME_ONE_MILLISECOND)); avedelayms = (double) (delayms / ((double) tracker->numDelayedLastInterval)); } /* log the things we are tracking */ logging_log(G_LOG_DOMAIN, level, __FUNCTION__, "[shadow-heartbeat] CPU %f \%, MEM %f KiB, interval %u seconds, alloc %f KiB, dealloc %f KiB, Rx %f B, Tx %f B, avgdelay %f milliseconds", cpuutil, mem, seconds, alloc, dealloc, in, out, avedelayms); /* clear interval stats */ tracker->processingTimeLastInterval = 0; tracker->delayTimeLastInterval = 0; tracker->numDelayedLastInterval = 0; tracker->inputBytesLastInterval = 0; tracker->outputBytesLastInterval = 0; tracker->allocatedBytesLastInterval = 0; tracker->deallocatedBytesLastInterval = 0; /* schedule the next heartbeat */ tracker->lastHeartbeat = worker_getPrivate()->clock_now; HeartbeatEvent* heartbeat = heartbeat_new(tracker); worker_scheduleEvent((Event*)heartbeat, interval, 0); }
static void _networkinterface_scheduleNextReceive(NetworkInterface* interface) { /* the next packets need to be received and processed */ SimulationTime batchTime = worker_getConfig()->interfaceBatchTime; /* receive packets in batches */ while(!g_queue_is_empty(interface->inBuffer) && interface->receiveNanosecondsConsumed <= batchTime) { /* get the next packet */ Packet* packet = g_queue_pop_head(interface->inBuffer); utility_assert(packet); /* successfully received */ packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_RECEIVED); _networkinterface_pcapWritePacket(interface, packet); /* free up buffer space */ guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet); interface->inBufferLength -= length; /* calculate how long it took to 'receive' this packet */ interface->receiveNanosecondsConsumed += (length * interface->timePerByteDown); /* hand it off to the correct socket layer */ gint key = packet_getDestinationAssociationKey(packet); Socket* socket = g_hash_table_lookup(interface->boundSockets, GINT_TO_POINTER(key)); /* if the socket closed, just drop the packet */ gint socketHandle = -1; if(socket) { socketHandle = *descriptor_getHandleReference((Descriptor*)socket); socket_pushInPacket(socket, packet); } else { packet_addDeliveryStatus(packet, PDS_RCV_INTERFACE_DROPPED); } packet_unref(packet); /* count our bandwidth usage by interface, and by socket handle if possible */ tracker_addInputBytes(host_getTracker(worker_getCurrentHost()),(guint64)length, socketHandle); } /* * we need to call back and try to receive more, even if we didnt consume all * of our batch time, because we might have more packets to receive then. */ SimulationTime receiveTime = (SimulationTime) floor(interface->receiveNanosecondsConsumed); if(receiveTime >= SIMTIME_ONE_NANOSECOND) { /* we are 'receiving' the packets */ interface->flags |= NIF_RECEIVING; /* call back when the packets are 'received' */ InterfaceReceivedEvent* event = interfacereceived_new(interface); /* event destination is our node */ worker_scheduleEvent((Event*)event, receiveTime, 0); } }
static void _networkinterface_scheduleNextReceive(NetworkInterface* interface) { /* the next packets need to be received and processed */ SimulationTime batchTime = worker_getConfig()->interfaceBatchTime; /* receive packets in batches */ while(!g_queue_is_empty(interface->inBuffer) && interface->receiveNanosecondsConsumed <= batchTime) { /* get the next packet */ Packet* packet = g_queue_pop_head(interface->inBuffer); g_assert(packet); /* free up buffer space */ guint length = packet_getPayloadLength(packet) + packet_getHeaderSize(packet); interface->inBufferLength -= length; /* hand it off to the correct socket layer */ gint key = packet_getDestinationAssociationKey(packet); Socket* socket = g_hash_table_lookup(interface->boundSockets, GINT_TO_POINTER(key)); gchar* packetString = packet_getString(packet); debug("packet in: %s", packetString); g_free(packetString); _networkinterface_pcapWritePacket(interface, packet); /* if the socket closed, just drop the packet */ gint socketHandle = -1; if(socket) { socketHandle = *descriptor_getHandleReference((Descriptor*)socket); gboolean needsRetransmit = socket_pushInPacket(socket, packet); if(needsRetransmit) { /* socket can not handle it now, so drop it */ _networkinterface_dropInboundPacket(interface, packet); } } /* successfully received, calculate how long it took to 'receive' this packet */ interface->receiveNanosecondsConsumed += (length * interface->timePerByteDown); tracker_addInputBytes(node_getTracker(worker_getPrivate()->cached_node),(guint64)length, socketHandle); } /* * we need to call back and try to receive more, even if we didnt consume all * of our batch time, because we might have more packets to receive then. */ SimulationTime receiveTime = (SimulationTime) floor(interface->receiveNanosecondsConsumed); if(receiveTime >= SIMTIME_ONE_NANOSECOND) { /* we are 'receiving' the packets */ interface->flags |= NIF_RECEIVING; /* call back when the packets are 'received' */ InterfaceReceivedEvent* event = interfacereceived_new(interface); /* event destination is our node */ worker_scheduleEvent((Event*)event, receiveTime, 0); } }
void tracker_heartbeat(Tracker* tracker) { MAGIC_ASSERT(tracker); TrackerFlags flags = _tracker_getFlags(tracker); GLogLevelFlags level = _tracker_getLogLevel(tracker); SimulationTime interval = _tracker_getLogInterval(tracker); /* check to see if node info is being logged */ if(flags & TRACKER_FLAGS_NODE) { _tracker_logNode(tracker, level, interval); } /* check to see if socket buffer info is being logged */ if(flags & TRACKER_FLAGS_SOCKET) { _tracker_logSocket(tracker, level, interval); } /* check to see if ram info is being logged */ if(flags & TRACKER_FLAGS_RAM) { _tracker_logRAM(tracker, level, interval); } /* make sure we have the latest global configured flags */ tracker->globalFlags = _tracker_parseGlobalFlags(); /* clear interval stats */ tracker->processingTimeLastInterval = 0; tracker->delayTimeLastInterval = 0; tracker->numDelayedLastInterval = 0; tracker->allocatedBytesLastInterval = 0; tracker->deallocatedBytesLastInterval = 0; /* clear the counters */ memset(&tracker->local, 0, sizeof(IFaceCounters)); memset(&tracker->remote, 0, sizeof(IFaceCounters)); SocketStats* ss = NULL; GHashTableIter socketIterator; g_hash_table_iter_init(&socketIterator, tracker->socketStats); while (g_hash_table_iter_next(&socketIterator, NULL, (gpointer*)&ss)) { if(ss) { memset(&ss->local, 0, sizeof(IFaceCounters)); memset(&ss->remote, 0, sizeof(IFaceCounters)); } } /* schedule the next heartbeat */ tracker->lastHeartbeat = worker_getCurrentTime(); HeartbeatEvent* heartbeat = heartbeat_new(tracker); worker_scheduleEvent((Event*)heartbeat, interval, 0); }
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); } }
void application_callback(Application* application, CallbackFunc userCallback, gpointer userData, gpointer userArgument, guint millisecondsDelay) { MAGIC_ASSERT(application); /* the application wants a callback. since we need it to happen in our * application and plug-in context, we create a callback to our own * function first, and then redirect and execute theirs */ ApplicationCallbackData* data = g_new0(ApplicationCallbackData, 1); data->callback = userCallback; data->data = userData; data->argument = userArgument; CallbackEvent* event = callback_new((CallbackFunc)_application_callbackTimerExpired, application, data); SimulationTime nanos = SIMTIME_ONE_MILLISECOND * millisecondsDelay; /* callback to our own node */ worker_scheduleEvent((Event*)event, nanos, 0); }
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); } }
static void _tcp_setState(TCP* tcp, enum TCPState state) { MAGIC_ASSERT(tcp); tcp->stateLast = tcp->state; tcp->state = state; debug("%s <-> %s: moved from TCP state '%s' to '%s'", tcp->super.boundString, tcp->super.peerString, tcp_stateToAscii(tcp->stateLast), tcp_stateToAscii(tcp->state)); /* some state transitions require us to update the descriptor status */ switch (state) { case TCPS_LISTEN: { descriptor_adjustStatus((Descriptor*)tcp, DS_ACTIVE, TRUE); break; } case TCPS_SYNSENT: { break; } case TCPS_SYNRECEIVED: { break; } case TCPS_ESTABLISHED: { tcp->flags |= TCPF_WAS_ESTABLISHED; if(tcp->state != tcp->stateLast) { _tcp_autotune(tcp); } descriptor_adjustStatus((Descriptor*)tcp, DS_ACTIVE|DS_WRITABLE, TRUE); break; } case TCPS_CLOSING: { break; } case TCPS_CLOSEWAIT: { break; } case TCPS_CLOSED: { /* user can no longer use socket */ descriptor_adjustStatus((Descriptor*)tcp, DS_ACTIVE, FALSE); /* * servers have to wait for all children to close. * children need to notify their parents when closing. */ if(!tcp->server || g_hash_table_size(tcp->server->children) <= 0) { if(tcp->child && tcp->child->parent) { TCP* parent = tcp->child->parent; /* tell my server to stop accepting packets for me * this will destroy the child and NULL out tcp->child */ g_hash_table_remove(tcp->child->parent->server->children, (gconstpointer)&(tcp->child->key)); /* if i was the server's last child and its waiting to close, close it */ g_assert(parent->server); if((parent->state == TCPS_CLOSED) && (g_hash_table_size(parent->server->children) <= 0)) { /* this will unbind from the network interface and free socket */ node_closeDescriptor(worker_getPrivate()->cached_node, parent->super.super.super.handle); } } /* this will unbind from the network interface and free socket */ node_closeDescriptor(worker_getPrivate()->cached_node, tcp->super.super.super.handle); } break; } case TCPS_TIMEWAIT: { /* schedule a close timer self-event to finish out the closing process */ TCPCloseTimerExpiredEvent* event = tcpclosetimerexpired_new(tcp); worker_scheduleEvent((Event*)event, CONFIG_TCPCLOSETIMER_DELAY, 0); break; } default: break; } }
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); } }