"Fossies" - the Fresh Open Source Software Archive 
Member "libcaca-0.99.beta20/src/cacaserver.c" (19 Oct 2021, 16596 Bytes) of package /linux/privat/libcaca-0.99.beta20.tar.bz2:
1 /*
2 * cacaserver Colour ASCII-Art library
3 * Copyright © 2006-2021 Sam Hocevar <sam@hocevar.net>
4 * 2016 Denis Fondras <ledeuns at github>
5 * 2006 Jean-Yves Lamoureux <jylam@lnxscene.org>
6 * All Rights Reserved
7 *
8 * This program is free software. It comes without any warranty, to
9 * the extent permitted by applicable law. You can redistribute it
10 * and/or modify it under the terms of the Do What the Fuck You Want
11 * to Public License, Version 2, as published by Sam Hocevar. See
12 * http://www.wtfpl.net/ for more details.
13 */
14
15 #include "config.h"
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #if defined(HAVE_ARPA_INET_H)
21 # include <arpa/inet.h>
22 #elif defined(HAVE_WINSOCK2_H)
23 # include <winsock2.h>
24 # include <ws2tcpip.h>
25 # define USE_WINSOCK 1
26 #endif
27 #if defined(HAVE_NETINET_IN_H)
28 # include <netinet/in.h>
29 #endif
30 #if defined(HAVE_UNISTD_H)
31 # include <unistd.h>
32 #endif
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netdb.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <errno.h>
39 #include <stdarg.h>
40
41 #ifndef USE_WINSOCK
42 # define USE_WINSOCK 0
43 #endif
44
45 #include "caca.h"
46
47 #define BACKLOG 1337 /* Number of pending connections */
48 #define INBUFFER 32 /* Size of per-client input buffer */
49 #define OUTBUFFER 300000 /* Size of per-client output buffer */
50
51 /* Following vars are static */
52 #define INIT_PREFIX \
53 "\xff\xfb\x01" /* WILL ECHO */ \
54 "\xff\xfb\x03" /* WILL SUPPRESS GO AHEAD */ \
55 "\xff\xfd\x31" /* DO NAWS */ \
56 "\xff\x1f\xfa____" /* SB NAWS */ \
57 "\xff\xf0" /* SE */ \
58 "\033]2;caca for the network\x07" /* Change window title */ \
59 "\033[H\033[J" /* Clear screen */
60 /*"\033[?25l"*/ /* Hide cursor */
61
62 #define ANSI_PREFIX \
63 "\033[1;1H" /* move(0,0) */ \
64 "\033[1;1H" /* move(0,0) again */
65
66 #define ANSI_RESET \
67 " " /* Garbage */ \
68 "\033[?1049h" /* Clear screen */ \
69 "\033[?1049h" /* Clear screen again */
70
71 static char const telnet_commands[16][5] =
72 {
73 "SE ", "NOP ", "DM ", "BRK ", "IP ", "AO ", "AYT ", "EC ",
74 "EL ", "GA ", "SB ", "WILL", "WONT", "DO ", "DONT", "IAC "
75 };
76
77 static char const telnet_options[37][5] =
78 {
79 "????", "ECHO", "????", "SUGH", "????", "STTS", "TIMK", "????",
80 "????", "????", "????", "????", "????", "????", "????", "????",
81 "????", "????", "????", "????", "????", "????", "????", "????",
82 "TTYP", "????", "????", "????", "????", "????", "????", "NAWS",
83 "TRSP", "RMFC", "LIMO", "????", "EVAR"
84 };
85
86 #define COMMAND_NAME(x) (x>=240)?telnet_commands[x-240]:"????"
87 #define OPTION_NAME(x) (x<=36)?telnet_options[x]:"????"
88
89 struct client
90 {
91 int fd;
92 int ready;
93 uint8_t inbuf[INBUFFER];
94 int inbytes;
95 uint8_t outbuf[OUTBUFFER];
96 int start, stop;
97 };
98
99 #define MAXSOCKS 16
100
101 struct sock {
102 int sockfd;
103 struct sockaddr_in my_addr;
104 };
105
106 struct server
107 {
108 unsigned int width, height;
109 unsigned int port;
110 int sock_count;
111 struct sock socks[MAXSOCKS];
112
113 /* Input buffer */
114 uint8_t *input;
115 unsigned int read;
116
117 char prefix[sizeof(INIT_PREFIX)];
118
119 caca_canvas_t *canvas;
120 void *buffer;
121 size_t buflen;
122
123 int client_count;
124 struct client *clients;
125
126 void (*sigpipe_handler)(int);
127 };
128
129 void fprint_ip(FILE *stream, struct sockaddr *ai);
130 static void manage_connections(struct server *server, int sockfd);
131 static int send_data(struct server *server, struct client *c);
132 ssize_t nonblock_write(int fd, void *buf, size_t len);
133
134 int main(void)
135 {
136 int i, yes = 1, flags, fd, error;
137 struct server *server;
138 struct addrinfo ai_hints, *ai, *res;
139 char port_str[6];
140 char *tmp;
141
142 #if USE_WINSOCK
143 WORD winsockVersion;
144 WSADATA wsaData;
145 winsockVersion = MAKEWORD(1, 1);
146
147 WSAStartup(winsockVersion, &wsaData);
148 #endif
149 server = malloc(sizeof(struct server));
150
151 server->input = malloc(12);
152 server->read = 0;
153
154 server->client_count = 0;
155 server->clients = NULL;
156 server->port = 0xCACA; /* 51914 */
157
158 /* FIXME, handle >255 sizes */
159 memcpy(server->prefix, INIT_PREFIX, sizeof(INIT_PREFIX));
160 tmp = strstr(server->prefix, "____");
161 tmp[0] = (uint8_t) (server->width & 0xff00) >> 8;
162 tmp[1] = (uint8_t) server->width & 0xff;
163 tmp[2] = (uint8_t) (server->height & 0xff00) >> 8;
164 tmp[3] = (uint8_t) server->height & 0xff;
165
166 memset(&ai_hints, 0, sizeof(ai_hints));
167 ai_hints.ai_family = AF_UNSPEC;
168 ai_hints.ai_socktype = SOCK_STREAM;
169 ai_hints.ai_flags = AI_PASSIVE;
170 memset(port_str, 0, sizeof(port_str));
171 snprintf(port_str, 6, "%d", server->port);
172 error = getaddrinfo(NULL, port_str, &ai_hints, &ai);
173 if (error)
174 {
175 perror("getaddrinfo");
176 return -1;
177 }
178
179 for (res = ai; res && server->sock_count < MAXSOCKS; res = res->ai_next)
180 {
181 if ((fd = socket(res->ai_addr->sa_family, SOCK_STREAM, 0)) == -1)
182 {
183 perror("socket");
184 continue;
185 }
186 if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
187 {
188 perror("setsockopt: SO_REUSEADDR");
189 continue;
190 }
191 if (res->ai_addr->sa_family == AF_INET6)
192 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) == -1)
193 {
194 perror("setsockopt: IPV6_V6ONLY");
195 continue;
196 }
197 if (bind(fd, res->ai_addr, res->ai_addrlen) == -1)
198 {
199 perror("bind");
200 continue;
201 }
202 flags = fcntl(fd, F_GETFL, 0);
203 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
204 if(listen(fd, BACKLOG) == -1)
205 {
206 perror("listen");
207 continue;
208 }
209
210 server->socks[server->sock_count].sockfd = fd;
211 server->sock_count++;
212 fprintf(stderr, "listening on ");
213 fprint_ip(stderr, res->ai_addr);
214 fprintf(stderr, "\n");
215 }
216 freeaddrinfo(ai);
217
218 if (server->sock_count == 0)
219 {
220 fprintf(stderr, "Not listening\n");
221 return -1;
222 }
223
224 server->canvas = caca_create_canvas(0, 0);
225 server->buffer = NULL;
226
227 /* Ignore SIGPIPE */
228 server->sigpipe_handler = signal(SIGPIPE, SIG_IGN);
229
230 fprintf(stderr, "initialised network, listening on port %i\n",
231 server->port);
232
233 /* Main loop */
234 for(;;)
235 {
236 restart:
237 /* Manage new connections as this function will be called sometimes
238 * more often than display */
239 for (i = 0; i < server->sock_count; i++)
240 manage_connections(server, server->socks[i].sockfd);
241
242 /* Read data from stdin */
243 if(server->read < 12)
244 {
245 read(0, server->input + server->read, 12 - server->read);
246 server->read = 12;
247 }
248
249 while(caca_import_canvas_from_memory(server->canvas, server->input,
250 server->read, "caca") < 0)
251 {
252 memmove(server->input, server->input + 1, server->read - 1);
253 read(0, server->input + server->read - 1, 1);
254 }
255
256 for(;;)
257 {
258 ssize_t needed, wanted;
259
260 needed = caca_import_canvas_from_memory(server->canvas,
261 server->input,
262 server->read, "caca");
263 if(needed < 0)
264 goto restart;
265
266 if(needed > 0)
267 {
268 server->read -= needed;
269 memmove(server->input, server->input + needed, server->read);
270 break;
271 }
272
273 server->input = realloc(server->input, server->read + 128);
274 wanted = read(0, server->input + server->read, 128);
275 if(wanted < 0)
276 goto restart;
277 server->read += wanted;
278 }
279
280 /* Free the previous export buffer, if any */
281 if(server->buffer)
282 {
283 free(server->buffer);
284 server->buffer = NULL;
285 }
286
287 /* Get ANSI representation of the image and skip the end-of buffer
288 * linefeed ("\r\n", 2 byte) */
289 server->buffer = caca_export_canvas_to_memory(server->canvas, "utf8cr",
290 &server->buflen);
291 server->buflen -= 2;
292
293 for(i = 0; i < server->client_count; i++)
294 {
295 if(server->clients[i].fd == -1)
296 continue;
297
298 if(send_data(server, &server->clients[i]))
299 {
300 fprintf(stderr, "[%i] dropped connection\n",
301 server->clients[i].fd);
302 close(server->clients[i].fd);
303 server->clients[i].fd = -1;
304 }
305 }
306 }
307
308 /* Kill all remaining clients */
309 for(i = 0; i < server->client_count; i++)
310 {
311 if(server->clients[i].fd == -1)
312 continue;
313
314 close(server->clients[i].fd);
315 server->clients[i].fd = -1;
316 }
317
318 if(server->buffer)
319 free(server->buffer);
320
321 caca_free_canvas(server->canvas);
322
323 /* Restore SIGPIPE handler */
324 signal(SIGPIPE, server->sigpipe_handler);
325
326 for (i = 0; i < server->sock_count; i++)
327 close(server->socks[i].sockfd);
328
329 free(server);
330
331 #if USE_WINSOCK
332 WSACleanup();
333 #endif
334 return 0;
335 }
336
337 /*
338 * XXX: The following functions are local
339 */
340
341 void fprint_ip(FILE *stream, struct sockaddr *ai)
342 {
343 char buffer[INET6_ADDRSTRLEN];
344 socklen_t len = sizeof(struct sockaddr_in6);
345
346 if (ai->sa_family == AF_INET)
347 len = sizeof(struct sockaddr_in);
348
349 int err = getnameinfo(ai, len, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST);
350 if (err != 0)
351 fprintf(stream, "n/a");
352 else
353 fprintf(stream, "%s", buffer);
354 }
355
356 static void manage_connections(struct server *server, int sockfd)
357 {
358 int fd, flags;
359 struct sockaddr_in6 remote_addr;
360 socklen_t len = sizeof(struct sockaddr_in6);
361
362 fd = accept(sockfd, (struct sockaddr*)&remote_addr, &len);
363 if(fd == -1)
364 return;
365
366 fprintf(stderr, "[%i] connected from ", fd);
367 fprint_ip(stderr, (struct sockaddr*)&remote_addr);
368 fprintf(stderr, "\n");
369
370 /* Non blocking socket */
371 flags = fcntl(fd, F_SETFL, 0);
372 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
373
374 if(server->clients == NULL)
375 {
376 server->clients = malloc(sizeof(struct client));
377 if(server->clients == NULL)
378 {
379 close(fd);
380 return;
381 }
382 }
383 else
384 {
385 server->clients = realloc(server->clients,
386 (server->client_count+1) * sizeof(struct client));
387 }
388
389 server->clients[server->client_count].fd = fd;
390 server->clients[server->client_count].ready = 0;
391 server->clients[server->client_count].inbytes = 0;
392 server->clients[server->client_count].start = 0;
393 server->clients[server->client_count].stop = 0;
394
395 /* If we already have data to send, send it to the new client */
396 if(send_data(server, &server->clients[server->client_count]))
397 {
398 fprintf(stderr, "[%i] dropped connection\n", fd);
399 close(fd);
400 server->clients[server->client_count].fd = -1;
401 return;
402 }
403
404 server->client_count++;
405 }
406
407 static int send_data(struct server *server, struct client *c)
408 {
409 ssize_t ret;
410
411 /* Not for us */
412 if(c->fd < 0)
413 return -1;
414
415 /* Listen to incoming data */
416 for(;;)
417 {
418 ret = read(c->fd, c->inbuf + c->inbytes, 1);
419 if(ret <= 0)
420 break;
421
422 c->inbytes++;
423
424 /* Check for telnet sequences */
425 if(c->inbuf[0] == 0xff)
426 {
427 if(c->inbytes == 1)
428 {
429 ;
430 }
431 else if(c->inbuf[1] == 0xfd || c->inbuf[1] == 0xfc)
432 {
433 if(c->inbytes == 3)
434 {
435 fprintf(stderr, "[%i] said: %.02x %.02x %.02x (%s %s %s)\n",
436 c->fd, c->inbuf[0], c->inbuf[1], c->inbuf[2],
437 COMMAND_NAME(c->inbuf[0]), COMMAND_NAME(c->inbuf[1]), OPTION_NAME(c->inbuf[2]));
438 /* Just ignore, lol */
439 c->inbytes = 0;
440 }
441 }
442 else
443 c->inbytes = 0;
444 }
445 else if(c->inbytes == 1)
446 {
447 if(c->inbuf[0] == 0x03)
448 {
449 fprintf(stderr, "[%i] pressed C-c\n", c->fd);
450 return -1; /* User requested to quit */
451 }
452
453 c->inbytes = 0;
454 }
455 }
456
457 /* Send the telnet initialisation commands */
458 if(!c->ready)
459 {
460 ret = nonblock_write(c->fd, server->prefix, sizeof(INIT_PREFIX));
461 if(ret == -1)
462 return (errno == EAGAIN) ? 0 : -1;
463
464 if(ret < (ssize_t)sizeof(INIT_PREFIX))
465 return 0;
466
467 c->ready = 1;
468 }
469
470 /* No error, there's just nothing to send yet */
471 if(!server->buffer)
472 return 0;
473
474 /* If we have backlog, send the backlog */
475 if(c->stop)
476 {
477 ret = nonblock_write(c->fd, c->outbuf + c->start, c->stop - c->start);
478
479 if(ret == -1)
480 {
481 if(errno == EAGAIN)
482 ret = 0;
483 else
484 {
485 fprintf(stderr, "[%i] failed (%s)\n",
486 c->fd, strerror(errno));
487 return -1;
488 }
489 }
490
491 if(ret == c->stop - c->start)
492 {
493 /* We got rid of the backlog! */
494 c->start = c->stop = 0;
495 }
496 else
497 {
498 c->start += ret;
499
500 if(c->stop - c->start + strlen(ANSI_PREFIX) + server->buflen
501 > OUTBUFFER)
502 {
503 /* Overflow! Empty buffer and start again */
504 memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
505 c->start = 0;
506 c->stop = strlen(ANSI_RESET);
507 return 0;
508 }
509
510 /* Need to move? */
511 if(c->stop + strlen(ANSI_PREFIX) + server->buflen > OUTBUFFER)
512 {
513 memmove(c->outbuf, c->outbuf + c->start, c->stop - c->start);
514 c->stop -= c->start;
515 c->start = 0;
516 }
517
518 memcpy(c->outbuf + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX));
519 c->stop += strlen(ANSI_PREFIX);
520 memcpy(c->outbuf + c->stop, server->buffer, server->buflen);
521 c->stop += server->buflen;
522
523 return 0;
524 }
525 }
526
527 /* We no longer have backlog, send our new data */
528
529 /* Send ANSI prefix */
530 ret = nonblock_write(c->fd, ANSI_PREFIX, strlen(ANSI_PREFIX));
531 if(ret == -1)
532 {
533 if(errno == EAGAIN)
534 ret = 0;
535 else
536 {
537 fprintf(stderr, "[%i] failed (%s)\n", c->fd, strerror(errno));
538 return -1;
539 }
540 }
541
542 if(ret < (ssize_t)strlen(ANSI_PREFIX))
543 {
544 if(strlen(ANSI_PREFIX) + server->buflen > OUTBUFFER)
545 {
546 /* Overflow! Empty buffer and start again */
547 memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
548 c->start = 0;
549 c->stop = strlen(ANSI_RESET);
550 return 0;
551 }
552
553 memcpy(c->outbuf, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret);
554 c->stop = strlen(ANSI_PREFIX) - ret;
555 memcpy(c->outbuf + c->stop, server->buffer, server->buflen);
556 c->stop += server->buflen;
557
558 return 0;
559 }
560
561 /* Send actual data */
562 ret = nonblock_write(c->fd, server->buffer, server->buflen);
563 if(ret == -1)
564 {
565 if(errno == EAGAIN)
566 ret = 0;
567 else
568 {
569 fprintf(stderr, "[%i] failed (%s)\n", c->fd, strerror(errno));
570 return -1;
571 }
572 }
573
574 if(ret < (int)server->buflen)
575 {
576 if(server->buflen > OUTBUFFER)
577 {
578 /* Overflow! Empty buffer and start again */
579 memcpy(c->outbuf, ANSI_RESET, strlen(ANSI_RESET));
580 c->start = 0;
581 c->stop = strlen(ANSI_RESET);
582 return 0;
583 }
584
585 memcpy(c->outbuf, server->buffer, server->buflen - ret);
586 c->stop = server->buflen - ret;
587
588 return 0;
589 }
590
591 return 0;
592 }
593
594 ssize_t nonblock_write(int fd, void *buf, size_t len)
595 {
596 size_t total = 0;
597 ssize_t ret;
598
599 while(total < len)
600 {
601 do
602 {
603 ret = write(fd, buf, len);
604 }
605 while(ret < 0 && errno == EINTR);
606
607 if(ret < 0)
608 return ret;
609 else if(ret == 0)
610 return total;
611
612 total += len;
613 buf = (void *)((uintptr_t)buf + len);
614 }
615
616 return total;
617 }
618