source: libcaca/trunk/caca/driver_network.c @ 585

Last change on this file since 585 was 585, checked in by Jean-Yves Lamoureux, 15 years ago
  • Fixed configure script to check for UTF8 enabled slang, removed network driver debug output, added size > 255 in telnet negociation, fixed scrolling bug in network driver
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
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
12/** \file driver_network.c
13 *  \version \$Id: driver_network.c 585 2006-03-10 14:41:24Z jylam $
14 *  \author Jean-Yves Lamoureux <jylam@lnxscene.org>
15 *  \brief Network driver
16 *
17 *  This file contains the libcaca network input and output driver
18 */
19
20#include "config.h"
21
22#if defined(USE_NETWORK)
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/types.h>
26#include <sys/socket.h>
27#include <arpa/inet.h>
28#include <fcntl.h>
29#include <string.h>
30
31#if defined(HAVE_UNISTD_H)
32#   include <unistd.h>
33#endif
34#include <stdarg.h>
35
36#include "caca.h"
37#include "caca_internals.h"
38#include "cucul.h"
39#include "cucul_internals.h"
40
41static void manage_connections(caca_t *kk);
42static int send_data(caca_t *kk, int fd);
43
44
45struct driver_private
46{
47    unsigned int width, height;
48    unsigned int port;
49    int sockfd;
50    struct sockaddr_in my_addr;
51    struct sockaddr_in remote_addr;
52    socklen_t sin_size;
53    int clilen;
54
55    char *buffer;
56    int size;
57
58    int client_count;
59    int *fd_list;
60};
61
62
63
64#define BACKLOG 1337    /* Number of pending connections */
65
66
67
68/* Following vars are static */
69static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO                                                             
70                       0xff, 0xfb, 0x03,  // WILL SUPPRESS GO AHEAD
71                       0xff, 253, 31,     // DO NAWS
72                       0xff, 254, 31,     // DON'T NAWS
73                       0xff, 31, 250, 0, 30, 0, 0xFF, // Set size, replaced in display
74                       0xff, 240};
75
76
77static int network_init_graphics(caca_t *kk)
78{
79    int yes=1;
80
81    kk->drv.p = malloc(sizeof(struct driver_private));
82    if(kk->drv.p == NULL)
83        return -1;
84
85    kk->drv.p->width = 80;
86    kk->drv.p->height = 23; // Avoid scrolling
87    kk->drv.p->port = 7575; // 75 75 decimal ASCII -> KK   // FIXME, sadly
88    kk->drv.p->client_count = 0;
89    kk->drv.p->fd_list = NULL;
90
91
92
93    _cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height);
94
95
96    if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
97        perror("socket");
98        return -1;
99    }
100
101    if (setsockopt(kk->drv.p->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
102        perror("setsockopt");
103        return -1;
104    }
105
106    kk->drv.p->my_addr.sin_family = AF_INET;
107    kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port);
108    kk->drv.p->my_addr.sin_addr.s_addr = INADDR_ANY;
109    memset(&(kk->drv.p->my_addr.sin_zero), '\0', 8);
110
111    if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr, sizeof(struct sockaddr))
112                                                                   == -1) {
113        perror("bind");
114        return -1;
115    }
116
117    /* Non blocking socket */
118    fcntl(kk->drv.p->sockfd, F_SETFL, O_NONBLOCK);
119
120    if (listen(kk->drv.p->sockfd, BACKLOG) == -1) {
121        perror("listen");
122        return -1;
123    }
124
125    kk->drv.p->buffer = NULL;
126
127    return 0;
128}
129
130static int network_end_graphics(caca_t *kk)
131{
132    int i;
133
134    for(i = 0; i < kk->drv.p->client_count; i++) {
135        close(kk->drv.p->fd_list[i]);
136    }
137
138    return 0;
139}
140
141static int network_set_window_title(caca_t *kk, char const *title)
142{
143    /* Not handled (yet)*/
144    return 0;
145}
146
147static unsigned int network_get_window_width(caca_t *kk)
148{
149    return kk->drv.p->width * 6;
150}
151
152static unsigned int network_get_window_height(caca_t *kk)
153{
154    return kk->drv.p->height * 10;
155}
156
157static void network_display(caca_t *kk)
158{
159    int i;
160
161    /* Get ANSI representation of the image */
162    kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size);;
163
164    for(i = 0; i < kk->drv.p->client_count; i++)
165    {
166        if(send_data(kk, kk->drv.p->fd_list[i]))
167            kk->drv.p->fd_list[i] = -1;
168    }
169
170    manage_connections(kk);
171}
172 
173static void network_handle_resize(caca_t *kk)
174{
175    /* Not handled */
176}
177
178static unsigned int network_get_event(caca_t *kk)
179{
180    /* Manage new connections as this function will be called sometimes
181     *  more often than display
182     */
183    manage_connections(kk);
184
185    /* Event not handled */
186    return 0;
187}
188
189/*
190 * XXX: The following functions are local
191 */
192
193static void manage_connections(caca_t *kk)
194{
195    int fd;
196
197    kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
198    fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
199    if(fd != -1) /* That's non blocking socket, -1 if no connection received */
200    {
201        if(kk->drv.p->fd_list == NULL)
202        {
203            kk->drv.p->fd_list = malloc(sizeof(int));
204            if(kk->drv.p->fd_list == NULL)
205                return;
206        }
207        else
208        {
209            kk->drv.p->fd_list = realloc(kk->drv.p->fd_list, (kk->drv.p->client_count+1) * sizeof(int));
210        }
211
212        if(send_data(kk, fd) == 0)
213        {
214            kk->drv.p->fd_list[kk->drv.p->client_count] = fd;
215            kk->drv.p->client_count++;
216        }
217    }
218}
219
220static int send_data(caca_t *kk, int fd)
221{
222    /* No error, there's just nothing to send yet */
223    if(!kk->drv.p->buffer)
224        return 0;
225
226    if(fd < 0)
227        return -1;
228
229    /* FIXME, handle >255 sizes */
230    codes[15] = (unsigned char) (kk->drv.p->width & 0xff00)>>8;
231    codes[16] = (unsigned char) kk->drv.p->width & 0xff;
232    codes[17] = (unsigned char) (kk->drv.p->height & 0xff00)>>8;
233    codes[18] = (unsigned char) kk->drv.p->height & 0xff;
234           
235    /* Send basic telnet codes */
236    if (send(fd, codes,sizeof(codes) , 0) == -1)
237        return -1;
238   
239    /* ANSI code for move(0,0)*/
240    if (send(fd, "\033[1,1H", 6, 0) == -1)
241        return -1;
242   
243    /* Send actual data */
244    if (send(fd, kk->drv.p->buffer, kk->drv.p->size, 0) == -1)
245        return -1;
246
247    return 0;
248}
249
250/*
251 * Driver initialisation
252 */
253
254void network_init_driver(caca_t *kk)
255{
256    kk->drv.driver = CACA_DRIVER_NETWORK;
257
258    kk->drv.init_graphics = network_init_graphics;
259    kk->drv.end_graphics = network_end_graphics;
260    kk->drv.set_window_title = network_set_window_title;
261    kk->drv.get_window_width = network_get_window_width;
262    kk->drv.get_window_height = network_get_window_height;
263    kk->drv.display = network_display;
264    kk->drv.handle_resize = network_handle_resize;
265    kk->drv.get_event = network_get_event;
266}
267
268#endif // USE_NETWORK
269
Note: See TracBrowser for help on using the repository browser.