/*
 * Generic client/server connection handler...
 *
 * Copyright 2000 by Gray Watson.
 *
 * This file is part of the connection library package.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose and without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies,
 * and that the name of Gray Watson not be used in advertising or
 * publicity pertaining to distribution of the document or software
 * without specific, written prior permission.
 *
 * Gray Watson makes no representations about the suitability of the
 * software described herein for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * The author may be contacted via http://256.com/gray/
 *
 * $Id: conn.h,v 1.11 2000/03/09 03:37:47 gray Exp $
 */

/*
 * Header file for connection code.
 */
 
#ifndef __CONN_H__
#define __CONN_H__

#include <stdarg.h>

/*
 * Type numbers to synchronize the type checking
 */
#define CONN_TYPE_CHAR			1	/* character */
#define CONN_TYPE_UNSIGNED_CHAR		2	/* unsigned character */
#define CONN_TYPE_SHORT			3	/* short integer */
#define CONN_TYPE_UNSIGNED_SHORT	4	/* unsigned short integer */
#define CONN_TYPE_INT			5	/* integer */
#define CONN_TYPE_UNSIGNED_INT		6	/* unsigned integer */
#define CONN_TYPE_LONG			7	/* long integer */
#define CONN_TYPE_UNSIGNED_LONG		8	/* unsigned long integer */
#define CONN_TYPE_FLOAT			9	/* floating point */
#define CONN_TYPE_DOUBLE		10	/* 2x precision floating pnt */
#define CONN_TYPE_LAST			11	/* mark for array last entry */

/* maximum conn type number for sanity checking */
#define CONN_TYPE_MAX			CONN_TYPE_LAST

/* macro to test whether a type is a valid connection type */
#define CONN_TYPE_IS_VALID(t)		((t) >= CONN_TYPE_CHAR \
					 && (t) < CONN_TYPE_MAX)

/*
 * Error codes
 */
#define CONN_ERROR_NONE			1	/* no error */
#define CONN_ERROR_ALLOC		2	/* allocation error */
#define CONN_ERROR_ARG_NULL		3	/* important arg is null */
#define CONN_ERROR_ARG_INVALID		4	/* important arg is invalid */
#define CONN_ERROR_TYPE_ARG		5	/* improper type in data */
#define CONN_ERROR_TYPE_SYNC		6	/* improper type from remote */
#define CONN_ERROR_TYPE_ALLOW		7	/* type is not allowed */
#define CONN_ERROR_MANY_ARG		8	/* improper many in data */
#define CONN_ERROR_MANY_SYNC		9	/* improper many from remote */
#define CONN_ERROR_MANY_UNKNOWN		10	/* must know inbound many */
#define CONN_ERROR_PNT			11	/* bad connection struct pnt */
#define CONN_ERROR_TIMEOUT		12	/* i/o timeout */
#define CONN_ERROR_SOCKET		13	/* could not create socket */
#define CONN_ERROR_SOCKETOPTS		14	/* problems with socket opts */
#define CONN_ERROR_NONBLOCK		15	/* set socket nonblock failed*/
#define CONN_ERROR_HOSTNAME		16	/* could not lookup host */
#define CONN_ERROR_CONNECT		17	/* no connection */
#define CONN_ERROR_BIND			18	/* could not bind socket */
#define CONN_ERROR_LISTEN		19	/* could not listen on socket*/
#define CONN_ERROR_SELECT		20	/* could not select on socket*/
#define CONN_ERROR_ACCEPT		21	/* could not accept on socket*/
#define CONN_ERROR_SOCKET_CLOSED	22	/* socket closed prematurely */
#define CONN_ERROR_MAGIC		23	/* improper connection magic */
#define CONN_ERROR_SYNCHRONIZE		24	/* could not sync connection */
#define CONN_ERROR_NEED_TYPES		25	/* needed types didn't match */
#define CONN_ERROR_TYPE_INVALID		26	/* remote type is invalid */
#define CONN_ERROR_TYPE_SIZE		27	/* remote type size diff */
#define CONN_ERROR_TYPE_DATA		28	/* remote type data diff */
#define CONN_ERROR_AUTHENTICATE		29	/* could not authenticate */
#define CONN_ERROR_CLIENT		30	/* improper use of client */
#define CONN_ERROR_SERVER		31	/* improper use of server */
#define CONN_ERROR_REMOTE_WRITE		32	/* could not write to server */
#define CONN_ERROR_REMOTE_READ		33	/* could not read from server*/
#define CONN_ERROR_REMOTE_DATA		34	/* improper data from server */

