diff --git a/installer/installer.c b/installer/installer.c index ea396c0..6343af3 100644 --- a/installer/installer.c +++ b/installer/installer.c @@ -166,8 +166,22 @@ static void step_inject(void){ ui_progress_msg("Starting orbisRPC..."); ui_progress_set(0); if(send_file_loopback(DAEMON_ELF, &port, ui_progress_set) == 0){ + /* Prove it booted: the daemon writes its log within seconds. + * No growth after ~25 s = sent but not running (say so). */ + long lsz = file_mtime("/data/orbisRPC/log.txt"); + int waited = 0; + int alive = 0; + ui_progress_msg("Waiting for first heartbeat..."); + while(waited < 25){ + sleep(2); + waited += 2; + if(file_mtime("/data/orbisRPC/log.txt") != lsz){ alive = 1; break; } + } ui_progress_close(); - snprintf(msg, sizeof msg, "orbisRPC is running (loader port %d).\n\nLaunch a game and watch Discord.", port); + if(alive) + snprintf(msg, sizeof msg, "orbisRPC is running (loader port %d).\n\nLaunch a game and watch Discord.", port); + else + snprintf(msg, sizeof msg, "Sent via port %d but no heartbeat yet.\n\nGive it a minute; if Discord stays dark, relaunch this app.", port); ui_ok(msg); } else { ui_progress_close(); diff --git a/installer/nettest.c b/installer/nettest.c index e8502a4..4b1fd45 100644 --- a/installer/nettest.c +++ b/installer/nettest.c @@ -6,11 +6,17 @@ #include #include #include +#include +#include #include #include #include #include #include +#include + +/* Non-blocking connect with a hard deadline lives in send.c (shared); + * blocking connect ignores SNDTIMEO on filtered hosts (75 s hole). */ int net_probe(const char *host, int port, int timeout_s){ struct addrinfo hints, *res = NULL, *rp; @@ -27,13 +33,8 @@ int net_probe(const char *host, int port, int timeout_s){ if(getaddrinfo(host, svc, &hints, &res) != 0 || !res) return 0; for(rp = res; rp; rp = rp->ai_next){ int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - struct timeval tv; if(fd < 0) continue; - tv.tv_sec = timeout_s; - tv.tv_usec = 0; - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); - if(connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) ok = 1; + if(sock_connect_deadline(fd, rp->ai_addr, rp->ai_addrlen, timeout_s) == 0) ok = 1; close(fd); if(ok) break; } diff --git a/installer/sce_sys/icon0.png b/installer/sce_sys/icon0.png index 98514b2..3db6651 100644 Binary files a/installer/sce_sys/icon0.png and b/installer/sce_sys/icon0.png differ diff --git a/installer/sce_sys/pic1.png b/installer/sce_sys/pic1.png index b04ab49..b9b49f3 100644 Binary files a/installer/sce_sys/pic1.png and b/installer/sce_sys/pic1.png differ diff --git a/installer/send.c b/installer/send.c index 2dd0c4b..8da5ef5 100644 --- a/installer/send.c +++ b/installer/send.c @@ -10,6 +10,7 @@ #include #include #include +#include #ifdef INSTALLER_PS4 #include #endif @@ -34,6 +35,36 @@ int net_init(void){ return 0; } +int sock_connect_deadline(int fd, const struct sockaddr *sa, socklen_t len, int timeout_s){ + int flags, rc, err = 0; + socklen_t elen = sizeof err; + fd_set wf; + struct timeval tv; + if(timeout_s < 1) timeout_s = 1; + if(timeout_s > 15) timeout_s = 15; + flags = fcntl(fd, F_GETFL, 0); + if(flags < 0) return -1; + if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) return -1; + rc = connect(fd, sa, len); + if(rc == 0){ + fcntl(fd, F_SETFL, flags); + return 0; + } + if(errno != EINPROGRESS){ + fcntl(fd, F_SETFL, flags); + return -1; + } + FD_ZERO(&wf); + FD_SET(fd, &wf); + tv.tv_sec = timeout_s; + tv.tv_usec = 0; + rc = select(fd + 1, NULL, &wf, NULL, &tv); + fcntl(fd, F_SETFL, flags); + if(rc <= 0) return -1; + if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &elen) != 0) return -1; + return err == 0 ? 0 : -1; +} + static int send_one(int fd, const char *path, void (*progress)(unsigned)){ FILE *f = fopen(path, "rb"); unsigned char buf[SEND_CHUNK]; @@ -77,15 +108,12 @@ int send_file_loopback(const char *path, int *port_used, void (*progress)(unsign for(i = 0; i < sizeof SEND_PORTS/sizeof SEND_PORTS[0]; i++){ int fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in sa; - struct timeval tv = { 5, 0 }; if(fd < 0) continue; - setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); - setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); memset(&sa, 0, sizeof sa); sa.sin_family = AF_INET; sa.sin_port = htons((uint16_t)SEND_PORTS[i]); sa.sin_addr.s_addr = inet_addr("127.0.0.1"); - if(connect(fd, (struct sockaddr *)&sa, sizeof sa) < 0){ + if(sock_connect_deadline(fd, (struct sockaddr *)&sa, sizeof sa, 5) < 0){ close(fd); continue; } diff --git a/installer/send.h b/installer/send.h index fa3abf4..df95af7 100644 --- a/installer/send.h +++ b/installer/send.h @@ -3,10 +3,15 @@ * 9020 is one-shot: accepted bytes count as sent. */ #ifndef INSTALLER_SEND_H #define INSTALLER_SEND_H +#include /* progress(pct) may be NULL. Returns 0 + port_used set on success. */ int send_file_loopback(const char *path, int *port_used, void (*progress)(unsigned pct)); +/* Non-blocking connect with a hard deadline (filtered hosts can't stall + * past timeout_s). 0 connected, -1 failed. Leaves fd blocking. */ +int sock_connect_deadline(int fd, const struct sockaddr *sa, socklen_t len, int timeout_s); + /* One-time network stack init (sceNetInit + pool). 0 ready, -1 dead. * No-op returning 0 on host test builds. Safe to call repeatedly. */ int net_init(void); diff --git a/tests/test_utils_asan b/tests/test_utils_asan deleted file mode 100755 index dd07bfb..0000000 Binary files a/tests/test_utils_asan and /dev/null differ