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

Last change on this file since 575 was 575, checked in by Jean-Yves Lamoureux, 15 years ago
  • Multiplexed sockets, it is now possible to have multiple clients at the same time watching for the same libcaca application. And no fork or threads involved. THAT'S high technology.
File size: 6.0 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_gl.c 330 2006-03-07 09:17:35Z sam $
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
41
42
43struct driver_private
44{
45    unsigned int width, height;
46    unsigned int port;
47    int sockfd, new_fd;
48    struct sockaddr_in my_addr;
49    struct sockaddr_in remote_addr;
50    socklen_t sin_size;
51    int clilen;
52    char buffer[256];
53
54    int client_count;
55    int *fd_list;
56
57};
58
59
60
61#define BACKLOG 1337    /* Number of pending connections */
62
63
64
65/* Following vars are static */
66static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO                                                             
67                       0xff, 0xfb, 0x03,  // WILL SUPPRESS GO AHEAD
68                       0xff, 253, 31,     // DO NAWS
69                       0xff, 254, 31,     // DON'T NAWS
70                       0xff, 31, 250, 0, 30, 0, 0xFF, // to be replaced
71                       0xff, 240};
72
73
74static int network_init_graphics(caca_t *kk)
75{
76    int yes=1;
77
78    printf("Initing network stack.\n");
79
80    kk->drv.p = malloc(sizeof(struct driver_private));
81    if(kk->drv.p == NULL)
82        return -1;
83
84    kk->drv.p->width = 80;
85    kk->drv.p->height = 24;
86    kk->drv.p->port = 7575; // 75 75 decimal ASCII -> KK   // FIXME, sadly
87    kk->drv.p->client_count = 0;
88    kk->drv.p->fd_list = NULL;
89
90
91
92    cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height);
93
94
95    printf("socket\n");
96    if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
97        perror("socket");
98        return -1;
99    }
100    printf("setsockopt\n");
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    printf("bind\n");
112    if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr, sizeof(struct sockaddr))
113                                                                   == -1) {
114        perror("bind");
115        return -1;
116    }
117
118    /* Non blocking socket */
119    fcntl(kk->drv.p->sockfd, F_SETFL, O_NONBLOCK);
120
121
122    printf("listen\n");
123    if (listen(kk->drv.p->sockfd, BACKLOG) == -1) {
124        perror("listen");
125        return -1;
126    }
127
128    printf("network ok.\n");
129
130    return 0;
131}
132
133static int network_end_graphics(caca_t *kk)
134{
135    int i;
136    for(i = 0; i < kk->drv.p->client_count; i++) {
137        close(kk->drv.p->fd_list[i]);
138    }
139    return 0;
140}
141
142static int network_set_window_title(caca_t *kk, char const *title)
143{
144    /* Not handled (yet)*/
145    return 0;
146}
147
148static unsigned int network_get_window_width(caca_t *kk)
149{
150    return kk->drv.p->width * 6;
151}
152
153static unsigned int network_get_window_height(caca_t *kk)
154{
155    return kk->drv.p->height * 10;
156}
157
158static void network_display(caca_t *kk)
159{
160    int size, i;
161    char *to_send = cucul_get_ansi(kk->qq, 0, &size);;
162 
163    kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
164    kk->drv.p->new_fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
165    if(kk->drv.p->new_fd != -1)
166        {
167
168            if(kk->drv.p->fd_list == NULL) {
169                kk->drv.p->fd_list = malloc(sizeof(int));
170                if(kk->drv.p->fd_list == NULL)
171                    return;
172                kk->drv.p->fd_list[kk->drv.p->client_count] = kk->drv.p->new_fd;
173            } else {
174                kk->drv.p->fd_list = realloc(kk->drv.p->fd_list, (kk->drv.p->client_count+1) * sizeof(int));
175                kk->drv.p->fd_list[kk->drv.p->client_count] = kk->drv.p->new_fd;
176            }
177
178            kk->drv.p->client_count++;
179
180        }
181
182    for(i = 0; i < kk->drv.p->client_count; i++) {
183        if(kk->drv.p->fd_list[i] == -1)
184           continue;
185       
186        /* FIXME, handle >255 sizes */
187            codes[16] = (unsigned char) kk->drv.p->width&0xff;
188            codes[18] = (unsigned char) kk->drv.p->height&0xff;
189           
190            /* Send basic telnet codes */
191            if (send(kk->drv.p->fd_list[i], codes,sizeof(codes) , 0) == -1) {
192                kk->drv.p->fd_list[i] = -1;
193             }
194           
195            /* ANSI code for move(0,0)*/
196            if (send(kk->drv.p->fd_list[i], "\033[1,1H", 6, 0) == -1) {
197                kk->drv.p->fd_list[i] = -1;
198            }
199           
200            if (send(kk->drv.p->fd_list[i], to_send, size, 0) == -1) {
201                kk->drv.p->fd_list[i] = -1;
202            }
203        }
204   
205}
206static void network_handle_resize(caca_t *kk)
207{
208    /* Not handled */
209}
210
211static unsigned int network_get_event(caca_t *kk)
212{
213    /* Not handled */
214    return 0;
215}
216
217
218/*
219 * Driver initialisation
220 */
221
222void network_init_driver(caca_t *kk)
223{
224    kk->drv.driver = CACA_DRIVER_NETWORK;
225
226    kk->drv.init_graphics = network_init_graphics;
227    kk->drv.end_graphics = network_end_graphics;
228    kk->drv.set_window_title = network_set_window_title;
229    kk->drv.get_window_width = network_get_window_width;
230    kk->drv.get_window_height = network_get_window_height;
231    kk->drv.display = network_display;
232    kk->drv.handle_resize = network_handle_resize;
233    kk->drv.get_event = network_get_event;
234}
235
236#endif // USE_NETWORK
237
Note: See TracBrowser for help on using the repository browser.