You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

270 regels
6.4 KiB

  1. /*
  2. * libcaca ASCII-Art library
  3. * Copyright (c) 2002-2006 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the Do What The Fuck You Want To
  8. * Public License, Version 2, as published by Sam Hocevar. See
  9. * http://sam.zoy.org/wtfpl/COPYING for more details.
  10. */
  11. /** \file driver_network.c
  12. * \version \$Id$
  13. * \author Jean-Yves Lamoureux <jylam@lnxscene.org>
  14. * \brief Network driver
  15. *
  16. * This file contains the libcaca network input and output driver
  17. */
  18. #include "config.h"
  19. #if defined(USE_NETWORK)
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <arpa/inet.h>
  25. #include <fcntl.h>
  26. #include <string.h>
  27. #if defined(HAVE_UNISTD_H)
  28. # include <unistd.h>
  29. #endif
  30. #include <stdarg.h>
  31. #include "caca.h"
  32. #include "caca_internals.h"
  33. #include "cucul.h"
  34. #include "cucul_internals.h"
  35. static void manage_connections(caca_t *kk);
  36. static int send_data(caca_t *kk, int fd);
  37. struct driver_private
  38. {
  39. unsigned int width, height;
  40. unsigned int port;
  41. int sockfd;
  42. struct sockaddr_in my_addr;
  43. struct sockaddr_in remote_addr;
  44. socklen_t sin_size;
  45. int clilen;
  46. char *buffer;
  47. int size;
  48. int client_count;
  49. int *fd_list;
  50. };
  51. #define BACKLOG 1337 /* Number of pending connections */
  52. /* Following vars are static */
  53. static char codes[] = {0xff, 0xfb, 0x01, // WILL ECHO
  54. 0xff, 0xfb, 0x03, // WILL SUPPRESS GO AHEAD
  55. 0xff, 253, 31, // DO NAWS
  56. 0xff, 254, 31, // DON'T NAWS
  57. 0xff, 31, 250, 0, 30, 0, 0xFF, // Set size, replaced in display
  58. 0xff, 240};
  59. static int network_init_graphics(caca_t *kk)
  60. {
  61. int yes=1;
  62. kk->drv.p = malloc(sizeof(struct driver_private));
  63. if(kk->drv.p == NULL)
  64. return -1;
  65. kk->drv.p->width = 80;
  66. kk->drv.p->height = 23; // Avoid scrolling
  67. kk->drv.p->port = 7575; // 75 75 decimal ASCII -> KK // FIXME, sadly
  68. kk->drv.p->client_count = 0;
  69. kk->drv.p->fd_list = NULL;
  70. _cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height);
  71. if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
  72. perror("socket");
  73. return -1;
  74. }
  75. if (setsockopt(kk->drv.p->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
  76. perror("setsockopt");
  77. return -1;
  78. }
  79. kk->drv.p->my_addr.sin_family = AF_INET;
  80. kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port);
  81. kk->drv.p->my_addr.sin_addr.s_addr = INADDR_ANY;
  82. memset(&(kk->drv.p->my_addr.sin_zero), '\0', 8);
  83. if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr, sizeof(struct sockaddr))
  84. == -1) {
  85. perror("bind");
  86. return -1;
  87. }
  88. /* Non blocking socket */
  89. fcntl(kk->drv.p->sockfd, F_SETFL, O_NONBLOCK);
  90. if (listen(kk->drv.p->sockfd, BACKLOG) == -1) {
  91. perror("listen");
  92. return -1;
  93. }
  94. kk->drv.p->buffer = NULL;
  95. return 0;
  96. }
  97. static int network_end_graphics(caca_t *kk)
  98. {
  99. int i;
  100. for(i = 0; i < kk->drv.p->client_count; i++) {
  101. close(kk->drv.p->fd_list[i]);
  102. }
  103. return 0;
  104. }
  105. static int network_set_window_title(caca_t *kk, char const *title)
  106. {
  107. /* Not handled (yet)*/
  108. return 0;
  109. }
  110. static unsigned int network_get_window_width(caca_t *kk)
  111. {
  112. return kk->drv.p->width * 6;
  113. }
  114. static unsigned int network_get_window_height(caca_t *kk)
  115. {
  116. return kk->drv.p->height * 10;
  117. }
  118. static void network_display(caca_t *kk)
  119. {
  120. int i;
  121. /* Get ANSI representation of the image */
  122. kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size);;
  123. for(i = 0; i < kk->drv.p->client_count; i++)
  124. {
  125. if(send_data(kk, kk->drv.p->fd_list[i]))
  126. kk->drv.p->fd_list[i] = -1;
  127. }
  128. manage_connections(kk);
  129. }
  130. static void network_handle_resize(caca_t *kk)
  131. {
  132. /* Not handled */
  133. }
  134. static unsigned int network_get_event(caca_t *kk)
  135. {
  136. /* Manage new connections as this function will be called sometimes
  137. * more often than display
  138. */
  139. manage_connections(kk);
  140. /* Event not handled */
  141. return 0;
  142. }
  143. /*
  144. * XXX: The following functions are local
  145. */
  146. static void manage_connections(caca_t *kk)
  147. {
  148. int fd;
  149. kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
  150. fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
  151. if(fd != -1) /* That's non blocking socket, -1 if no connection received */
  152. {
  153. if(kk->drv.p->fd_list == NULL)
  154. {
  155. kk->drv.p->fd_list = malloc(sizeof(int));
  156. if(kk->drv.p->fd_list == NULL)
  157. return;
  158. }
  159. else
  160. {
  161. kk->drv.p->fd_list = realloc(kk->drv.p->fd_list, (kk->drv.p->client_count+1) * sizeof(int));
  162. }
  163. if(send_data(kk, fd) == 0)
  164. {
  165. kk->drv.p->fd_list[kk->drv.p->client_count] = fd;
  166. kk->drv.p->client_count++;
  167. }
  168. }
  169. }
  170. static int send_data(caca_t *kk, int fd)
  171. {
  172. /* No error, there's just nothing to send yet */
  173. if(!kk->drv.p->buffer)
  174. return 0;
  175. if(fd < 0)
  176. return -1;
  177. /* FIXME, handle >255 sizes */
  178. codes[15] = (unsigned char) (kk->drv.p->width & 0xff00)>>8;
  179. codes[16] = (unsigned char) kk->drv.p->width & 0xff;
  180. codes[17] = (unsigned char) (kk->drv.p->height & 0xff00)>>8;
  181. codes[18] = (unsigned char) kk->drv.p->height & 0xff;
  182. /* Send basic telnet codes */
  183. if (send(fd, codes,sizeof(codes) , 0) == -1)
  184. return -1;
  185. /* ANSI code for move(0,0)*/
  186. if (send(fd, "\033[1,1H", 6, 0) == -1)
  187. return -1;
  188. /* Send actual data */
  189. if (send(fd, kk->drv.p->buffer, kk->drv.p->size, 0) == -1)
  190. return -1;
  191. return 0;
  192. }
  193. /*
  194. * Driver initialisation
  195. */
  196. void network_init_driver(caca_t *kk)
  197. {
  198. kk->drv.driver = CACA_DRIVER_NETWORK;
  199. kk->drv.init_graphics = network_init_graphics;
  200. kk->drv.end_graphics = network_end_graphics;
  201. kk->drv.set_window_title = network_set_window_title;
  202. kk->drv.get_window_width = network_get_window_width;
  203. kk->drv.get_window_height = network_get_window_height;
  204. kk->drv.display = network_display;
  205. kk->drv.handle_resize = network_handle_resize;
  206. kk->drv.get_event = network_get_event;
  207. }
  208. #endif // USE_NETWORK