#ifdef CONN_MAIN

#include "conn_loc.h"

#else

/* generic connection type -- in debugger, seen externally as conn_ext_t */
typedef	void	conn_t;

#endif

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/*<<<<<<<<<<  The below prototypes are auto-generated by fillproto */

/*
 * conn_t *conn_client
 *
 * DESCRIPTION:
 *
 * Originate a connection with a remote host.  This negotiates a
 * connection with a server running with conn_serve.
 *
 * RETURNS:
 *
 * Success - Allocated connection structure which must be passed to
 * conn_close later.
 *
 * Failure - NULL
 *
 * ARGUMENTS:
 *
 * server_hostname - Name of the server host we are connecting.
 *
 * server_port - Port number on the server that we are connection.
 *
 * buffer_size - Size of our internal i/o buffer.  Set to 0 to use the
 * library default of 1k.
 *
 * connect_timeout - Milleseconds timeout value to wait for the
 * connection.
 *
 * io_timeout - Milleseconds timeout value to wait for any i/o.
 *
 * send_recv_b - If set to 1 then use the send and recv functions
 * instead of the read and write functions.  NT must have this set to
 * 1.
 *
 * error_p - Pointer to an integer which upon return contains a conn
 * error-code.
 */
extern
conn_t	*conn_client(const char *server_hostname,
		     const unsigned short server_port,
		     const int buffer_size, const unsigned int connect_timeout,
		     const unsigned int io_timeout, const int send_recv_b,
		     int *error_p);

/*
 * conn_t *conn_client_sd
 *
 * DESCRIPTION:
 *
 * Configurate an already established socket connection as a
 * client-side.  This assumes that the socket is already connected.
 * It will negotiate a connection with a server running with
 * conn_serve or conn_serve_sd.  This is useful when you need to
 * connect the socket yourself and negotiate a little bit before
 * firing off the transactions.
 *
 * RETURNS:
 *
 * Success - Allocated connection structure which must be passed to
 * conn_close later.
 *
 * Failure - NULL
 *
 * ARGUMENTS:
 *
 * client_sd - Socket descriptor that we are associating with this
 * client connection.
 *
 * buffer_size - Size of our internal i/o buffer.  Set to 0 to use the
 * library default of 1k.
 *
 * io_timeout - Milleseconds timeout value to wait for any i/o.
 *
 * send_recv_b - If set to 1 then use the send and recv functions
 * instead of the read and write functions.  NT must have this set to
 * 1.
 *
 * error_p - Pointer to an integer which upon return contains a conn
 * error-code.
 */
extern
conn_t	*conn_client_sd(const int client_sd, const int buffer_size,
			const unsigned int io_timeout, const int send_recv_b,
			int *error_p);

/*
 * conn_t *conn_server
 *
 * DESCRIPTION:
 *
 * Serve a port to remote clients.  This sets up the connection
 * however will not wait for a connection.  You must then use
 * conn_accept to accept connections on the port.
 *
 * RETURNS:
 *
 * Success - Allocated connection structure which must be passed to
 * conn_close later.
 *
 * Failure - NULL
 *
 * ARGUMENTS:
 *
 * port - Port number to listen for connections.
 *
 * listen_queue - Number to pass to listen to set up the connection
 * queue for our socket.
 *
 * send_recv_b - If set to 1 then use the send and recv functions
 * instead of the read and write functions.  NT must have this set to
 * 1.
 *
 * error_p - Pointer to an integer which upon return contains a conn
 * error-code.
 */
extern
conn_t	*conn_server(const unsigned short port, const int listen_queue,
		     const int send_recv_b, int *error_p);

/*
 * conn_t *conn_serve_sd
 *
 * DESCRIPTION:
 *
 * Startup a server-side connection on an already established and
 * connected socket.  This will negotiate with the remote client and
 * after it returns you are ready to start sending an receiving data.
 *
 * RETURNS:
 *
 * Success - Allocated connection structure which must be passed to
 * conn_close later.
 *
 * Failure - NULL
 *
 * ARGUMENTS:
 *
 * server_sd - Already established socket descriptor.
 *
 * send_recv_b - If set to 1 then use the send and recv functions
 * instead of the read and write functions.  NT must have this set to
 * 1.
 *
 * buffer_size - Size of our internal i/o buffer.  Set to 0 to use the
 * library default of 1k.
 *
 * io_timeout - Milleseconds timeout value to wait for any i/o.
 *
 * send_recv_b - If set to 1 then use the send and recv functions
 * instead of the read and write functions.  NT must have this set to
 * 1.
 *
 * error_p - Pointer to an integer which upon return contains a conn
 * error-code.
 */
