io.c 17 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>
36
#include <signal.h>
Niels Möller's avatar
Niels Möller committed
37

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

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

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

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

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

67
68
69
      switch(errno)
	{
	case EINTR:
70
71
	  continue;  /* FIXME: Is it really worth looping here,
		      * instead of in the select loop? */
72
73
	case EWOULDBLOCK:  /* aka EAGAIN */
	  return 0;
Niels Möller's avatar
Niels Möller committed
74
75
76
	case EPIPE:
	  werror("io.c: read() returned EPIPE! Treating it as EOF.\n");
	  return A_EOF;
77
	default:
Niels Möller's avatar
Niels Möller committed
78
79
80
81
	  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);
82
83
84
85
	  return A_FAIL;
	}
    }
}
Niels Möller's avatar
Niels Möller committed
86

87
88
89
#define FOR_FDS(type, fd, list, extra)				\
{								\
  type **(_fd);							\
Niels Möller's avatar
Niels Möller committed
90
  type *(fd);							\
Niels Möller's avatar
Niels Möller committed
91
  for(_fd = &(list); ((fd) = *_fd); (extra)) {
92
93


Niels Möller's avatar
Niels Möller committed
94
95
96
#define END_FOR_FDS _fd = &(*_fd)->next; } }

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

Niels Möller's avatar
Niels Möller committed
99
static void really_close_fd(struct io_fd *fd)
100
101
102
103
104
{
  /* FIXME: The value returned from the close callback could be used
   * to choose an exit code. */
  if (fd->close_callback && fd->close_reason)
    (void) CLOSE_CALLBACK(fd->close_callback, fd->close_reason);
105
106
107

  debug("Closing fd %d.\n", fd->fd);

108
  close(fd->fd);
109
110
111
112
113

  /* Make sure writing to the buffer fails. */
  if (fd->buffer)
    write_buffer_close(fd->buffer);
  
114
115
116
117
  /* There can be other objects around that may still
   * attempt to write to the buffer. So let gc handle it
   * instead of freeing it explicitly */
#if 0
118
  lsh_object_free(fd->buffer);
119
#endif
120
121
122

  /* There may be pointers to fd objects. So don't free them here. */
#if 0
123
  /* Handlers are not shared, so it should be ok to free them. */
124
125
  lsh_object_free(fd->handler);
  lsh_object_free(fd);
126
#endif
127
128
}

129
130
/* FIXME: This code breaks horribly if new files are created by a
 * callback function. */
Niels Möller's avatar
Niels Möller committed
131
int io_iter(struct io_backend *b)
Niels Möller's avatar
Niels Möller committed
132
{
133
134
135
136
137
138
  struct pollfd *fds;
  int i;
  unsigned long nfds; /* FIXME: Should be nfds_t if that type is defined */
  int timeout;
  int res;

139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  /* We must first look at the write descriptors, to see if any of
   * them should be closed. */

  i = 0;
  FOR_FDS(struct io_fd, fd, b->io, i++)
    {
      /* pre_write returns 0 if the buffer is empty */
      if (fd->buffer)
	{
	  /* Ignores return value. Look at the empty attribute instead- */
	  (void) write_buffer_pre_write(fd->buffer);

	  if (fd->buffer->empty && fd->buffer->closed)
	    {
	      really_close_fd(fd);
	    
	      UNLINK_FD;
	    
	      b->nio--;
	      continue;
	    }
	}
    }
  END_FOR_FDS;
  
164
165
166
  nfds = b->nio + b->nlisten + b->nconnect;

  if (b->callouts)
Niels Möller's avatar
Niels Möller committed
167
    {
168
169
170
      time_t now = time(NULL);
      if (now >= b->callouts->when)
	timeout = 0;
Niels Möller's avatar
Niels Möller committed
171
      else
172
173
174
175
176
177
178
179
180
181
182
183
184
185
	{
	  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;
    }
186

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

189
190
  /* Handle fds in order: write, read, accept, connect. */
  i = 0;
191

192
193
194
195
  FOR_FDS(struct io_fd, fd, b->io, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = 0;
Niels Möller's avatar
Niels Möller committed
196
      if (fd->handler && !fd->on_hold)
197
198
	fds[i].events |= POLLIN;

199
200
      if (fd->buffer && !fd->buffer->empty)
	fds[i].events |= POLLOUT;
201
202
    }
  END_FOR_FDS;
203

204
205
206
207
208
209
  FOR_FDS(struct listen_fd, fd, b->listen, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = POLLIN;
    }
  END_FOR_FDS;
210

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  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;
228
      lsh_object_free(f);
229
230
231
232
233
234
235
236
237
    }
  if (res<0)
    {
      switch(errno)
	{
	case EAGAIN:
	case EINTR:
	  return 1;
	default:
Niels Möller's avatar
Niels Möller committed
238
	  fatal("io_iter:poll failed: %s", strerror(errno));
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
	}
    }
  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;
263
264
265
266
267
		  case EPIPE:
		    werror("Broken pipe\n");
		    fd->close_reason = CLOSE_WRITE_FAILED;
		    fd->close_now = 1;
		    break;
268
269
270
		  default:
		    werror("io.c: write failed, %s\n", strerror(errno));

271
272
		    fd->close_reason = CLOSE_WRITE_FAILED;
		    fd->close_now = 1;
273
274
275
276
277
278
279

		    break;
		  }
	      else
		fd->buffer->start += res;
	    }
	}
