From 1c32e18c74decdbd62d3b6aa819d9e45a57d500f Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sun, 13 Aug 2023 03:11:40 +0000 Subject: [PATCH] Json now uses Int64 for integers. This should fix all timestamp errors on 32-bit systems in Cytoplasm and Telodendria. --- Cytoplasm/src/Json.c | 47 +++++++++++++++++++++++++++----- Cytoplasm/src/include/Int64.h | 22 +++------------ Cytoplasm/src/include/Json.h | 7 +++-- Cytoplasm/tools/j2s.c | 7 +++-- src/Config.c | 11 ++++---- src/Filter.c | 2 +- src/Main.c | 13 +++++---- src/RegToken.c | 25 +++++++++-------- src/Room.c | 2 +- src/Routes/RouteAliasDirectory.c | 5 ++-- src/Routes/RouteFilter.c | 2 +- src/Routes/RouteProcControl.c | 18 +++++++++++- src/Uia.c | 4 +-- src/User.c | 19 +++++++------ src/include/RegToken.h | 11 ++++---- src/include/User.h | 4 +-- tools/src/json.c | 32 ++++++++++++++++++++-- 17 files changed, 153 insertions(+), 78 deletions(-) diff --git a/Cytoplasm/src/Json.c b/Cytoplasm/src/Json.c index 8441e93..83ad602 100644 --- a/Cytoplasm/src/Json.c +++ b/Cytoplasm/src/Json.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,7 @@ struct JsonValue HashMap *object; Array *array; char *string; - long integer; + Int64 integer; double floating; int boolean:1; } as; @@ -200,7 +201,7 @@ JsonValueAsString(JsonValue * value) } JsonValue * -JsonValueInteger(long integer) +JsonValueInteger(Int64 integer) { JsonValue *value; @@ -216,12 +217,12 @@ JsonValueInteger(long integer) return value; } -long +Int64 JsonValueAsInteger(JsonValue * value) { if (!value || value->type != JSON_INTEGER) { - return 0; + return Int64Create(0, 0); } return value->as.integer; @@ -605,6 +606,8 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level) Array *arr; int length = 0; + char ibuf[INT64_STRBUF]; + switch (value->type) { case JSON_OBJECT: @@ -641,7 +644,8 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level) length += JsonEncodeString(value->as.string, out); break; case JSON_INTEGER: - length += StreamPrintf(out, "%ld", value->as.integer); + Int64Str(value->as.integer, 10, ibuf, INT64_STRBUF); + length += StreamPrintf(out, "%s", ibuf); break; case JSON_FLOAT: length += StreamPrintf(out, "%f", value->as.floating); @@ -979,7 +983,7 @@ JsonTokenSeek(JsonParserState * state) break; } - if (state->tokenLen >= allocated) + if (state->tokenLen + 1 >= allocated) { char *tmp; @@ -1119,6 +1123,10 @@ JsonDecodeValue(JsonParserState * state) JsonValue *value; char *strValue; + Int64 iValue; + size_t i; + int neg; + switch (state->tokenType) { case TOKEN_OBJECT_OPEN: @@ -1138,7 +1146,32 @@ JsonDecodeValue(JsonParserState * state) Free(strValue); break; case TOKEN_INTEGER: - value = JsonValueInteger(atol(state->token)); + iValue = Int64Create(0, 0); + i = 0; + neg = 0; + + while (state->token[i]) + { + int d; + + if (i == 0 && !neg && state->token[i] == '-') + { + neg = 1; + i++; + continue; + } + + d = state->token[i] - '0'; + iValue = Int64Mul(iValue, Int64Create(0, 10)); + iValue = Int64Add(iValue, Int64Create(0, d)); + i++; + } + + if (neg) + { + iValue = Int64Neg(iValue); + } + value = JsonValueInteger(iValue); break; case TOKEN_FLOAT: value = JsonValueFloat(atof(state->token)); diff --git a/Cytoplasm/src/include/Int64.h b/Cytoplasm/src/include/Int64.h index 8e917dd..08083c1 100644 --- a/Cytoplasm/src/include/Int64.h +++ b/Cytoplasm/src/include/Int64.h @@ -122,25 +122,11 @@ typedef signed long Int64; #define Int64Neg(x) (Int64Add(Int64Not(x), Int64Create(0, 1))) /** - * For platforms that do not have a native integer large enough to - * store a 64 bit integer, this struct is used. i[0] contains the low - * bits of integer, and i[1] contains the high bits of the integer. - * .Pp - * This struct should not be accessed directly, because UInt64 may not - * actually be this struct, it might be an actual integer type. For - * maximum portability, only use the functions defined here to - * manipulate 64 bit integers. + * The internal bit representation of a signed integer is identical + * to an unsigned integer, the difference is in the algorithms and + * the way the bits are interpreted. */ -typedef struct -{ - /* - * Unsigned, because we will deal with the sign bits ourselves. - * This also allows well-defined casting between signed and - * unsigned integers. - */ - UInt32 i[2]; -} Int64; - +typedef UInt64 Int64; /** * Create a new signed 64 bit integer using the given high and low diff --git a/Cytoplasm/src/include/Json.h b/Cytoplasm/src/include/Json.h index 03bcfae..4185260 100644 --- a/Cytoplasm/src/include/Json.h +++ b/Cytoplasm/src/include/Json.h @@ -71,6 +71,7 @@ #include #include #include +#include #include #include @@ -101,7 +102,7 @@ typedef enum JsonType JSON_OBJECT, /* Maps to a HashMap of JsonValues */ JSON_ARRAY, /* Maps to an Array of JsonValues */ JSON_STRING, /* Maps to a null-terminated C string */ - JSON_INTEGER, /* Maps to a C long */ + JSON_INTEGER, /* Maps to an Int64 */ JSON_FLOAT, /* Maps to a C double */ JSON_BOOLEAN /* Maps to a C integer of either 0 or 1 */ } JsonType; @@ -151,7 +152,7 @@ extern char * JsonValueAsString(JsonValue *); * Encode a number as a JSON value that can be added to an object or * an array. */ -extern JsonValue * JsonValueInteger(long); +extern JsonValue * JsonValueInteger(Int64); /** * Unwrap a JSON value that represents a number. This function will @@ -159,7 +160,7 @@ extern JsonValue * JsonValueInteger(long); * misleading. Check the type of the value before making assumptions * about its value. */ -extern long JsonValueAsInteger(JsonValue *); +extern Int64 JsonValueAsInteger(JsonValue *); /** * Encode a floating point number as a JSON value that can be added diff --git a/Cytoplasm/tools/j2s.c b/Cytoplasm/tools/j2s.c index c05bf2f..fe3bde8 100644 --- a/Cytoplasm/tools/j2s.c +++ b/Cytoplasm/tools/j2s.c @@ -443,6 +443,7 @@ Main(Array * args) StreamPrintf(headerFile, "#include \n"); StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); StreamPutc(headerFile, '\n'); @@ -491,7 +492,7 @@ Main(Array * args) } else if (StrEquals(fieldType, "integer")) { - cType = "long"; + cType = "Int64"; } else if (StrEquals(fieldType, "boolean")) { @@ -664,7 +665,7 @@ Main(Array * args) if (StrEquals(fieldType, "integer")) { - cType = "long"; + cType = "Int64"; } else if (StrEquals(fieldType, "float")) { @@ -907,7 +908,7 @@ Main(Array * args) if (StrEquals(fieldType, "integer")) { - cType = "long"; + cType = "Int64"; } else if (StrEquals(fieldType, "float")) { diff --git a/src/Config.c b/src/Config.c index 475aaba..50aff21 100644 --- a/src/Config.c +++ b/src/Config.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,7 @@ tConfig->err = "Expected " key " to be of type JSON_INTEGER"; \ goto error; \ } \ - into = JsonValueAsInteger(value); \ + into = Int64Low(JsonValueAsInteger(value)); \ } \ else \ { \ @@ -146,9 +147,9 @@ ConfigParseListen(Config * tConfig, Array * listen) obj = JsonValueAsObject(val); - serverCfg->port = JsonValueAsInteger(HashMapGet(obj, "port")); - serverCfg->threads = JsonValueAsInteger(HashMapGet(obj, "threads")); - serverCfg->maxConnections = JsonValueAsInteger(HashMapGet(obj, "maxConnections")); + serverCfg->port = Int64Low(JsonValueAsInteger(HashMapGet(obj, "port"))); + serverCfg->threads = Int64Low(JsonValueAsInteger(HashMapGet(obj, "threads"))); + serverCfg->maxConnections = Int64Low(JsonValueAsInteger(HashMapGet(obj, "maxConnections"))); if (!serverCfg->port) { @@ -450,7 +451,7 @@ ConfigCreateDefault(Db * db) listeners = ArrayCreate(); listen = HashMapCreate(); - HashMapSet(listen, "port", JsonValueInteger(8008)); + HashMapSet(listen, "port", JsonValueInteger(Int64Create(0, 8008))); HashMapSet(listen, "tls", JsonValueBoolean(0)); ArrayAdd(listeners, JsonValueObject(listen)); HashMapSet(json, "listen", JsonValueArray(listeners)); diff --git a/src/Filter.c b/src/Filter.c index 2527e51..b1e91bb 100644 --- a/src/Filter.c +++ b/src/Filter.c @@ -26,7 +26,7 @@ #include HashMap * -FilterApply(Filter *filter, HashMap *event) +FilterApply(Filter * filter, HashMap * event) { return NULL; } diff --git a/src/Main.c b/src/Main.c index a2533b2..c6fca80 100644 --- a/src/Main.c +++ b/src/Main.c @@ -247,7 +247,7 @@ start: } token = StrRandom(32); - info = RegTokenCreate(matrixArgs.db, token, NULL, 0, 1, USER_ALL); + info = RegTokenCreate(matrixArgs.db, token, NULL, UInt64Create(0, 0), Int64Create(0, 1), USER_ALL); if (!info) { Free(token); @@ -259,8 +259,8 @@ start: RegTokenClose(info); RegTokenFree(info); - /* Don't free token, because we need to print it when logging is - * set up. */ + /* Don't free token, because we need to print it when logging + * is set up. */ } Log(LOG_NOTICE, "Loading configuration..."); @@ -339,7 +339,8 @@ start: goto finish; } - /* If a token was created with a default config, print it to the log */ + /* If a token was created with a default config, print it to the + * log */ if (token) { Log(LOG_NOTICE, "Admin Registration token: %s", token); @@ -384,14 +385,14 @@ start: if (serverCfg->flags & HTTP_FLAG_TLS) { - if (!UtilLastModified(serverCfg->tlsCert)) + if (UInt64Eq(UtilLastModified(serverCfg->tlsCert), UInt64Create(0, 0))) { Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsCert); exit = EXIT_FAILURE; goto finish; } - if (!UtilLastModified(serverCfg->tlsKey)) + if (UInt64Eq(UtilLastModified(serverCfg->tlsKey), UInt64Create(0, 0))) { Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsKey); exit = EXIT_FAILURE; diff --git a/src/RegToken.c b/src/RegToken.c index e2fcc40..25fbd6d 100644 --- a/src/RegToken.c +++ b/src/RegToken.c @@ -31,14 +31,15 @@ #include #include #include +#include int RegTokenValid(RegTokenInfo * token) { HashMap *tokenJson; - int uses, used; + Int64 uses, used; - unsigned long expiration; + UInt64 expiration; if (!token || !RegTokenExists(token->db, token->name)) { @@ -50,8 +51,9 @@ RegTokenValid(RegTokenInfo * token) used = JsonValueAsInteger(HashMapGet(tokenJson, "used")); expiration = JsonValueAsInteger(HashMapGet(tokenJson, "expires_on")); - return (!expiration || (UtilServerTs() <= expiration)) && - (uses == -1 || used < uses); + return (UInt64Eq(expiration, UInt64Create(0, 0)) || + UInt64Geq(UtilServerTs(), expiration)) && + (Int64Eq(uses, Int64Neg(Int64Create(0, 1))) || Int64Lt(used, uses)); } void RegTokenUse(RegTokenInfo * token) @@ -63,12 +65,13 @@ RegTokenUse(RegTokenInfo * token) return; } - if (token->uses >= 0 && token->used >= token->uses) + if (Int64Geq(token->uses, Int64Create(0, 0)) && + Int64Geq(token->used, token->uses)) { return; } - token->used++; + token->used = Int64Add(token->used, Int64Create(0, 1)); /* Write the information to the hashmap */ tokenJson = DbJson(token->ref); @@ -196,12 +199,12 @@ RegTokenVerify(char *token) } RegTokenInfo * -RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses, int privileges) +RegTokenCreate(Db * db, char *name, char *owner, UInt64 expires, Int64 uses, int privileges) { RegTokenInfo *ret; HashMap *tokenJson; - unsigned long timestamp = UtilServerTs(); + UInt64 timestamp = UtilServerTs(); if (!db || !name) { @@ -211,13 +214,13 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses /* -1 indicates infinite uses; zero and all positive values are a * valid number of uses; althought zero would be rather useless. * Anything less than -1 doesn't make sense. */ - if (uses < -1) + if (Int64Lt(uses, Int64Neg(Int64Create(0, 1)))) { return NULL; } /* Verify the token */ - if (!RegTokenVerify(name) || (expires > 0 && expires < timestamp)) + if (!RegTokenVerify(name) || (UInt64Gt(expires, UInt64Create(0, 0)) && UInt64Lt(expires, timestamp))) { return NULL; } @@ -233,7 +236,7 @@ RegTokenCreate(Db * db, char *name, char *owner, unsigned long expires, int uses } ret->name = StrDuplicate(name); ret->owner = StrDuplicate(owner); - ret->used = 0; + ret->used = Int64Create(0, 0); ret->uses = uses; ret->created = timestamp; ret->expires = expires; diff --git a/src/Room.c b/src/Room.c index 55de283..a1d67ff 100644 --- a/src/Room.c +++ b/src/Room.c @@ -40,7 +40,7 @@ struct Room }; Room * -RoomCreate(Db * db, RoomCreateRequest *req) +RoomCreate(Db * db, RoomCreateRequest * req) { return NULL; } diff --git a/src/Routes/RouteAliasDirectory.c b/src/Routes/RouteAliasDirectory.c index 77d5cea..982843c 100644 --- a/src/Routes/RouteAliasDirectory.c +++ b/src/Routes/RouteAliasDirectory.c @@ -93,7 +93,7 @@ ROUTE_IMPL(RouteAliasDirectory, path, argp) HashMap *newAlias; /* TODO: Validate alias domain and make sure it matches - server name and is well formed. */ + * server name and is well formed. */ if (JsonGet(aliases, 2, "alias", alias)) { @@ -117,7 +117,8 @@ ROUTE_IMPL(RouteAliasDirectory, path, argp) goto finish; } - /* TODO: Validate room ID to make sure it is well formed. */ + /* TODO: Validate room ID to make sure it is well + * formed. */ newAlias = HashMapCreate(); HashMapSet(newAlias, "createdBy", JsonValueString(UserGetName(user))); diff --git a/src/Routes/RouteFilter.c b/src/Routes/RouteFilter.c index 5b79901..b5e3d1b 100644 --- a/src/Routes/RouteFilter.c +++ b/src/Routes/RouteFilter.c @@ -139,7 +139,7 @@ ROUTE_IMPL(RouteFilter, path, argp) DbRef *ref; char *filterId; - Filter filter = { 0 }; + Filter filter = {0}; char *parseErr; HashMap *filterJson; diff --git a/src/Routes/RouteProcControl.c b/src/Routes/RouteProcControl.c index adc8758..6653e8a 100644 --- a/src/Routes/RouteProcControl.c +++ b/src/Routes/RouteProcControl.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -80,10 +81,25 @@ ROUTE_IMPL(RouteProcControl, path, argp) case HTTP_GET: if (StrEquals(op, "stats")) { + size_t allocated = MemoryAllocated(); + Int64 a; + response = HashMapCreate(); + if (sizeof(size_t) == sizeof(Int64)) + { + UInt32 high = (UInt32) (allocated >> 32); + UInt32 low = (UInt32) (allocated); + + a = Int64Create(high, low); + } + else + { + a = Int64Create(0, allocated); + } + HashMapSet(response, "version", JsonValueString(TELODENDRIA_VERSION)); - HashMapSet(response, "memory_allocated", JsonValueInteger(MemoryAllocated())); + HashMapSet(response, "memory_allocated", JsonValueInteger(a)); goto finish; } diff --git a/src/Uia.c b/src/Uia.c index de6b04e..9927576 100644 --- a/src/Uia.c +++ b/src/Uia.c @@ -491,7 +491,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args) char *session = ArrayGet(sessions, i); DbRef *ref = DbLock(args->db, 2, "user_interactive", session); - unsigned long lastAccess; + UInt64 lastAccess; if (!ref) { @@ -506,7 +506,7 @@ UiaCleanup(MatrixHttpHandlerArgs * args) /* If last access was greater than 15 minutes ago, remove this * session */ - if (UtilServerTs() - lastAccess > 1000 * 60 * 15) + if (UInt64Gt(UInt64Sub(UtilServerTs(), lastAccess), UInt64Create(0, 1000 * 60 * 15))) { DbDelete(args->db, 2, "user_interactive", session); Log(LOG_DEBUG, "Deleted session %s", session); diff --git a/src/User.c b/src/User.c index ce022e0..7bc0532 100644 --- a/src/User.c +++ b/src/User.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include @@ -128,7 +130,7 @@ UserAuthenticate(Db * db, char *accessToken) char *userName; char *deviceId; - long expires; + UInt64 expires; if (!db || !accessToken) { @@ -143,7 +145,7 @@ UserAuthenticate(Db * db, char *accessToken) userName = JsonValueAsString(HashMapGet(DbJson(atRef), "user")); deviceId = JsonValueAsString(HashMapGet(DbJson(atRef), "device")); - expires = JsonValueAsInteger(HashMapGet(DbJson(atRef), "expires")); + expires = JsonValueAsInteger(HashMapGet(DbJson(atRef), "expires")); user = UserLock(db, userName); if (!user) @@ -152,7 +154,8 @@ UserAuthenticate(Db * db, char *accessToken) return NULL; } - if (expires && UtilServerTs() >= (unsigned long) expires) + if (UInt64Neq(expires, UInt64Create(0, 0)) && + UInt64Geq(UtilServerTs(), expires)) { UserUnlock(user); DbUnlock(db, atRef); @@ -190,7 +193,7 @@ UserCreate(Db * db, char *name, char *password) User *user = NULL; HashMap *json = NULL; - unsigned long ts = UtilServerTs(); + UInt64 ts = UtilServerTs(); /* TODO: Put some sort of password policy(like for example at least * 8 chars, or maybe check it's entropy)? */ @@ -495,11 +498,11 @@ UserAccessTokenGenerate(User * user, char *deviceId, int withRefresh) if (withRefresh) { - token->lifetime = 1000 * 60 * 60 * 24 * 7; /* 1 Week */ + token->lifetime = Int64Create(0, 1000 * 60 * 60 * 24 * 7); /* 1 Week */ } else { - token->lifetime = 0; + token->lifetime = Int64Create(0, 0); } return token; @@ -528,9 +531,9 @@ UserAccessTokenSave(Db * db, UserAccessToken * token) HashMapSet(json, "user", JsonValueString(token->user)); HashMapSet(json, "device", JsonValueString(token->deviceId)); - if (token->lifetime) + if (Int64Neq(token->lifetime, Int64Create(0, 0))) { - HashMapSet(json, "expires", JsonValueInteger(UtilServerTs() + token->lifetime)); + HashMapSet(json, "expires", JsonValueInteger(UInt64Add(UtilServerTs(), token->lifetime))); } return DbUnlock(db, ref); diff --git a/src/include/RegToken.h b/src/include/RegToken.h index 76f14e3..42ce0a8 100644 --- a/src/include/RegToken.h +++ b/src/include/RegToken.h @@ -40,6 +40,7 @@ */ #include +#include /** * This structure describes a registration token that is in the @@ -64,23 +65,23 @@ typedef struct RegTokenInfo /* * How many times the token was used. */ - int used; + Int64 used; /* * How many uses are allowed. */ - int uses; + Int64 uses; /* * Timestamp when this token was created. */ - unsigned long created; + UInt64 created; /* * Timestamp when this token expires, or 0 if it does not * expire. */ - unsigned long expires; + UInt64 expires; /* * A bit field describing the privileges this token grants. See @@ -123,7 +124,7 @@ extern RegTokenInfo * RegTokenGetInfo(Db *, char *); * structure will be returned. Otherwise, NULL will be returned. */ extern RegTokenInfo * -RegTokenCreate(Db *, char *, char *, unsigned long, int, int); +RegTokenCreate(Db *, char *, char *, UInt64, Int64, int); /** * Free the memory associated with the registration token. This should diff --git a/src/include/User.h b/src/include/User.h index b813c33..275471e 100644 --- a/src/include/User.h +++ b/src/include/User.h @@ -38,8 +38,8 @@ * users, among many other tasks. */ +#include #include - #include /** @@ -74,7 +74,7 @@ typedef struct UserAccessToken char *user; char *string; char *deviceId; - long lifetime; + Int64 lifetime; } UserAccessToken; /** diff --git a/tools/src/json.c b/tools/src/json.c index c5b6bc0..76bd6d3 100644 --- a/tools/src/json.c +++ b/tools/src/json.c @@ -69,14 +69,42 @@ query(char *select, HashMap * json, int canonical) { if (StrEquals(keyName + 1, "length")) { + UInt64 len; + switch (JsonValueType(val)) { case JSON_ARRAY: - val = JsonValueInteger(ArraySize(JsonValueAsArray(val))); + if (sizeof(size_t) == sizeof(UInt64)) + { + size_t slen = ArraySize(JsonValueAsArray(val)); + UInt32 high = slen >> 32; + UInt32 low = slen; + + len = UInt64Create(high, low); + } + else + { + len = UInt64Create(0, ArraySize(JsonValueAsArray(val))); + } + + val = JsonValueInteger(len); ArrayAdd(cleanUp, val); break; case JSON_STRING: - val = JsonValueInteger(strlen(JsonValueAsString(val))); + if (sizeof(size_t) == sizeof(UInt64)) + { + size_t slen = strlen(JsonValueAsString(val)); + UInt32 high = slen >> 32; + UInt32 low = slen; + + len = UInt64Create(high, low); + } + else + { + len = UInt64Create(0, strlen(JsonValueAsString(val))); + } + + val = JsonValueInteger(len); ArrayAdd(cleanUp, val); break; default: