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 }