void connectnetwork_run(ConnectNetworkAction* action) { MAGIC_ASSERT(action); internetwork_connectNetworks(worker_getInternet(), action->sourceClusterID, action->destinationClusterID, action->latency, action->jitter, action->packetloss, action->latencymin, action->latencyQ1, action->latencymean, action->latencyQ3, action->latencymax); }
void worker_scheduleEvent(Event* event, SimulationTime nano_delay, GQuark receiver_node_id) { /* TODO create accessors, or better yet refactor the work to event class */ MAGIC_ASSERT(event); MAGIC_ASSERT((&(event->super))); /* get our thread-private worker */ Worker* worker = worker_getPrivate(); Engine* engine = worker->cached_engine; /* when the event will execute */ event->time = worker->clock_now + nano_delay; /* parties involved. sender may be NULL, receiver may not! */ Node* sender = worker->cached_node; /* we MAY NOT OWN the receiver, so do not write to it! */ Node* receiver = receiver_node_id == 0 ? sender : internetwork_getNode(worker_getInternet(), receiver_node_id); g_assert(receiver); /* the NodeEvent needs a pointer to the correct node */ event->node = receiver; /* if we are not going to execute any more events, free it and return */ if(engine_isKilled(engine)) { shadowevent_free(event); return; } /* engine is not killed, assert accurate worker clock */ g_assert(worker->clock_now != SIMTIME_INVALID); /* non-local events must be properly delayed */ SimulationTime jump = engine_getMinTimeJump(engine); if(!node_isEqual(receiver, sender)) { SimulationTime minTime = worker->clock_now + jump; /* warn and adjust time if needed */ if(event->time < minTime) { debug("Inter-node event time %lu changed to %lu due to minimum delay %lu", event->time, minTime, jump); event->time = minTime; } } /* figure out where to push the event */ if(engine_getNumThreads(engine) > 1) { /* multi-threaded, push event to receiver node */ EventQueue* eventq = node_getEvents(receiver); eventqueue_push(eventq, event); } else { /* single-threaded, push to master queue */ engine_pushEvent(engine, (Event*)event); } }
int system_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { /* FIXME this is not fully implemented */ if(!sa) { return EAI_FAIL; } gint retval = 0; Node* node = _system_switchInShadowContext(); GQuark convertedIP = (GQuark) (((struct sockaddr_in*)sa)->sin_addr.s_addr); const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP); if(hostname) { g_utf8_strncpy(host, hostname, hostlen); } else { retval = EAI_NONAME; } _system_switchOutShadowContext(node); return retval; }
void createnetwork_run(CreateNetworkAction* action) { MAGIC_ASSERT(action); internetwork_createNetwork(worker_getInternet(), action->id, action->bandwidthdown, action->bandwidthup, action->packetloss); }
gint system_getAddrInfo(gchar *name, const gchar *service, const struct addrinfo *hgints, struct addrinfo **res) { Node* node = _system_switchInShadowContext(); gint result = 0; *res = NULL; if(name != NULL && node != NULL) { /* node may be a number-and-dots address, or a hostname. lets hope for hostname * and try that first, o/w convert to the in_addr_t and do a second lookup. */ in_addr_t address = (in_addr_t) internetwork_resolveName(worker_getInternet(), name); if(address == 0) { /* name was not in hostname format. convert to IP format and try again */ struct in_addr inaddr; gint r = inet_pton(AF_INET, name, &inaddr); if(r == 1) { /* successful conversion to IP format, now find the real hostname */ GQuark convertedIP = (GQuark) inaddr.s_addr; const gchar* hostname = internetwork_resolveID(worker_getInternet(), convertedIP); if(hostname != NULL) { /* got it, so convertedIP is a valid IP */ address = (in_addr_t) convertedIP; } else { /* name not mapped by resolver... */ result = EAI_FAIL; goto done; } } else if(r == 0) { /* not in correct form... hmmm, too bad i guess */ result = EAI_NONAME; goto done; } else { /* error occured */ result = EAI_SYSTEM; goto done; } } /* should have address now */ struct sockaddr_in* sa = g_malloc(sizeof(struct sockaddr_in)); /* application will expect it in network order */ // sa->sin_addr.s_addr = (in_addr_t) htonl((guint32)(*addr)); sa->sin_addr.s_addr = address; sa->sin_family = AF_INET; /* libcurl expects this to be set */ struct addrinfo* ai_out = g_malloc(sizeof(struct addrinfo)); ai_out->ai_addr = (struct sockaddr*) sa; ai_out->ai_addrlen = sizeof(struct sockaddr_in); ai_out->ai_canonname = NULL; ai_out->ai_family = AF_INET; ai_out->ai_flags = 0; ai_out->ai_next = NULL; ai_out->ai_protocol = 0; ai_out->ai_socktype = SOCK_STREAM; *res = ai_out; result = 0; goto done; } errno = EINVAL; result = EAI_SYSTEM; done: _system_switchOutShadowContext(node); return result; }
static void _tcp_autotune(TCP* tcp) { MAGIC_ASSERT(tcp); if(!CONFIG_TCPAUTOTUNE) { return; } /* our buffers need to be large enough to send and receive * a full delay*bandwidth worth of bytes to keep the pipe full. * but not too large that we'll just buffer everything. autotuning * is meant to tune it to an optimal rate. estimate that by taking * the 80th percentile. */ Internetwork* internet = worker_getInternet(); GQuark sourceID = (GQuark) tcp_getIP(tcp); GQuark destinationID = (GQuark) tcp_getPeerIP(tcp); if(sourceID == destinationID) { /* 16 MiB as max */ g_assert(16777216 > tcp->super.inputBufferSize); g_assert(16777216 > tcp->super.outputBufferSize); tcp->super.inputBufferSize = 16777216; tcp->super.outputBufferSize = 16777216; debug("set loopback buffer sizes to 16777216"); return; } /* get latency in milliseconds */ guint32 send_latency = (guint32) internetwork_getLatency(internet, sourceID, destinationID, 0.8); guint32 receive_latency = (guint32) internetwork_getLatency(internet, destinationID, sourceID, 0.8); g_assert(send_latency > 0 && receive_latency > 0); guint32 rtt_milliseconds = send_latency + receive_latency; /* i got delay, now i need values for my send and receive buffer * sizes based on bandwidth in both directions. do my send size first. */ guint32 my_send_bw = internetwork_getNodeBandwidthUp(internet, sourceID); guint32 their_receive_bw = internetwork_getNodeBandwidthDown(internet, destinationID); /* KiBps is the same as Bpms, which works with our RTT calculation. */ guint32 send_bottleneck_bw = my_send_bw < their_receive_bw ? my_send_bw : their_receive_bw; /* the delay bandwidth product is how many bytes I can send at once to keep the pipe full */ guint64 sendbuf_size = (guint64) (rtt_milliseconds * send_bottleneck_bw * 1.25f); /* now the same thing for my receive buf */ guint32 my_receive_bw = internetwork_getNodeBandwidthDown(internet, sourceID); guint32 their_send_bw = internetwork_getNodeBandwidthUp(internet, destinationID); /* KiBps is the same as Bpms, which works with our RTT calculation. */ guint32 receive_bottleneck_bw = my_receive_bw < their_send_bw ? my_receive_bw : their_send_bw; /* the delay bandwidth product is how many bytes I can receive at once to keep the pipe full */ guint64 receivebuf_size = (guint64) (rtt_milliseconds * receive_bottleneck_bw * 1.25); /* keep minimum buffer size bounds */ if(sendbuf_size < CONFIG_SEND_BUFFER_MIN_SIZE) { sendbuf_size = CONFIG_SEND_BUFFER_MIN_SIZE; } if(receivebuf_size < CONFIG_RECV_BUFFER_MIN_SIZE) { receivebuf_size = CONFIG_RECV_BUFFER_MIN_SIZE; } /* make sure the user hasnt already written to the buffer, because if we * shrink it, our buffer math would overflow the size variable */ g_assert(tcp->super.inputBufferLength == 0); g_assert(tcp->super.outputBufferLength == 0); /* its ok to change buffer sizes since the user hasn't written anything yet */ tcp->super.inputBufferSize = receivebuf_size; tcp->super.outputBufferSize = sendbuf_size; debug("set network buffer sizes: send %lu receive %lu", sendbuf_size, receivebuf_size); }