static void _tgentransfer_readChecksum(TGenTransfer* transfer) { TGEN_ASSERT(transfer); if(_tgentransfer_getLine(transfer)) { /* transfer is done */ _tgentransfer_changeState(transfer, TGEN_XFER_SUCCESS); transfer->time.checksum = g_get_monotonic_time(); /* we have read the entire checksum from the other end */ gssize sha1Length = g_checksum_type_get_length(G_CHECKSUM_MD5); g_assert(sha1Length >= 0); gchar* computedSum = g_strdup(g_checksum_get_string(transfer->payloadChecksum)); gchar* line = g_string_free(transfer->readBuffer, FALSE); transfer->readBuffer = NULL; gchar** parts = g_strsplit(line, " ", 0); const gchar* receivedSum = parts[1]; g_assert(receivedSum); /* check that the sums match */ if(!g_ascii_strncasecmp(computedSum, receivedSum, (gsize)sha1Length)) { tgen_message("transport %s transfer %s MD5 checksums passed: computed=%s received=%s", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer), computedSum, receivedSum); } else { tgen_message("MD5 checksums failed: computed=%s received=%s", computedSum, receivedSum); } g_strfreev(parts); g_free(line); g_free(computedSum); } else { /* unable to receive entire checksum, wait for next chance to read */ } }
void tgenio_checkTimeouts(TGenIO* io) { TGEN_ASSERT(io); /* TODO this was a quick polling approach to checking for timeouts, which * could be more efficient if replaced with an asynchronous notify design. */ GList* items = g_hash_table_get_values(io->children); GList* item = g_list_first(items); while(item) { TGenIOChild* child = item->data; if(child && child->checkTimeout) { /* this calls tgentransfer_onCheckTimeout to check and handle if a timeout is present */ gboolean hasTimeout = child->checkTimeout(child->data, child->descriptor); if(hasTimeout) { _tgenio_deregister(io, child->descriptor); } } item = g_list_next(item); } if(items != NULL) { g_list_free(items); } }
static void _tgentransfer_readCommand(TGenTransfer* transfer) { TGEN_ASSERT(transfer); if(_tgentransfer_getLine(transfer)) { /* we have read the entire command from the other end */ gboolean hasError = FALSE; transfer->time.command = g_get_monotonic_time(); gchar* line = g_string_free(transfer->readBuffer, FALSE); transfer->readBuffer = NULL; if(g_ascii_strncasecmp(line, TGEN_AUTH_PW, 20)) { /* password doesn't match */ tgen_info("transfer authentication error: passwords don't match") hasError = TRUE; _tgentransfer_changeState(transfer, TGEN_XFER_ERROR); _tgentransfer_changeError(transfer, TGEN_XFER_ERR_AUTH); } else { /* password matches, lets parse the rest of the string */ gchar** parts = g_strsplit(line, " ", 0); if(parts[0] == NULL || parts[1] == NULL || parts[2] == NULL || parts[3] == NULL || parts[4] == NULL || parts[5] == NULL) { tgen_critical("error parsing command '%s'", line); hasError = TRUE; } else { g_assert(!transfer->remoteName); transfer->remoteName = g_strdup(parts[1]); /* we are not the commander so we should not have an id yet */ g_assert(transfer->id == NULL); transfer->id = g_strdup(parts[2]); transfer->remoteCount = (gsize)g_ascii_strtoull(parts[3], NULL, 10); if(transfer->remoteCount == 0) { tgen_critical("error parsing command ID '%s'", parts[3]); hasError = TRUE; } if(!g_ascii_strncasecmp(parts[4], "GET", 3)) { /* they are trying to GET, then we need to PUT to them */ transfer->type = TGEN_TYPE_PUT; /* we read command, but now need to write payload */ transfer->events |= TGEN_EVENT_WRITE; } else if(!g_ascii_strncasecmp(parts[4], "PUT", 3)) { /* they want to PUT, so we will GET from them */ transfer->type = TGEN_TYPE_GET; } else { tgen_critical("error parsing command type '%s'", parts[4]); hasError = TRUE; } transfer->size = (gsize)g_ascii_strtoull(parts[5], NULL, 10); if(transfer->size == 0) { tgen_critical("error parsing command size '%s'", parts[5]); hasError = TRUE; } } g_strfreev(parts); g_free(line); /* payload phase is next unless there was an error parsing */ if(hasError) { _tgentransfer_changeState(transfer, TGEN_XFER_ERROR); _tgentransfer_changeError(transfer, TGEN_XFER_ERR_READ); } else { /* we need to update our string with the new command info */ _tgentransfer_resetString(transfer); _tgentransfer_changeState(transfer, TGEN_XFER_RESPONSE); transfer->events |= TGEN_EVENT_WRITE; } } } else { /* unable to receive entire command, wait for next chance to read */ } }
void tgenpool_unref(TGenPool* pool) { TGEN_ASSERT(pool); if(--(pool->refcount) == 0) { _tgenpool_free(pool); } }
gboolean tgengraph_hasEdges(TGenGraph* g) { TGEN_ASSERT(g); return (g->edgeCount > 0) ? TRUE : FALSE; }
static GError* _tgengraph_parseGraphEdges(TGenGraph* g) { TGEN_ASSERT(g); tgen_debug("checking graph edges..."); /* we will iterate through the edges */ igraph_eit_t edgeIterator; gint result = igraph_eit_create(g->graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &edgeIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_eit_create return non-success code %i", result); } /* count the edges as we iterate */ igraph_integer_t edgeCount = 0; GError* error = NULL; while (!IGRAPH_EIT_END(edgeIterator)) { igraph_integer_t edgeIndex = IGRAPH_EIT_GET(edgeIterator); igraph_integer_t fromVertexIndex, toVertexIndex; gint result = igraph_edge(g->graph, edgeIndex, &fromVertexIndex, &toVertexIndex); if(result != IGRAPH_SUCCESS) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_edge return non-success code %i", result); break; } const gchar* fromIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", fromVertexIndex) : NULL; if(!fromIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)fromVertexIndex); break; } const gchar* toIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", toVertexIndex) : NULL; if(!toIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)toVertexIndex); break; } tgen_debug("found edge %li from vertex %li (%s) to vertex %li (%s)", (glong)edgeIndex, (glong)fromVertexIndex, fromIDStr, (glong)toVertexIndex, toIDStr); const gchar* weightStr = (g->knownAttributes&TGEN_EA_WEIGHT) ? EAS(g->graph, "weight", edgeIndex) : NULL; if(weightStr != NULL) { if(g_ascii_strncasecmp(weightStr, "\0", (gsize) 1)) { gdouble weight = g_ascii_strtod(weightStr, NULL); _tgengraph_storeWeight(g, weight, edgeIndex); } } edgeCount++; IGRAPH_EIT_NEXT(edgeIterator); } igraph_eit_destroy(&edgeIterator); if(!error) { g->edgeCount = igraph_ecount(g->graph); if(g->edgeCount != edgeCount) { tgen_warning("igraph_vcount %f does not match iterator count %f", g->edgeCount, edgeCount); } tgen_info("%u graph edges ok", (guint) g->edgeCount); } return error; }
static GError* _tgengraph_parseGraphVertices(TGenGraph* g) { TGEN_ASSERT(g); tgen_debug("checking graph vertices..."); /* we will iterate through the vertices */ igraph_vit_t vertexIterator; gint result = igraph_vit_create(g->graph, igraph_vss_all(), &vertexIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_vit_create return non-success code %i", result); } /* count the vertices as we iterate */ igraph_integer_t vertexCount = 0; GError* error = NULL; while (!IGRAPH_VIT_END(vertexIterator)) { igraph_integer_t vertexIndex = (igraph_integer_t)IGRAPH_VIT_GET(vertexIterator); /* get vertex attributes: S for string and N for numeric */ const gchar* idStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", vertexIndex) : NULL; if(!idStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing action 'id' attribute", (glong)vertexIndex); break; } if(g_strstr_len(idStr, (gssize)-1, "start")) { error = _tgengraph_parseStartVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "end")) { error = _tgengraph_parseEndVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "pause")) { error = _tgengraph_parsePauseVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "synchronize")) { error = _tgengraph_parseSynchronizeVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "transfer")) { error = _tgengraph_parseTransferVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "choose")) { error = _tgengraph_parseChooseVertex(g, idStr, vertexIndex); } else { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "found vertex %li (%s) with an unknown action id '%s'", (glong)vertexIndex, idStr, idStr); } if(error) { break; } vertexCount++; IGRAPH_VIT_NEXT(vertexIterator); } /* clean up */ igraph_vit_destroy(&vertexIterator); if(!g->startHasPeers && g->transferMissingPeers) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "peers required in either the 'start' action, or *every* 'transfer' action"); } if(!error) { g->vertexCount = igraph_vcount(g->graph); if(g->vertexCount != vertexCount) { tgen_warning("igraph_vcount %f does not match iterator count %f", g->vertexCount, vertexCount); } tgen_info("%u graph vertices ok", (guint) g->vertexCount); } return error; }
static gdouble* _tgengraph_getWeight(TGenGraph* g, igraph_integer_t edgeIndex) { TGEN_ASSERT(g); return g_hash_table_lookup(g->weights, GINT_TO_POINTER(edgeIndex)); }
static void _tgengraph_storeAction(TGenGraph* g, TGenAction* a, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); tgenaction_setKey(a, GINT_TO_POINTER(vertexIndex)); g_hash_table_insert(g->actions, tgenaction_getKey(a), a); }
static void init_rings(void) { struct lcore_cfg *lconf; char ring_name[3] = "A"; for (uint8_t lcore_id = 0; lcore_id < RTE_MAX_LCORE; ++lcore_id) { if (!rte_lcore_is_enabled(lcore_id) || lcore_id == tgen_cfg.master) { continue; } lconf = &lcore_cfg[lcore_id]; uint8_t socket = rte_lcore_to_socket_id(lcore_id); mprintf("\t*** Initializing core %u ***\n", lcore_id); for (uint8_t task_id = 0; task_id < lconf->nb_tasks; ++task_id) { struct task_startup_cfg *sstartup_cfg = &lconf->startup_cfg[task_id]; if (sstartup_cfg->ring_size == 0) { sstartup_cfg->ring_size = RING_RX_SIZE; } uint8_t tot_nb_txrings = 0; for (uint8_t idx = 0; idx < MAX_PROTOCOLS; ++idx) { if (!sstartup_cfg->thread_list[idx].active) { continue; } for (uint8_t ring_idx = 0; ring_idx < sstartup_cfg->thread_list[idx].nb_threads; ++ring_idx, ++tot_nb_txrings) { TGEN_ASSERT(ring_idx < MAX_WT_PER_LB); TGEN_ASSERT(tot_nb_txrings < MAX_RINGS_PER_CORE); uint8_t lcore_worker = sstartup_cfg->thread_list[idx].thread_id[ring_idx]; TGEN_PANIC(!rte_lcore_is_enabled(lcore_worker) || lcore_worker == tgen_cfg.master, "Invalid worker: lcore %u is not enabled\n", lcore_worker); struct lcore_cfg *lworker = &lcore_cfg[lcore_worker]; uint8_t dest_task = sstartup_cfg->thread_list[idx].dest_task; struct task_startup_cfg *dstartup_cfg = &lworker->startup_cfg[dest_task]; TGEN_PANIC(!(dstartup_cfg->flags & PORT_STARTUP_RX_RING), "Invalid worker: lcore %u task %u is not expecting to receive through a ring\n", lcore_worker, dest_task); TGEN_PANIC(dest_task >= lworker->nb_tasks, "Invalid worker: lcore %u task %u not configured\n", lcore_worker, dest_task); mprintf("\t\tCreating ring (size: %u) to connect core %u (socket %u) with worker core %u worker %u...\n", sstartup_cfg->ring_size, lcore_id, socket, lcore_worker, ring_idx); /* socket used is the one that the sending core resides on */ struct rte_ring *ring = rte_ring_create(ring_name, sstartup_cfg->ring_size, socket, RING_F_SP_ENQ | RING_F_SC_DEQ); TGEN_PANIC(ring == NULL, "Cannot create ring to connect I/O core %u with worker core %u\n", lcore_id, lcore_worker); ring_name[0]++; TGEN_ASSERT(dstartup_cfg->nb_rxrings < MAX_RINGS_PER_CORE); /* will skip inactive rings */ sstartup_cfg->tx_rings[tot_nb_txrings] = ring; dstartup_cfg->rx_rings[dstartup_cfg->nb_rxrings] = ring; ++dstartup_cfg->nb_rxrings; dstartup_cfg->nb_slave_threads = sstartup_cfg->thread_list[idx].nb_threads; mprintf("\t\tCore %u port %u tx_ring[%u] => core %u task %u rx_ring[%u] %p %s %u WT\n", lcore_id, task_id, ring_idx, lcore_worker, dest_task, dstartup_cfg->nb_rxrings, ring, ring->name, dstartup_cfg->nb_slave_threads); } if (LB_QINQ == sstartup_cfg->mode || LB_NETWORK == sstartup_cfg->mode) { if (lb_nb_txrings == 0xff) { lb_nb_txrings = sstartup_cfg->nb_worker_threads; } else if (lb_nb_txrings != sstartup_cfg->nb_worker_threads) { TGEN_PANIC(tot_nb_txrings != 1, "All LB should have same number of tx_rings: %u != %u\n", lb_nb_txrings, sstartup_cfg->nb_txrings); } } } } } }
gint tgentimer_getDescriptor(TGenTimer* timer) { TGEN_ASSERT(timer); return timer->timerD; }
void tgentimer_unref(TGenTimer* timer) { TGEN_ASSERT(timer); if(--(timer->refcount) <= 0) { _tgentimer_free(timer); } }
void tgentimer_ref(TGenTimer* timer) { TGEN_ASSERT(timer); timer->refcount++; }
gpointer tgenpool_getRandom(TGenPool* pool) { TGEN_ASSERT(pool); const gint position = (gint) (rand() % g_tree_nnodes(pool->items)); return (gpointer)g_tree_lookup(pool->items, &position); }
void tgenpool_add(TGenPool* pool, gpointer item) { TGEN_ASSERT(pool); gint* key = g_new(gint, 1); *key = (pool->counter)++; g_tree_insert(pool->items, key, item); }
gint tgenio_getEpollDescriptor(TGenIO* io) { TGEN_ASSERT(io); return io->epollD; }
void tgentransfer_ref(TGenTransfer* transfer) { TGEN_ASSERT(transfer); transfer->refcount++; }
void tgenio_ref(TGenIO* io) { TGEN_ASSERT(io); io->refcount++; }
static TGenAction* _tgengraph_getAction(TGenGraph* g, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); return g_hash_table_lookup(g->actions, GINT_TO_POINTER(vertexIndex)); }
void tgenio_unref(TGenIO* io) { TGEN_ASSERT(io); if(--(io->refcount) <= 0) { _tgenio_free(io); } }
static GError* _tgengraph_parseChooseVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); tgen_debug("found vertex %li (%s)", (glong)vertexIndex, idStr); GError* error = NULL; /* Assure the edges from this choose action have either all weights or no weights. Store in data */ igraph_es_t edgeSelector; igraph_eit_t edgeIterator; gint result = igraph_es_incident(&edgeSelector, vertexIndex, IGRAPH_OUT); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_es_incident return non-success code %i", result); } result = igraph_eit_create(g->graph, edgeSelector, &edgeIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_eit_create return non-success code %i", result); } /* Get initial case for first edge */ igraph_integer_t edgeIndex = IGRAPH_EIT_GET(edgeIterator); gdouble* weight = _tgengraph_getWeight(g, edgeIndex); gboolean lastWeight; gdouble totalWeight = 0.0; if(weight != NULL) { lastWeight = TRUE; totalWeight += *weight; } else { lastWeight = FALSE; } IGRAPH_EIT_NEXT(edgeIterator); while (!IGRAPH_EIT_END(edgeIterator)) { edgeIndex = IGRAPH_EIT_GET(edgeIterator); gdouble* weight = _tgengraph_getWeight(g, edgeIndex); gboolean thisWeight; if(weight != NULL) { thisWeight = TRUE; totalWeight += *weight; } else { thisWeight = FALSE; } /* Assure weights is still constant */ if (thisWeight != lastWeight){ igraph_es_destroy(&edgeSelector); igraph_eit_destroy(&edgeIterator); return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "choose action must have all weights or no weights"); } lastWeight = thisWeight; IGRAPH_EIT_NEXT(edgeIterator); } TGenAction* a = tgenaction_newChooseAction(&error, lastWeight, totalWeight); /* clean up */ igraph_es_destroy(&edgeSelector); igraph_eit_destroy(&edgeIterator); if(a) { _tgengraph_storeAction(g, a, vertexIndex); } return error; }
void tgentransport_ref(TGenTransport* transport) { TGEN_ASSERT(transport); transport->refcount++; }
static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { TGEN_ASSERT(g); gint result = 0; tgen_debug("checking graph properties..."); /* IGRAPH_WEAK means the undirected version of the graph is connected * IGRAPH_STRONG means a vertex can reach all others via a directed path */ result = igraph_is_connected(g->graph, &(g->isConnected), IGRAPH_WEAK); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_is_connected return non-success code %i", result); } igraph_integer_t clusterCount; result = igraph_clusters(g->graph, NULL, NULL, &(g->clusterCount), IGRAPH_WEAK); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_clusters return non-success code %i", result); } /* it must be connected */ if(!g->isConnected || g->clusterCount > 1) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "graph must be but is not connected"); } g->isDirected = igraph_is_directed(g->graph); tgen_debug("checking graph attributes..."); /* now check list of all attributes */ igraph_strvector_t gnames, vnames, enames; igraph_vector_t gtypes, vtypes, etypes; igraph_strvector_init(&gnames, 25); igraph_vector_init(>ypes, 25); igraph_strvector_init(&vnames, 25); igraph_vector_init(&vtypes, 25); igraph_strvector_init(&enames, 25); igraph_vector_init(&etypes, 25); result = igraph_cattribute_list(g->graph, &gnames, >ypes, &vnames, &vtypes, &enames, &etypes); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_cattribute_list return non-success code %i", result); } gint i = 0; for(i = 0; i < igraph_strvector_size(&gnames); i++) { gchar* name = NULL; igraph_strvector_get(&gnames, (glong) i, &name); tgen_debug("found graph attribute '%s'", name); } for(i = 0; i < igraph_strvector_size(&vnames); i++) { gchar* name = NULL; igraph_strvector_get(&vnames, (glong) i, &name); tgen_debug("found vertex attribute '%s'", name); g->knownAttributes |= _tgengraph_vertexAttributeToFlag(name); } for(i = 0; i < igraph_strvector_size(&enames); i++) { gchar* name = NULL; igraph_strvector_get(&enames, (glong) i, &name); tgen_debug("found edge attribute '%s'", name); g->knownAttributes |= _tgengraph_edgeAttributeToFlag(name); } igraph_strvector_destroy(&gnames); igraph_vector_destroy(>ypes); igraph_strvector_destroy(&vnames); igraph_vector_destroy(&vtypes); igraph_strvector_destroy(&enames); igraph_vector_destroy(&etypes); tgen_info("successfully verified graph properties and attributes"); return NULL; }
gint tgentransport_getDescriptor(TGenTransport* transport) { TGEN_ASSERT(transport); return transport->socketD; }
TGenAction* tgengraph_getStartAction(TGenGraph* g) { TGEN_ASSERT(g); return _tgengraph_getAction(g, g->startActionVertexIndex); }
TGenEvent tgentransport_onEvent(TGenTransport* transport, TGenEvent events) { TGEN_ASSERT(transport); if(!tgentransport_wantsEvents(transport)) { return TGEN_EVENT_NONE; } switch(transport->state) { case TGEN_XPORT_CONNECT: { if(!(events & TGEN_EVENT_WRITE)) { return TGEN_EVENT_WRITE; } else { /* we are now connected and can send the socks init */ transport->time.socketConnect = g_get_monotonic_time(); if(transport->proxy) { /* continue with SOCKS handshake next */ _tgentransport_changeState(transport, TGEN_XPORT_PROXY_INIT); /* process the next step */ return tgentransport_onEvent(transport, events); } else { /* no proxy, this is a direct connection, we are all done */ _tgentransport_changeState(transport, TGEN_XPORT_SUCCESS); return TGEN_EVENT_DONE; } } } case TGEN_XPORT_PROXY_INIT: { if(!(events & TGEN_EVENT_WRITE)) { return TGEN_EVENT_WRITE; } else { return _tgentransport_sendSocksInit(transport); } } case TGEN_XPORT_PROXY_CHOICE: { if(!(events & TGEN_EVENT_READ)) { return TGEN_EVENT_READ; } else { return _tgentransport_receiveSocksChoice(transport); } } case TGEN_XPORT_PROXY_REQUEST: { if(!(events & TGEN_EVENT_WRITE)) { return TGEN_EVENT_WRITE; } else { return _tgentransport_sendSocksRequest(transport); } } case TGEN_XPORT_PROXY_RESPONSE: { if(!(events & TGEN_EVENT_READ)) { return TGEN_EVENT_READ; } else { return _tgentransport_receiveSocksResponse(transport); } } case TGEN_XPORT_SUCCESS: { return TGEN_EVENT_DONE; } case TGEN_XPORT_ERROR: default: { return TGEN_EVENT_NONE; } } }
const gchar* tgengraph_getGraphPath(TGenGraph* g) { TGEN_ASSERT(g); return g->graphPath; }
void tgenpool_ref(TGenPool* pool) { TGEN_ASSERT(pool); pool->refcount++; }