extern
conn_t	*conn_serve_sd(const int server_sd, const int buffer_size,
		       const unsigned int io_timeout, const int send_recv_b,
		       int *error_p);

/*
 * conn_t *conn_accept
 *
 * DESCRIPTION:
 *
 * Wait for a connection on our port from a remote client.  If one
 * arrives then accept the connection and negotiates with the remote
 * client.
 *
 * RETURNS:
 *
 * Success - Allocated connection structure which must be passed to
 * conn_close later.
 *
 * Failure - NULL
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that was created by conn_serve.
 *
 * buffer_size - Size of our internal i/o buffer.  Set to 0 to use the
 * library default of 1k.
 *
 * accept_timeout - Milleseconds timeout value to wait for any
 * connections.
 *
 * io_timeout - Millisecond timeout value for input/output
 * negotiations with the client.
 *
 * ip_buf - Buffer which, if not NULL, will be copied the ascii
 * version of the remote host's IP address.
 *
 * ip_len - Length of the ip_buf.
 *
 * error_p - Pointer to an integer which upon return contains a conn
 * error-code.
 */
extern
conn_t	*conn_accept(conn_t *conn_p, const int buffer_size,
		     const int accept_timeout, const int io_timeout,
		     char *ip_buf, const int ip_len, int *error_p);

/*
 * int conn_close
 *
 * DESCRIPTION:
 *
 * Close a connection previously opened with conn_client or
 * conn_server and free any allocations associated with the
 * structures.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection we are closing.
 */
extern
int	conn_close(conn_t *conn_p);

/*
 * int conn_encrypt
 *
 * DESCRIPTION:
 *
 * Sets (or replaces) the encryption string for the connection.  This
 * is done after the connection is established.  The remote machine do
 * call this with the same string, before data flowing between the two
 * is properly decrypted.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection we are encrypting.
 *
 * encrypt_string - Encryption string of bytes which is used to
 * encrypt the data stream with the remote host.  NOTE: it can include
 * '\0' and other binary characters.
 *
 * encrypt_len - Length of the encryption_string.
 */
extern
int	conn_encrypt(conn_t *conn_p, const char *encrypt_string,
		     const int encrypt_len);

/*
 * int conn_buffer_sizes
 *
 * DESCRIPTION:
 *
 * Sets the socket read or write buffer sizes on a connection.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection we are modifying.
 *
 * read_buf_size - If > 0 then set the receive buffer size on the
 * socket to this value.
 *
 * write_buf_size - If > 0 then set the send buffer size on the socket
 * to this value.
 */
extern
int	conn_buffer_sizes(conn_t *conn_p, const int read_buf_size,
			  const int write_buf_size);

/*
 * int conn_type_okay
 *
 * DESCRIPTION:
 *
 * Determines whether the type is safe to pass across the connection.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that was created by conn_serve.
 *
 * type_num - Type number to test for safety.
 *
 * allow_bp - Pointer to an integer which will be set upon return to 1
 * if the type is okay to use else 0.
 */
extern
int	conn_type_okay(const conn_t *conn_p, const int type_num, int *allow_bp);

/*
 * int conn_info
 *
 * DESCRIPTION:
 *
 * Get information about the connection from the structure.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that was created by conn_serve.
 *
 * read_bytes_np - Pointer to an unsigned long integer which will be
 * set upon return to the number of bytes read from the remote system
 * over the connection.
 *
 * write_bytes_np - Pointer to an unsigned long integer which will be
 * set upon return (if not NULL) to the number of bytes written to the
 * remote system over the connection.
 *
 * read_np - Pointer to an unsigned long integer which will be set
 * upon return (if not NULL) to the number of read calls made by the
 * connection.
 *
 * write_np - Pointer to an unsigned long integer which will be set
 * upon return (if not NULL) to the number of write calls made by the
 * connection.
 *
 * sd_p - Pointer to an integer which will be set upon return (if not
 * NULL) to the associated socket file descriptor.  NOTE: this is for
 * information purposes only.  Nothing should be read or written to
 * the descriptor directly.
 */
