io.c 16.3 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 105 106
{
  /* 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);
  
  close(fd->fd);
107 108 109 110 111

  /* Make sure writing to the buffer fails. */
  if (fd->buffer)
    write_buffer_close(fd->buffer);
  
112 113 114 115
  /* 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
116
  lsh_object_free(fd->buffer);
117
#endif
118 119 120

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

Niels Möller's avatar
Niels Möller committed
127
int io_iter(struct io_backend *b)
Niels Möller's avatar
Niels Möller committed
128
{
129 130 131 132 133 134 135 136 137
  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
138
    {
139 140 141
      time_t now = time(NULL);
      if (now >= b->callouts->when)
	timeout = 0;
Niels Möller's avatar
Niels Möller committed
142
      else
143 144 145 146 147 148 149 150 151 152 153 154 155 156
	{
	  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;
    }
157

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

160 161
  /* Handle fds in order: write, read, accept, connect. */
  i = 0;
162

163 164 165 166
  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
167
      if (fd->handler && !fd->on_hold)
168 169 170
	fds[i].events |= POLLIN;

      /* pre_write returns 0 if the buffer is empty */
171 172 173 174 175 176 177 178 179 180 181
      if (fd->buffer)
	{
	  if (write_buffer_pre_write(fd->buffer))
	    fds[i].events |= POLLOUT;
	  else
	    /* Buffer is empty. Should we close? */
	    if (fd->buffer->closed)
	      {
		fd->close_now = 1;
	      }
	}
182 183
    }
  END_FOR_FDS;
184

185 186 187 188 189 190
  FOR_FDS(struct listen_fd, fd, b->listen, i++)
    {
      fds[i].fd = fd->fd;
      fds[i].events = POLLIN;
    }
  END_FOR_FDS;
191

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  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;
209
      lsh_object_free(f);
210 211 212 213 214 215 216 217 218
    }
  if (res<0)
    {
      switch(errno)
	{
	case EAGAIN:
	case EINTR:
	  return 1;
	default:
Niels Möller's avatar
Niels Möller committed
219
	  fatal("io_iter:poll failed: %s", strerror(errno));
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
	}
    }
  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;
244 245 246 247 248
		  case EPIPE:
		    werror("Broken pipe\n");
		    fd->close_reason = CLOSE_WRITE_FAILED;
		    fd->close_now = 1;
		    break;
249 250 251
		  default:
		    werror("io.c: write failed, %s\n", strerror(errno));

252 253
		    fd->close_reason = CLOSE_WRITE_FAILED;
		    fd->close_now = 1;
254 255 256 257 258 259 260

		    break;
		  }
	      else
		fd->buffer->start += res;
	    }
	}
261 262
      END_FOR_FDS;

