diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 355f32f..9b22654 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,7 +86,7 @@ jobs: esac - name: Build tgen - run: mkdir -p build && cd build && CC=${{ matrix.cc }} cmake .. && make + run: mkdir -p build && cd build && CC=${{ matrix.cc }} cmake -DCMAKE_C_FLAGS="-Wall -Werror" .. && make - name: Install test dependencies run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 68de9b2..773b623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,15 @@ find_package(M REQUIRED) pkg_check_modules(IGRAPH REQUIRED igraph) pkg_check_modules(GLIB REQUIRED glib-2.0) +## Parse out igraph version. Needed to work around breaking API changes in igraph. +string(REPLACE "." ";" IGRAPH_VERSION_LIST ${IGRAPH_VERSION}) +list(GET IGRAPH_VERSION_LIST 0 IGRAPH_VERSION_MAJOR) +list(GET IGRAPH_VERSION_LIST 1 IGRAPH_VERSION_MINOR) +list(GET IGRAPH_VERSION_LIST 2 IGRAPH_VERSION_PATCH) +add_definitions(-DIGRAPH_VERSION_MAJOR=${IGRAPH_VERSION_MAJOR}) +add_definitions(-DIGRAPH_VERSION_MINOR=${IGRAPH_VERSION_MINOR}) +add_definitions(-DIGRAPH_VERSION_PATCH=${IGRAPH_VERSION_PATCH}) + ## recurse our project tree add_subdirectory(${CMAKE_SOURCE_DIR}/src/) add_subdirectory(${CMAKE_SOURCE_DIR}/test/) diff --git a/src/tgen-graph.c b/src/tgen-graph.c index f69b56d..c9c16c6 100644 --- a/src/tgen-graph.c +++ b/src/tgen-graph.c @@ -6,6 +6,7 @@ #include #include "tgen.h" +#include "tgen-igraph-compat.h" typedef enum { TGEN_A_NONE = 0, @@ -1090,7 +1091,6 @@ static GError* _tgengraph_parseGraphProperties(TGenGraph* g) { "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, @@ -1272,7 +1272,7 @@ TGenGraph* tgengraph_new(gchar* path) { * uses dlmopen to get a private namespace for each plugin. */ /* use the built-in C attribute handler */ - igraph_attribute_table_t* oldHandler = igraph_i_set_attribute_table(&igraph_cattribute_table); + igraph_attribute_table_t* oldHandler = igraph_set_attribute_table(&igraph_cattribute_table); g->graph = _tgengraph_loadNewGraph(g->graphPath); if(!g->graph) { @@ -1292,7 +1292,7 @@ TGenGraph* tgengraph_new(gchar* path) { } /* replace the old handler */ - igraph_i_set_attribute_table(oldHandler); + igraph_set_attribute_table(oldHandler); } if(error) { diff --git a/src/tgen-igraph-compat.h b/src/tgen-igraph-compat.h new file mode 100644 index 0000000..799be0c --- /dev/null +++ b/src/tgen-igraph-compat.h @@ -0,0 +1,13 @@ +/* + * See LICENSE for licensing information + */ + +#ifndef TGEN_IGRAPH_COMPAT_H_ +#define TGEN_IGRAPH_COMPAT_H_ + +/* Renamed in in igraph 0.9.0 */ +#if IGRAPH_VERSION_MAJOR==0 && IGRAPH_VERSION_MINOR<9 +#define igraph_set_attribute_table igraph_i_set_attribute_table +#endif + +#endif \ No newline at end of file diff --git a/src/tgen-log.c b/src/tgen-log.c index 922a572..89444b5 100644 --- a/src/tgen-log.c +++ b/src/tgen-log.c @@ -101,7 +101,7 @@ void tgenlog_printMessage(GLogLevelFlags level, const gchar* fileName, const gin g_date_time_get_year(dt), g_date_time_get_month(dt), g_date_time_get_day_of_month(dt), g_date_time_get_hour(dt), g_date_time_get_minute(dt), g_date_time_get_second(dt), g_date_time_to_unix(dt), g_date_time_get_microsecond(dt), - _tgenlog_logLevelToString(level), fileStr, lineNum, functionName, format); + _tgenlog_logLevelToString(level), fileStr, lineNum, functionStr, format); gchar* messageStr = g_strdup_vprintf(newformat->str, vargs); diff --git a/src/tgen-markovmodel.c b/src/tgen-markovmodel.c index f4684c3..4fc5e79 100644 --- a/src/tgen-markovmodel.c +++ b/src/tgen-markovmodel.c @@ -10,6 +10,7 @@ #include +#include "tgen-igraph-compat.h" #include "tgen-log.h" #include "tgen-markovmodel.h" @@ -382,9 +383,9 @@ static gboolean _tgenmarkovmodel_checkVertexAttributes(TGenMarkovModel* mmodel, "but you gave %s='%s'", _tgenmarkovmodel_vertexTypeToString(VERTEX_TYPE_OBSERVATION), (glong)vertexIndex, - _tgenmarkovmodel_vertexTypeToString(VERTEX_ID_TO_SERVER), - _tgenmarkovmodel_vertexTypeToString(VERTEX_ID_TO_ORIGIN), - _tgenmarkovmodel_vertexTypeToString(VERTEX_ID_END), + _tgenmarkovmodel_vertexIDToString(VERTEX_ID_TO_SERVER), + _tgenmarkovmodel_vertexIDToString(VERTEX_ID_TO_ORIGIN), + _tgenmarkovmodel_vertexIDToString(VERTEX_ID_END), idKey, idStr); isSuccess = FALSE; } @@ -881,7 +882,7 @@ static igraph_t* _tgenmarkovmodel_loadGraph(FILE* graphFileStream, const gchar* igraph_t* graph = g_new0(igraph_t, 1); /* make sure we use the correct attribute handler */ - igraph_i_set_attribute_table(&igraph_cattribute_table); + igraph_set_attribute_table(&igraph_cattribute_table); result = igraph_read_graph_graphml(graph, graphFileStream, 0); @@ -1337,12 +1338,24 @@ static guint64 _tgenmarkovmodel_generateDelay(TGenMarkovModel* mmodel, g_assert_not_reached(); } - if(generatedValue > UINT64_MAX) { - return (guint64)UINT64_MAX; - } else if(generatedValue < 0) { - return (guint64)0; + double rounded = round(generatedValue); + if (rounded < 0) { + return 0; + /* Naively we'd check for > UINT64_MAX, but UINT64_MAX can't be precisely + * represented as a double. 2**64 *can* be precisely represented as a double, + * so we can check if it's >= that. + * + * See https://stackoverflow.com/a/17822304 + */ + } else if (rounded >= ldexp(1.0, 64)) { + return UINT64_MAX; } else { - return (guint64)round(generatedValue); + guint64 rv = (guint64)rounded; + + /* Should "round-trip" */ + g_assert((double)rv == rounded); + + return rv; } } diff --git a/src/tgen-stream.c b/src/tgen-stream.c index eadf9b6..9315402 100644 --- a/src/tgen-stream.c +++ b/src/tgen-stream.c @@ -528,9 +528,9 @@ static GString* _tgenstream_getLine(TGenStream* stream) { } if(lineBuffer) { - lineBuffer = g_string_append_len(lineBuffer, &buffer[0], bytes); + lineBuffer = g_string_append_len(lineBuffer, (char*)&buffer[0], bytes); } else { - lineBuffer = g_string_new_len(&buffer[0], bytes); + lineBuffer = g_string_new_len((char*)&buffer[0], bytes); } } @@ -659,6 +659,9 @@ static gboolean _tgenstream_readHeader(TGenStream* stream) { tgen_info("Client running protocol version %s is unsupported", value); theError = TGEN_STREAM_ERR_HEADER_VERSION; } + + // Minor version number needn't match. + (void)minor; } if(versions != NULL) { @@ -1329,7 +1332,6 @@ static gboolean _tgenstream_writePayload(TGenStream* stream) { } gsize cumulativeSize = 0; - guint64 cumulativeDelay = 0; guint64 interPacketDelay = 0; while(cumulativeSize < limit) { @@ -1343,7 +1345,6 @@ static gboolean _tgenstream_writePayload(TGenStream* stream) { /* the other end is sending us a packet, we have nothing to do. * but this delay should be included in the delay for our next outgoing packet. */ interPacketDelay += obsDelay; - cumulativeDelay += obsDelay; } else if((stream->isCommander && obs == OBSERVATION_TO_SERVER) || (!stream->isCommander && obs == OBSERVATION_TO_ORIGIN)) { /* this means we should send a packet */ @@ -1351,7 +1352,6 @@ static gboolean _tgenstream_writePayload(TGenStream* stream) { stream->send.expectedBytes += TGEN_MMODEL_PACKET_DATA_SIZE; /* since we sent a packet, now we reset the delay */ interPacketDelay = obsDelay; - cumulativeDelay += obsDelay; } else if(obs == OBSERVATION_END) { /* if we have a specific requested send size, we need to reset and keep sending. * we never reset when requestedBytes is 0 (it either means no bytes, or end diff --git a/src/tgen-transport.c b/src/tgen-transport.c index f12c35b..bc72acd 100644 --- a/src/tgen-transport.c +++ b/src/tgen-transport.c @@ -761,22 +761,22 @@ static TGenEvent _tgentransport_receiveSocksAuth(TGenTransport* transport) { return TGEN_EVENT_READ; } else { /* we read it all, we can move on */ - gboolean versionMatch = (transport->socksBuffer->str[0] == 0x01) ? TRUE : FALSE; + int version = transport->socksBuffer->str[0]; + gboolean versionMatch = (version == 0x01) ? TRUE : FALSE; gboolean authSuccess = (transport->socksBuffer->str[1] == 0x00) ? TRUE : FALSE; g_string_free(transport->socksBuffer, TRUE); transport->socksBuffer = NULL; - if(authSuccess) { - tgen_info("socks server %s authentication succeeded with username='%s' and password='%s'", - tgenpeer_toString(transport->proxy), - transport->username ? transport->username : "", - transport->password ? transport->password : ""); + if (!versionMatch) { + tgen_warning("socks server %s returned unexpected version %d", + tgenpeer_toString(transport->proxy), version); + _tgentransport_changeState(transport, TGEN_XPORT_ERROR); + _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_VERSION); + return TGEN_EVENT_NONE; + } - /* now we can move on to the request */ - _tgentransport_changeState(transport, TGEN_XPORT_PROXY_REQUEST); - return TGEN_EVENT_WRITE; - } else { + if (!authSuccess){ tgen_warning("socks server %s authentication failed with username='%s' and password='%s'", tgenpeer_toString(transport->proxy), transport->username ? transport->username : "", @@ -786,6 +786,15 @@ static TGenEvent _tgentransport_receiveSocksAuth(TGenTransport* transport) { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_AUTH); return TGEN_EVENT_NONE; } + + tgen_info("socks server %s authentication succeeded with username='%s' and password='%s'", + tgenpeer_toString(transport->proxy), + transport->username ? transport->username : "", + transport->password ? transport->password : ""); + + /* now we can move on to the request */ + _tgentransport_changeState(transport, TGEN_XPORT_PROXY_REQUEST); + return TGEN_EVENT_WRITE; } } @@ -1007,6 +1016,7 @@ static TGenEvent _tgentransport_receiveSocksResponseType(TGenTransport* transpor return TGEN_EVENT_READ; } else { gchar reserved = transport->socksBuffer->str[0]; + (void)reserved; gchar addressType = transport->socksBuffer->str[1]; g_string_free(transport->socksBuffer, TRUE);