280
281
      END_FOR_FDS;

282
283
284
285
      /* Handle reading */
      i = 0; /* Start over */
      FOR_FDS(struct io_fd, fd, b->io, i++)
	{
286
	  if (!fd->close_now
287
288
	      && (fds[i].revents & POLLIN))
	    {
289
290
	      int res;
	      
291
	      struct fd_read r =
Niels Möller's avatar
Niels Möller committed
292
	      { { STACK_HEADER, do_read }, fd->fd };
Niels Möller's avatar
Niels Möller committed
293

294
	      /* The handler function may install a new handler */
295
296
	      res = READ_HANDLER(fd->handler,
				 &r.super);
297
298
299
	      /* NOTE: These flags are not mutually exclusive. All
	       * combination must be handled correctly. */

300
301
302
303
	      /* NOTE: (i) If LSH_DIE is set, LSH_CLOSE is ignored.
	       * (ii) If the fd is read_only, LSH_CLOSE is the same as LSH_DIE.
	       */
#if 0
304
305
306
307
308
309
310
311
312
313
	      if ( (res & (LSH_CLOSE | LSH_DIE)) == (LSH_CLOSE | LSH_DIE) )
		{
		  debug("return code %x, both LSH_CLOSE and LSH_DIE set.\n",
			res);
		  /* LSH_DIE takes precedence */
		  res &= ~LSH_CLOSE;

		  /* FIXME: Perhaps we should always set LSH_FAIL in
		   * this case? */
		}
314
#endif
Niels Möller's avatar
Niels Möller committed
315
316
317
	      /* This condition must be taken care of earlier. */
	      assert(!(res & LSH_CHANNEL_FINISHED));
	      
318
319
320
321
322
323
	      if (res & LSH_HOLD)
		{
		  /* This flag should not be combined with anything else */
		  assert(res == LSH_HOLD);
		  fd->on_hold = 1;
		}
324
325
326
327
328
329
330
	      if (res & LSH_DIE)
		{
		  if (fd->buffer)
		    write_buffer_close(fd->buffer);
		  
		  fd->close_reason = LSH_FAILUREP(res)
		    ? CLOSE_PROTOCOL_FAILURE : 0;
331
		  fd->close_now = 1;
332
		}
333
334
335
	      else if (res & LSH_CLOSE)
		{
		  if (fd->buffer)
336
337
338
339
340
341
		    {
		      write_buffer_close(fd->buffer);
		      /* Don't attempt to read any further. */
		      /* FIXME: Is it safe to free the handler here? */
		      fd->handler = NULL;
		    }
342
343
344
345
346
347
		  else
		    fd->close_now = 1;
		  
		  fd->close_reason
		    = LSH_FAILUREP(res) ? CLOSE_PROTOCOL_FAILURE : CLOSE_EOF;
		}
348
349
350
351
352
353
354
	      if (res & LSH_KILL_OTHERS)
		{
		  /* Close all other files. We have probably fork()ed. */
		  {
		    struct io_fd *p;
		    struct io_fd *next;
		    
355
		    for (p = b->io; p; p = next)
356
357
358
359
360
361
362
363
364
		      {
			next = p->next;
			
			if (p->fd != fd->fd)
			  {
			    p->close_reason = 0;
			    
			    /* In this case, it should be safe to
			     * deallocate the buffer immediately */
365
			    lsh_object_free(p->buffer);
Niels Möller's avatar
Niels Möller committed
366
			    really_close_fd(p);
367
368
369
370
371
			  }
		      }
		    if (fd->close_now)
		      {
			/* Some error occured. So close this fd too! */
Niels Möller's avatar
Niels Möller committed
372
			really_close_fd(fd);
373
374
375
376
377
378
379
380
381
382
383
384
			b->io = NULL;
			b->nio = 0;
		      }
		    else
		      { /* Keep this single descriptor open */
			fd->next = NULL;
			b->io = fd;
			b->nio = 1;
		      }
		  }{
		    struct listen_fd *p;
		    struct listen_fd *next;
385
386

		    for (p = b->listen; p; p = next)
387
388
389
		      {
			next = p->next;
			close(p->fd);
390
			lsh_space_free(p);
391
392
393
394
395
396
		      }
		    b->listen = NULL;
		    b->nlisten = 0;
		  }{
		    struct connect_fd *p;
		    struct connect_fd *next;
397
398

		    for (p = b->connect; p; p = next)
399
400
401
		      {
			next = p->next;
			close(p->fd);
402
			lsh_space_free(p);
403
404
405
406
407
408
		      }
		    b->connect = NULL;
		    b->nconnect = 0;
		  }{
		    struct callout *p;
		    struct callout *next;
409
410

		    for (p = b->callouts; p; p = next)
411
412
		      {
			next = p->next;
413
			lsh_space_free(p);
414
415
416
		      }
		    b->callouts = NULL;
		  }
Niels Möller's avatar
Niels Möller committed
417
		  /* Skip the rest of this iteration */
418
		  return 1;
Niels Möller's avatar
Niels Möller committed
419
		}
420
	    }
Niels Möller's avatar
Niels Möller committed
421
#if 0
422
	  if (fd->close_now)
423
424
425
426
427
	    {
	      /* FIXME: Cleanup properly...
	       *
	       * After a write error, read state must be freed,
	       * and vice versa. */
428

Niels Möller's avatar
Niels Möller committed
429
	      really_close_fd(fd);
430

431
	      UNLINK_FD;
432

433
434
435
	      b->nio--;
	      continue;
	    }
Niels Möller's avatar
Niels Möller committed
436
#endif
437
438
	}
      END_FOR_FDS;
