static TGenEvent _tgentransport_receiveSocksChoice(TGenTransport* transport) { /* 2 socks choice client <-- server \x05 (version 5) \x00 (auth method choice - \xFF means none supported) */ gchar buffer[8]; memset(buffer, 0, 8); gssize bytesReceived = tgentransport_read(transport, buffer, 2); g_assert(bytesReceived == 2); transport->time.proxyChoice = g_get_monotonic_time(); if(buffer[0] == 0x05 && buffer[1] == 0x00) { tgen_debug("socks choice supported by proxy %s", tgenpeer_toString(transport->proxy)); _tgentransport_changeState(transport, TGEN_XPORT_PROXY_REQUEST); return TGEN_EVENT_WRITE; } else { tgen_debug("socks choice unsupported by proxy %s", tgenpeer_toString(transport->proxy)); _tgentransport_changeState(transport, TGEN_XPORT_ERROR); _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_CHOICE); return TGEN_EVENT_NONE; } }
static GError* _tgengraph_parseTransferVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); const gchar* typeStr = (g->knownAttributes&TGEN_VA_TYPE) ? VAS(g->graph, "type", vertexIndex) : NULL; const gchar* protocolStr = (g->knownAttributes&TGEN_VA_PROTOCOL) ? VAS(g->graph, "protocol", vertexIndex) : NULL; const gchar* sizeStr = (g->knownAttributes&TGEN_VA_SIZE) ? VAS(g->graph, "size", vertexIndex) : NULL; const gchar* peersStr = (g->knownAttributes&TGEN_VA_PEERS) ? VAS(g->graph, "peers", vertexIndex) : NULL; const gchar* timeoutStr = (g->knownAttributes&TGEN_VA_TIMEOUT) ? VAS(g->graph, "timeout", vertexIndex) : NULL; tgen_debug("found vertex %li (%s), type=%s protocol=%s size=%s peers=%s timeout=%s", (glong)vertexIndex, idStr, typeStr, protocolStr, sizeStr, peersStr, timeoutStr); GError* error = NULL; TGenAction* a = tgenaction_newTransferAction(typeStr, protocolStr, sizeStr, peersStr, timeoutStr, &error); if(a) { _tgengraph_storeAction(g, a, vertexIndex); if(!tgenaction_getPeers(a)) { g->transferMissingPeers = TRUE; } } return error; }
static GError* _tgengraph_parseSynchronizeVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); tgen_debug("found vertex %li (%s)", (glong)vertexIndex, idStr); /* Count up the total incoming edges */ /* initialize a vector to hold the result neighbor vertices for this action */ igraph_vector_t* resultNeighborVertices = g_new0(igraph_vector_t, 1); /* initialize with 0 entries, since we dont know how many neighbors we have */ gint result = igraph_vector_init(resultNeighborVertices, 0); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_vector_init return non-success code %i", result); g_free(resultNeighborVertices); return FALSE; } /* now get all incoming 1-hop neighbors of the given action */ result = igraph_neighbors(g->graph, resultNeighborVertices, vertexIndex, IGRAPH_IN); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_neighbors return non-success code %i", result); igraph_vector_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return NULL; } /* handle the results */ glong totalIncoming = igraph_vector_size(resultNeighborVertices); tgen_debug("found %li neighbors to vertex %i", totalIncoming, (gint)vertexIndex); /* cleanup */ igraph_vector_destroy(resultNeighborVertices); g_free(resultNeighborVertices); GError* error = NULL; TGenAction* a = tgenaction_newSynchronizeAction(totalIncoming, &error); if(a) { _tgengraph_storeAction(g, a, vertexIndex); } return error; }
static void _tgenio_helper(TGenIO* io, TGenIOChild* child, gboolean in, gboolean out) { TGEN_ASSERT(io); g_assert(child); TGenEvent inEvents = TGEN_EVENT_NONE; /* check if we need read flag */ if(in) { tgen_debug("descriptor %i is readable", child->descriptor); inEvents |= TGEN_EVENT_READ; } /* check if we need write flag */ if(out) { tgen_debug("descriptor %i is writable", child->descriptor); inEvents |= TGEN_EVENT_WRITE; } /* activate the transfer */ TGenEvent outEvents = child->notify(child->data, child->descriptor, inEvents); /* now check if we should update our epoll events */ if(outEvents & TGEN_EVENT_DONE) { _tgenio_deregister(io, child->descriptor); } else if(inEvents != outEvents) { guint32 newEvents = 0; if(outEvents & TGEN_EVENT_READ) { newEvents |= EPOLLIN; } if(outEvents & TGEN_EVENT_WRITE) { newEvents |= EPOLLOUT; } struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = newEvents; ee.data.fd = child->descriptor; gint result = epoll_ctl(io->epollD, EPOLL_CTL_MOD, child->descriptor, &ee); if(result != 0) { tgen_warning("epoll_ctl(): epoll %i descriptor %i returned %i error %i: %s", io->epollD, child->descriptor, result, errno, g_strerror(errno)); } } }
static void _tgentransfer_onReadable(TGenTransfer* transfer) { TGEN_ASSERT(transfer); tgen_debug("active transfer %s is readable", _tgentransfer_toString(transfer)); gsize startBytes = transfer->bytes.totalRead; /* first check if we need to read a command from the other end */ if(!transfer->isCommander && transfer->state == TGEN_XFER_COMMAND) { _tgentransfer_readCommand(transfer); } if(transfer->isCommander && transfer->state == TGEN_XFER_RESPONSE) { _tgentransfer_readResponse(transfer); } /* check if we are responsible for reading payload bytes */ if(transfer->type == TGEN_TYPE_GET && transfer->state == TGEN_XFER_PAYLOAD) { _tgentransfer_readPayload(transfer); } if(transfer->type == TGEN_TYPE_GET && transfer->state == TGEN_XFER_CHECKSUM) { _tgentransfer_readChecksum(transfer); } if(transfer->readBuffer || (transfer->type == TGEN_TYPE_GET && transfer->state != TGEN_XFER_SUCCESS)) { /* we have more to read */ transfer->events |= TGEN_EVENT_READ; } else { /* done reading */ transfer->events &= ~TGEN_EVENT_READ; } gsize endBytes = transfer->bytes.totalRead; gsize totalBytes = endBytes - startBytes; tgen_debug("active transfer %s read %"G_GSIZE_FORMAT" more bytes", _tgentransfer_toString(transfer), totalBytes); if(totalBytes > 0) { transfer->time.lastProgress = g_get_monotonic_time(); } }
static void _tgentransfer_onWritable(TGenTransfer* transfer) { TGEN_ASSERT(transfer); tgen_debug("active transfer %s is writable", _tgentransfer_toString(transfer)); gsize startBytes = transfer->bytes.totalWrite; /* first check if we need to send a command to the other end */ if(transfer->isCommander && transfer->state == TGEN_XFER_COMMAND) { _tgentransfer_writeCommand(transfer); } if(!transfer->isCommander && transfer->state == TGEN_XFER_RESPONSE) { _tgentransfer_writeResponse(transfer); } /* check if we are responsible for writing payload bytes */ if(transfer->type == TGEN_TYPE_PUT && transfer->state == TGEN_XFER_PAYLOAD) { _tgentransfer_writePayload(transfer); } if(transfer->type == TGEN_TYPE_PUT && transfer->state == TGEN_XFER_CHECKSUM) { _tgentransfer_writeChecksum(transfer); } if(transfer->writeBuffer || (transfer->type == TGEN_TYPE_PUT && transfer->state == TGEN_XFER_PAYLOAD)) { /* we have more to write */ transfer->events |= TGEN_EVENT_WRITE; } else { /* done writing */ transfer->events &= ~TGEN_EVENT_WRITE; } gsize endBytes = transfer->bytes.totalWrite; gsize totalBytes = endBytes - startBytes; tgen_debug("active transfer %s wrote %"G_GSIZE_FORMAT" more bytes", _tgentransfer_toString(transfer), totalBytes); if(totalBytes > 0) { transfer->time.lastProgress = g_get_monotonic_time(); } }
GQueue* tgengraph_getNextActions(TGenGraph* g, TGenAction* action) { TGEN_ASSERT(g); /* given an action, get all of the next actions in the dependency graph */ gpointer key = tgenaction_getKey(action); igraph_integer_t srcVertexIndex = (igraph_integer_t) GPOINTER_TO_INT(key); /* initialize a vector to hold the result neighbor vertices for this action */ igraph_vector_t* resultNeighborVertices = g_new0(igraph_vector_t, 1); /* initialize with 0 entries, since we dont know how many neighbors we have */ gint result = igraph_vector_init(resultNeighborVertices, 0); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_vector_init return non-success code %i", result); g_free(resultNeighborVertices); return FALSE; } /* now get all outgoing 1-hop neighbors of the given action */ result = igraph_neighbors(g->graph, resultNeighborVertices, srcVertexIndex, IGRAPH_OUT); if(result != IGRAPH_SUCCESS) { tgen_critical("igraph_neighbors return non-success code %i", result); igraph_vector_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return NULL; } /* handle the results */ glong nVertices = igraph_vector_size(resultNeighborVertices); tgen_debug("found %li neighbors to vertex %i", nVertices, (gint)srcVertexIndex); GQueue* nextActions = g_queue_new(); for (gint i = 0; i < nVertices; i++) { igraph_integer_t dstVertexIndex = igraph_vector_e(resultNeighborVertices, i); TGenAction* nextAction = _tgengraph_getAction(g, dstVertexIndex); if(nextAction) { g_queue_push_tail(nextActions, nextAction); } } /* cleanup */ igraph_vector_destroy(resultNeighborVertices); g_free(resultNeighborVertices); return nextActions; }
static GError* _tgengraph_parsePauseVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); const gchar* timeStr = (g->knownAttributes&TGEN_VA_TIME) ? VAS(g->graph, "time", vertexIndex) : NULL; tgen_debug("found vertex %li (%s), time=%s", (glong)vertexIndex, idStr, timeStr); GError* error = NULL; TGenAction* a = tgenaction_newPauseAction(timeStr, &error); if(a) { _tgengraph_storeAction(g, a, vertexIndex); } return error; }
static TGenEvent _tgentransport_sendSocksInit(TGenTransport* transport) { TGEN_ASSERT(transport); /* 1 socks init client --> server \x05 (version 5) \x01 (1 supported auth method) \x00 (method is "no auth") */ gssize bytesSent = tgentransport_write(transport, "\x05\x01\x00", 3); g_assert(bytesSent == 3); transport->time.proxyInit = g_get_monotonic_time(); tgen_debug("sent socks init to proxy %s", tgenpeer_toString(transport->proxy)); _tgentransport_changeState(transport, TGEN_XPORT_PROXY_CHOICE); return TGEN_EVENT_READ; }
static GError* _tgengraph_parseStartVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); const gchar* timeStr = (g->knownAttributes&TGEN_VA_TIME) ? VAS(g->graph, "time", vertexIndex) : NULL; const gchar* timeoutStr = (g->knownAttributes&TGEN_VA_TIMEOUT) ? VAS(g->graph, "timeout", vertexIndex) : NULL; const gchar* serverPortStr = (g->knownAttributes&TGEN_VA_SERVERPORT) ? VAS(g->graph, "serverport", vertexIndex) : NULL; const gchar* peersStr = (g->knownAttributes&TGEN_VA_PEERS) ? VAS(g->graph, "peers", vertexIndex) : NULL; const gchar* socksProxyStr = (g->knownAttributes&TGEN_VA_SOCKSPROXY) ? VAS(g->graph, "socksproxy", vertexIndex) : NULL; tgen_debug("validating action '%s' at vertex %li, time=%s timeout=%s serverport=%s socksproxy=%s peers=%s", idStr, (glong)vertexIndex, timeStr, timeoutStr, serverPortStr, socksProxyStr, peersStr); if(g->hasStartAction) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "only one start vertex is allowed in the action graph"); } if(_tgengraph_hasSelfLoop(g, vertexIndex)) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "start vertex must not contain a self-loop"); } GError* error = NULL; TGenAction* a = tgenaction_newStartAction(timeStr, timeoutStr, serverPortStr, peersStr, socksProxyStr, &error); if(a) { _tgengraph_storeAction(g, a, vertexIndex); g_assert(!g->hasStartAction); g->startActionVertexIndex = vertexIndex; g->hasStartAction = TRUE; if(tgenaction_getPeers(a)) { g->startHasPeers = TRUE; } } return error; }
static gboolean _tgentransfer_getLine(TGenTransfer* transfer) { TGEN_ASSERT(transfer); /* create a new buffer if we have not done that yet */ if(!transfer->readBuffer) { transfer->readBuffer = g_string_new(NULL); } gchar c; gssize bytes = 1; while(bytes > 0) { bytes = tgentransport_read(transfer->transport, &c, 1); if(bytes < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { _tgentransfer_changeState(transfer, TGEN_XFER_ERROR); _tgentransfer_changeError(transfer, TGEN_XFER_ERR_READ); tgen_critical("read(): transport %s transfer %s error %i: %s", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer), errno, g_strerror(errno)); } else if(bytes == 0) { _tgentransfer_changeState(transfer, TGEN_XFER_ERROR); _tgentransfer_changeError(transfer, TGEN_XFER_ERR_READ); tgen_critical("read(): transport %s transfer %s closed unexpectedly", tgentransport_toString(transfer->transport), _tgentransfer_toString(transfer)); } else if(bytes == 1) { transfer->bytes.totalRead += 1; if(c == '\n') { tgen_debug("finished receiving line: '%s'", transfer->readBuffer->str); return TRUE; } g_string_append_c(transfer->readBuffer, c); } } return FALSE; }
static GError* _tgengraph_parseEndVertex(TGenGraph* g, const gchar* idStr, igraph_integer_t vertexIndex) { TGEN_ASSERT(g); /* the following termination conditions are optional */ const gchar* timeStr = (g->knownAttributes&TGEN_VA_TIME) ? VAS(g->graph, "time", vertexIndex) : NULL; const gchar* countStr = (g->knownAttributes&TGEN_VA_COUNT) ? VAS(g->graph, "count", vertexIndex) : NULL; const gchar* sizeStr = (g->knownAttributes&TGEN_VA_SIZE) ? VAS(g->graph, "size", vertexIndex) : NULL; tgen_debug("found vertex %li (%s), time=%s count=%s size=%s", (glong)vertexIndex, idStr, timeStr, countStr, sizeStr); GError* error = NULL; TGenAction* a = tgenaction_newEndAction(timeStr, countStr, sizeStr, &error); if(a) { _tgengraph_storeAction(g, a, vertexIndex); } return error; }
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 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; }
static TGenEvent _tgentransport_sendSocksRequest(TGenTransport* transport) { /* 3 socks request client --> server \x05 (version 5) \x01 (tcp stream) \x00 (reserved) the client asks the server to connect to a remote 3a ip address client --> server \x01 (ipv4) in_addr_t (4 bytes) in_port_t (2 bytes) 3b hostname client --> server \x03 (domain name) \x__ (1 byte name len) (name) in_port_t (2 bytes) */ /* prefer name mode if we have it, and let the proxy lookup IP as needed */ const gchar* name = tgenpeer_getName(transport->remote); if(name && g_str_has_suffix(name, ".onion")) { // FIXME remove suffix matching to have proxy do lookup for us /* case 3b - domain name */ glong nameLength = g_utf8_strlen(name, -1); guint8 guint8max = -1; if(nameLength > guint8max) { nameLength = (glong)guint8max; tgen_warning("truncated name '%s' in socks request from %i to %u bytes", name, nameLength, (guint)guint8max); } in_addr_t port = tgenpeer_getNetworkPort(transport->remote); gchar buffer[nameLength+8]; memset(buffer, 0, nameLength+8); g_memmove(&buffer[0], "\x05\x01\x00\x03", 4); g_memmove(&buffer[4], &nameLength, 1); g_memmove(&buffer[5], name, nameLength); g_memmove(&buffer[5+nameLength], &port, 2); gssize bytesSent = tgentransport_write(transport, buffer, nameLength+7); g_assert(bytesSent == nameLength+7); } else { tgenpeer_performLookups(transport->remote); // FIXME remove this to have proxy do lookup for us /* case 3a - IPv4 */ in_addr_t ip = tgenpeer_getNetworkIP(transport->remote); in_addr_t port = tgenpeer_getNetworkPort(transport->remote); gchar buffer[16]; memset(buffer, 0, 16); g_memmove(&buffer[0], "\x05\x01\x00\x01", 4); g_memmove(&buffer[4], &ip, 4); g_memmove(&buffer[8], &port, 2); gssize bytesSent = tgentransport_write(transport, buffer, 10); g_assert(bytesSent == 10); } transport->time.proxyRequest = g_get_monotonic_time(); tgen_debug("requested connection from %s through socks proxy %s to remote %s", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_PROXY_RESPONSE); return TGEN_EVENT_READ; }