Changeset 703 for libcaca/trunk/src/cacaserver.c
- Timestamp:
- Mar 27, 2006, 11:37:52 PM (15 years ago)
- Location:
- libcaca/trunk/src
- Files:
-
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
libcaca/trunk/src
- Property svn:ignore
-
old new 9 9 cacaplas 10 10 cacaplay 11 cacaserver 11 12 *.exe
-
- Property svn:ignore
-
libcaca/trunk/src/cacaserver.c
r698 r703 1 1 /* 2 * libcaca Colour ASCII-Art library 3 * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org> 2 * cacaserver Colour ASCII-Art library 3 * Copyright (c) 2006 Jean-Yves Lamoureux <jylam@lnxscene.org> 4 * 2006 Sam Hocevar <sam@zoy.org> 4 5 * All Rights Reserved 5 6 * 6 * This libraryis free software; you can redistribute it and/or7 * This program is free software; you can redistribute it and/or 7 8 * modify it under the terms of the Do What The Fuck You Want To 8 9 * Public License, Version 2, as published by Sam Hocevar. See … … 10 11 */ 11 12 12 /** \file driver_network.c13 * \version \$Id$14 * \author Jean-Yves Lamoureux <jylam@lnxscene.org>15 * \brief Network driver16 *17 * This file contains the libcaca network input and output driver18 */19 20 13 #include "config.h" 21 14 22 #if defined(USE_NETWORK)23 15 #include <stdio.h> 16 #include <string.h> 24 17 #include <stdlib.h> 25 18 #include <sys/types.h> … … 27 20 #include <arpa/inet.h> 28 21 #include <fcntl.h> 29 #include <string.h>30 22 #include <signal.h> 31 23 #include <errno.h> 24 25 #include "cucul.h" 26 #include "caca.h" 27 28 #include "config.h" 32 29 33 30 #if defined(HAVE_UNISTD_H) 34 31 # include <unistd.h> 35 32 #endif 33 36 34 #include <stdarg.h> 37 35 38 36 #include "caca.h" 39 #include "caca_internals.h"40 37 #include "cucul.h" 41 #include "cucul_internals.h"42 38 43 39 #define BACKLOG 1337 /* Number of pending connections */ … … 65 61 "\x1b[?1049h" /* Clear screen again */ 66 62 67 68 63 static char const telnet_commands[16][5] = 69 {"SE ", "NOP ", "DM ", "BRK ", "IP ", "AO ", "AYT ", "EC ", 70 "EL ", "GA ", "SB ", "WILL", "WONT", "DO ", "DONT", "IAC "}; 64 { 65 "SE ", "NOP ", "DM ", "BRK ", "IP ", "AO ", "AYT ", "EC ", 66 "EL ", "GA ", "SB ", "WILL", "WONT", "DO ", "DONT", "IAC " 67 }; 71 68 72 69 static char const telnet_options[37][5] = 73 {"????", "ECHO", "????", "SUGH", "????", "STTS", "TIMK", "????", "????", "????", 74 "????", "????", "????", "????", "????", "????", "????", "????", "????", "????", 75 "????", "????", "????", "????", "TTYP", "????", "????", "????", "????", "????", 76 "????", "NAWS", "TRSP", "RMFC", "LIMO", "????", "EVAR"}; 77 70 { 71 "????", "ECHO", "????", "SUGH", "????", "STTS", "TIMK", "????", 72 "????", "????", "????", "????", "????", "????", "????", "????", 73 "????", "????", "????", "????", "????", "????", "????", "????", 74 "TTYP", "????", "????", "????", "????", "????", "????", "NAWS", 75 "TRSP", "RMFC", "LIMO", "????", "EVAR" 76 }; 78 77 79 78 #define COMMAND_NAME(x) (x>=240)?telnet_commands[x-240]:"????" 80 79 #define OPTION_NAME(x) (x<=36)?telnet_options[x]:"????" 81 82 80 83 81 struct client … … 91 89 }; 92 90 93 struct driver_private91 struct server 94 92 { 95 93 unsigned int width, height; … … 99 97 socklen_t sin_size; 100 98 99 /* Input buffer */ 100 101 101 char prefix[sizeof(INIT_PREFIX)]; 102 102 … … 109 109 }; 110 110 111 static void manage_connections( caca_t *kk);112 static int send_data( caca_t *kk, struct client *c);111 static void manage_connections(struct server *server); 112 static int send_data(struct server *server, struct client *c); 113 113 ssize_t nonblock_write(int fd, void *buf, size_t len); 114 114 115 static int network_init_graphics(caca_t *kk)116 { 117 int yes = 1, flags;118 int port = 0xCACA; /* 51914 */119 unsigned int width = 0, height = 0;115 int main(void) 116 { 117 cucul_t *qq; 118 int i, yes = 1, flags; 119 struct server *server; 120 120 char *tmp; 121 121 122 kk->drv.p = malloc(sizeof(struct driver_private)); 123 if(kk->drv.p == NULL) 124 return -1; 125 126 #if defined(HAVE_GETENV) 127 tmp = getenv("CACA_PORT"); 128 if(tmp && *tmp) 129 { 130 int new_port = atoi(tmp); 131 if(new_port) 132 port = new_port; 133 } 134 135 tmp = getenv("CACA_GEOMETRY"); 136 if(tmp && *tmp) 137 sscanf(tmp, "%ux%u", &width, &height); 138 #endif 139 140 if(width && height) 141 { 142 kk->drv.p->width = width; 143 kk->drv.p->height = height; 144 } 145 else 146 { 147 kk->drv.p->width = 80; 148 kk->drv.p->height = 24; 149 } 150 151 kk->drv.p->client_count = 0; 152 kk->drv.p->clients = NULL; 153 kk->drv.p->port = port; 154 155 _cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height); 122 server = malloc(sizeof(struct server)); 123 124 server->client_count = 0; 125 server->clients = NULL; 126 server->port = 0xCACA; /* 51914 */ 156 127 157 128 /* FIXME, handle >255 sizes */ 158 memcpy( kk->drv.p->prefix, INIT_PREFIX, sizeof(INIT_PREFIX));159 tmp = strstr( kk->drv.p->prefix, "____");160 tmp[0] = (unsigned char) ( kk->drv.p->width & 0xff00) >> 8;161 tmp[1] = (unsigned char) kk->drv.p->width & 0xff;162 tmp[2] = (unsigned char) ( kk->drv.p->height & 0xff00) >> 8;163 tmp[3] = (unsigned char) kk->drv.p->height & 0xff;164 165 if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)129 memcpy(server->prefix, INIT_PREFIX, sizeof(INIT_PREFIX)); 130 tmp = strstr(server->prefix, "____"); 131 tmp[0] = (unsigned char) (server->width & 0xff00) >> 8; 132 tmp[1] = (unsigned char) server->width & 0xff; 133 tmp[2] = (unsigned char) (server->height & 0xff00) >> 8; 134 tmp[3] = (unsigned char) server->height & 0xff; 135 136 if((server->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 166 137 { 167 138 perror("socket"); … … 169 140 } 170 141 171 if (setsockopt(kk->drv.p->sockfd, SOL_SOCKET,172 142 if(setsockopt(server->sockfd, SOL_SOCKET, 143 SO_REUSEADDR, &yes, sizeof(int)) == -1) 173 144 { 174 145 perror("setsockopt SO_REUSEADDR"); … … 176 147 } 177 148 178 kk->drv.p->my_addr.sin_family = AF_INET;179 kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port);180 kk->drv.p->my_addr.sin_addr.s_addr = INADDR_ANY;181 memset(&( kk->drv.p->my_addr.sin_zero), '\0', 8);182 183 if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr,149 server->my_addr.sin_family = AF_INET; 150 server-> my_addr.sin_port = htons(server->port); 151 server->my_addr.sin_addr.s_addr = INADDR_ANY; 152 memset(&(server->my_addr.sin_zero), '\0', 8); 153 154 if(bind(server->sockfd, (struct sockaddr *)&server->my_addr, 184 155 sizeof(struct sockaddr)) == -1) 185 156 { … … 189 160 190 161 /* Non blocking socket */ 191 flags = fcntl( kk->drv.p->sockfd, F_GETFL, 0);192 fcntl( kk->drv.p->sockfd, F_SETFL, flags | O_NONBLOCK);193 194 if (listen(kk->drv.p->sockfd, BACKLOG) == -1)162 flags = fcntl(server->sockfd, F_GETFL, 0); 163 fcntl(server->sockfd, F_SETFL, flags | O_NONBLOCK); 164 165 if(listen(server->sockfd, BACKLOG) == -1) 195 166 { 196 167 perror("listen"); … … 198 169 } 199 170 200 kk->drv.p->ex = NULL;171 server->ex = NULL; 201 172 202 173 /* Ignore SIGPIPE */ 203 kk->drv.p->sigpipe_handler = signal(SIGPIPE, SIG_IGN);174 server->sigpipe_handler = signal(SIGPIPE, SIG_IGN); 204 175 205 176 fprintf(stderr, "initialised network, listening on port %i\n", 206 kk->drv.p->port); 207 208 return 0; 209 } 210 211 static int network_end_graphics(caca_t *kk) 212 { 213 int i; 214 215 for(i = 0; i < kk->drv.p->client_count; i++) 216 { 217 close(kk->drv.p->clients[i].fd); 218 kk->drv.p->clients[i].fd = -1; 219 } 220 221 if(kk->drv.p->ex) 222 cucul_free_export(kk->drv.p->ex); 177 server->port); 178 179 /* Main loop */ 180 for(;;) 181 { 182 /* Manage new connections as this function will be called sometimes 183 * more often than display */ 184 manage_connections(server); 185 186 /* Read data from stdin */ 187 /* FIXME: read data, then continue if there was a new image */ 188 189 /* Free the previous export buffer, if any */ 190 if(server->ex) 191 { 192 cucul_free_export(server->ex); 193 server->ex = NULL; 194 } 195 196 /* Get ANSI representation of the image and skip the end-of buffer 197 * linefeed ("\r\n\0", 3 bytes) */ 198 server->ex = cucul_create_export(qq, CUCUL_FORMAT_ANSI); 199 server->ex->size -= 3; 200 201 for(i = 0; i < server->client_count; i++) 202 { 203 if(server->clients[i].fd == -1) 204 continue; 205 206 if(send_data(server, &server->clients[i])) 207 { 208 fprintf(stderr, "client %i dropped connection\n", 209 server->clients[i].fd); 210 close(server->clients[i].fd); 211 server->clients[i].fd = -1; 212 } 213 } 214 } 215 216 /* Kill all remaining clients */ 217 for(i = 0; i < server->client_count; i++) 218 { 219 if(server->clients[i].fd == -1) 220 continue; 221 222 close(server->clients[i].fd); 223 server->clients[i].fd = -1; 224 } 225 226 if(server->ex) 227 cucul_free_export(server->ex); 223 228 224 229 /* Restore SIGPIPE handler */ 225 signal(SIGPIPE, kk->drv.p->sigpipe_handler); 226 227 free(kk->drv.p); 228 229 return 0; 230 } 231 232 static int network_set_window_title(caca_t *kk, char const *title) 233 { 234 /* Not handled (yet) */ 235 return 0; 236 } 237 238 static unsigned int network_get_window_width(caca_t *kk) 239 { 240 return kk->drv.p->width * 6; 241 } 242 243 static unsigned int network_get_window_height(caca_t *kk) 244 { 245 return kk->drv.p->height * 10; 246 } 247 248 static void network_display(caca_t *kk) 249 { 250 int i; 251 252 /* Free the previous export buffer, if any */ 253 if(kk->drv.p->ex) 254 { 255 cucul_free_export(kk->drv.p->ex); 256 kk->drv.p->ex = NULL; 257 } 258 259 /* Get ANSI representation of the image and skip the end-of buffer 260 * linefeed ("\r\n\0", 3 bytes) */ 261 kk->drv.p->ex = cucul_create_export(kk->qq, CUCUL_FORMAT_ANSI); 262 kk->drv.p->ex->size -= 3; 263 264 for(i = 0; i < kk->drv.p->client_count; i++) 265 { 266 if(kk->drv.p->clients[i].fd == -1) 267 continue; 268 269 if(send_data(kk, &kk->drv.p->clients[i])) 270 { 271 fprintf(stderr, "client %i dropped connection\n", 272 kk->drv.p->clients[i].fd); 273 close(kk->drv.p->clients[i].fd); 274 kk->drv.p->clients[i].fd = -1; 275 } 276 } 277 278 manage_connections(kk); 279 } 280 281 static void network_handle_resize(caca_t *kk) 282 { 283 /* Not handled */ 284 } 285 286 static int network_get_event(caca_t *kk, struct caca_event *ev) 287 { 288 /* Manage new connections as this function will be called sometimes 289 * more often than display */ 290 manage_connections(kk); 291 292 /* Event not handled */ 230 signal(SIGPIPE, server->sigpipe_handler); 231 232 free(server); 233 293 234 return 0; 294 235 } … … 298 239 */ 299 240 300 static void manage_connections( caca_t *kk)241 static void manage_connections(struct server *server) 301 242 { 302 243 int fd, flags; … … 304 245 socklen_t len = sizeof(struct sockaddr_in); 305 246 306 fd = accept( kk->drv.p->sockfd, (struct sockaddr *)&remote_addr, &len);247 fd = accept(server->sockfd, (struct sockaddr *)&remote_addr, &len); 307 248 if(fd == -1) 308 249 return; … … 315 256 fcntl(fd, F_SETFL, flags | O_NONBLOCK); 316 257 317 if( kk->drv.p->clients == NULL)318 { 319 kk->drv.p->clients = malloc(sizeof(struct client));320 if( kk->drv.p->clients == NULL)258 if(server->clients == NULL) 259 { 260 server->clients = malloc(sizeof(struct client)); 261 if(server->clients == NULL) 321 262 return; 322 263 } 323 264 else 324 265 { 325 kk->drv.p->clients = realloc(kk->drv.p->clients,326 (kk->drv.p->client_count+1) * sizeof(struct client));327 } 328 329 kk->drv.p->clients[kk->drv.p->client_count].fd = fd;330 kk->drv.p->clients[kk->drv.p->client_count].ready = 0;331 kk->drv.p->clients[kk->drv.p->client_count].inbytes = 0;332 kk->drv.p->clients[kk->drv.p->client_count].start = 0;333 kk->drv.p->clients[kk->drv.p->client_count].stop = 0;266 server->clients = realloc(server->clients, 267 (server->client_count+1) * sizeof(struct client)); 268 } 269 270 server->clients[server->client_count].fd = fd; 271 server->clients[server->client_count].ready = 0; 272 server->clients[server->client_count].inbytes = 0; 273 server->clients[server->client_count].start = 0; 274 server->clients[server->client_count].stop = 0; 334 275 335 276 /* If we already have data to send, send it to the new client */ 336 if(send_data( kk, &kk->drv.p->clients[kk->drv.p->client_count]))277 if(send_data(server, &server->clients[server->client_count])) 337 278 { 338 279 fprintf(stderr, "client %i dropped connection\n", fd); 339 280 close(fd); 340 kk->drv.p->clients[kk->drv.p->client_count].fd = -1;281 server->clients[server->client_count].fd = -1; 341 282 return; 342 283 } 343 284 344 kk->drv.p->client_count++;285 server->client_count++; 345 286 } 346 287 347 static int send_data( caca_t *kk, struct client *c)288 static int send_data(struct server *server, struct client *c) 348 289 { 349 290 ssize_t ret; … … 398 339 if(!c->ready) 399 340 { 400 ret = nonblock_write(c->fd, kk->drv.p->prefix, sizeof(INIT_PREFIX));341 ret = nonblock_write(c->fd, server->prefix, sizeof(INIT_PREFIX)); 401 342 if(ret == -1) 402 343 return (errno == EAGAIN) ? 0 : -1; … … 409 350 410 351 /* No error, there's just nothing to send yet */ 411 if(! kk->drv.p->ex)352 if(!server->ex) 412 353 return 0; 413 354 … … 434 375 c->start += ret; 435 376 436 if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->ex->size377 if(c->stop - c->start + strlen(ANSI_PREFIX) + server->ex->size 437 378 > OUTBUFFER) 438 379 { … … 445 386 446 387 /* Need to move? */ 447 if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER)388 if(c->stop + strlen(ANSI_PREFIX) + server->ex->size > OUTBUFFER) 448 389 { 449 390 memmove(c->outbuf, c->outbuf + c->start, c->stop - c->start); … … 454 395 memcpy(c->outbuf + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX)); 455 396 c->stop += strlen(ANSI_PREFIX); 456 memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size);457 c->stop += kk->drv.p->ex->size;397 memcpy(c->outbuf + c->stop, server->ex->buffer, server->ex->size); 398 c->stop += server->ex->size; 458 399 459 400 return 0; … … 475 416 if(ret < (ssize_t)strlen(ANSI_PREFIX)) 476 417 { 477 if(strlen(ANSI_PREFIX) + kk->drv.p->ex->size > OUTBUFFER)418 if(strlen(ANSI_PREFIX) + server->ex->size > OUTBUFFER) 478 419 { 479 420 /* Overflow! Empty buffer and start again */ … … 486 427 memcpy(c->outbuf, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret); 487 428 c->stop = strlen(ANSI_PREFIX) - ret; 488 memcpy(c->outbuf + c->stop, kk->drv.p->ex->buffer, kk->drv.p->ex->size);489 c->stop += kk->drv.p->ex->size;429 memcpy(c->outbuf + c->stop, server->ex->buffer, server->ex->size); 430 c->stop += server->ex->size; 490 431 491 432 return 0; … … 493 434 494 435 /* Send actual data */ 495 ret = nonblock_write(c->fd, kk->drv.p->ex->buffer, kk->drv.p->ex->size);436 ret = nonblock_write(c->fd, server->ex->buffer, server->ex->size); 496 437 if(ret == -1) 497 438 { … … 502 443 } 503 444 504 if(ret < (int) kk->drv.p->ex->size)505 { 506 if( kk->drv.p->ex->size > OUTBUFFER)445 if(ret < (int)server->ex->size) 446 { 447 if(server->ex->size > OUTBUFFER) 507 448 { 508 449 /* Overflow! Empty buffer and start again */ … … 513 454 } 514 455 515 memcpy(c->outbuf, kk->drv.p->ex->buffer, kk->drv.p->ex->size - ret);516 c->stop = kk->drv.p->ex->size - ret;456 memcpy(c->outbuf, server->ex->buffer, server->ex->size - ret); 457 c->stop = server->ex->size - ret; 517 458 518 459 return 0; … … 547 488 } 548 489 549 /*550 * Driver initialisation551 */552 553 int network_install(caca_t *kk)554 {555 kk->drv.driver = CACA_DRIVER_NETWORK;556 557 kk->drv.init_graphics = network_init_graphics;558 kk->drv.end_graphics = network_end_graphics;559 kk->drv.set_window_title = network_set_window_title;560 kk->drv.get_window_width = network_get_window_width;561 kk->drv.get_window_height = network_get_window_height;562 kk->drv.display = network_display;563 kk->drv.handle_resize = network_handle_resize;564 kk->drv.get_event = network_get_event;565 kk->drv.set_mouse = NULL;566 567 return 0;568 }569 570 #endif /* USE_NETWORK */571
Note: See TracChangeset
for help on using the changeset viewer.