~ubuntu-branches/ubuntu/gutsy/stunnel4/gutsy

« back to all changes in this revision

Viewing changes to src/network.c

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lemoine
  • Date: 2006-11-07 20:22:04 UTC
  • mfrom: (3.1.5 feisty)
  • Revision ID: james.westby@ubuntu.com-20061107202204-b8b3rivwi3nla2pz
Tags: 3:4.18-2
* Updated chroot default path in configuration file
* Added LSB section in init script

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *   stunnel       Universal SSL tunnel
3
 
 *   Copyright (c) 1998-2005 Michal Trojnara <Michal.Trojnara@mirt.net>
 
3
 *   Copyright (c) 1998-2006 Michal Trojnara <Michal.Trojnara@mirt.net>
4
4
 *                 All Rights Reserved
5
5
 *
6
6
 *   This program is free software; you can redistribute it and/or modify
31
31
#include "common.h"
32
32
#include "prototypes.h"
33
33
 
 
34
/* #define DEBUG_UCONTEXT */
 
35
 
34
36
#ifndef USE_WIN32
35
 
static int signal_pipe[2];
 
37
static int signal_pipe[2]={-1, -1};
36
38
static char signal_buffer[16];
37
39
static void sigchld_handler(int);
 
40
#ifdef __INNOTEK_LIBC__
 
41
struct sockaddr_un {
 
42
    u_char  sun_len;             /* sockaddr len including null */
 
43
    u_char  sun_family;          /* AF_OS2 or AF_UNIX */
 
44
    char    sun_path[108];       /* path name */
 
45
};
 
46
#endif
38
47
static void signal_pipe_empty(void);
39
48
#ifdef USE_FORK
40
49
static void client_status(void); /* dead children detected */
41
50
#endif
42
51
#endif /* !defined(USE_WIN32) */
43
52
 
44
 
static void setnonblock(int, unsigned long);
 
53
/**************************************** s_poll functions */
45
54
 
46
 
#ifdef HAVE_POLL
 
55
#ifdef USE_POLL
47
56
 
48
57
void s_poll_zero(s_poll_set *fds) {
49
58
    fds->nfds=0;
75
84
 
76
85
    for(i=0; i<fds->nfds; i++)
77
86
        if(fds->ufds[i].fd==fd)
78
 
            return fds->ufds[i].revents&POLLIN;
 
87
            return fds->ufds[i].revents&~POLLOUT; /* read or error */
79
88
    return 0;
80
89
}
81
90
 
84
93
 
85
94
    for(i=0; i<fds->nfds; i++)
86
95
        if(fds->ufds[i].fd==fd)
87
 
            return fds->ufds[i].revents&POLLOUT;
 
96
            return fds->ufds[i].revents&POLLOUT; /* write */
88
97
    return 0;
89
98
}
90
99
 
91
 
