/*
 * Copyright (c) 1998-2001 Caucho Technology -- all rights reserved
 *
 * Caucho Technology permits redistribution, modification and use
 * of this file in source and binary form ("the Software") under the
 * Caucho Developer Source License ("the License").  The following
 * conditions must be met:
 *
 * 1. Each copy or derived work of the Software must preserve the copyright
 *    notice and this notice unmodified.
 *
 * 2. Redistributions of the Software in source or binary form must include 
 *    an unmodified copy of the License, normally in a plain ASCII text
 *
 * 3. The names "Resin" or "Caucho" are trademarks of Caucho Technology and
 *    may not be used to endorse products derived from this software.
 *    "Resin" or "Caucho" may not appear in the names of products derived
 *    from this software.
 *
 * 4. Caucho Technology requests that attribution be given to Resin
 *    in any manner possible.  We suggest using the "Resin Powered"
 *    button or creating a "powered by Resin(tm)" link to
 *    http://www.caucho.com for each page served by Resin.
 *
 * This Software is provided "AS IS," without a warranty of any kind. 
 * ALL EXPRESS OR IMPLIED REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
 * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
 *
 * CAUCHO TECHNOLOGY AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
 * SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A RESULT OF USING OR
 * DISTRIBUTING SOFTWARE. IN NO EVENT WILL CAUCHO OR ITS LICENSORS BE LIABLE
 * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
 * INABILITY TO USE SOFTWARE, EVEN IF HE HAS BEEN ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGES.      
 *
 * @author Scott Ferguson
 */

#ifndef HARDCORE_H
#define HARDCORE_H

#ifdef DEBUG
#define LOG(x) log x
#else
#define LOG(x)
#endif

enum connection_state {
  RHC_IDLE,
  
  RHC_BROWSER_START,
  RHC_BROWSER_SPACE,
  RHC_BROWSER_METHOD,
  RHC_BROWSER_URL,
  RHC_BROWSER_PROTOCOL,
  
  RHC_BROWSER_EOL,
  
  RHC_BROWSER_KEY,
  RHC_BROWSER_VALUE,
  RHC_BROWSER_HEADER_DONE,
  
  RHC_BROWSER_BODY,

  RHC_SRUN_CONNECTING,
  RHC_SRUN_SEND,
  RHC_SRUN_START,
  
  RHC_SRUN_RECV_HEADER,
  RHC_SRUN_RECV_STATUS,
  RHC_SRUN_RECV_KEY,
  RHC_SRUN_RECV_VALUE,
  
  RHC_SRUN_RECV_SKIP,
  
  RHC_SRUN_POST, /* read post from browser, send to srun */
  
  RHC_SRUN_BODY,
  RHC_SRUN_RECV_BODY,
  RHC_SRUN_RECV_DATA,

  RHC_CACHE_WRITE,
  
  RHC_BROWSER_READ,
  RHC_BROWSER_WRITE,
  
  RHC_BROWSER_QUIT,
};

/**
 * Represents a connection to a browser
 */
typedef struct browser_t {
  struct browser_t *next;

  struct browser_t *next_browser;
  struct browser_t *prev_browser;
  
  struct resin_t *resin;

  struct sock *browser_sock;
  
  struct srun_conn_t *srun_conn;
  struct socket *srun_sock;

  int is_active;
  
  int state;
  int next_state;
  int write_state;

  int is_dead;

  int now;

  char cin_buf[4096];
  int cin_offset;
  int cin_length;

  char *method;
  char *url;
  char *protocol;

  int in_header;
  int post_offset;
  int request_length;

  char cout_buf[4096];
  int cout_offset;
  int cout_length;

  char sin_buf[4096];
  int sin_offset;
  int sin_length;

  int packet_len;

  char *key_start;
  char *value_start;

  int expires;

  char sout_buf[4096 + 1024];
  int sout_offset;
  int sout_length;

  char *key[64];
  char *value[64];
  int header_count;
  
  struct iovec iov[16];
  int iov_index;

  int status;
  int keepalive;

  struct entry_t *cache;
  int cache_offset;
} browser_t;

/* Represents a connection to a Resin srun port. */
typedef struct srun_conn_t {
  struct srun_t *parent;

  struct srun_conn_t *next;
  struct srun_conn_t *prev;

  struct socket *sock;
  
  struct browser_t *browser;
  
  int is_dead;
} srun_conn_t;

/* Represents all the connections to a Resin srun port. */
typedef struct srun_t {
  struct resin_t *resin;
  
  struct in_addr addr;           /* Address of the srun          */
  int port;                      /* Port of the srun             */

  int session_index;             /* session index                */
  int is_backup;                 /* true if the srun is a backup */
  
  struct srun_conn_t *conn_head;

  int is_live;
} srun_t;

typedef struct resin_t {
  int accept_port;
  struct socket *accept_socket;
  
  struct tty_struct *tty;

  int srun_count;
  struct srun_t srun_list[64];

  int is_dead;
} resin_t;

extern resin_t g_resin;

/* log.c */
void log(char *fmt, ...);
char *browser_state_name(browser_t *browser);

/* request.c */
int request_parse(browser_t *browser);

/* browser.c */
int accept_socket_create(struct sockaddr_in *sin, resin_t *resin);

void browser_wake(browser_t *browser);
void browser_printf(browser_t *browser, char *fmt, ...);
int browser_write_iov(browser_t *browser);
void browser_execute();

void browser_close(browser_t *browser);

void browser_init(resin_t *resin);
void browser_cleanup(resin_t *resin);

/* srun_conn.c */
void srun_init(resin_t *resin);

void srun_set_count(resin_t *resin, int count);
void srun_create(resin_t *resin, int index, int ipv4, int port);

int srun_connect(srun_t *srun, browser_t *browser);

void srun_send(browser_t *browser);
int srun_recv(browser_t *browser);

void srun_recycle(srun_conn_t *srun_conn);
void srun_execute(resin_t *resin);

void srun_close(srun_t *srun);
void srun_cleanup(resin_t *resin);

/* srun_protocol.c */
int resin_srun(browser_t *browser);

void srun_send_post(browser_t *browser);

int srun_read_header(browser_t *browser);

int socket_recv(struct sock *sock, char *buf, int len);

/* proc.c */
void resin_proc_init(resin_t *resin);
void resin_proc_exit(resin_t *resin);

/* cache.c */
int cache_init();
void cache_cleanup();

int cache_start(browser_t *browser);
void cache_write(browser_t *browser, char *data, int len);
void cache_kill(browser_t *browser);
void cache_finish(browser_t *browser);

int cache_lookup(browser_t *browser);
int cache_read(browser_t *browser);

/* date.c */
int format_date(char *buf, int time);
int format_now(char *buf);

int parse_date(char *string);

/* main.c */
void resind_wake(void);

#ifdef TEST
#undef current
#define current get_caucho_current()
struct task_struct *get_caucho_current();

#undef spin_lock_irq
#define spin_lock_irq(x)

#undef spin_unlock_irq
#define spin_unlock_irq(x)

#undef write_lock_irqsave
#define write_lock_irqsave(x, y)

#undef signal_pending
#define signal_pending(x) 0

#undef wait_event_interruptible
#define wait_event_interruptible(x, y) do_wait(&x, &y)

extern char *p_test_segment;

#undef get_fs
#define get_fs() (*(mm_segment_t *) p_test_segment)

#undef set_fs
#define set_fs(x)

#undef IS_ERR
#define IS_ERR(ptr)	(! (unsigned long)(ptr))

#endif /* test */

#endif /* HARDCORE_H */
