#ifndef COMMON_CHANNEL_H
#define COMMON_CHANNEL_H

/*
 * Copyright (c) 2002, The EROS Group, LLC and Johns Hopkins
 * University. All rights reserved.
 * 
 * This software was developed to support the EROS secure operating
 * system project (http://www.eros-os.org). The latest version of
 * the OpenCM software can be found at http://www.opencm.org.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 * 
 * 3. Neither the name of the The EROS Group, LLC nor the name of
 *    Johns Hopkins University, nor the names of its contributors
 *    may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Encapsulation of all network protocol-specific variables.
 * (For plain TCP/IP sockets, this is just the socket variables.
 * Other protocols will require additional information.)
 */
typedef struct Channel Channel;
typedef void (*ChannelCompletionFn)(Channel *);
typedef struct PendingWrite PendingWrite;

void NullChannelCallback(Channel *);

#define CHAN_RDBOUND 1024

struct Channel {
  int sockfd;
  OC_bool handshake_done;

  URI *uri;			/* client side only */

  /* These two flags are for protocols like
   * SSL that may need to bypass a blocking
   * select command because they maintain a
   * "middle" buffer: */
  OC_bool pendingRead;
  OC_bool pendingWrite;

  /* Callback for asynchronous read: */
  ChannelCompletionFn rCallback;

  /* Callback for asynchronous handshake: */
  ChannelCompletionFn hCallback;

  /* Vars for reading: */
  unsigned char *read_scratch;
  Buffer *read_buf;
  size_t read_wanted;		/* number of bytes we want */
  size_t read_so_far;
  size_t rbuf_limit;

  /* Queue for writing: */
  struct PendingWrite {
    const void *buf;
    size_t len;
    size_t sent;
    ChannelCompletionFn callback;
    PendingWrite *next;
  } *writeQueue;

  /* SSL related items, only relevant if SSL is in use. Using void *
   * so that things will compile even if SSL headers are not
   * available. */
  void *ctx;			/* SSL_CTX * */
  void *ssl;			/* SSL * */
  void *sbio;			/* BIO * */

  /* Note: send/receive are ASYNCHRONOUS */
  /** Perform an asynchronous write.

      On completion, the ChannelCompletionFn (if present) will be passed the 
      Channel pointer. Channel draining is handled inside chan_select, so 
      chan_select must be called to ensure that the completion function is
      reliably invoked. It may be invoked immediately if the async write on
      the underlying socket succeeds without overrunning the underlying buffer.
   */
  void (*send)(Channel *, const void *, size_t len, ChannelCompletionFn);
  void (*flush)(Channel *, OC_bool andWait);

  /** Perform an asynchronous read.
   */
  void (*receive)(Channel *, size_t len, ChannelCompletionFn);
  void (*pull)(Channel *, OC_bool andWait);

  /* Used to complete the protocol handshake */
  void (*shake)(Channel *, OC_bool andWait);

  void (*aclose)(Channel *);
  void (*close)(Channel *);
  OC_bool closed; /* Flag for aclose */

  PubKey *peerCert;		/* peer certificate, if any */
  void *xinfo; /* any additional info, such as reference to session data */

  /* Used to determine if Channel is idle too long */
  OC_bool check_idleness;
  time_t max_idle_time;
  time_t last_activity; 
  unsigned int connection_id;
}; 

/* Constructors for a Channel: */
Channel *chan_create(void);
Channel *chan_alisten_tcp(ChannelCompletionFn, char *, unsigned short port);
Channel *chan_accept_tcp(Channel *);
Channel *chan_connect_tcp(URI *);
Channel *chan_alisten_ssl(ChannelCompletionFn, char *, unsigned short port);
Channel *chan_accept_ssl(Channel *);
Channel *chan_connect_ssl(URI *);

int chan_select(Channel **, int maxfd, struct timeval *tv);
void chan_blockForReading(Channel *, struct timeval *);
void chan_blockForWriting(Channel *, struct timeval *);

/* Use these two to initiate non-blocking I/O.
 * The callbacks must be provided if you specifically need to know
 * when the I/O has completed: */
void chan_aread(Channel *, size_t len, ChannelCompletionFn);
void chan_awrite(Channel *, const void *buf, size_t len, ChannelCompletionFn);

void chan_ashake(Channel *, ChannelCompletionFn);  /* non-blocking */
void chan_shake(Channel *);   /* blocking */

/* Use these two for blocking I/O.  Specify a non-NULL timeout
 * if you need to. */
void chan_read(Channel *, void *buf, size_t len, struct timeval *timeout);
void chan_write(Channel *, const void *buf, size_t len, 
		struct timeval *timeout);

void chan_set_max_idle_time(Channel *, time_t seconds);
OC_bool chan_idle_too_long(Channel *);

#endif /* COMMON_CHANNEL_H */