439

Niels Möller's avatar
Niels Möller committed
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
      /* Close files */
      i = 0; /* Start over */
      FOR_FDS(struct io_fd, fd, b->io, i++)
	if (fd->close_now)
	  {
	    /* FIXME: Cleanup properly...
	     *
	     * After a write error, read state must be freed,
	     * and vice versa. */
	    
	    really_close_fd(fd);
	    
	    UNLINK_FD;
	    
	    b->nio--;
	    continue;
	  }
      END_FOR_FDS;
	
459
460
461
      FOR_FDS(struct listen_fd, fd, b->listen, i++)
	{
	  if (fds[i].revents & POLLIN)
Niels Möller's avatar
Niels Möller committed
462
	    {
463
464
465
	      /* FIXME: Do something with the peer address? */
	      struct sockaddr_in peer;
	      size_t addr_len = sizeof(peer);
466
467
	      int res;
	      
468
469
470
471
472
473
	      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
474
		}
475
	      res = FD_CALLBACK(fd->callback, conn);
476
	      if (LSH_ACTIONP(res))
Niels Möller's avatar
Niels Möller committed
477
		{
478
479
480
		  werror("Strange: Accepted a connection, "
			 "but failed before writing anything.\n");
		  close(fd->fd);
481
		  UNLINK_FD;
482
		  lsh_object_free(fd);
Niels Möller's avatar
Niels Möller committed
483
		  continue;
Niels Möller's avatar
Niels Möller committed
484
485
		}
	    }
