Changeset 596


Ignore:
Timestamp:
Mar 13, 2006, 8:04:29 PM (15 years ago)
Author:
Sam Hocevar
Message:
  • Improvements to the network output: + Changed port to 51914 (rationale: it's 0xCACA; so okay, it's outside

the registered ports area, but we'd never be accepted anyway).

+ Retry network sends in caca_get_event(), too.
+ Have a per-client buffer in case of network congestion. If that buffer

gets full, just drop it and start again at the next frame.

+ Set the window title to "caca for the network".
+ Do not send the ANSI buffer's terminating \0.
+ Restore the SIGPIPE handler on close.
+ Set window size to 80x24 instead of 80x25.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcaca/trunk/caca/driver_network.c

    r590 r596  
    4141#include "cucul_internals.h"
    4242
    43 static void manage_connections(caca_t *kk);
    44 static int send_data(caca_t *kk, int fd);
    45 ssize_t nonblock_write(int fd, char *buf, size_t len);
     43#define BACKLOG 1337    /* Number of pending connections */
     44#define BACKBUFFER 300000 /* Size of per-client buffer */
     45
     46/* Following vars are static */
     47#define INIT_PREFIX \
     48    "\xff\xfb\x01" /* WILL ECHO */ \
     49    "\xff\xfb\x03" /* WILL SUPPRESS GO AHEAD */ \
     50    "\xff\xfd\x31" /* DO NAWS */ \
     51    "\xff\xfe\x1f" /* DON'T NAWS */ \
     52    "\xff\x1f\xfa____" /* Set size, replaced in display */ \
     53    "\xff\xf0" \
     54    "\x1b]2;caca for the network\x07" /* Change window title */ \
     55    "\x1b[?1049h" /* Clear screen */ \
     56    /*"\x1b[?25l"*/ /* Hide cursor */ \
     57
     58#define ANSI_PREFIX \
     59    "\x1b[1;1H" /* move(0,0) */ \
     60    "\x1b[1;1H" /* move(0,0) again */
     61
     62#define ANSI_RESET \
     63    "    " /* Garbage */ \
     64    "\x1b[?1049h" /* Clear screen */ \
     65    "\x1b[?1049h" /* Clear screen again */
     66
     67struct client
     68{
     69    int fd;
     70    int ready;
     71    char buffer[BACKBUFFER];
     72    int start, stop;
     73};
    4674
    4775struct driver_private
     
    5179    int sockfd;
    5280    struct sockaddr_in my_addr;
    53     struct sockaddr_in remote_addr;
    5481    socklen_t sin_size;
    55     int clilen;
     82
     83    char prefix[sizeof(INIT_PREFIX)];
    5684
    5785    char *buffer;
     
    5987
    6088    int client_count;
    61     int *fd_list;
     89    struct client *clients;
     90
     91    void (*sigpipe_handler)(int);
    6292};
    6393
    64 
    65 
    66 #define BACKLOG 1337    /* Number of pending connections */
    67 
    68 
    69 
    70 /* Following vars are static */
    71 static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO
    72                        0xff, 0xfb, 0x03,  // WILL SUPPRESS GO AHEAD
    73                        0xff, 253, 31,     // DO NAWS
    74                        0xff, 254, 31,     // DON'T NAWS
    75                        0xff, 31, 250, 0, 30, 0, 0xFF, // Set size, replaced in display
    76                        0xff, 240};
    77 
     94static void manage_connections(caca_t *kk);
     95static int send_data(caca_t *kk, struct client *c);
     96ssize_t nonblock_write(int fd, char *buf, size_t len);
    7897
    7998static int network_init_graphics(caca_t *kk)
    8099{
    81     int yes=1;
    82     int net_port = 7575;
    83     char *network_port;
    84 
     100    int yes = 1, flags;
     101    int port = 51914;
     102    char *network_port, *tmp;
    85103
    86104    kk->drv.p = malloc(sizeof(struct driver_private));
     
    88106        return -1;
    89107
    90 
    91108#if defined(HAVE_GETENV)
    92109    network_port = getenv("CACA_NETWORK_PORT");
    93     if(network_port && *network_port) {
    94         net_port = atoi(network_port);
    95         if(!net_port)
    96             net_port = 7575;
     110    if(network_port && *network_port)
     111    {
     112        int new_port = atoi(network_port);
     113        if(new_port)
     114            port = new_port;
    97115    }
    98116#endif
    99117
    100 
    101118    kk->drv.p->width = 80;
    102     kk->drv.p->height = 23; // Avoid scrolling
     119    kk->drv.p->height = 24;
    103120    kk->drv.p->client_count = 0;
    104     kk->drv.p->fd_list = NULL;
    105     kk->drv.p->port = net_port;
    106 
     121    kk->drv.p->clients = NULL;
     122    kk->drv.p->port = port;
    107123
    108124    _cucul_set_size(kk->qq, kk->drv.p->width, kk->drv.p->height);
    109125
    110 
    111     if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
     126    /* FIXME, handle >255 sizes */
     127    memcpy(kk->drv.p->prefix, INIT_PREFIX, sizeof(INIT_PREFIX));
     128    tmp = strstr(kk->drv.p->prefix, "____");
     129    tmp[0] = (unsigned char) (kk->drv.p->width & 0xff00) >> 8;
     130    tmp[1] = (unsigned char) kk->drv.p->width & 0xff;
     131    tmp[2] = (unsigned char) (kk->drv.p->height & 0xff00) >> 8;
     132    tmp[3] = (unsigned char) kk->drv.p->height & 0xff;
     133
     134    if ((kk->drv.p->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
     135    {
    112136        perror("socket");
    113137        return -1;
    114138    }
    115139
    116     if (setsockopt(kk->drv.p->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
     140    if (setsockopt(kk->drv.p->sockfd, SOL_SOCKET,
     141                   SO_REUSEADDR, &yes, sizeof(int)) == -1)
     142    {
    117143        perror("setsockopt SO_REUSEADDR");
    118144        return -1;
     
    124150    memset(&(kk->drv.p->my_addr.sin_zero), '\0', 8);
    125151
    126     if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr, sizeof(struct sockaddr))
    127                                                                    == -1) {
     152    if (bind(kk->drv.p->sockfd, (struct sockaddr *)&kk->drv.p->my_addr,
     153             sizeof(struct sockaddr)) == -1)
     154    {
    128155        perror("bind");
    129156        return -1;
     
    131158
    132159    /* Non blocking socket */
    133     fcntl(kk->drv.p->sockfd, F_SETFL, O_NONBLOCK);
    134 
    135     if (listen(kk->drv.p->sockfd, BACKLOG) == -1) {
     160    flags = fcntl(kk->drv.p->sockfd, F_GETFL, 0);
     161    fcntl(kk->drv.p->sockfd, F_SETFL, flags | O_NONBLOCK);
     162
     163    if (listen(kk->drv.p->sockfd, BACKLOG) == -1)
     164    {
    136165        perror("listen");
    137166        return -1;
     
    139168
    140169    kk->drv.p->buffer = NULL;
     170    kk->drv.p->size = 0;
    141171
    142172    /* Ignore SIGPIPE */
    143     signal(SIGPIPE, SIG_IGN);
     173    kk->drv.p->sigpipe_handler = signal(SIGPIPE, SIG_IGN);
    144174
    145175    return 0;
     
    150180    int i;
    151181
    152     for(i = 0; i < kk->drv.p->client_count; i++) {
    153         close(kk->drv.p->fd_list[i]);
    154     }
     182    for(i = 0; i < kk->drv.p->client_count; i++)
     183    {
     184        close(kk->drv.p->clients[i].fd);
     185        kk->drv.p->clients[i].fd = -1;
     186    }
     187
     188    /* Restore SIGPIPE handler */
     189    signal(SIGPIPE, kk->drv.p->sigpipe_handler);
     190
     191    free(kk->drv.p);
    155192
    156193    return 0;
     
    159196static int network_set_window_title(caca_t *kk, char const *title)
    160197{
    161     /* Not handled (yet)*/
     198    /* Not handled (yet) */
    162199    return 0;
    163200}
     
    177214    int i;
    178215
    179     /* Get ANSI representation of the image */
    180     kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size);;
     216    /* Get ANSI representation of the image and skip the end-of buffer
     217     * linefeed ("\r\n\0", 3 bytes) */
     218    kk->drv.p->buffer = cucul_get_ansi(kk->qq, 0, &kk->drv.p->size);
     219    kk->drv.p->size -= 3;
    181220
    182221    for(i = 0; i < kk->drv.p->client_count; i++)
    183222    {
    184         if(kk->drv.p->fd_list[i] == -1)
     223        if(kk->drv.p->clients[i].fd == -1)
    185224            continue;
    186225
    187         if(send_data(kk, kk->drv.p->fd_list[i]))
    188             kk->drv.p->fd_list[i] = -1;
     226        if(send_data(kk, &kk->drv.p->clients[i]))
     227            kk->drv.p->clients[i].fd = -1;
    189228    }
    190229
     
    200239{
    201240    /* Manage new connections as this function will be called sometimes
    202      *  more often than display
    203      */
     241     * more often than display */
    204242    manage_connections(kk);
    205243
     
    214252static void manage_connections(caca_t *kk)
    215253{
    216     int fd;
    217 
    218     kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
    219     fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
    220 
     254    int fd, flags;
     255    struct sockaddr_in remote_addr;
     256    socklen_t len = sizeof(struct sockaddr_in);
     257
     258    fd = accept(kk->drv.p->sockfd, (struct sockaddr *)&remote_addr, &len);
    221259    if(fd == -1)
    222260        return;
    223261
    224262    /* Non blocking socket */
    225     fcntl(fd, F_SETFL, O_NONBLOCK);
    226 
    227     if(kk->drv.p->fd_list == NULL)
    228     {
    229         kk->drv.p->fd_list = malloc(sizeof(int));
    230         if(kk->drv.p->fd_list == NULL)
     263    flags = fcntl(fd, F_SETFL, 0);
     264    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
     265
     266    if(kk->drv.p->clients == NULL)
     267    {
     268        kk->drv.p->clients = malloc(sizeof(struct client));
     269        if(kk->drv.p->clients == NULL)
    231270            return;
    232271    }
    233272    else
    234273    {
    235         kk->drv.p->fd_list = realloc(kk->drv.p->fd_list,
    236                                      (kk->drv.p->client_count+1) * sizeof(int));
    237     }
    238 
    239     if(send_data(kk, fd) == 0)
    240     {
    241         kk->drv.p->fd_list[kk->drv.p->client_count] = fd;
    242         kk->drv.p->client_count++;
    243     }
    244 }
    245 
    246 static int send_data(caca_t *kk, int fd)
     274        kk->drv.p->clients = realloc(kk->drv.p->clients,
     275                                     (kk->drv.p->client_count+1) * sizeof(struct client));
     276    }
     277
     278    kk->drv.p->clients[kk->drv.p->client_count].fd = fd;
     279    kk->drv.p->clients[kk->drv.p->client_count].ready = 0;
     280    kk->drv.p->clients[kk->drv.p->client_count].start = 0;
     281    kk->drv.p->clients[kk->drv.p->client_count].stop = 0;
     282
     283    /* If we already have data to send, send it to the new client */
     284    send_data(kk, &kk->drv.p->clients[kk->drv.p->client_count]);
     285
     286    kk->drv.p->client_count++;
     287}
     288
     289static int send_data(caca_t *kk, struct client *c)
    247290{
    248291    ssize_t ret;
     292
     293    /* Not for us */
     294    if(c->fd < 0)
     295        return -1;
     296
     297    /* Debug: show incoming data */
     298    for(;;)
     299    {
     300        unsigned char in;
     301        ret = read(c->fd, &in, 1);
     302        if(ret <= 0)
     303            break;
     304
     305        fprintf(stderr, "client %i said \\x%.02x\n", c->fd, in);
     306    }
     307
     308    /* Send the telnet initialisation commands */
     309    if(!c->ready)
     310    {
     311        ret = nonblock_write(c->fd, kk->drv.p->prefix, sizeof(INIT_PREFIX));
     312        if(ret == -1)
     313            return (errno == EAGAIN) ? 0 : -1;
     314
     315        if(ret < (ssize_t)sizeof(INIT_PREFIX))
     316            return 0;
     317
     318        c->ready = 1;
     319    }
    249320
    250321    /* No error, there's just nothing to send yet */
     
    252323        return 0;
    253324
    254     if(fd < 0)
    255         return -1;
    256 
    257     /* FIXME, handle >255 sizes */
    258     codes[15] = (unsigned char) (kk->drv.p->width & 0xff00)>>8;
    259     codes[16] = (unsigned char) kk->drv.p->width & 0xff;
    260     codes[17] = (unsigned char) (kk->drv.p->height & 0xff00)>>8;
    261     codes[18] = (unsigned char) kk->drv.p->height & 0xff;
    262 
    263     /* Send basic telnet codes */
    264     ret = nonblock_write(fd, codes, sizeof(codes));
     325    /* If we have backlog, send the backlog */
     326    if(c->stop)
     327    {
     328        ret = nonblock_write(c->fd, c->buffer + c->start, c->stop - c->start);
     329
     330        if(ret == -1)
     331        {
     332            if(errno == EAGAIN)
     333                ret = 0;
     334            else
     335                return -1;
     336        }
     337
     338        if(ret == c->stop - c->start)
     339        {
     340            /* We got rid of the backlog! */
     341            c->start = c->stop = 0;
     342        }
     343        else
     344        {
     345            c->start += ret;
     346
     347            if(c->stop - c->start + strlen(ANSI_PREFIX) + kk->drv.p->size
     348                > BACKBUFFER)
     349            {
     350                /* Overflow! Empty buffer and start again */
     351                memcpy(c->buffer, ANSI_RESET, strlen(ANSI_RESET));
     352                c->start = 0;
     353                c->stop = strlen(ANSI_RESET);
     354                return 0;
     355            }
     356
     357            /* Need to move? */
     358            if(c->stop + strlen(ANSI_PREFIX) + kk->drv.p->size > BACKBUFFER)
     359            {
     360                memmove(c->buffer, c->buffer + c->start, c->stop - c->start);
     361                c->stop -= c->start;
     362                c->start = 0;
     363            }
     364
     365            memcpy(c->buffer + c->stop, ANSI_PREFIX, strlen(ANSI_PREFIX));
     366            c->stop += strlen(ANSI_PREFIX);
     367            memcpy(c->buffer + c->stop, kk->drv.p->buffer, kk->drv.p->size);
     368            c->stop += kk->drv.p->size;
     369
     370            return 0;
     371        }
     372    }
     373
     374    /* We no longer have backlog, send our new data */
     375
     376    /* Send ANSI prefix */
     377    ret = nonblock_write(c->fd, ANSI_PREFIX, strlen(ANSI_PREFIX));
    265378    if(ret == -1)
    266         return (errno == EAGAIN) ? 0 : -1;
    267 
    268     /* ANSI code for move(0,0)*/
    269     ret = nonblock_write(fd, "\033[1,1H", 6);
     379    {
     380        if(errno == EAGAIN)
     381            ret = 0;
     382        else
     383            return -1;
     384    }
     385
     386    if(ret < (ssize_t)strlen(ANSI_PREFIX))
     387    {
     388        if(strlen(ANSI_PREFIX) + kk->drv.p->size > BACKBUFFER)
     389        {
     390            /* Overflow! Empty buffer and start again */
     391            memcpy(c->buffer, ANSI_RESET, strlen(ANSI_RESET));
     392            c->start = 0;
     393            c->stop = strlen(ANSI_RESET);
     394            return 0;
     395        }
     396
     397        memcpy(c->buffer, ANSI_PREFIX, strlen(ANSI_PREFIX) - ret);
     398        c->stop = strlen(ANSI_PREFIX) - ret;
     399        memcpy(c->buffer + c->stop, kk->drv.p->buffer, kk->drv.p->size);
     400        c->stop += kk->drv.p->size;
     401
     402        return 0;
     403    }
     404
     405    /* Send actual data */
     406    ret = nonblock_write(c->fd, kk->drv.p->buffer, kk->drv.p->size);
    270407    if(ret == -1)
    271         return (errno == EAGAIN) ? 0 : -1;
    272 
    273     /* Send actual data */
    274     ret = nonblock_write(fd, kk->drv.p->buffer, kk->drv.p->size);
    275     if(ret == -1)
    276         return (errno == EAGAIN) ? 0 : -1;
     408    {
     409        if(errno == EAGAIN)
     410            ret = 0;
     411        else
     412            return -1;
     413    }
     414
     415    if(ret < kk->drv.p->size)
     416    {
     417        if(kk->drv.p->size > BACKBUFFER)
     418        {
     419            /* Overflow! Empty buffer and start again */
     420            memcpy(c->buffer, ANSI_RESET, strlen(ANSI_RESET));
     421            c->start = 0;
     422            c->stop = strlen(ANSI_RESET);
     423            return 0;
     424        }
     425
     426        memcpy(c->buffer, kk->drv.p->buffer, kk->drv.p->size - ret);
     427        c->stop = kk->drv.p->size - ret;
     428
     429        return 0;
     430    }
    277431
    278432    return 0;
     
    281435ssize_t nonblock_write(int fd, char *buf, size_t len)
    282436{
    283     int retries = 10;
    284437    size_t total = 0;
    285438    ssize_t ret;
     
    290443        {
    291444            ret = write(fd, buf, len);
    292             if(ret < 0 && errno == EAGAIN)
    293             {
    294                 retries--;
    295                 if(retries < 0)
    296                     break;
    297             }
    298         }
    299         while(ret < 0 && (errno == EINTR || errno == EAGAIN));
     445        }
     446        while(ret < 0 && errno == EINTR);
    300447
    301448        if(ret < 0)
     
    330477
    331478
    332 #endif // USE_NETWORK
    333 
     479#endif /* USE_NETWORK */
     480
Note: See TracChangeset for help on using the changeset viewer.