263 264 265 266
      /* Handle reading */
      i = 0; /* Start over */
      FOR_FDS(struct io_fd, fd, b->io, i++)
	{
267
	  if (!fd->close_now
268 269
	      && (fds[i].revents & POLLIN))
	    {
270 271
	      int res;
	      
272
	      struct fd_read r =
Niels Möller's avatar
Niels Möller committed
273
	      { { STACK_HEADER, do_read }, fd->fd };
Niels Möller's avatar
Niels Möller committed
274

275
	      /* The handler function may install a new handler */
276 277
	      res = READ_HANDLER(fd->handler,
				 &r.super);
278 279 280
	      /* NOTE: These flags are not mutually exclusive. All
	       * combination must be handled correctly. */

281 282 283 284
	      /* 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
285 286 287 288 289 290 291 292 293 294
	      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? */
		}
295
#endif
Niels Möller's avatar
Niels Möller committed
296 297 298
	      /* This condition must be taken care of earlier. */
	      assert(!(res & LSH_CHANNEL_FINISHED));
	      
299 300 301 302 303 304
	      if (res & LSH_HOLD)
		{
		  /* This flag should not be combined with anything else */
		  assert(res == LSH_HOLD);
		  fd->on_hold = 1;
		}
305 306 307 308 309 310 311
	      if (res & LSH_DIE)
		{
		  if (fd->buffer)
		    write_buffer_close(fd->buffer);
		  
		  fd->close_reason = LSH_FAILUREP(res)
		    ? CLOSE_PROTOCOL_FAILURE : 0;
312
		  fd->close_now = 1;
313
		}
314 315 316 317 318 319 320 321 322 323
	      else if (res & LSH_CLOSE)
		{
		  if (fd->buffer)
		    write_buffer_close(fd->buffer);
		  else
		    fd->close_now = 1;
		  
		  fd->close_reason
		    = LSH_FAILUREP(res) ? CLOSE_PROTOCOL_FAILURE : CLOSE_EOF;
		}
324 325 326 327 328 329 330
	      if (res & LSH_KILL_OTHERS)
		{
		  /* Close all other files. We have probably fork()ed. */
		  {
		    struct io_fd *p;
		    struct io_fd *next;
		    
331
		    for (p = b->io; p; p = next)
332 333 334 335 336 337 338 339 340
		      {
			next = p->next;
			
			if (p->fd != fd->fd)
			  {
			    p->close_reason = 0;
			    
			    /* In this case, it should be safe to
			     * deallocate the buffer immediately */
341
			    lsh_object_free(p->buffer);
Niels Möller's avatar
Niels Möller committed
342
			    really_close_fd(p);
343 344 345 346 347
			  }
		      }
		    if (fd->close_now)
		      {
			/* Some error occured. So close this fd too! */
Niels Möller's avatar
Niels Möller committed
348
			really_close_fd(fd);
349 350 351 352 353 354 355 356 357 358 359 360
			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;
361 362

		    for (p = b->listen; p; p = next)
363 364 365
		      {
			next = p->next;
			close(p->fd);
366
			lsh_space_free(p);
367 368 369 370 371 372
		      }
		    b->listen = NULL;
		    b->nlisten = 0;
		  }{
		    struct connect_fd *p;
		    struct connect_fd *next;
373 374

		    for (p = b->connect; p; p = next)
375 376 377
		      {
			next = p->next;
			close(p->fd);
378
			lsh_space_free(p);
379 380 381 382 383 384
		      }
		    b->connect = NULL;
		    b->nconnect = 0;
		  }{
		    struct callout *p;
		    struct callout *next;
385 386

		    for (p = b->callouts; p; p = next)
387 388
		      {
			next = p->next;
389
			lsh_space_free(p);
390 391 392
		      }
		    b->callouts = NULL;
		  }
Niels Möller's avatar
Niels Möller committed
393
		  /* Skip the rest of this iteration */
394
		  return 1;
Niels Möller's avatar
Niels Möller committed
395
		}
396
	    }
Niels Möller's avatar
Niels Möller committed
397
#if 0
398
	  if (fd->close_now)
399 400 401 402 403
	    {
	      /* FIXME: Cleanup properly...
	       *
	       * After a write error, read state must be freed,
	       * and vice versa. */
404

Niels Möller's avatar
Niels Möller committed
405
	      really_close_fd(fd);
406

407
	      UNLINK_FD;
408

409 410 411
	      b->nio--;
	      continue;
	    }
Niels Möller's avatar
Niels Möller committed
412
#endif
413 414
	}
      END_FOR_FDS;
415

Niels Möller's avatar
Niels Möller committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
      /* 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;
	
435 436 437
      FOR_FDS(struct listen_fd, fd, b->listen, i++)
	{
	  if (fds[i].revents & POLLIN)
Niels Möller's avatar
Niels Möller committed
438
	    {
439 440 441
	      /* FIXME: Do something with the peer address? */
	      struct sockaddr_in peer;
	      size_t addr_len = sizeof(peer);
442 443
	      int res;
	      
444 445 446 447 448 449
	      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
450
		}
451
	      res = FD_CALLBACK(fd->callback, conn);
452
	      if (LSH_ACTIONP(res))
Niels Möller's avatar
Niels Möller committed
453
		{
454 455 456
		  werror("Strange: Accepted a connection, "
			 "but failed before writing anything.\n");
		  close(fd->fd);
457
		  UNLINK_FD;
458
		  lsh_object_free(fd);
Niels Möller's avatar
Niels Möller committed
459
		  continue;
Niels Möller's avatar
Niels Möller committed
460 461
		}
	    }
462
	}
463 464 465 466 467 468
      END_FOR_FDS;
	  
      FOR_FDS(struct connect_fd, fd, b->connect, i++)
	{
	  if (fds[i].revents & POLLOUT)
	    {
469 470
	      int res = FD_CALLBACK(fd->callback, fd->fd);

471
	      if (LSH_ACTIONP(res))
472 473
		werror("Strange: Connected, "
		       "but failed before writing anything.\n");
474 475
	      b->nconnect--;
	      UNLINK_FD;
476
	      lsh_object_free(fd);
477 478 479 480 481 482 483 484
	      continue;
	    }
	}
      END_FOR_FDS;
    }
  return 1;
}