486
	}
487
488
489
490
491
492
      END_FOR_FDS;
	  
      FOR_FDS(struct connect_fd, fd, b->connect, i++)
	{
	  if (fds[i].revents & POLLOUT)
	    {
493
494
	      int res = FD_CALLBACK(fd->callback, fd->fd);

495
	      if (LSH_ACTIONP(res))
496
497
		werror("Strange: Connected, "
		       "but failed before writing anything.\n");
498
499
	      b->nconnect--;
	      UNLINK_FD;
500
	      lsh_object_free(fd);
501
502
503
504
505
506
507
508
	      continue;
	    }
	}
      END_FOR_FDS;
    }
  return 1;
}

509
/* FIXME: Prehaps this function should return a suitable exit code? */
510
511
void io_run(struct io_backend *b)
{
Niels Möller's avatar
Niels Möller committed
512
513
514
515
516
517
518
519
520
  struct sigaction pipe;

  pipe.sa_handler = SIG_IGN;
  sigemptyset(&pipe.sa_mask);
  pipe.sa_flags = 0;
  pipe.sa_restorer = NULL;
  
  if (sigaction(SIGPIPE, &pipe, NULL) < 0)
    fatal("Failed to ignore SIGPIPE.\n");
521
  
522
523
  while(io_iter(b))
    ;
524
525
}

526
527
528
529
530
531
532
533
534
535
536
void init_backend(struct io_backend *b)
{
  b->nio = 0;
  b->io = NULL;
  b->nlisten = 0;
  b->listen = NULL;
  b->nconnect = 0;
  b->connect = NULL;
  b->callouts = NULL;
}

537
538
539
/*
 * Fill in ADDR from HOST, SERVICE and PROTOCOL.
 * Supplying a null pointer for HOST means use INADDR_ANY.
540
 * Otherwise HOST is an numbers-and-dots ip-number or a dns name.
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
 *
 * 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
602
603
	}
    }
604
605

  return 1;
Niels Möller's avatar
Niels Möller committed
606
607
608
609
610
611
612
613
}

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

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
void io_set_close_on_exec(int fd)
{
  if (fcntl(fd, F_SETFD, 1) < 0)
    fatal("Can't set close-on-exec flag for fd %d: %s\n",
	  fd, strerror(errno));
}

/* ALL file descripters handled by the backend should use non-blocking mode,
 * and have the close-on-exec flag set. */

void io_init_fd(int fd)
{
  io_set_nonblocking(fd);
  io_set_close_on_exec(fd);
}

