io.c 9.93 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1
2
/* io.c
 *
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 *
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
24
25
 */

Niels Möller's avatar
Niels Möller committed
26
27
28
#include <assert.h>
#include <string.h>

Niels Möller's avatar
Niels Möller committed
29
30
31
32
33
34
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
Niels Möller's avatar
Niels Möller committed
35
#include <arpa/inet.h>
Niels Möller's avatar
Niels Möller committed
36

Niels Möller's avatar
Niels Möller committed
37
38
39
40
41
#include "io.h"
#include "werror.h"
#include "write_buffer.h"
#include "xalloc.h"

Niels Möller's avatar
Niels Möller committed
42
43
44
45
46
/* A little more than an hour */
#define MAX_TIMEOUT 4000

struct fd_read
{
47
  struct abstract_read super;
Niels Möller's avatar
Niels Möller committed
48
49
50
  int fd;
};

Niels Möller's avatar
Niels Möller committed
51
static int do_read(struct abstract_read **r, UINT32 length, UINT8 *buffer)
Niels Möller's avatar
Niels Möller committed
52
{
53
54
55
  struct fd_read *closure
    = (struct fd_read *) *r;

56
57
58
59
60
61
62
  while(1)
    {
      int res = read(closure->fd, buffer, length);
      if (!res)
	return A_EOF;
      if (res > 0)
	return res;
63

64
65
66
67
68
69
70
      switch(errno)
	{
	case EINTR:
	  continue;
	case EWOULDBLOCK:  /* aka EAGAIN */
	  return 0;
	default:
Niels Möller's avatar
Niels Möller committed
71
72
73
74
	  werror("io.c: do_read: read() failed (errno %d), %s\n",
		 errno, strerror(errno));
	  debug("  fd = %d, buffer = %p, length = %ud\n",
		closure->fd, buffer, length);
75
76
77
78
	  return A_FAIL;
	}
    }
}
Niels Möller's avatar
Niels Möller committed
79

