juegos

Juegos de terminal de Pancho: Catan (TUI, GUI, web, servidor, PicoCalc), ajedrez, calculadora y minijuegos
git clone https://git.lu3dhn.xyz/juegos.git
Log | Files | Refs

netline.c (5308B)


      1 /* netline.c - conexion TCP de lineas de texto. */
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 #include <string.h>
      5 #include <sys/stat.h>
      6 #include "plat.h"
      7 #include "netline.h"
      8 #include "paths.h"
      9 
     10 int lc_dial(const char *host, int port, char *err, int errlen)
     11 {
     12     sock_init();
     13     char ps[16];
     14     snprintf(ps, sizeof ps, "%d", port);
     15     struct addrinfo hints, *res, *ai;
     16     memset(&hints, 0, sizeof hints);
     17     hints.ai_socktype = SOCK_STREAM;
     18     int r = getaddrinfo(host, ps, &hints, &res);
     19     if (r) { snprintf(err, (size_t)errlen, "%s: %s", host, gai_strerror(r)); return -1; }
     20     int fd = -1;
     21     for (ai = res; ai; ai = ai->ai_next) {
     22         fd = (int)socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     23         if (fd < 0) continue;
     24         sock_nonblock(fd, 1);
     25         r = connect(fd, ai->ai_addr, (socklen_t)ai->ai_addrlen);
     26         int e = r < 0 ? sock_err() : 0;
     27         if (r < 0 && sock_pending(e)) {
     28             struct pollfd p = { fd, POLLOUT, 0 };
     29             int soerr = 0;
     30             socklen_t sl = sizeof soerr;
     31             if (poll(&p, 1, 4000) == 1 && getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&soerr, &sl) == 0 && soerr == 0) r = 0;
     32             else e = soerr ? soerr : SOCK_ETIMEDOUT;
     33         }
     34         if (r == 0) { sock_nonblock(fd, 0); break; }
     35         snprintf(err, (size_t)errlen, "%s:%d: %s", host, port, sock_strerror(e));
     36         sock_close(fd);
     37         fd = -1;
     38     }
     39     freeaddrinfo(res);
     40     return fd;
     41 }
     42 
     43 void lc_init(LineConn *c, int fd)
     44 {
     45     c->fd = fd;
     46     c->inlen = 0;
     47     c->last_tx = now_ms();
     48 }
     49 
     50 bool lc_send(LineConn *c, const char *fmt, ...)
     51 {
     52     if (c->fd < 0) return false;
     53     char buf[LC_LINE + 8];
     54     va_list ap;
     55     va_start(ap, fmt);
     56     int len = vsnprintf(buf, sizeof buf - 1, fmt, ap);
     57     va_end(ap);
     58     if (len < 0 || len > LC_LINE - 2) return false;
     59     buf[len++] = '\n';
     60     int off = 0;
     61     while (off < len) {
     62         ssize_t w = send(c->fd, buf + off, len - off, MSG_NOSIGNAL);
     63         if (w <= 0) { sock_close(c->fd); c->fd = -1; return false; }
     64         off += (int)w;
     65     }
     66     c->last_tx = now_ms();
     67     return true;
     68 }
     69 
     70 bool lc_take(LineConn *c, char *line, int len)
     71 {
     72     char *nl = memchr(c->in, '\n', (size_t)c->inlen);
     73     if (!nl) return false;
     74     int l = (int)(nl - c->in);
     75     int k = l < len - 1 ? l : len - 1;
     76     memcpy(line, c->in, (size_t)k);
     77     line[k] = 0;
     78     if (k && line[k - 1] == '\r') line[k - 1] = 0;
     79     c->inlen -= l + 1;
     80     memmove(c->in, nl + 1, (size_t)c->inlen);
     81     return true;
     82 }
     83 
     84 static bool fill(LineConn *c, int timeout_ms)
     85 {
     86     if (c->fd < 0) return false;
     87     struct pollfd p = { c->fd, POLLIN, 0 };
     88     int r;
     89     if (c->idle) {
     90         long long end = now_ms() + timeout_ms;
     91         do {
     92             c->idle(c->idle_ctx);
     93             r = poll(&p, 1, 5);
     94         } while (r == 0 && now_ms() < end);
     95     } else r = poll(&p, 1, timeout_ms);
     96     if (r <= 0) return r == 0;
     97     if ((size_t)c->inlen >= sizeof c->in - 1) return false;
     98     ssize_t got = recv(c->fd, c->in + c->inlen, (int)(sizeof c->in - 1 - (size_t)c->inlen), 0);
     99     if (got <= 0) { sock_close(c->fd); c->fd = -1; return false; }
    100     c->inlen += (int)got;
    101     return true;
    102 }
    103 
    104 bool lc_read_line(LineConn *c, char *line, int len, int timeout_ms)
    105 {
    106     long long end = now_ms() + timeout_ms;
    107     for (;;) {
    108         if (lc_take(c, line, len)) return true;
    109         long long left = end - now_ms();
    110         if (left <= 0 || c->fd < 0) return false;
    111         if (!fill(c, (int)left) && c->fd < 0) return false;
    112     }
    113 }
    114 
    115 bool lc_pump(LineConn *c)
    116 {
    117     struct pollfd p = { c->fd, POLLIN, 0 };
    118     while (c->fd >= 0 && poll(&p, 1, 0) > 0) {
    119         if ((size_t)c->inlen >= sizeof c->in - 1) break;
    120         ssize_t got = recv(c->fd, c->in + c->inlen, (int)(sizeof c->in - 1 - (size_t)c->inlen), 0);
    121         if (got <= 0) {
    122             sock_close(c->fd);
    123             c->fd = -1;
    124             return false;
    125         }
    126         c->inlen += (int)got;
    127     }
    128     return c->fd >= 0;
    129 }
    130 
    131 void lc_close(LineConn *c)
    132 {
    133     if (c->fd >= 0) sock_close(c->fd);
    134     c->fd = -1;
    135 }
    136 
    137 /* ------------------------------------------------------------ tokens */
    138 
    139 static void saved_path(char *out, size_t n) { snprintf(out, n, "%s/online", data_dir()); }
    140 
    141 int saved_games(const char *server, SavedGame *out, int max)
    142 {
    143     char path[600], line[400];
    144     saved_path(path, sizeof path);
    145     FILE *f = fopen(path, "r");
    146     if (!f) return 0;
    147     int k = 0;
    148     while (k < max && fgets(line, sizeof line, f)) {
    149         SavedGame g;
    150         if (sscanf(line, "%127s %7s %d %32s", g.server, g.code, &g.seat, g.token) != 4) continue;
    151         if (strcmp(g.server, server)) continue;
    152         bool dup = false;
    153         for (int i = 0; i < k; i++) if (!strcmp(out[i].code, g.code)) { out[i] = g; dup = true; }
    154         if (!dup) out[k++] = g;
    155     }
    156     fclose(f);
    157     return k;
    158 }
    159 
    160 void saved_game_add(const char *server, const char *code, int seat, const char *token)
    161 {
    162     SavedGame tmp[256];
    163     int n = saved_games(server, tmp, 256);
    164     for (int i = 0; i < n; i++) if (!strcmp(tmp[i].code, code) && !strcmp(tmp[i].token, token)) return;
    165     char path[600];
    166     saved_path(path, sizeof path);
    167     FILE *f = fopen(path, "a");
    168     if (!f) return;
    169     fchmod(fileno(f), 0600);
    170     fprintf(f, "%s %s %d %s\n", server, code, seat, token);
    171     fclose(f);
    172     paths_flush();
    173 }