extern
int	conn_info(const conn_t *conn_p,
		  unsigned long *read_bytes_np, unsigned long *write_bytes_np,
		  unsigned long *read_np, unsigned long *write_np,
		  int *sd_p);

/*
 * int conn_send_data
 *
 * DESCRIPTION:
 *
 * Add to a buffer a list of (const int data_type, const int
 * data_many, void *data) triplets, advancing the connection buffer
 * pointers so they are always at the end of the data.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that we will be using to send the
 * data.
 *
 * io_timeout - Millisecond timeout value for input/output with the
 * remote host.
 *
 * ... - Variable arguments list of (const int data_type, const int
 * data_many, void *data) triplets.  The data_type should be one of
 * the defined connection types in the conn.h file.  The list of items
 * is terminated if the data_type is CONN_TYPE_LAST.  If the data_many
 * is < 0 then the type should be character or unsigned character.
 * The routine will then add a string including the '\0' to the
 * buffer.
 */
extern
int	conn_send_data(conn_t *conn_p, const int io_timeout, ...);

/*
 * int conn_flush
 *
 * DESCRIPTION:
 *
 * Flush any output buffered in the connection structure to the remote
 * host.  This is only necessary after a conn_send.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that we will are flushing.
 *
 * io_timeout - Millisecond timeout value for input/output with the
 * remote host.
 */
extern
int	conn_flush(conn_t *conn_p, const int io_timeout);

/*
 * int conn_receive_data
 *
 * DESCRIPTION:
 *
 * Remove from the buffer a list of (const int data_type, const char
 * data_alloc_b, const int data_many, void *data) fivesomes, advancing
 * the connection buffer pointers so they are always at the end of the
 * data.
 *
 * WARNING: This is very dependent on the same data alignment passed
 * to conn_send_data as is passed here.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code.
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that we will be using to send the
 * data.
 *
 * io_timeout - Millisecond timeout value for input/output with the
 * remote host.
 *
 * ... - Variable arguments list of (const int data_type, const char
 * data_alloc_b, const int data_many, const int *data_many_p, void
 * *data) fivesomes.  The data_type should be one of the defined
 * connection types in the conn.h file.  The list of items is
 * terminated if the data_type is CONN_TYPE_LAST.  If data_alloc_b is
 * 1 then the routine will assume that the data type is a pointer to a
 * pointer of the type.  Space for the data is malloc'ed and the
 * pointer is pointed to this new space.  If the data_many is < 0 then
 * you are not limiting the receive of this type to any size so the
 * data_allow_b flag must be set to 1.  If data_many >= 0 it is the
 * number of the type that we are receiving.  If data_many_p is not
 * null then it will be set with the number of the type that we got
 * from the stream.  The routine will then add a string including the
 * '\0' to the buffer.
 */
extern
int	conn_receive_data(conn_t *conn_p, const int io_timeout, ...);

/*
 * int conn_check_magic
 *
 * DESCRIPTION:
 *
 * This routine is used to exchange a magic number with the remote
 * host to verify that both sides are running the same software.
 *
 * RETURNS:
 *
 * Success - CONN_ERROR_NONE
 *
 * Failure - Connection error code
 *
 * ARGUMENTS:
 *
 * conn_p - Connection structure that we will be using to send the
 * data.
 *
 * magic - Data that will will exchange with the remote system and we
 * will verify that we get back from the remote.
 *
 * magic_len - Length of the magic data.  If < 0 then the routine will
 * do an internal strlen.
 *
 * io_timeout - Millisecond timeout value for input/output with the
 * remote host.
 */
extern
int	conn_check_magic(conn_t *conn_p, const void *magic,
			 const int magic_len, const int io_timeout);

/*
 * const char *conn_strerror
 *
 * DESCRIPTION:
 *
 * Return the string equivalent of a connection error value.
 *
 * RETURNS:
 *
 * Success - String equivalent of the error.
 *
 * Failure - String "invalid error code".
 *
 * ARGUMENTS:
 *
 * error - Error value to translate into a string.
 */
extern
const char	*conn_strerror(const int error);

/*<<<<<<<<<<   This is end of the auto-generated output from fillproto. */

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __CONN_H__ */