485
/* FIXME: Prehaps this function should return a suitable exit code? */
486 487
void io_run(struct io_backend *b)
{
Niels Möller's avatar
Niels Möller committed
488 489 490 491 492 493 494 495 496
  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");
497
  
498 499
  while(io_iter(b))
    ;
500 501
}

502 503 504 505 506 507 508 509 510 511 512
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;
}

513 514 515
/*
 * Fill in ADDR from HOST, SERVICE and PROTOCOL.
 * Supplying a null pointer for HOST means use INADDR_ANY.
516
 * Otherwise HOST is an numbers-and-dots ip-number or a dns name.
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 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
 *
 * 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
578 579
	}
    }
580 581

  return 1;
Niels Möller's avatar
Niels Möller committed
582 583 584 585 586 587 588 589
}

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

590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
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);
}

606 607 608 609 610
/* 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
611
{
612 613
  struct connect_fd *fd;
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Niels Möller's avatar
Niels Möller committed
614
  
615 616
  if (s<0)
    return NULL;
Niels Möller's avatar
Niels Möller committed
617

618 619
  debug("io.c: connecting using fd %d\n", s);
  
620
  io_init_fd(s);
Niels Möller's avatar
Niels Möller committed
621

622 623 624 625 626 627 628
  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
629

630 631 632 633 634 635 636 637 638
  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
639
  NEW(fd);
640
  fd->fd = s;
Niels Möller's avatar
Niels Möller committed
641
  fd->callback = f;
642 643 644

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

646 647 648
  b->nconnect++;
  
  return fd;
Niels Möller's avatar
Niels Möller committed
649 650
}

651 652 653 654 655 656
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
657
  
658 659 660
  if (s<0)
    return NULL;

661 662
  debug("io.c: listening on fd %d\n", s);
  
663
  io_init_fd(s);
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681

  {
    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
682
  NEW(fd);
683 684 685 686 687 688 689

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

  fd->next = b->listen;
  b->listen = fd;
  b->nlisten++;
Niels Möller's avatar
Niels Möller committed
690
  
691 692 693
  return fd;
}

Niels Möller's avatar
Niels Möller committed
694 695
struct abstract_write *io_read_write(struct io_backend *b,
				     int fd,
Niels Möller's avatar
Niels Möller committed
696
				     struct read_handler *read_callback,
Niels Möller's avatar
Niels Möller committed
697
				     UINT32 block_size,
698
				     struct close_callback *close_callback)
699
{
Niels Möller's avatar
Niels Möller committed
700
  struct io_fd *f;
701
  struct write_buffer *buffer = write_buffer_alloc(block_size);
Niels Möller's avatar
Niels Möller committed
702

703 704
  debug("io.c: Preparing fd %d for reading and writing\n", fd);
  
705 706
  io_init_fd(fd);
  
Niels Möller's avatar
Niels Möller committed
707
  NEW(f);
Niels Möller's avatar
Niels Möller committed
708
  f->fd = fd;
709 710 711
  
  f->close_reason = -1; /* Invalid reason */
  f->close_now = 0;
712 713

  /* Reading */
Niels Möller's avatar
Niels Möller committed
714
  f->handler = read_callback;
715 716 717
  f->on_hold = 0;

  /* Writing */
Niels Möller's avatar
Niels Möller committed
718
  f->buffer = buffer;
719
  f->close_callback = close_callback;
720

Niels Möller's avatar
Niels Möller committed
721 722
  f->next = b->io;
  b->io = f;
Niels Möller's avatar
Niels Möller committed
723
  b->nio++;
724

725
  return &buffer->super;
726
}
727 728 729 730 731 732 733 734

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;

735 736
  debug("io.c: Preparing fd %d for reading\n", fd);
  
737 738
  io_init_fd(fd);

739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  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;
}

761 762 763 764
struct io_fd *io_write(struct io_backend *b,
		       int fd,
		       UINT32 block_size,
		       struct close_callback *close_callback)
765 766 767 768
{
  struct io_fd *f;
  struct write_buffer *buffer = write_buffer_alloc(block_size);

769 770
  debug("io.c: Preparing fd %d for writing\n", fd);
  
771 772
  io_init_fd(fd);
  
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
  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++;

790
  return f;
791
}
Niels Möller's avatar
Niels Möller committed
792 793 794 795 796 797 798 799

/* 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)
{
  fd->close_now = 1;
}