630
631
632
633
634
/* 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
635
{
636
637
  struct connect_fd *fd;
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Niels Möller's avatar
Niels Möller committed
638
  
639
640
  if (s<0)
    return NULL;
Niels Möller's avatar
Niels Möller committed
641

642
643
  debug("io.c: connecting using fd %d\n", s);
  
644
  io_init_fd(s);
Niels Möller's avatar
Niels Möller committed
645

646
647
648
649
650
651
652
  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
653

654
655
656
657
658
659
660
661
662
  if ( (connect(s, (struct sockaddr *)remote, sizeof *remote) < 0)
       && (errno != EINPROGRESS) )       
    {
      int saved_errno = errno;
      close(s);
      errno = saved_errno;
      return NULL;
    }
  
Niels Möller's avatar
Niels Möller committed
663
  NEW(fd);
664
  fd->fd = s;
Niels Möller's avatar
Niels Möller committed
665
  fd->callback = f;
666
667
668

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

670
671
672
  b->nconnect++;
  
  return fd;
Niels Möller's avatar
Niels Möller committed
673
674
}

675
676
677
678
679
680
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
681
  
682
683
684
  if (s<0)
    return NULL;

685
686
  debug("io.c: listening on fd %d\n", s);
  
687
  io_init_fd(s);
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

  {
    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;
    }

Niels Möller's avatar
Niels Möller committed
706
  NEW(fd);
707
708
709
710
711
712
713

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

  fd->next = b->listen;
  b->listen = fd;
  b->nlisten++;
Niels Möller's avatar
Niels Möller committed
714
  
715
716
717
  return fd;
}

Niels Möller's avatar
Niels Möller committed
718
719
struct abstract_write *io_read_write(struct io_backend *b,
				     int fd,
Niels Möller's avatar
Niels Möller committed
720
				     struct read_handler *read_callback,
Niels Möller's avatar
Niels Möller committed
721
				     UINT32 block_size,
722
				     struct close_callback *close_callback)
723
{
Niels Möller's avatar
Niels Möller committed
724
  struct io_fd *f;
725
  struct write_buffer *buffer = write_buffer_alloc(block_size);
Niels Möller's avatar
Niels Möller committed
726

727
728
  debug("io.c: Preparing fd %d for reading and writing\n", fd);
  
729
730
  io_init_fd(fd);
  
Niels Möller's avatar
Niels Möller committed
731
  NEW(f);
Niels Möller's avatar
Niels Möller committed
732
  f->fd = fd;
733
734
735
  
  f->close_reason = -1; /* Invalid reason */
  f->close_now = 0;
736
737

  /* Reading */
Niels Möller's avatar
Niels Möller committed
738
  f->handler = read_callback;
739
740
741
  f->on_hold = 0;

  /* Writing */
Niels Möller's avatar
Niels Möller committed
742
  f->buffer = buffer;
743
  f->close_callback = close_callback;
744

Niels Möller's avatar
Niels Möller committed
745
746
  f->next = b->io;
  b->io = f;
Niels Möller's avatar
Niels Möller committed
747
  b->nio++;
748

749
  return &buffer->super;
750
}
751
752
753
754
755
756
757
758

struct io_fd *io_read(struct io_backend *b,
		      int fd,
		      struct read_handler *read_callback,
		      struct close_callback *close_callback)
{
  struct io_fd *f;

759
760
  debug("io.c: Preparing fd %d for reading\n", fd);
  
761
762
  io_init_fd(fd);

763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
  NEW(f);
  f->fd = fd;
  
  f->close_reason = -1; /* Invalid reason */
  f->close_now = 0;

  /* Reading */
  f->handler = read_callback;
  f->on_hold = 0;

  /* Writing */
  f->buffer = NULL;

  f->close_callback = close_callback;

  f->next = b->io;
  b->io = f;
  b->nio++;

  return f;
}

785
786
787
788
struct io_fd *io_write(struct io_backend *b,
		       int fd,
		       UINT32 block_size,
		       struct close_callback *close_callback)
789
790
791
792
{
  struct io_fd *f;
  struct write_buffer *buffer = write_buffer_alloc(block_size);

793
794
  debug("io.c: Preparing fd %d for writing\n", fd);
  
795
796
  io_init_fd(fd);
  
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
  NEW(f);
  f->fd = fd;
  
  f->close_reason = -1; /* Invalid reason */
  f->close_now = 0;

  /* Reading */
  f->handler = NULL;

  /* Writing */
  f->buffer = buffer;
  f->close_callback = close_callback;

  f->next = b->io;
  b->io = f;
  b->nio++;

814
  return f;
815
}
Niels Möller's avatar
Niels Möller committed
816
817
818
819
820
821

/* Marks a file for closing, at the end of the current iteration.
 * FIXME: Could be generalized for other fd:s than read-write fds. */

void close_fd(struct io_fd *fd)
{
822
823
  debug("Marking fd %d for closing.\n", fd->fd);
  
Niels Möller's avatar
Niels Möller committed
824
825
  fd->close_now = 1;
}