static void _tgentransfer_changeError(TGenTransfer* transfer, TGenTransferError error) { TGEN_ASSERT(transfer); tgen_info("transfer %s moving from error %s to error %s", _tgentransfer_toString(transfer), _tgentransfer_errorToString(transfer->error), _tgentransfer_errorToString(error)); transfer->error = error; _tgentransfer_resetString(transfer); }
static void _tgentransfer_changeState(TGenTransfer* transfer, TGenTransferState state) { TGEN_ASSERT(transfer); tgen_info("transfer %s moving from state %s to state %s", _tgentransfer_toString(transfer), _tgentransfer_stateToString(transfer->state), _tgentransfer_stateToString(state)); transfer->state = state; _tgentransfer_resetString(transfer); }
static void _tgentransport_changeError(TGenTransport* transport, TGenTransportError error) { TGEN_ASSERT(transport); tgen_info("transport %s moving from error %s to error %s", tgentransport_toString(transport), _tgentransport_errorToString(transport->error), _tgentransport_errorToString(error)); transport->error = error; _tgentransport_resetString(transport); }
static void _tgentransport_changeState(TGenTransport* transport, TGenTransportState state) { TGEN_ASSERT(transport); tgen_info("transport %s moving from state %s to state %s", tgentransport_toString(transport), _tgentransport_stateToString(transport->state), _tgentransport_stateToString(state)); transport->state = state; _tgentransport_resetString(transport); }
static void _tgentransfer_log(TGenTransfer* transfer, gboolean wasActive) { TGEN_ASSERT(transfer); if(transfer->state == TGEN_XFER_ERROR) { /* we had an error at some point and will unlikely be able to complete. * only log an error once. */ if(transfer->time.lastTimeErrorReport == 0) { gchar* bytesMessage = _tgentransfer_getBytesStatusReport(transfer); gchar* timeMessage = _tgentransfer_getTimeStatusReport(transfer); tgen_message("[transfer-error] transport %s transfer %s %s %s", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer), bytesMessage, timeMessage); gint64 now = g_get_monotonic_time(); transfer->time.lastBytesStatusReport = now; transfer->time.lastTimeErrorReport = now; g_free(bytesMessage); } } else if(transfer->state == TGEN_XFER_SUCCESS) { /* we completed the transfer. yay. only log once. */ if(transfer->time.lastTimeStatusReport == 0) { gchar* bytesMessage = _tgentransfer_getBytesStatusReport(transfer); gchar* timeMessage = _tgentransfer_getTimeStatusReport(transfer); tgen_message("[transfer-complete] transport %s transfer %s %s %s", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer), bytesMessage, timeMessage); gint64 now = g_get_monotonic_time(); transfer->time.lastBytesStatusReport = now; transfer->time.lastTimeStatusReport = now; g_free(bytesMessage); g_free(timeMessage); } } else { /* the transfer is still working. only log on new activity */ if(wasActive) { gchar* bytesMessage = _tgentransfer_getBytesStatusReport(transfer); tgen_info("[transfer-status] transport %s transfer %s %s", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer), bytesMessage); transfer->time.lastBytesStatusReport = g_get_monotonic_time();; g_free(bytesMessage); } } }
static igraph_t* _tgengraph_loadNewGraph(const gchar* path) { /* get the file */ FILE* graphFile = fopen(path, "r"); if(!graphFile) { tgen_critical("fopen returned NULL, problem opening graph file path '%s'", path); return FALSE; } tgen_info("reading graphml action graph at '%s'...", path); igraph_t* graph = g_new0(igraph_t, 1); gint result = igraph_read_graph_graphml(graph, graphFile, 0); fclose(graphFile); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_read_graph_graphml return non-success code %i", result); g_free(graph); return NULL; } tgen_info("successfully read graphml action graph at '%s'", path); return graph; }
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_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; }
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 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 */ } }
static TGenEvent _tgentransport_receiveSocksResponse(TGenTransport* transport) { /* 4 socks response client <-- server \x05 (version 5) \x00 (request granted) \x00 (reserved) the server can tell us that we need to reconnect elsewhere 4a ip address client <-- server \x01 (ipv4) in_addr_t (4 bytes) in_port_t (2 bytes) 4b hostname client <-- server \x03 (domain name) \x__ (1 byte name len) (name) in_port_t (2 bytes) */ gchar buffer[256]; memset(buffer, 0, 256); gssize bytesReceived = tgentransport_read(transport, buffer, 256); g_assert(bytesReceived >= 4); transport->time.proxyResponse = g_get_monotonic_time(); if(buffer[0] == 0x05 && buffer[1] == 0x00) { if(buffer[3] == 0x01) { /* case 4a - IPV4 mode - get address server told us */ g_assert(bytesReceived == 10); /* check if they want us to connect elsewhere */ in_addr_t socksBindAddress = 0; in_port_t socksBindPort = 0; g_memmove(&socksBindAddress, &buffer[4], 4); g_memmove(&socksBindPort, &buffer[8], 2); /* reconnect not supported */ if(socksBindAddress == 0 && socksBindPort == 0) { tgen_info("connection from %s through socks proxy %s to %s successful", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_SUCCESS); return TGEN_EVENT_DONE; } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_RECONN); tgen_warning("connection from %s through socks proxy %s to %s failed: " "proxy requested unsupported reconnection to %i:u", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (gint)socksBindAddress, (guint)ntohs(socksBindPort)); } } else if (buffer[3] == 0x03) { /* case 4b - domain name mode */ guint8 nameLength = 0; g_memmove(&nameLength, &buffer[4], 1); g_assert(bytesReceived == nameLength+7); gchar namebuf[nameLength+1]; memset(namebuf, 0, nameLength); in_port_t socksBindPort = 0; g_memmove(namebuf, &buffer[5], nameLength); g_memmove(&socksBindPort, &buffer[5+nameLength], 2); /* reconnect not supported */ if(!g_ascii_strncasecmp(namebuf, "\0", (gsize) 1) && socksBindPort == 0) { tgen_info("connection from %s through socks proxy %s to %s successful", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_SUCCESS); return TGEN_EVENT_DONE; } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_RECONN); tgen_warning("connection from %s through socks proxy %s to %s failed: " "proxy requested unsupported reconnection to %s:u", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), namebuf, (guint)ntohs(socksBindPort)); } } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_ADDR); tgen_warning("connection from %s through socks proxy %s to %s failed: unsupported address type %i", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (gint)buffer[3]); } } else { _tgentransport_changeError(transport, (buffer[0] != 0x05) ? TGEN_XPORT_ERR_PROXY_VERSION : TGEN_XPORT_ERR_PROXY_STATUS); tgen_warning("connection from %s through socks proxy %s to %s failed: unsupported %s %i", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (buffer[0] != 0x05) ? "version" : "status", (buffer[0] != 0x05) ? (gint)buffer[0] : (gint)buffer[1]); } _tgentransport_changeState(transport, TGEN_XPORT_ERROR); return TGEN_EVENT_NONE; }