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 */
91
int s_poll_wait(s_poll_set *fds, int timeout) {
94
do { /* skip "Interrupted system call" errors */
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])) {
102
/* move ready contexts from waiting queue to ready queue */
103
static void scan_waiting_queue(void) {
109
short *signal_revents;
110
static int max_nfds=0;
111
static struct pollfd *ufds=NULL;
114
/* count file descriptors */
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;
123
/* setup ufds structure */
124
if(nfds>max_nfds) { /* need to allocate more memory */
125
ufds=realloc(ufds, nfds*sizeof(struct pollfd));
127
s_log(LOG_CRIT, "Memory allocation failed");
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;
143
#ifdef DEBUG_UCONTEXT
144
s_log(LOG_DEBUG, "Waiting %d second(s) for %d file descriptor(s)",
147
do { /* skip "Interrupted system call" errors */
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 */
154
} while(retry || (retval<0 && get_last_socket_error()==EINTR));
156
/* process the returned data */
158
prev=NULL; /* previous element of the waiting queue */
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" : "");
176
if(ufds[nfds].revents)
180
if(ctx->ready || (ctx->finish>=0 && ctx->finish<=now)) {
181
/* remove context ctx from the waiting queue */
183
prev->next=ctx->next;
185
waiting_head=ctx->next;
186
if(!ctx->next) /* same as ctx==waiting_tail */
189
/* append context ctx to the ready queue */
192
ready_tail->next=ctx;
196
} else { /* leave the context ctx in the waiting queue */
199
ctx=prev ? prev->next : waiting_head;
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 */
208
/* remove the current context from ready queue */
210
ready_head=ready_head->next;
211
if(!ready_head) /* the queue is empty */
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 */
220
waiting_tail->next=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);
232
s_log(LOG_DEBUG, "Releasing context %ld", to_free->id);
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 */
241
s_log(LOG_DEBUG, "Releasing context %ld", to_free->id);
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 */
255
#else /* USE_UCONTEXT */
257
int s_poll_wait(s_poll_set *fds, int sec, int msec) {
260
do { /* skip "Interrupted system call" errors */
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 */
156
#endif /* HAVE_POLL */
324
#endif /* USE_POLL */
158
326
#ifndef USE_WIN32
160
328
static void sigchld_handler(int sig) { /* SIGCHLD detected */
161
int save_errno=errno;
336
while(wait_for_pid(-1, &status, WNOHANG)>0) {
337
/* no logging is possible in a signal handler */
339
--num_clients; /* one client less */
340
#endif /* USE_FORK */
343
#ifdef __INNOTEK_LIBC__
344
writesocket(signal_pipe[1], signal_buffer, 1);
163
346
write(signal_pipe[1], signal_buffer, 1);
347
#endif /* __INNOTEK_LIBC__ */
164
349
signal(SIGCHLD, sigchld_handler);
165
350
errno=save_errno;
353
/**************************************** signal pipe */
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;
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);
367
alloc_fd(signal_pipe[0]);
368
alloc_fd(signal_pipe[1]);
370
/* Connect the two endpoints */
371
memset(&un, 0, sizeof(un));
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);
388
#else /* __INNOTEK_LIBC__ */
169
389
if(pipe(signal_pipe)) {
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);
399
#endif /* FD_CLOEXEC */
400
#endif /* __INNOTEK_LIBC__ */
180
401
signal(SIGCHLD, sigchld_handler);
181
402
return signal_pipe[0];
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));
185
410
read(signal_pipe[0], signal_buffer, sizeof(signal_buffer));
187
exec_status(); /* report status of 'exec' process */
188
#endif /* USE_PTHREAD */
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 */
194
void exec_status(void) { /* dead local ('exec') process detected */
197
#ifdef HAVE_WAIT_FOR_PID
198
while((pid=wait_for_pid(-1, &status, WNOHANG))>0) {
200
if((pid=wait(&status))>0) {
203
if(WIFSIGNALED(status)) {
204
s_log(LOG_INFO, "Local process %d terminated on signal %d",
205
pid, WTERMSIG(status));
207
s_log(LOG_INFO, "Local process %d finished with code %d",
208
pid, WEXITSTATUS(status));
211
s_log(LOG_INFO, "Local process %d finished with status %d",
218
420
static void client_status(void) { /* dead children detected */
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 */
225
427
if((pid=wait(&status))>0) {
226
num_clients--; /* one client less */
428
--num_clients; /* one client less */
228
430
#ifdef WIFSIGNALED
229
431
if(WIFSIGNALED(status)) {
313
540
return 0; /* OK */
316
int write_blocking(CLI *c, int fd, u8 *ptr, int len) {
543
/**************************************** simulate blocking I/O */
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 */
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)) {
327
555
sockerror("write_blocking: s_poll_wait");
328
return -1; /* error */
556
longjmp(c->err, 1); /* error */
330
558
s_log(LOG_INFO, "write_blocking: s_poll_wait timeout");
331
return -1; /* timeout */
559
longjmp(c->err, 1); /* timeout */
335
563
s_log(LOG_ERR, "write_blocking: s_poll_wait unknown result");
336
return -1; /* error */
564
longjmp(c->err, 1); /* error */
338
566
num=writesocket(fd, ptr, len);
340
568
case -1: /* error */
341
569
sockerror("writesocket (write_blocking)");
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 */
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)) {
361
587
sockerror("read_blocking: s_poll_wait");
362
return -1; /* error */
588
longjmp(c->err, 1); /* error */
364
590
s_log(LOG_INFO, "read_blocking: s_poll_wait timeout");
365
return -1; /* timeout */
591
longjmp(c->err, 1); /* timeout */
369
595
s_log(LOG_ERR, "read_blocking: s_poll_wait unknown result");
370
return -1; /* error */
596
longjmp(c->err, 1); /* error */
372
598
num=readsocket(fd, ptr, len);
374
600
case -1: /* error */
375
601
sockerror("readsocket (read_blocking)");
377
603
case 0: /* EOF */
378
604
s_log(LOG_ERR, "Unexpected socket close (read_blocking)");
612
void fdputline(CLI *c, int fd, const char *line) {
613
char tmpline[STRLEN];
614
const char crlf[]="\r\n";
617
safecopy(tmpline, line);
618
safeconcat(tmpline, crlf);
620
write_blocking(c, fd, tmpline, len);
621
tmpline[len-2]='\0'; /* remove CRLF */
623
s_log(LOG_DEBUG, " -> %s", tmpline);
626
void fdgetline(CLI *c, int fd, char *line) {
627
char tmpline[STRLEN];
633
s_poll_add(&fds, fd, 1, 0); /* read */
634
switch(s_poll_wait(&fds, c->opt->timeout_busy, 0)) {
636
sockerror("fdgetline: s_poll_wait");
637
longjmp(c->err, 1); /* error */
639
s_log(LOG_INFO, "fdgetline: s_poll_wait timeout");
640
longjmp(c->err, 1); /* timeout */
644
s_log(LOG_ERR, "fdgetline: s_poll_wait unknown result");
645
longjmp(c->err, 1); /* error */
647
switch(readsocket(fd, line+ptr, 1)) {
649
sockerror("readsocket (fdgetline)");
652
s_log(LOG_ERR, "Unexpected socket close (fdgetline)");
662
s_log(LOG_ERR, "Input line too long");
667
safecopy(tmpline, line);
669
s_log(LOG_DEBUG, " <- %s", tmpline);
387
672
int fdprintf(CLI *c, int fd, const char *format, ...) {
389
char line[STRLEN], logline[STRLEN];
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);
397
681
len=vsprintf(line, format, arglist);
402
s_log(LOG_ERR, "Line too long in fdprintf");
685
s_log(LOG_ERR, "fdprintf: vs(n)printf failed");
405
safecopy(logline, line); /* The line without crlf */
406
safeconcat(line, crlf);
407
if(write_blocking(c, fd, line, len)<0)
410
s_log(LOG_DEBUG, " -> %s", logline);
688
fdputline(c, fd, line);
414
692
int fdscanf(CLI *c, int fd, const char *format, char *buffer) {
415
char line[STRLEN], logline[STRLEN], lformat[STRLEN];
693
char line[STRLEN], lformat[STRLEN];
419
for(ptr=0; ptr<STRLEN-1; ptr++) {
421
s_poll_add(&fds, fd, 1, 0); /* read */
422
switch(s_poll_wait(&fds, c->opt->timeout_busy)) {
424
sockerror("fdscanf: s_poll_wait");
425
return -1; /* error */
427
s_log(LOG_INFO, "fdscanf: s_poll_wait timeout");
428
return -1; /* timeout */
432
s_log(LOG_ERR, "fdscanf: s_poll_wait unknown result");
433
return -1; /* error */
435
switch(readsocket(fd, line+ptr, 1)) {
437
sockerror("readsocket (fdscanf)");
440
s_log(LOG_ERR, "Unexpected socket close (fdscanf)");
449
safecopy(logline, line);
451
s_log(LOG_DEBUG, " <- %s", logline);
696
fdgetline(c, fd, line);
452
698
retval=sscanf(line, format, buffer);
455
702
s_log(LOG_DEBUG, "fdscanf falling back to lowercase");
456
703
safecopy(lformat, format);
457
704
for(ptr=0; lformat[ptr]; ptr++)