Ignore:
Timestamp:
Mar 10, 2006, 8:21:33 PM (14 years ago)
Author:
Sam Hocevar
Message:
  • Set the client sockets as non-blocking, and implemented non-blocking writes. Currently works very badly with more than one client.
File:
1 edited

Legend:

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

    r586 r590  
    2828#include <fcntl.h>
    2929#include <string.h>
     30#include <signal.h>
     31#include <errno.h>
    3032
    3133#if defined(HAVE_UNISTD_H)
     
    4143static void manage_connections(caca_t *kk);
    4244static int send_data(caca_t *kk, int fd);
    43 
     45ssize_t nonblock_write(int fd, char *buf, size_t len);
    4446
    4547struct driver_private
    46 { 
     48{
    4749    unsigned int width, height;
    4850    unsigned int port;
     
    6769
    6870/* Following vars are static */
    69 static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO                                                             
     71static char codes[] = {0xff, 0xfb, 0x01,  // WILL ECHO
    7072                       0xff, 0xfb, 0x03,  // WILL SUPPRESS GO AHEAD
    7173                       0xff, 253, 31,     // DO NAWS
     
    9597    }
    9698#endif
    97    
     99
    98100
    99101    kk->drv.p->width = 80;
     
    113115
    114116    if (setsockopt(kk->drv.p->sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
    115         perror("setsockopt");
     117        perror("setsockopt SO_REUSEADDR");
    116118        return -1;
    117119    }
    118120
    119121    kk->drv.p->my_addr.sin_family = AF_INET;
    120     kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port); 
     122    kk->drv.p-> my_addr.sin_port = htons(kk->drv.p->port);
    121123    kk->drv.p->my_addr.sin_addr.s_addr = INADDR_ANY;
    122124    memset(&(kk->drv.p->my_addr.sin_zero), '\0', 8);
     
    138140    kk->drv.p->buffer = NULL;
    139141
     142    /* Ignore SIGPIPE */
     143    signal(SIGPIPE, SIG_IGN);
     144
    140145    return 0;
    141146}
     
    177182    for(i = 0; i < kk->drv.p->client_count; i++)
    178183    {
     184        if(kk->drv.p->fd_list[i] == -1)
     185            continue;
     186
    179187        if(send_data(kk, kk->drv.p->fd_list[i]))
    180188            kk->drv.p->fd_list[i] = -1;
     
    183191    manage_connections(kk);
    184192}
    185  
     193
    186194static void network_handle_resize(caca_t *kk)
    187195{
     
    192200{
    193201    /* Manage new connections as this function will be called sometimes
    194      *  more often than display 
     202     *  more often than display
    195203     */
    196204    manage_connections(kk);
     
    210218    kk->drv.p->clilen = sizeof(kk->drv.p->remote_addr);
    211219    fd = accept(kk->drv.p->sockfd, (struct sockaddr *) &kk->drv.p->remote_addr, &kk->drv.p->clilen);
    212     if(fd != -1) /* That's non blocking socket, -1 if no connection received */
    213     {
     220
     221    if(fd == -1)
     222        return;
     223
     224    /* 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));
    214230        if(kk->drv.p->fd_list == NULL)
    215         {
    216             kk->drv.p->fd_list = malloc(sizeof(int));
    217             if(kk->drv.p->fd_list == NULL)
    218                 return;
    219         }
    220         else
    221         {
    222             kk->drv.p->fd_list = realloc(kk->drv.p->fd_list, (kk->drv.p->client_count+1) * sizeof(int));
    223         }
    224 
    225         if(send_data(kk, fd) == 0)
    226         {
    227             kk->drv.p->fd_list[kk->drv.p->client_count] = fd;
    228             kk->drv.p->client_count++;
    229         }
     231            return;
     232    }
     233    else
     234    {
     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++;
    230243    }
    231244}
     
    233246static int send_data(caca_t *kk, int fd)
    234247{
     248    ssize_t ret;
     249
    235250    /* No error, there's just nothing to send yet */
    236251    if(!kk->drv.p->buffer)
     
    245260    codes[17] = (unsigned char) (kk->drv.p->height & 0xff00)>>8;
    246261    codes[18] = (unsigned char) kk->drv.p->height & 0xff;
    247            
     262
    248263    /* Send basic telnet codes */
    249     if (send(fd, codes,sizeof(codes) , 0) == -1)
    250         return -1;
    251    
     264    ret = nonblock_write(fd, codes, sizeof(codes));
     265    if(ret == -1)
     266        return (errno == EAGAIN) ? 0 : -1;
     267
    252268    /* ANSI code for move(0,0)*/
    253     if (send(fd, "\033[1,1H", 6, 0) == -1)
    254         return -1;
    255    
     269    ret = nonblock_write(fd, "\033[1,1H", 6);
     270    if(ret == -1)
     271        return (errno == EAGAIN) ? 0 : -1;
     272
    256273    /* Send actual data */
    257     if (send(fd, kk->drv.p->buffer, kk->drv.p->size, 0) == -1)
    258         return -1;
    259 
    260     return 0;
     274    ret = nonblock_write(fd, kk->drv.p->buffer, kk->drv.p->size);
     275    if(ret == -1)
     276        return (errno == EAGAIN) ? 0 : -1;
     277
     278    return 0;
     279}
     280
     281ssize_t nonblock_write(int fd, char *buf, size_t len)
     282{
     283    int retries = 10;
     284    size_t total = 0;
     285    ssize_t ret;
     286
     287    while(total < len)
     288    {
     289        do
     290        {
     291            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));
     300
     301        if(ret < 0)
     302            return ret;
     303        else if(ret == 0)
     304            return total;
     305
     306        total += len;
     307        buf += len;
     308    }
     309
     310    return total;
    261311}
    262312
Note: See TracChangeset for help on using the changeset viewer.