/* -*- c -*-
** Copyright (C) 2000 by Kevin L. Mitchell <klmitch@mit.edu>
**
** 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**
** @(#)$Id: sock.h.top,v 1.7 2000/12/11 03:21:25 klmitch Exp $
*/
#ifndef __include_sock_h__
#define __include_sock_h__

#ifndef __defined__s_ul__
typedef unsigned long	_s_ul;
#define __defined__s_ul__
#endif
#ifndef __defined__s_us__
typedef unsigned short	_s_us;
#define __defined__s_us__
#endif

typedef struct _sock		sock;		/* socket descriptor */
typedef struct _sock_addr	sock_addr;	/* socket address */

typedef struct _sock_call	sock_call;	/* socket callbacks */

/* When there is data to be read from the socket, and the application has
 * expressed interest in read notifications, the sock_read callback is
 * called.  The application unfortunately must handle buffering itself.
 */
typedef void (*scb_read)(sock *);

/* When data can be written to a socket, and the application has expressed
 * interest in write notifications, the sock_write callback is called.
 * Again, buffering is left up to the application.
 */
typedef void (*scb_write)(sock *);

/* When a listening socket reports that it has a connection pending,
 * the sock_accept callback is called to accept the connection.  Its first
 * order of business will be to allocate another sock structure and call
 * the accept function.
 */
typedef void (*scb_accept)(sock *);

/* When a connection in progress has been completed, the socket is
 * passed to the sock_connect callback.
 */
typedef void (*scb_connect)(sock *);

/* If an end-of-file indication is seen on the socket, and the application
 * has expressed interest in read readiness, the sock_eof callback will be
 * called to process the indication.  The socket will not be closed by the
 * library.
 */
typedef void (*scb_eof)(sock *);

/* If an error occurs on a socket, the offending socket and the error
 * code will be fed to the sock_error callback, which may choose to
 * close the offending socket or take other action.
 */
typedef void (*scb_error)(sock *, _s_ul);

struct _sock_call {
  _s_ul		sc_magic;	/* magic number */
  scb_read	sc_read;	/* socket has data to read */
  scb_write	sc_write;	/* can write data to socket */
  scb_accept	sc_accept;	/* listening socket has connection pending */
  scb_connect	sc_connect;	/* connection completed on socket */
  scb_eof	sc_eof;		/* end-of-file from peer */
  scb_error	sc_error;	/* error on socket */
};

#define SOCK_CALL_MAGIC 0x5372d53b
#define SOCK_CALL_INIT(read, write, accept, connect, eof, error) \
{				\
  SOCK_CALL_MAGIC,		\
  (read),			\
  (write),			\
  (accept),			\
  (connect),			\
  (eof),			\
  (error)			\
}

#define sc_verify(sc)	((sc) && (sc)->sc_magic == SOCK_CALL_MAGIC)

struct _sock {
  _s_ul		s_magic;	/* magic number */
  sock	       *s_next;		/* next socket */
  sock	      **s_prev_p;	/* what points to us */
  int		s_fd;		/* file descriptor */
  _s_us		s_proto;	/* protocol and type */
  _s_us		s_events;	/* events we're interested in */
  const sock_addr
	       *s_local;	/* local address of endpoint */
  const sock_addr
	       *s_remote;	/* remote address of endpoint */
  const sock_call
	       *s_call;		/* callbacks */
  void	       *s_data;		/* application-defined data--buffering, etc. */
};

#define SOCK_MAGIC 0xe9819889

#define sock_verify(s)	((s) && (s)->s_magic == SOCK_MAGIC)

#define sock_fd(s)	((s)->s_fd)
#define sock_proto(s)	((s)->s_proto & SOCK_PROTO_MASK)
#define sock_type(s)	((s)->s_proto & SOCK_TYPE_MASK)
#define sock_events(s)	((s)->s_events & SOCK_EVENT_MASK)
#define sock_local(s)	((s)->s_local)
#define sock_remote(s)	((s)->s_remote)
#define sock_call(s)	((s)->s_call)
#define sock_data(s)	((s)->s_data)

#define SOCK_PROTO_MASK		0xff00	/* protocol mask */
#define SOCK_PROTO_PICK		0x0000	/* pick a protocol */
#define SOCK_PROTO_IP		0x0100	/* IP protocol */
#define SOCK_PROTO_IP6		0x0200	/* IP6 protocol */
#define SOCK_PROTO_UN		0x0300	/* UNIX domain protocol */
#define SOCK_PROTO_PIPE		0xfe00	/* "magic" protocol for pipes */
#define SOCK_PROTO_NONE		0xff00	/* no protocol at all */

#define SOCK_TYPE_MASK		0x00ff	/* type mask */
#define SOCK_TYPE_PICK		0x0000	/* pick a type */
#define SOCK_TYPE_STREAM	0x0001	/* stream type */
#define SOCK_TYPE_DGRAM		0x0002	/* datagram type */
#define SOCK_TYPE_RAW		0x0003	/* raw type */
#define SOCK_TYPE_NONE		0x00ff	/* no type at all */

