diff --git a/orbisrpc/cfg.c b/orbisrpc/cfg.c index 4d4bc60..ee16f37 100644 --- a/orbisrpc/cfg.c +++ b/orbisrpc/cfg.c @@ -63,6 +63,7 @@ int cfg_load(const char *path, cfg_t *c) { #undef STR o = jl_obj_get(root, "enabled"); if (o && o->type == JL_BOOL) c->enabled = (int)o->num; o = jl_obj_get(root, "auto_update"); if (o && o->type == JL_BOOL) c->auto_update = (int)o->num; + o = jl_obj_get(root, "debug"); if (o && o->type == JL_BOOL) c->debug = (int)o->num; o = jl_obj_get(root, "poll_interval_s"); if (o && o->type == JL_NUMBER) c->poll_interval_s = (int)o->num; jl_free(root); clamp_cfg(c); @@ -78,6 +79,7 @@ void cfg_save(const char *path, const cfg_t *c) { jl_obj_set(r, "art_base_url", jl_new_string(c->art_base_url)); jl_obj_set(r, "enabled", jl_new_bool(c->enabled)); jl_obj_set(r, "auto_update", jl_new_bool(c->auto_update)); + jl_obj_set(r, "debug", jl_new_bool(c->debug)); jl_obj_set(r, "poll_interval_s", jl_new_number((double)c->poll_interval_s)); jl_obj_set(r, "presence_state", jl_new_string(c->presence_state)); char *s = jl_stringify(r); diff --git a/orbisrpc/cfg.h b/orbisrpc/cfg.h index e474d91..3b4eb8b 100644 --- a/orbisrpc/cfg.h +++ b/orbisrpc/cfg.h @@ -13,6 +13,7 @@ typedef struct { * large_image becomes .png */ int enabled; int auto_update; /* check GitHub releases once per boot, stage newer */ + int debug; /* verbose debug logging (per-poll detail, no secrets) */ int poll_interval_s; /* game-check cadence */ char presence_state[128]; /* activity "state" line, e.g. "On PS4" */ } cfg_t; diff --git a/orbisrpc/clock.h b/orbisrpc/clock.h new file mode 100644 index 0000000..fca3478 --- /dev/null +++ b/orbisrpc/clock.h @@ -0,0 +1,14 @@ +/* clock.h - monotonic time for measuring durations. + * + * Rule: wall clock (time(NULL)) is ONLY for values that must be wall + * clock (Discord epoch timestamps, log stamps). Every duration/deadline + * uses orbis_mono_s() so a clock jump can never break local timing. + * + * PS4: sceKernelGetProcessTime (microseconds, monotonic). + * Host: clock_gettime(CLOCK_MONOTONIC). */ +#ifndef ORBISRPC_CLOCK_H +#define ORBISRPC_CLOCK_H +#include +/* Monotonic seconds (arbitrary epoch, never goes backward). */ +int64_t orbis_mono_s(void); +#endif diff --git a/orbisrpc/compat.c b/orbisrpc/compat.c index e884d32..590e047 100644 --- a/orbisrpc/compat.c +++ b/orbisrpc/compat.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include "clock.h" int *__errno_location(void) __attribute__((weak)); int *__errno_location(void){ @@ -70,3 +72,21 @@ int mbedtls_platform_entropy_poll(void *data, unsigned char *out, *olen = len; return 0; } + +int64_t orbis_mono_s(void){ +#if defined(__PS4__) || (defined(__FreeBSD__) && !defined(__APPLE__)) + /* PS4 builds (--target=x86_64-pc-freebsd12-elf, -D__PS4__). Declared + * here instead of including orbis headers so host builds stay clean. */ + extern unsigned long long sceKernelGetProcessTime(void); + return (int64_t)(sceKernelGetProcessTime() / 1000000ull); +#else + struct timespec ts; +#if defined(CLOCK_MONOTONIC) + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + ts.tv_sec = time(NULL); + ts.tv_nsec = 0; +#endif + return (int64_t)ts.tv_sec; +#endif +} diff --git a/orbisrpc/daemon.c b/orbisrpc/daemon.c index ca0eeb1..acb5bfc 100644 --- a/orbisrpc/daemon.c +++ b/orbisrpc/daemon.c @@ -14,6 +14,7 @@ * recover, but suspend behavior is UNVERIFIED on hardware. */ #include "cfg.h" +#include "clock.h" #include "log.h" #include "ws.h" #include "discord.h" @@ -85,6 +86,8 @@ int daemon_run(const char *fixed_game_name){ log_msg("config load failed; running on defaults until valid config appears"); } if(!g_cfg.enabled){ log_msg("disabled in config; exiting"); log_close(); return 0; } + log_set_debug(g_cfg.debug); + if(g_cfg.debug) log_dbg("debug logging on (config)"); if(!have_token(&g_cfg)){ log_msg("FATAL: put your Discord user token in %s as \"token\":\"...\"", CFG_PATH); log_close(); @@ -111,7 +114,12 @@ int daemon_run(const char *fixed_game_name){ * On parse failure keep last-good config instead of stale defaults. */ { cfg_t next = g_cfg; - if(cfg_load(CFG_PATH, &next) == 0) g_cfg = next; + if(cfg_load(CFG_PATH, &next) == 0){ + if(next.debug != g_cfg.debug) + log_msg("debug logging %s", next.debug ? "on" : "off"); + g_cfg = next; + log_set_debug(g_cfg.debug); + } else log_msg("config reload failed; keeping last-good config"); } if(!have_token(&g_cfg)){ @@ -140,12 +148,17 @@ int daemon_run(const char *fixed_game_name){ * A reconnect re-posts presence only when needed, timer intact. */ static int active = 0; static char last[128] = ""; + static char sess_tid[16] = ""; static int64_t started = 0; + /* Transition debounce: shell flickers during launches, so a new + * title (or disappearance) needs consecutive polls (2 at ~1s). */ + static char cand_title[16] = ""; + static int cand_hits = 0, miss_hits = 0; int64_t last_poll = 0; /* re-post after every (re)connect so Discord never sticks on stale */ int need_post = active && last[0]; while(!s_stop){ /* inner: live session, serviced every second */ - int64_t now = time(NULL); + int64_t now = orbis_mono_s(); if(now != last_poll){ last_poll = now; char name[128] = ""; @@ -160,24 +173,46 @@ int daemon_run(const char *fixed_game_name){ } if(name[0]){ - if(!active || strncmp(name,last,sizeof last)!=0){ + const char *cur_tid = detect_last_titleid(); + if(!cur_tid) cur_tid = ""; + if(!strncmp(cur_tid, cand_title, sizeof cand_title)){ + cand_hits++; + } else { + strncpy(cand_title, cur_tid, sizeof cand_title-1); + cand_title[sizeof cand_title-1] = 0; + cand_hits = 1; + } + miss_hits = 0; + if(fixed_game_name || cand_hits >= 2){ + if(!active || strncmp(cur_tid,sess_tid,sizeof sess_tid)!=0){ + active = 1; + strncpy(sess_tid, cur_tid, sizeof sess_tid-1); + strncpy(last, name, sizeof last-1); + last[sizeof last-1] = 0; started = time(NULL); need_post = 1; + log_msg("GAME_DETECTED title=%s name=%s", cur_tid[0]?cur_tid:"?", name); + } else if(strncmp(name,last,sizeof last)!=0){ + strncpy(last, name, sizeof last-1); + last[sizeof last-1] = 0; + need_post = 1; } if(need_post){ const char *state = g_cfg.presence_state[0] ? g_cfg.presence_state : NULL; - const char *tid = detect_last_titleid(); const char *tart = detect_last_art(); - discord_set_presence_ex(&dc, state, name, tid, g_cfg.application_id, g_cfg.art_base_url, tart, started); - log_msg("presence: %s", name); - strncpy(last, name, sizeof last-1); - last[sizeof last-1] = 0; + discord_set_presence_ex(&dc, state, last, sess_tid[0]?sess_tid:NULL, g_cfg.application_id, g_cfg.art_base_url, tart, started); + log_msg("presence: %s", last); active = 1; need_post = 0; } + } }else if(active){ - discord_clear_presence(&dc); - log_msg("presence cleared"); - last[0]=0; active=0; started=0; + cand_title[0] = 0; + cand_hits = 0; + if(++miss_hits >= 2){ + discord_clear_presence(&dc); + log_msg("presence cleared"); + last[0]=0; sess_tid[0]=0; active=0; started=0; + } } } diff --git a/orbisrpc/detect.c b/orbisrpc/detect.c index 4a7c182..8b37cad 100644 --- a/orbisrpc/detect.c +++ b/orbisrpc/detect.c @@ -93,8 +93,32 @@ static int is_title_prefix(const char *n){ * detect_current_game / detect_name_for_title. */ static char s_last_titleid[16] = ""; static char s_last_art[256] = ""; +static char s_res_titleid[16] = ""; +static char s_res_name[128] = ""; +static char s_res_art[256] = ""; +static int s_res_valid = 0; const char *detect_last_titleid(void){ return s_last_titleid[0] ? s_last_titleid : NULL; } const char *detect_last_art(void){ return s_last_art[0] ? s_last_art : NULL; } +static void remember_resolved(const char *ti, const char *name, const char *art){ + if(!ti || !name) return; + strncpy(s_res_titleid, ti, sizeof s_res_titleid - 1); + s_res_titleid[sizeof s_res_titleid - 1] = 0; + strncpy(s_res_name, name, sizeof s_res_name - 1); + s_res_name[sizeof s_res_name - 1] = 0; + if(art){ + strncpy(s_res_art, art, sizeof s_res_art - 1); + s_res_art[sizeof s_res_art - 1] = 0; + } else s_res_art[0] = 0; + s_res_valid = 1; +} +static int cached_resolve(const char *ti, char *out_name, size_t cap){ + if(!s_res_valid || !ti || !ti[0] || strcmp(ti, s_res_titleid) != 0) return 0; + strncpy(out_name, s_res_name, cap - 1); + out_name[cap - 1] = 0; + strncpy(s_last_art, s_res_art, sizeof s_last_art - 1); + s_last_art[sizeof s_last_art - 1] = 0; + return 1; +} static void remember_titleid(const char *ti){ if(!ti) return; strncpy(s_last_titleid, ti, sizeof s_last_titleid - 1); @@ -213,9 +237,13 @@ int detect_current_game(char *out_name, size_t cap, char *out_path, size_t p_cap if(scan_recent_titleid(titleId,sizeof titleId)==0){ remember_titleid(titleId); s_last_art[0] = 0; + if(cached_resolve(titleId, out_name, cap)){ + log_msg("name: %s via cache", out_name); + named = 1; + } /* cheap, game-process-safe sources first; Sony TMDB (network) * resolves anything local sources miss, on any console. */ - if(pronunc_title(titleId, out_name, cap)==0){ named=1; log_msg("name: %s via appmeta", out_name); } + if(!named && pronunc_title(titleId, out_name, cap)==0){ named=1; log_msg("name: %s via appmeta", out_name); } if(!named){ if(sfo_file_title(titleId, out_name, cap)==0){ named=1; log_msg("name: %s via sfo", out_name); } } if(!named){ if(appxml_title(titleId, out_name, cap)==0){ named=1; log_msg("name: %s via appxml", out_name); } } if(!named){ if(nametable_lookup(titleId, out_name, cap)==0){ named=1; log_msg("name: %s via table", out_name); } } @@ -227,7 +255,10 @@ int detect_current_game(char *out_name, size_t cap, char *out_path, size_t p_cap } else s_last_art[0] = 0; } if(!named){ strncpy(out_name, titleId, cap-1); out_name[cap-1]=0; } + remember_resolved(titleId, out_name, s_last_art); }else{ + remember_titleid(""); + s_last_art[0] = 0; strncpy(out_name, "(unknown game)", cap-1); out_name[cap-1]=0; } if(out_path){ snprintf(out_path, p_cap, "/data/orbisRPC/.lastgame/%s", titleId[0]?titleId:"unknown"); } @@ -241,21 +272,27 @@ int detect_name_for_title(const char *titleId, char *out_name, size_t cap){ if(!titleId || !titleId[0] || !out_name || cap==0) return -1; remember_titleid(titleId); s_last_art[0] = 0; + if(cached_resolve(titleId, out_name, cap)){ + log_msg("name: %s via cache", out_name); + return 0; + } /* Game-process-safe only: small reads plus one bounded network * lookup; no multi-megabyte scans anywhere in this codebase. */ - if(pronunc_title(titleId, out_name, cap)==0){ log_msg("name: %s via appmeta", out_name); return 0; } + if(pronunc_title(titleId, out_name, cap)==0){ log_msg("name: %s via appmeta", out_name); remember_resolved(titleId, out_name, ""); return 0; } else log_msg("name: appmeta miss for %s", titleId); - if(sfo_file_title(titleId, out_name, cap)==0){ log_msg("name: %s via sfo", out_name); return 0; } - if(appxml_title(titleId, out_name, cap)==0){ log_msg("name: %s via appxml", out_name); return 0; } - if(nametable_lookup(titleId, out_name, cap)==0){ log_msg("name: %s via table", out_name); return 0; } + if(sfo_file_title(titleId, out_name, cap)==0){ log_msg("name: %s via sfo", out_name); remember_resolved(titleId, out_name, ""); return 0; } + if(appxml_title(titleId, out_name, cap)==0){ log_msg("name: %s via appxml", out_name); remember_resolved(titleId, out_name, ""); return 0; } + if(nametable_lookup(titleId, out_name, cap)==0){ log_msg("name: %s via table", out_name); remember_resolved(titleId, out_name, ""); return 0; } { char art[256] = ""; if(tmdb_resolve(titleId, out_name, cap, art, sizeof art)==0){ strncpy(s_last_art, art, sizeof s_last_art-1); + remember_resolved(titleId, out_name, art); return 0; /* tmdb_resolve already logged */ } s_last_art[0] = 0; } strncpy(out_name, titleId, cap-1); out_name[cap-1]=0; + remember_resolved(titleId, out_name, ""); return 0; } \ No newline at end of file diff --git a/orbisrpc/discord.c b/orbisrpc/discord.c index cab9baf..6cea33c 100644 --- a/orbisrpc/discord.c +++ b/orbisrpc/discord.c @@ -9,6 +9,7 @@ * (close 4004) is reported as fatal instead of looping forever. */ #include "discord.h" +#include "clock.h" #include "b64.h" #include "log.h" #include "jsonlite.h" @@ -99,7 +100,7 @@ static int rx_frame(discord_t *d, char *buf, size_t cap, int *op, int *fin, int6 int nr=ws_recv_frame(&d->ws,buf,cap,op,fin); if(nr==-3){ log_msg("skipped oversized gateway frame"); continue; } if(nr!=0) return nr; - if(time(NULL)>deadline) return -4; + if(orbis_mono_s()>deadline) return -4; usleep(50000); } } @@ -141,7 +142,7 @@ int discord_connect(discord_t *d, const char *token){ int rc=ws_connect(&d->ws, GW_HOST, GW_PORT, GW_PATH, key); if(rc){ log_msg("ws connect fail %d",rc); return -1; } d->connected=1; - int64_t now=time(NULL); + int64_t now=orbis_mono_s(); d->last_heartbeat=now; d->last_ack=now; /* HELLO (text frame carrying {"op":10,...}) */ char buf[2048]; int op=0,fin=0; @@ -175,7 +176,7 @@ int discord_connect(discord_t *d, const char *token){ log_msg("discord: identify sent, hb=%llds",(long long)(d->hb_interval_ms/1000)); /* READY confirms the token was accepted. `op` is the WebSocket frame * type; the gateway event is JSON inside — parse it, don't switch on it. */ - int64_t dl=time(NULL)+20; + int64_t dl=orbis_mono_s()+20; for(;;){ nr=rx_frame(d,buf,sizeof buf,&op,&fin,dl); if(nr==-4){ log_msg("no READY after identify (timeout)"); break; } @@ -191,7 +192,7 @@ int discord_connect(discord_t *d, const char *token){ if(op==9){ ws_pong(&d->ws); continue; } if(op!=1) continue; int go = gw_op(buf, (size_t)nr); - if(go==11){ d->last_ack=time(NULL); continue; } + if(go==11){ d->last_ack=orbis_mono_s(); continue; } if(go==0 && is_ready(buf, (size_t)nr)){ gw_seq(d, buf, (size_t)nr); log_msg("discord: gateway ready"); @@ -322,7 +323,7 @@ int discord_clear_presence(discord_t *d){ int discord_tick(discord_t *d){ if(!d || !d->connected) return -1; - int64_t now=time(NULL); + int64_t now=orbis_mono_s(); long hb_s=(long)(d->hb_interval_ms/1000); if(hb_s<5)hb_s=5; /* gateway must ack heartbeats; 2 missed intervals means it's gone */ if(d->sent_hb && now-d->last_ack > hb_s*2+15){ diff --git a/orbisrpc/log.c b/orbisrpc/log.c index 455da69..a1ed290 100644 --- a/orbisrpc/log.c +++ b/orbisrpc/log.c @@ -15,6 +15,8 @@ static FILE *g_log = NULL; static int g_klog = -1; static volatile int g_log_lock = 0; +static volatile int g_debug = 0; +void log_set_debug(int on){ g_debug = on ? 1 : 0; } static void log_lock(void){ while(__sync_lock_test_and_set(&g_log_lock, 1)) usleep(1000); } static void log_unlock(void){ __sync_lock_release(&g_log_lock); } @@ -92,3 +94,24 @@ void log_close(void) { g_log = NULL; if (g_klog >= 0) { close(g_klog); g_klog = -1; } } + +void log_dbg(const char *fmt, ...) { + if (!g_debug || !fmt) return; + log_lock(); + if (!g_log) { g_log = stderr; } + va_list ap; + va_start(ap, fmt); + time_t t = time(NULL); + struct tm tmv; struct tm *tm = NULL; + extern struct tm *gmtime_r(const time_t *, struct tm *); + tm = gmtime_r(&t, &tmv); + char ts[20]; + if(tm) strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S", tm); + else { strncpy(ts, "1970-01-01 00:00:00", sizeof ts); ts[sizeof ts-1]=0; } + fprintf(g_log, "[%s] DBG ", ts); + vfprintf(g_log, fmt, ap); + fprintf(g_log, "\n"); + fflush(g_log); + va_end(ap); + log_unlock(); +} diff --git a/orbisrpc/log.h b/orbisrpc/log.h index 4b11b23..b22fc6e 100644 --- a/orbisrpc/log.h +++ b/orbisrpc/log.h @@ -5,5 +5,9 @@ /* Selects the first writable log path, falling back to stderr if needed. */ void log_init(const char *path); void log_msg(const char *fmt, ...); +/* Debug logging: compiled in, emitted only when log_set_debug(1) is on. + * Zero overhead otherwise. For per-poll detail — never for secrets. */ +void log_set_debug(int on); +void log_dbg(const char *fmt, ...); void log_close(void); #endif \ No newline at end of file diff --git a/orbisrpc/tls.c b/orbisrpc/tls.c index ba6e373..9daaee6 100644 --- a/orbisrpc/tls.c +++ b/orbisrpc/tls.c @@ -13,6 +13,7 @@ */ #include "tls.h" #include "log.h" +#include "clock.h" #include #include #include @@ -135,7 +136,7 @@ tls_ctx_t *tls_start(int fd, const char *host){ log_msg("tls: handshake start"); { - int64_t dl = time(NULL) + 15; + int64_t dl = orbis_mono_s() + 15; extern int daemon_stop_requested(void) __attribute__((weak)); for(;;){ if(daemon_stop_requested && daemon_stop_requested()){ log_msg("tls: aborted (stop)"); goto fail; } @@ -146,7 +147,7 @@ tls_ctx_t *tls_start(int fd, const char *host){ log_msg("tls: handshake fail %d (mbedTLS 0x%08x)", rc, (unsigned)rc); goto fail; } - if(time(NULL) > dl){ log_msg("tls: handshake timeout"); goto fail; } + if(orbis_mono_s() > dl){ log_msg("tls: handshake timeout"); goto fail; } usleep(20000); } } @@ -176,7 +177,7 @@ int tls_write(tls_ctx_t *t, const void *buf, size_t len){ if(!t || (!buf && len)) return -1; const unsigned char *p = (const unsigned char *)buf; size_t done = 0; - int64_t dl = time(NULL) + 10; + int64_t dl = orbis_mono_s() + 10; while(done < len){ int r = mbedtls_ssl_write(&t->ssl, p + done, len - done); if(r > 0){ done += (size_t)r; continue; } @@ -184,7 +185,7 @@ int tls_write(tls_ctx_t *t, const void *buf, size_t len){ log_msg("tls: write fail %d", r); return -1; } - if(time(NULL) > dl){ log_msg("tls: write timeout"); return -1; } + if(orbis_mono_s() > dl){ log_msg("tls: write timeout"); return -1; } usleep(10000); } return (int)done; diff --git a/orbisrpc/tmdb.c b/orbisrpc/tmdb.c index fd4dc75..3205696 100644 --- a/orbisrpc/tmdb.c +++ b/orbisrpc/tmdb.c @@ -2,6 +2,7 @@ * Transport mirrors ws.c patterns (resolver pool, SNDTIMEO connect cap, * recv deadline). One attempt, no retries: failure falls through. */ #include "tmdb.h" +#include "clock.h" #include "tmdb_crypto.h" #include "log.h" #include @@ -78,11 +79,11 @@ static int http_get(const char *host, const char *path, path, host); if(rl <= 0 || rl >= (int)sizeof req){ sceNetSocketClose(fd); return -1; } int sent = 0; - int64_t dl = time(NULL) + TMDB_DEADLINE_S; + int64_t dl = orbis_mono_s() + TMDB_DEADLINE_S; while(sent < rl){ int r = sceNetSend(fd, req+sent, rl-sent, 0); if(r > 0){ sent += r; continue; } - if(time(NULL) > dl || r == 0){ sceNetSocketClose(fd); return -1; } + if(orbis_mono_s() > dl || r == 0){ sceNetSocketClose(fd); return -1; } } /* read headers then body; cap total */ char hb[2048]; @@ -113,7 +114,7 @@ static int http_get(const char *host, const char *path, body[bl++] = tmp[off++]; } if(bl >= cap - 1) break; - if(time(NULL) > dl) break; + if(orbis_mono_s() > dl) break; } sceNetSocketClose(fd); body[bl] = 0; diff --git a/orbisrpc/updater.c b/orbisrpc/updater.c index e9aa859..f6eb927 100644 --- a/orbisrpc/updater.c +++ b/orbisrpc/updater.c @@ -10,6 +10,7 @@ * injection. Never deletes, never writes unvalidated bytes. */ #include "updater.h" +#include "clock.h" #include "version.h" #include "jsonlite.h" #include "log.h" @@ -95,13 +96,13 @@ static char *https_get(const char *host, const char *path, size_t bl = 0, hl = 0; static char hb[2048]; int hdr_done = 0, status = 0; - int64_t dl = time(NULL) + UPD_DEADLINE_S + 20; + int64_t dl = orbis_mono_s() + UPD_DEADLINE_S + 20; for(;;){ char tmp[2048]; int r = tls_read(t, tmp, sizeof tmp); if(r < 0) break; if(r == 0){ - if(time(NULL) > dl) break; + if(orbis_mono_s() > dl) break; usleep(20000); continue; } @@ -121,7 +122,7 @@ static char *https_get(const char *host, const char *path, } else continue; } while(off < (size_t)r && bl < cap - 1) body[bl++] = tmp[off++]; - if(bl >= cap - 1 || time(NULL) > dl) break; + if(bl >= cap - 1 || orbis_mono_s() > dl) break; } tls_free(t); body[bl] = 0; diff --git a/orbisrpc/ws.c b/orbisrpc/ws.c index 5399142..e2d2ca8 100644 --- a/orbisrpc/ws.c +++ b/orbisrpc/ws.c @@ -5,6 +5,7 @@ * All client->server frames are masked per RFC 6455 5.3, control frames too. */ #include "ws.h" +#include "clock.h" #include "tls.h" #include "log.h" #include @@ -49,7 +50,7 @@ static int ws_send_all(ws_t *w, const unsigned char *data, size_t n){ static void next_mask(unsigned char mk[4]){ static uint32_t mk_seed; - if(!mk_seed) mk_seed = (uint32_t)time(NULL) ^ 0x9e3779b9u ^ (uint32_t)(uintptr_t)&mk_seed; + if(!mk_seed) mk_seed = (uint32_t)orbis_mono_s() ^ 0x9e3779b9u ^ (uint32_t)(uintptr_t)&mk_seed; mk_seed = mk_seed*1664525u + 1013904223u; mk[0]=(unsigned char)(mk_seed&0xff); mk[1]=(unsigned char)((mk_seed>>8)&0xff); mk[2]=(unsigned char)((mk_seed>>16)&0xff); mk[3]=(unsigned char)((mk_seed>>24)&0xff); @@ -141,7 +142,7 @@ int ws_connect(ws_t *w, const char *host, int port, const char *resource, const log_msg("hs request sent (%dB)", n); /* Read response headers; bytes past "\r\n\r\n" are the first websocket * frame (usually HELLO arriving early) and MUST be kept, not dropped. */ - char hdr[2048]; int hlen=0, rd; int64_t t0=time(NULL); + char hdr[2048]; int hlen=0, rd; int64_t t0=orbis_mono_s(); int header_end = -1; extern int daemon_stop_requested(void) __attribute__((weak)); while(hlen<(int)sizeof hdr-1){ @@ -159,7 +160,7 @@ int ws_connect(ws_t *w, const char *host, int port, const char *resource, const continue; } if(rd==0){ - if(time(NULL)-t0 > 10){ log_msg("hs timeout (got %dB)", hlen); goto fail; } + if(orbis_mono_s()-t0 > 10){ log_msg("hs timeout (got %dB)", hlen); goto fail; } usleep(20000); continue; } goto fail;