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