#define SOCK_EVENT_READ		0x0001	/* interested in readable events */
#define SOCK_EVENT_WRITE	0x0002	/* interested in writable events */
#define SOCK_EVENT_MASK		0x00ff	/* mask the event bits */

#define SOCK_SET		0x8000	/* set the bits in the event mask */
#define SOCK_CLR		0x4000	/* clear the bits in the event mask */

#define SOCK_READ	0x0001	/* action will be on read direction */
#define SOCK_WRITE	0x0002	/* action will be on write direction */
#define SOCK_BOTH	(SOCK_DIR_READ|SOCK_DIR_WRITE) /* action on both */

/* sock_addr_2_sockaddr() turns a sock_addr into a sockaddr--*sigh* I
 * don't like the name collision, either.
 *
 * sock_sockaddr_2_addr() turns a sockaddr into a sock_addr
 */
_s_ul sock_addr_2_sockaddr(const sock_addr *address, struct sockaddr *addr,
			   socklen_t *addr_len_p);
_s_ul sock_sockaddr_2_addr(sock_addr **address_p, const struct sockaddr *addr,
			   socklen_t addr_len);

/* sock_addr_2_presentation() takes a sock_addr and returns the appropriate
 * ASCII presentation representation.
 *
 * sock_presentation_2_addr() takes a string and converts it to the
 * appropriate sock_addr format.
 */
_s_ul sock_addr_2_presentation(const sock_addr *address, char *buf,
			       _s_ul *buf_len_p);
_s_ul sock_presentation_2_addr(sock_addr **address_p, const char *buf,
			       _s_ul buf_len);

/* sock_fdopen() is intended to take a currently opened file descriptor
 * and create a sock struct around it.  The proto_hint parameter is meant
 * to give the library a hint as to the protocol family (IPv4, IPv6,
 * UNIX domain, etc.) and type (stream or datagram) of the fd; if it's 0,
 * the library will attempt to figure this out for itself.
 */
_s_ul sock_fdopen(sock *s, int fd, _s_us proto_hint, sock_addr *local,
		  sock_addr *remote, const sock_call *cb);

/* sock_stream() opens a stream socket; if <local> is null, binds a
 * wildcard locally; if <remote> is null, sets up a listening socket.
 * The <cb> parameter is a structure containing function pointers to
 * functions to be called when various events occur on the socket.
 */
_s_ul sock_stream(sock *s, sock_addr *local, sock_addr *remote,
		  const sock_call *cb);

/* sock_dgram() opens a datagram socket; if <local> is null, binds a
 * wildcard locally; if <remote> is non-null, connects to the specified
 * remote destination.  The <cb> parameter is a structure containing
 * function pointers to functions to be called when various events occur
 * on the socket.
 */
_s_ul sock_dgram(sock *s, sock_addr *local, sock_addr *remote,
		 const sock_call *cb);

/* sock_accept() accepts a connection on a listening socket, assuming one
 * is pending, storing the <local> and <remote> addresses, if they are
 * non-null.  The <cb> parameter is a structure containing function pointers
 * to functions to be called when various events occur on the socket.
 */
_s_ul sock_accept(sock *new_s, sock *list_s, sock_addr *local,
		  sock_addr *remote, const sock_call *cb);

/* sock_call_set() sets the callbacks for a given socket to the structure
 * passed in through the <cb> parameter.
 */
_s_ul sock_call_set(sock *s, const sock_call *cb);

/* sock_event_set() sets the events that we're interested in for a given
 * socket.  If the <events> parameter is just one of SOCK_READ, SOCK_WRITE
 * or SOCK_BOTH, the socket's event mask is set to that.  It can, however,
 * be ORed with SOCK_SET or SOCK_CLR to set or clear a specific event type.
 */
_s_ul sock_event_set(sock *s, _s_us events);

/* sock_data_set() simply sets the application-defined data associated with
 * the given socket.
 */
_s_ul sock_data_set(sock *s, void *data);

/* sock_close() closes a socket.  If the socket is a stream socket,
 * sock_shutdown() may be substituted.  Buffered data will be written
 * first; use sock_abort() or manually flush the buffers to inhibit
 * this behavior.
 */
_s_ul sock_close(sock *s);

/* sock_shutdown() may be used to perform half-closes of stream
 * sockets; its use on datagram sockets isn't well defined.
 */
_s_ul sock_shutdown(sock *s, _s_us which);

/* sock_abort() may be used to abort a connection; it will cause a TCP
 * RST to be sent to the other end.  This only makes sense on stream
 * sockets.
 */
_s_ul sock_abort(sock *s);

/* sock_loop() is the select loop that drives a libsock program. */
void sock_loop(void);

/* begin sock_err.h */