int s_poll_wait(s_poll_set *fds, int timeout) {
92
 
    int retval, retry;
93
 
 
94
 
    do { /* skip "Interrupted system call" errors */
95
 
        retry=0;
96
 
        retval=poll(fds->ufds, fds->nfds, timeout<0 ? -1 : 1000*timeout);
97
 
        if(timeout<0 && retval>0 && s_poll_canread(fds, signal_pipe[0])) {
 
100
#ifdef USE_UCONTEXT
 
101
 
 
102
/* move ready contexts from waiting queue to ready queue */
 
103
static void scan_waiting_queue(void) {
 
104
    int retval, retry;
 
105
    CONTEXT *ctx, *prev;
 
106
    int min_timeout;
 
107
    int nfds, i;
 
108
    time_t now;
 
109
    short *signal_revents;
 
110
    static int max_nfds=0;
 
111
    static struct pollfd *ufds=NULL;
 
112
 
 
113
    time(&now);
 
114
    /* count file descriptors */
 
115
    min_timeout=-1;
 
116
    nfds=0;
 
117
    for(ctx=waiting_head; ctx; ctx=ctx->next) {
 
118
        nfds+=ctx->fds->nfds;
 
119
        if(ctx->finish>=0) /* finite time */
 
120
            if(min_timeout<0 || min_timeout>ctx->finish-now)
 
121
                min_timeout=ctx->finish-now<0 ? 0 : ctx->finish-now;
 
122
    }
 
123
    /* setup ufds structure */
 
124
    if(nfds>max_nfds) { /* need to allocate more memory */
 
125
        ufds=realloc(ufds, nfds*sizeof(struct pollfd));
 
126
        if(!ufds) {
 
127
            s_log(LOG_CRIT, "Memory allocation failed");
 
128
            exit(1);
 
129
        }
 
130
        max_nfds=nfds;
 
131
    }
 
132
    nfds=0;
 
133
    signal_revents=NULL;
 
134
    for(ctx=waiting_head; ctx; ctx=ctx->next)
 
135
        for(i=0; i<ctx->fds->nfds; i++) {
 
136
            ufds[nfds].fd=ctx->fds->ufds[i].fd;
 
137
            ufds[nfds].events=ctx->fds->ufds[i].events;
 
138
            if(ufds[nfds].fd==signal_pipe[0])
 
139
                signal_revents=&ufds[nfds].revents;
 
140
            nfds++;
 
141
        }
 
142
 
 
143
#ifdef DEBUG_UCONTEXT
 
144
    s_log(LOG_DEBUG, "Waiting %d second(s) for %d file descriptor(s)",
 
145
        min_timeout, nfds);
 
146
#endif
 
147
    do { /* skip "Interrupted system call" errors */
 
148
        retry=0;
 
149
        retval=poll(ufds, nfds, min_timeout<0 ? -1 : 1000*min_timeout);
 
150
        if(retval>0 && signal_revents && (*signal_revents & POLLIN)) {
 
151
            signal_pipe_empty(); /* no timeout -> main loop */
 
152
            retry=1;
 
153
        }
 
154
    } while(retry || (retval<0 && get_last_socket_error()==EINTR));
 
155
    time(&now);
 
156
    /* process the returned data */
 
157
    nfds=0;
 
158
    prev=NULL; /* previous element of the waiting queue */
 
159
    ctx=waiting_head;
 
160
    while(ctx) {
 
161
        ctx->ready=0;
 
162
        /* count ready file descriptors in each context */
 
163
        for(i=0; i<ctx->fds->nfds; i++) {
 
164
            ctx->fds->ufds[i].revents=ufds[nfds].revents;
 
165
#ifdef DEBUG_UCONTEXT
 
166
            s_log(LOG_DEBUG, "CONTEXT %ld, FD=%d, (%s%s)->(%s%s%s%s%s)",
 
167
                ctx->id, ufds[nfds].fd,
 
168
                ufds[nfds].events & POLLIN ? "IN" : "",
 
169
                ufds[nfds].events & POLLOUT ? "OUT" : "",
 
170
                ufds[nfds].revents & POLLIN ? "IN" : "",
 
171
                ufds[nfds].revents & POLLOUT ? "OUT" : "",
 
172
                ufds[nfds].revents & POLLERR ? "ERR" : "",
 
173
                ufds[nfds].revents & POLLHUP ? "HUP" : "",
 
174
                ufds[nfds].revents & POLLNVAL ? "NVAL" : "");
 
175
#endif
 
176
            if(ufds[nfds].revents)
 
177
                ctx->ready++;
 
178
            nfds++;
 
179
        }
 
180
        if(ctx->ready || (ctx->finish>=0 && ctx->finish<=now)) {
 
181
            /* remove context ctx from the waiting queue */
 
182
            if(prev)
 
183
                prev->next=ctx->next;
 
184
            else
 
185
                waiting_head=ctx->next;
 
186
            if(!ctx->next) /* same as ctx==waiting_tail */
 
187
                waiting_tail=prev;
 
188
 
 
189
            /* append context ctx to the ready queue */
 
190
            ctx->next=NULL;
 
191
            if(ready_tail)
 
192
                ready_tail->next=ctx;
 
193
            ready_tail=ctx;
 
194
            if(!ready_head)
 
195
                ready_head=ctx;
 
196
        } else { /* leave the context ctx in the waiting queue */
 
197
            prev=ctx;
 
198
        }
 
199
        ctx=prev ? prev->next : waiting_head;
 
200
    }
 
201
}
 
202
 
 
203
int s_poll_wait(s_poll_set *fds, int sec, int msec) {
 
204
    /* FIXME: msec parameter is currently ignored with UCONTEXT threads */
 
205
    CONTEXT *ctx; /* current context */
 
206
    static CONTEXT *to_free=NULL; /* delayed memory deallocation */
 
207
 
 
208
    /* remove the current context from ready queue */
 
209
    ctx=ready_head;
 
210
    ready_head=ready_head->next;
 
211
    if(!ready_head) /* the queue is empty */
 
212
        ready_tail=NULL;
 
213
 
 
214
    if(fds) { /* something to wait for -> swap the context */
 
215
        ctx->fds=fds; /* set file descriptors to wait for */
 
216
        ctx->finish=sec<0 ? -1 : time(NULL)+sec;
 
217
        /* move (append) the current context to the waiting queue */
 
218
        ctx->next=NULL;
 
219
        if(waiting_tail)
 
220
            waiting_tail->next=ctx;
 
221
        waiting_tail=ctx;
 
222
        if(!waiting_head)
 
223
            waiting_head=ctx;
 
224
        while(!ready_head) /* no context ready */
 
225
            scan_waiting_queue();
 
226
        if(ctx->id!=ready_head->id) {
 
227
            s_log(LOG_DEBUG, "Context swap: %ld -> %ld",
 
228
                ctx->id, ready_head->id);
 
229
            swapcontext(&ctx->ctx, &ready_head->ctx);
 
230
            s_log(LOG_DEBUG, "Current context: %ld", ready_head->id);
 
231
            if(to_free) {
 
232
                s_log(LOG_DEBUG, "Releasing context %ld", to_free->id);
 
233
                free(to_free);
 
234
                to_free=NULL;
 
235
            }
 
236
        }
 
237
        return ready_head->ready;
 
238
    } else { /* nothing to wait for -> drop the context */
 
239
        /* it's illegal to deallocate the stack of the current context */
 
240
        if(to_free) {
 
241
            s_log(LOG_DEBUG, "Releasing context %ld", to_free->id);
 
242
            free(to_free);
 
243
        }
 
244
        to_free=ctx;
 
245
        while(!ready_head) /* no context ready */
 
246
            scan_waiting_queue();
 
247
        s_log(LOG_DEBUG, "Context set: %ld (dropped) -> %ld",
 
248
            ctx->id, ready_head->id);
 
249
        setcontext(&ready_head->ctx);
 
250
        ioerror("setcontext"); /* should not ever happen */
 
251
        return 0;
 
252
    }
 
253
}
 
254
 
 
255
#else /* USE_UCONTEXT */
 
256
 
 
257
int s_poll_wait(s_poll_set *fds, int sec, int msec) {
 
258
    int retval, retry;
 
259
 
 
260
    do { /* skip "Interrupted system call" errors */
 
261
        retry=0;
 
262
        retval=poll(fds->ufds, fds->nfds, sec<0 ? -1 : 1000*sec+msec);
 
263
        if(sec<0 && retval>0 && s_poll_canread(fds, signal_pipe[0])) {
98
264
            signal_pipe_empty(); /* no timeout -> main loop */
99
265
            retry=1;
100
266
        }
102
268
    return retval;
103
269
}
104
270
 
105
 
#else /* HAVE_POLL */
 
271
#endif /* USE_UCONTEXT */
 
272
 
 
273
#else /* select */
106
274
 
107
275
void s_poll_zero(s_poll_set *fds) {
108
276
    FD_ZERO(&fds->irfds);
127
295
    return FD_ISSET(fd, &fds->owfds);
128
296
}
129
297
 
130
 
int s_poll_wait(s_poll_set *fds, int timeout) {
 
298
int s_poll_wait(s_poll_set *fds, int sec, int msec) {
131
299
    int retval, retry;
132
300
    struct timeval tv, *tv_ptr;
133
301
 
135
303
        retry=0;
136
304
        memcpy(&fds->orfds, &fds->irfds, sizeof(fd_set));
137
305
        memcpy(&fds->owfds, &fds->iwfds, sizeof(fd_set));
138
 
        if(timeout<0) { /* infinite timeout */
 
306
        if(sec<0) { /* infinite timeout */
139
307
            tv_ptr=NULL;
140
308
        } else {
141
 
            tv.tv_sec=timeout;
142
 
            tv.tv_usec=0;
 
309
            tv.tv_sec=sec;
 
310
            tv.tv_usec=1000*msec;
143
311
            tv_ptr=&tv;
144
312
        }
145
313
        retval=select(fds->max+1, &fds->orfds, &fds->owfds, NULL, tv_ptr);
146
 
#ifndef USE_WIN32
147
 
        if(timeout<0 && retval>0 && s_poll_canread(fds, signal_pipe[0])) {
 
314
#if !defined(USE_WIN32) && !defined(USE_OS2)
 
315
        if(sec<0 && retval>0 && s_poll_canread(fds, signal_pipe[0])) {
148
316
            signal_pipe_empty(); /* no timeout -> main loop */
149
317
            retry=1;
150
318
        }
153
321
    return retval;
154
322
}
155
323
 
156
 
#endif /* HAVE_POLL */
 
324
#endif /* USE_POLL */
157
325
 
158
326
#ifndef USE_WIN32
159
327
 
160
328
static void sigchld_handler(int sig) { /* SIGCHLD detected */
161
 
    int save_errno=errno;
 
329
    int save_errno;
 
330
#ifdef __sgi
 
331
    int status;
 
332
#endif
162
333
 
 
334
    save_errno=errno;
 
335
#ifdef __sgi
 
336
    while(wait_for_pid(-1, &status, WNOHANG)>0) {
 
337
        /* no logging is possible in a signal handler */
 
338
#ifdef USE_FORK
 
339
        --num_clients; /* one client less */
 
340
#endif /* USE_FORK */
 
341
    }
 
342
#else /* __sgi */
 
343
#ifdef __INNOTEK_LIBC__
 
344
    writesocket(signal_pipe[1], signal_buffer, 1);
 
345
#else
163
346
    write(signal_pipe[1], signal_buffer, 1);
 
347
#endif /* __INNOTEK_LIBC__ */
 
348
#endif /* __sgi */
164
349
    signal(SIGCHLD, sigchld_handler);
165
350
    errno=save_errno;
166
351
}
167
352
 
 
353
/**************************************** signal pipe */
 
354
 
168
355
int signal_pipe_init(void) {
 
356
#if defined(__INNOTEK_LIBC__)
 
357
    /* Innotek port of GCC can not use select on a pipe, use local socket instead */
 
358
    struct sockaddr_un un;
 
359
    fd_set set_pipe;
 
360
    int pipe_in;
 
361
 
 
362
    FD_ZERO(&set_pipe);
 
363
    signal_pipe[0] = socket(PF_OS2, SOCK_STREAM, 0);
 
364
    pipe_in=signal_pipe[0];
 
365
    signal_pipe[1] = socket(PF_OS2, SOCK_STREAM, 0);
 
366
 
 
367
    alloc_fd(signal_pipe[0]);
 
368
    alloc_fd(signal_pipe[1]);
 
369
 
 
370
    /* Connect the two endpoints */
 
371
    memset(&un, 0, sizeof(un));
 
372
 
 
373
    un.sun_len = sizeof(un);
 
374
    un.sun_family = AF_OS2;
 
375
    sprintf(un.sun_path, "\\socket\\stunnel-%u", getpid());
 
376
    /* Make the first endpoint listen */
 
377
    bind(signal_pipe[0], (struct sockaddr *)&un, sizeof(un));
 
378
    listen(signal_pipe[0], 5);
 
379
    connect(signal_pipe[1], (struct sockaddr *)&un, sizeof(un));
 
380
    FD_SET(signal_pipe[0], &set_pipe);
 
381
    if (select(signal_pipe[0]+1, &set_pipe, NULL, NULL, NULL)>0) {
 
382
        signal_pipe[0]=accept(signal_pipe[0], NULL, 0);
 
383
        closesocket(pipe_in);
 
384
    } else {
 
385
        sockerror("select");
 
386
        exit(1);
 
387
    }
 
388
#else /* __INNOTEK_LIBC__ */
169
389
    if(pipe(signal_pipe)) {
170
390
        ioerror("pipe");
171
391
        exit(1);
176
396
    /* close the pipe in child execvp */
177
397
    fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
178
398
    fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
179
 
#endif
 
399
#endif /* FD_CLOEXEC */
 
400
#endif /* __INNOTEK_LIBC__ */
180
401
    signal(SIGCHLD, sigchld_handler);
181
402
    return signal_pipe[0];
182
403
}
183
404
 
184
405
static void signal_pipe_empty(void) {
 
406
    s_log(LOG_DEBUG, "Cleaning up the signal pipe");
 
407
#ifdef __INNOTEK_LIBC__
 
408
    readsocket(signal_pipe[0], signal_buffer, sizeof(signal_buffer));
 
409
#else
185
410
    read(signal_pipe[0], signal_buffer, sizeof(signal_buffer));
186
 
#ifdef USE_PTHREAD
187
 
    exec_status(); /* report status of 'exec' process */
188
 
#endif /* USE_PTHREAD */
 
411
#endif
189
412
#ifdef USE_FORK
190
413
    client_status(); /* report status of client process */
 
414
#else /* USE_UCONTEXT || USE_PTHREAD */
 
415
    child_status();  /* report status of libwrap or 'exec' process */
191
416
#endif /* defined USE_FORK */
192
417
}
193
418
 
194
 
void exec_status(void) { /* dead local ('exec') process detected */
195
 
    int pid, status;
196
 
 
197
 
#ifdef HAVE_WAIT_FOR_PID
198
 
    while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
199
 
#else
200
 
    if((pid=wait(&status))>0) {
201
 
#endif
202
 
#ifdef WIFSIGNALED
203
 
        if(WIFSIGNALED(status)) {
204
 
            s_log(LOG_INFO, "Local process %d terminated on signal %d",
205
 
                pid, WTERMSIG(status));
206
 
        } else {
207
 
            s_log(LOG_INFO, "Local process %d finished with code %d",
208
 
                pid, WEXITSTATUS(status));
209
 
        }
210
 
#else
211
 
        s_log(LOG_INFO, "Local process %d finished with status %d",
212
 
            pid, status);
213
 
#endif
214
 
    }
215
 
}
216
 
 
217
419
#ifdef USE_FORK
218
420
static void client_status(void) { /* dead children detected */
219
421
    int pid, status;
220
422
 
221
423
#ifdef HAVE_WAIT_FOR_PID
222
424
    while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
223
 
        num_clients--; /* one client less */
 
425
        --num_clients; /* one client less */
224
426
#else
225
427
    if((pid=wait(&status))>0) {
226
 
        num_clients--; /* one client less */
 
428
        --num_clients; /* one client less */
227
429
#endif
228
430
#ifdef WIFSIGNALED
229
431
        if(WIFSIGNALED(status)) {
242
444
}
243
445
#endif /* defined USE_FORK */
244
446
 
 
447
void child_status(void) { /* dead libwrap or 'exec' process detected */
 
448
    int pid, status;
 
449
 
 
450
#ifdef HAVE_WAIT_FOR_PID
 
451
    while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
 
452
#else
 
453
    if((pid=wait(&status))>0) {
 
454
#endif
 
455
#ifdef WIFSIGNALED
 
456
        if(WIFSIGNALED(status)) {
 
457
            s_log(LOG_INFO, "Child process %d terminated on signal %d",
 
458
                pid, WTERMSIG(status));
 
459
        } else {
 
460
            s_log(LOG_INFO, "Child process %d finished with code %d",
 
461
                pid, WEXITSTATUS(status));
 
462
        }
 
463
#else
 
464
        s_log(LOG_INFO, "Child process %d finished with status %d",
 
465
            pid, status);
 
466
#endif
 
467
    }
 
468
}
 
469
 
245
470
#endif /* !defined USE_WIN32 */
246
471
 
 
472
/**************************************** fd management */
 
473
 
247
474
int alloc_fd(int sock) {
248
475
#ifndef USE_WIN32
249
476
    if(!max_fds || sock>=max_fds) {
262
489
#define O_NONBLOCK O_NDELAY
263
490
#endif
264
491
 
265
 
static void setnonblock(int sock, unsigned long l) {
266
 
#if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK
 
492
void setnonblock(int sock, unsigned long l) {
 
493
#if defined F_GETFL && defined F_SETFL && defined O_NONBLOCK && !defined __INNOTEK_LIBC__
267
494
    int retval, flags;
268
495
    do {
269
496
        flags=fcntl(sock, F_GETFL, 0);
270
497
    }while(flags<0 && get_last_socket_error()==EINTR);
271
 
    flags=l ? flags|O_NONBLOCK : flags&(~O_NONBLOCK);
 
498
    flags=l ? flags|O_NONBLOCK : flags&~O_NONBLOCK;
272
499
    do {
273
500
        retval=fcntl(sock, F_SETFL, flags);
274
501
    }while(retval<0 && get_last_socket_error()==EINTR);
313
540
    return 0; /* OK */
314
541
}
315
542
 
316
 
int write_blocking(CLI *c, int fd, u8 *ptr, int len) {
 
543
/**************************************** simulate blocking I/O */
 
544
 
 
545
void write_blocking(CLI *c, int fd, void *ptr, int len) {
317
546
        /* simulate a blocking write */
318
 
        /* returns 0 on success, -1 on failure */
319
547
    s_poll_set fds;
320
548
    int num;
321
549
 
322
550
    while(len>0) {
323
551
        s_poll_zero(&fds);
324
552
        s_poll_add(&fds, fd, 0, 1); /* write */
325
 
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
 
553
        switch(s_poll_wait(&fds, c->opt->timeout_busy, 0)) {
326
554
        case -1:
327
555
            sockerror("write_blocking: s_poll_wait");
328
 
            return -1; /* error */
 
556
            longjmp(c->err, 1); /* error */
329
557
        case 0:
330
558
            s_log(LOG_INFO, "write_blocking: s_poll_wait timeout");
331
 
            return -1; /* timeout */
 
559
            longjmp(c->err, 1); /* timeout */
332
560
        case 1:
333
561
            break; /* OK */
334
562
        default:
335
563
            s_log(LOG_ERR, "write_blocking: s_poll_wait unknown result");
336
 
            return -1; /* error */
 
564
            longjmp(c->err, 1); /* error */
337
565
        }
338
566
        num=writesocket(fd, ptr, len);
339
567
        switch(num) {
340
568
        case -1: /* error */
341
569
            sockerror("writesocket (write_blocking)");
342
 
            return -1;
 
570
            longjmp(c->err, 1);
343
571
        }
344
 
        ptr+=num;
 
572
        ptr=(u8 *)ptr+num;
345
573
        len-=num;
346
574
    }
347
 
    return 0; /* OK */
348
575
}
349
576
 
350
 
int read_blocking(CLI *c, int fd, u8 *ptr, int len) {
 
577
void read_blocking(CLI *c, int fd, void *ptr, int len) {
351
578
        /* simulate a blocking read */
352
 
        /* returns 0 on success, -1 on failure */
353
579
    s_poll_set fds;
354
580
    int num;
355
581
 
356
582
    while(len>0) {
357
583
        s_poll_zero(&fds);
358
584
        s_poll_add(&fds, fd, 1, 0); /* read */
359
 
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
 
585
        switch(s_poll_wait(&fds, c->opt->timeout_busy, 0)) {
360
586
        case -1:
361
587
            sockerror("read_blocking: s_poll_wait");
362
 
            return -1; /* error */
 
588
            longjmp(c->err, 1); /* error */
363
589
        case 0:
364
590
            s_log(LOG_INFO, "read_blocking: s_poll_wait timeout");
365
 
            return -1; /* timeout */
 
591
            longjmp(c->err, 1); /* timeout */
366
592
        case 1:
367
593
            break; /* OK */
368
594
        default:
369
595
            s_log(LOG_ERR, "read_blocking: s_poll_wait unknown result");
370
 
            return -1; /* error */
 
596
            longjmp(c->err, 1); /* error */
371
597
        }
372
598
        num=readsocket(fd, ptr, len);
373
599
        switch(num) {
374
600
        case -1: /* error */
375
601
            sockerror("readsocket (read_blocking)");
376
 
            return -1;
 
602
            longjmp(c->err, 1);
377
603
        case 0: /* EOF */
378
604
            s_log(LOG_ERR, "Unexpected socket close (read_blocking)");
379
 
            return -1;
 
605
            longjmp(c->err, 1);
380
606
        }
381
 
        ptr+=num;
 
607
        ptr=(u8 *)ptr+num;
382
608
        len-=num;
383
609
    }
384
 
    return 0; /* OK */
 
610
}
 
611
 
 
612
void fdputline(CLI *c, int fd, const char *line) {
 
613
    char tmpline[STRLEN];
 
614
    const char crlf[]="\r\n";
 
615
    int len;
 
616
 
 
617
    safecopy(tmpline, line);
 
618
    safeconcat(tmpline, crlf);
 
619
    len=strlen(tmpline);
 
620
    write_blocking(c, fd, tmpline, len);
 
621
    tmpline[len-2]='\0'; /* remove CRLF */
 
622
    safestring(tmpline);
 
623
    s_log(LOG_DEBUG, " -> %s", tmpline);
 
624
}
 
625
 
 
626
void fdgetline(CLI *c, int fd, char *line) {
 
627
    char tmpline[STRLEN];
 
628
    s_poll_set fds;
 
629
    int ptr;
 
630
 
 
631
    for(ptr=0;;) {
 
632
        s_poll_zero(&fds);
 
633
        s_poll_add(&fds, fd, 1, 0); /* read */
 
634
        switch(s_poll_wait(&fds, c->opt->timeout_busy, 0)) {
 
635
        case -1:
 
636
            sockerror("fdgetline: s_poll_wait");
 
637
            longjmp(c->err, 1); /* error */
 
638
        case 0:
 
639
            s_log(LOG_INFO, "fdgetline: s_poll_wait timeout");
 
640
            longjmp(c->err, 1); /* timeout */
 
641
        case 1:
 
642
            break; /* OK */
 
643
        default:
 
644
            s_log(LOG_ERR, "fdgetline: s_poll_wait unknown result");
 
645
            longjmp(c->err, 1); /* error */
 
646
        }
 
647
        switch(readsocket(fd, line+ptr, 1)) {
 
648
        case -1: /* error */
 
649
            sockerror("readsocket (fdgetline)");
 
650
            longjmp(c->err, 1);
 
651
        case 0: /* EOF */
 
652
            s_log(LOG_ERR, "Unexpected socket close (fdgetline)");
 
653
            longjmp(c->err, 1);
 
654
        }
 
655
        if(line[ptr]=='\r')
 
656
            continue;
 
657
        if(line[ptr]=='\n')
 
658
            break;
 
659
        if(!line[ptr])
 
660
            break;
 
661
        if(++ptr==STRLEN) {
 
662
            s_log(LOG_ERR, "Input line too long");
 
663
            longjmp(c->err, 1);
 
664
        }
 
665
    }
 
666
    line[ptr]='\0';
 
667
    safecopy(tmpline, line);
 
668
    safestring(tmpline);
 
669
    s_log(LOG_DEBUG, " <- %s", tmpline);
385
670
}
386
671
 
387
672
int fdprintf(CLI *c, int fd, const char *format, ...) {
388
673
    va_list arglist;
389
 
    char line[STRLEN], logline[STRLEN];
390
 
    char crlf[]="\r\n";
 
674
    char line[STRLEN];
391
675
    int len;
392
676
 
393
677
    va_start(arglist, format);
394
678
#ifdef HAVE_VSNPRINTF
395
 
    len=vsnprintf(line, STRLEN, format, arglist);
 
679
    len=vsnprintf(line, STRLEN-2, format, arglist);
396
680
#else
397
681
    len=vsprintf(line, format, arglist);
398
682
#endif
399
683
    va_end(arglist);
400
 
    len+=2;
401
 
    if(len>=STRLEN) {
402
 
        s_log(LOG_ERR, "Line too long in fdprintf");
403
 
        return -1;
 
684
    if(len<0) {
 
685
        s_log(LOG_ERR, "fdprintf: vs(n)printf failed");
 
686
        longjmp(c->err, 1);
404
687
    }
405
 
    safecopy(logline, line); /* The line without crlf */
406
 
    safeconcat(line, crlf);
407
 
    if(write_blocking(c, fd, line, len)<0)
408
 
        return -1;
409
 
    safestring(logline);
410
 
    s_log(LOG_DEBUG, " -> %s", logline);
411
 
    return len;
 
688
    fdputline(c, fd, line);
 
689
    return len+2;
412
690
}
413
691
 
414
692
int fdscanf(CLI *c, int fd, const char *format, char *buffer) {
415
 
    char line[STRLEN], logline[STRLEN], lformat[STRLEN];
416
 
    s_poll_set fds;
 
693
    char line[STRLEN], lformat[STRLEN];
417
694
    int ptr, retval;
418
695
 
419
 
    for(ptr=0; ptr<STRLEN-1; ptr++) {
420
 
        s_poll_zero(&fds);
421
 
        s_poll_add(&fds, fd, 1, 0); /* read */
422
 
        switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
423
 
        case -1:
424
 
            sockerror("fdscanf: s_poll_wait");
425
 
            return -1; /* error */
426
 
        case 0:
427
 
            s_log(LOG_INFO, "fdscanf: s_poll_wait timeout");
428
 
            return -1; /* timeout */
429
 
        case 1:
430
 
            break; /* OK */
431
 
        default:
432
 
            s_log(LOG_ERR, "fdscanf: s_poll_wait unknown result");
433
 
            return -1; /* error */
434
 
        }
435
 
        switch(readsocket(fd, line+ptr, 1)) {
436
 
        case -1: /* error */
437
 
            sockerror("readsocket (fdscanf)");
438
 
            return -1;
439
 
        case 0: /* EOF */
440
 
            s_log(LOG_ERR, "Unexpected socket close (fdscanf)");
441
 
            return -1;
442
 
        }
443
 
        if(line[ptr]=='\r')
444
 
            continue;
445
 
        if(line[ptr]=='\n')
446
 
            break;
447
 
    }
448
 
    line[ptr]='\0';
449
 
    safecopy(logline, line);
450
 
    safestring(logline);
451
 
    s_log(LOG_DEBUG, " <- %s", logline);
 
696
    fdgetline(c, fd, line);
 
697
 
452
698
    retval=sscanf(line, format, buffer);
453
699
    if(retval>=0)
454
700
        return retval;
 
701
 
455
702
    s_log(LOG_DEBUG, "fdscanf falling back to lowercase");
456
703
    safecopy(lformat, format);
457
704
    for(ptr=0; lformat[ptr]; ptr++)