80
81
82
#define FOR_FDS(type, fd, list, extra)				\
{								\
  type **(_fd);							\
Niels Möller's avatar
Niels Möller committed
83
  type *(fd);							\
Niels Möller's avatar
Niels Möller committed
84
  for(_fd = &(list); ((fd) = *_fd); (extra)) {
85
86


Niels Möller's avatar
Niels Möller committed
87
88
89
#define END_FOR_FDS _fd = &(*_fd)->next; } }

/* UNLINK_FD must be followed by a continue, to avoid updating _fd */
90
#define UNLINK_FD (*_fd = (*_fd)->next)
91

92
static int io_iter(struct io_backend *b)
Niels Möller's avatar
Niels Möller committed
93
{
94
95
96
97
98
99
100
101
102
  struct pollfd *fds;
  int i;
  unsigned long nfds; /* FIXME: Should be nfds_t if that type is defined */
  int timeout;
  int res;

  nfds = b->nio + b->nlisten + b->nconnect;

  if (b->callouts)
Niels Möller's avatar
Niels Möller committed
103
    {
104
105
106
      time_t now = time(NULL);
      if (now >= b->callouts->when)
	timeout = 0;
Niels Möller's avatar
Niels Möller committed
107
      else
108
109
110
111
112
113
114
115
116
117
118
119
120
121
	{
	  if (b->callouts->when > now + MAX_TIMEOUT)
	    timeout = MAX_TIMEOUT * 1000;
	  else
	    timeout = (b->callouts->when - now) * 1000;
	}
    }
  else
    {
      if (!nfds)
	/* All done */
	return 0;
      timeout = -1;
    }
122

123
  fds = alloca(sizeof(struct pollfd) * nfds);
Niels Möller's avatar
Niels Möller committed
124

125
126
  /* Handle fds in order: write, read, accept, connect. */
  i = 0;
127

128
129
130
131
132
133
134
135
136
137
138
139
  FOR_FDS(struct io_fd, fd, b->io, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = 0;
      if (!fd->on_hold)
	fds[i].events |= POLLIN;

      /* pre_write returns 0 if the buffer is empty */
      if (write_buffer_pre_write(fd->buffer))
	fds[i].events |= POLLOUT;
    }
  END_FOR_FDS;
140

141
142
143
144
145
146
  FOR_FDS(struct listen_fd, fd, b->listen, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = POLLIN;
    }
  END_FOR_FDS;
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  FOR_FDS(struct connect_fd, fd, b->connect, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = POLLOUT;
    }
  END_FOR_FDS;

  res = poll(fds, nfds, timeout);

  if (!res)
    {
      /* Timeout. Run the callout */
      struct callout *f = b->callouts;

      if (!CALLBACK(f->callout))
	fatal("What now?");
      b->callouts = f->next;
      lsh_free(f);
    }
  if (res<0)
    {
      switch(errno)
	{
	case EAGAIN:
	case EINTR:
	  return 1;
	default:
	  fatal("io_run:poll failed: %s", strerror(errno));
	}
    }
  else
    { /* Process files */
      i = 0;

      /* Handle writing first */
      FOR_FDS(struct io_fd, fd, b->io, i++)
	{
	  if (fds[i].revents & POLLOUT)
	    {
	      UINT32 size = MIN(fd->buffer->end - fd->buffer->start,
				fd->buffer->block_size);
	      int res = write(fd->fd,
			      fd->buffer->buffer + fd->buffer->start,
			      size);
	      if (!res)
		fatal("Closed?");
	      if (res < 0)
		switch(errno)
		  {
		  case EINTR:
		  case EAGAIN:
		    break;
		  default:
		    werror("io.c: write failed, %s\n", strerror(errno));
		    CALLBACK(fd->close_callback);

		    fd->please_close = 1;

		    break;
		  }
	      else if (!res)
		fatal("What now?");
	      else
		fd->buffer->start += res;
	    }
	}
214
215
      END_FOR_FDS;

216
217
218
219
220
221
222
223
224
      /* Handle reading */
      i = 0; /* Start over */
      FOR_FDS(struct io_fd, fd, b->io, i++)
	{
	  if (!fd->please_close
	      && (fds[i].revents & POLLIN))
	    {
	      struct fd_read r =
	      { { do_read }, fd->fd };
Niels Möller's avatar
Niels Möller committed
225

226
227
228
	      /* The handler function may install a new handler */
	      if (!READ_HANDLER(fd->handler,
				&r.super))
Niels Möller's avatar
Niels Möller committed
229
		{
230
231
232
233
234
235
236
		  /* FIXME: Perhaps we should not close yet, but
		   * stop reading and close as soon as the write
		   * buffer is flushed? But in that case, we
		   * probably also want to set some flag on the
		   * write buffer so that no more data can be
		   * written into it. */
		  fd->please_close = 1;
Niels Möller's avatar
Niels Möller committed
237
		}
238
	    }
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	  if (fd->please_close)
	    {
	      /* FIXME: Cleanup properly...
	       *
	       * After a write error, read state must be freed,
	       * and vice versa. */
	      UNLINK_FD;
	      b->nio--;
	      if (fd->handler)
		lsh_free(fd->handler);
	      lsh_free(fd->buffer);
	      lsh_free(fd);
	      continue;
	    }
	}
      END_FOR_FDS;
255

256
257
258
      FOR_FDS(struct listen_fd, fd, b->listen, i++)
	{
	  if (fds[i].revents & POLLIN)
Niels Möller's avatar
Niels Möller committed
259
	    {
260
261
262
	      /* FIXME: Do something with the peer address? */
	      struct sockaddr_in peer;
	      size_t addr_len = sizeof(peer);
Niels Möller's avatar
Niels Möller committed
263
		  
264
265
266
267
268
269
	      int conn = accept(fd->fd,
				(struct sockaddr *) &peer, &addr_len);
	      if (conn < 0)
		{
		  werror("io.c: accept() failed, %s", strerror(errno));
		  continue;
Niels Möller's avatar
Niels Möller committed
270
		}
271
	      if (!FD_CALLBACK(fd->callback, conn))
Niels Möller's avatar
Niels Möller committed
272
		{
273
		  /* FIXME: Should fd be closed here? */
274
		  UNLINK_FD;
Niels Möller's avatar
Niels Möller committed
275
		  lsh_free(fd);
Niels Möller's avatar
Niels Möller committed
276
		  continue;
Niels Möller's avatar
Niels Möller committed
277
278
		}
	    }
279
	}
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
      END_FOR_FDS;
	  
      FOR_FDS(struct connect_fd, fd, b->connect, i++)
	{
	  if (fds[i].revents & POLLOUT)
	    {
	      if (!FD_CALLBACK(fd->callback, fd->fd))
		fatal("What now?");
	      b->nconnect--;
	      UNLINK_FD;
	      lsh_free(fd);
	      continue;
	    }
	}
      END_FOR_FDS;
    }
  return 1;
}

void io_run(struct io_backend *b)
{
  while(io_iter(b))
    ;
303
304
305
306
307
}

/*
 * Fill in ADDR from HOST, SERVICE and PROTOCOL.
 * Supplying a null pointer for HOST means use INADDR_ANY.
308
 * Otherwise HOST is an numbers-and-dots ip-number or a dns name.
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
 *
 * PROTOCOL can be tcp or udp.
 *
 * Supplying a null pointer for SERVICE, means use port 0, i.e. no port.
 * 
 * Returns zero on errors, 1 if everything is ok.
 */
int
get_inaddr(struct sockaddr_in	* addr,
	   const char		* host,
	   const char		* service,
	   const char		* protocol)
{
  memset(addr, 0, sizeof *addr);
  addr->sin_family = AF_INET;

  /*
   *  Set host part of ADDR
   */
  if (host == NULL)
    addr->sin_addr.s_addr = INADDR_ANY;
  else
    {
      /* First check for numerical ip-number */
      addr->sin_addr.s_addr = inet_addr(host);
      if (addr->sin_addr.s_addr == (unsigned long)-1)
	{
	  struct hostent * hp;
	  
	  hp = gethostbyname(host);
	  if (hp == NULL)
	    return 0;
	  memcpy(&addr->sin_addr, hp->h_addr, hp->h_length);
	  addr->sin_family = hp->h_addrtype;
	}
    }

  /*
   *  Set port part of ADDR
   */
  if (service == NULL)
    addr->sin_port = htons(0);
  else
    {
      char		* end;
      long		  portno;

      portno = strtol(service, &end, 10);
      if (portno > 0  &&  portno <= 65535
	  &&  end != service  &&  *end == '\0')
	{
	  addr->sin_port = htons(portno);
	}
      else
	{
	  struct servent	* serv;

	  serv = getservbyname(service, "tcp");
	  if (serv == NULL)
	    return 0;
	  addr->sin_port = serv->s_port;
Niels Möller's avatar
Niels Möller committed
370
371
	}
    }
372
373

  return 1;
Niels Möller's avatar
Niels Möller committed
374
375
376
377
378
379
380
381
}

void io_set_nonblocking(int fd)
{
  if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
    fatal("io_set_nonblocking: fcntl() failed, %s", strerror(errno));
}

382
383
384
385
386
/* Some code is taken from bellman's tcputils. */
struct connect_fd *io_connect(struct io_backend *b,
			      struct sockaddr_in *remote,
			      struct sockaddr_in *local,
			      struct fd_callback *f)
Niels Möller's avatar
Niels Möller committed
387
{
388
389
  struct connect_fd *fd;
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Niels Möller's avatar
Niels Möller committed
390
  
391
392
  if (s<0)
    return NULL;
Niels Möller's avatar
Niels Möller committed
393

394
  io_set_nonblocking(s);
Niels Möller's avatar
Niels Möller committed
395

396
397
398
399
400
401
402
  if (local  &&  bind(s, (struct sockaddr *)local, sizeof *local) < 0)
    {
      int saved_errno = errno;
      close(s);
      errno = saved_errno;
      return NULL;
    }
Niels Möller's avatar
Niels Möller committed
403

404
405
406
407
408
409
410
411
412
413
414
  if ( (connect(s, (struct sockaddr *)remote, sizeof *remote) < 0)
       && (errno != EINPROGRESS) )       
    {
      int saved_errno = errno;
      close(s);
      errno = saved_errno;
      return NULL;
    }
  
  fd = xalloc(sizeof(struct connect_fd));
  fd->fd = s;
Niels Möller's avatar
Niels Möller committed
415
  fd->callback = f;
416
417
418

  fd->next = b->connect;
  b->connect = fd;
Niels Möller's avatar
Niels Möller committed
419

420
421
422
  b->nconnect++;
  
  return fd;
Niels Möller's avatar
Niels Möller committed
423
424
}

425
426
427
428
429
430
struct listen_fd *io_listen(struct io_backend *b,
			    struct sockaddr_in *local,
			    struct fd_callback *callback)
{
  struct listen_fd *fd;
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Niels Möller's avatar
Niels Möller committed
431
  
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
  if (s<0)
    return NULL;

  io_set_nonblocking(s);

  {
    int yes = 1;
    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof yes);
  }

  if (bind(s, (struct sockaddr *)local, sizeof *local) < 0)
    {
      close(s);
      return NULL;
    }

  if (listen(s, 256) < 0) 
    {
      close(s);
      return NULL;
    }

  fd = xalloc(sizeof(struct connect_fd));

  fd->fd = s;
  fd->callback = callback;

  fd->next = b->listen;
  b->listen = fd;
  b->nlisten++;
Niels Möller's avatar
Niels Möller committed
462
  
463
464
465
  return fd;
}

Niels Möller's avatar
Niels Möller committed
466
467
struct abstract_write *io_read_write(struct io_backend *b,
				     int fd,
Niels Möller's avatar
Niels Möller committed
468
				     struct read_handler *read_callback,
Niels Möller's avatar
Niels Möller committed
469
470
				     UINT32 block_size,
				     struct callback *close_callback)
471
{
Niels Möller's avatar
Niels Möller committed
472
  struct io_fd *f= xalloc(sizeof(struct io_fd));
473
474
  struct write_buffer *buffer = write_buffer_alloc(block_size);
  
Niels Möller's avatar
Niels Möller committed
475
476
  f->fd = fd;
  f->please_close = 0;
Niels Möller's avatar
Niels Möller committed
477
  
Niels Möller's avatar
Niels Möller committed
478
479
480
  f->handler = read_callback;
  f->close_callback = close_callback;
  f->buffer = buffer;
481

Niels Möller's avatar
Niels Möller committed
482
483
  f->next = b->io;
  b->io = f;
Niels Möller's avatar
Niels Möller committed
484
  b->nio++;
485

486
  return &buffer->super;
487
}