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