/*
Copyright (c) 2000-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  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.
*/

/**	@file dktcpip.h	Portable TCP/IP and UDP client API.
*/

#ifndef DK_TCPIP_INC
#define DK_TCPIP_INC 1

#include <dk.h>
#include <dktypes.h>

#if defined(EXTERN)
#undef EXTERN
#endif
#ifndef DK_TPCIP_C
#if !DK_HAVE_PROTOTYPES
#define EXTERN extern
#else
#define EXTERN /* nix */
#endif
#else
#define EXTERN /* nix */
#endif

#if defined(__cplusplus)
extern "C" {
#endif


/**	Start TCP/IP subsystem.
	On Windows the TCP/IP protocol is not necessarily installed on a
	computer. This function checks whether the protocol is installed
	and attempts to load the DLLs. On other systems it does imply nothing.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_start DK_PR((void));



/**	End TCP/IP subsystem.
	On Windows the TCP/IP subsystem should be brought down by applications
	which started it. On other systems this function simply does nothing.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_end DK_PR((void));



/**	Create new TCP/IP support structure. The structure is created in
	dynamically allocated memory, use dktcpip_delete() to destroy
	it and release the memory.
	@return	Pointer to new structure on success, NULL on error.
*/
EXTERN dk_tcpip_t *
dktcpip_new DK_PR((void));



/**	Destroy TCP/IP support structure created by dktcpip_new() and
	release memory. The endpoint is brought down if necessary.
	@param	t	TCP/IP support structure.
*/
EXTERN void
dktcpip_delete DK_PR((dk_tcpip_t *t));



/**	Initialize TCP/IP support structure (for static variables
	not created by dktcpip_new()).
	@param	t	TCP/IP support structure.
*/
EXTERN void
dktcpip_init DK_PR((dk_tcpip_t *t));



/**	Get pointer to address structure of TCP/IP support structure.
	@param	t	TCP/IP support structure.
	@param	w	Indicator, which address to choose:
			DK_IP_ADDR_REMOTE_WISHED,
			DK_IP_ADDR_REMOTE_FOUND,
			DK_IP_ADDR_LOCAL_WISHED or
			DK_IP_ADDR_LOCAL_FOUND.
	@return	Pointer to address on success, NULL on error.
*/
EXTERN dk_ip_addr_t *
dktcpip_get_addr DK_PR((dk_tcpip_t *t, int w));



/**	Set address structure to point to a given host.
	@param	a	Address structure.
	@param	h	Host (IP address or host name).
	@param	t	TCP/IP support structure.
			The error code (if any) is stored here.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpipaddr_set_ip_byname DK_PR((dk_ip_addr_t *a, char *h, dk_tcpip_t *t));



/**	Set address structure to loopback interface address.
	@param	a	Address structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpipaddr_set_ip_loopback DK_PR((dk_ip_addr_t *a));



/**	Set address structure to local IP address.
	@param	a	Adress structure.
	@param	t	TCP/IP support structure.
			The error code (if any) is stored here.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpipaddr_set_ip_local DK_PR((dk_ip_addr_t *a, dk_tcpip_t *t));



/**	Set address structure to use any address.
	This is useful for binding local addresses.
	@param	a	Adress structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpipaddr_set_ip_any DK_PR((dk_ip_addr_t *a));



/**	Set port range for address.
	Some applications might want to bind local addresses from
	a specific range. For the remote addresses the \a min
	and \a max parameter should be equal.
	@param	a	Address structure.
	@param	min	Minimum port number to use.
	@param	max	Maximum port number to use.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_addr_set_port DK_PR((dk_ip_addr_t *a, unsigned short min, unsigned short max));



/**	Set up connection-oriented (TCP) or connectionless (UDP)
	use.
	@param	t	TCP/IP support structure.
	@param	f	Flag, use connectionless mode.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_connectionless DK_PR((dk_tcpip_t *t, int f));



/**	Bring endpoint up.
	This function brings the endpoint into a state allowing to
	send and receive data. Depending on whether TCP or UDP is
	used the endpoint is opened, a local address is bound and
	a connection is established (for TCP).
	@param	t	TCP/IP support structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_up DK_PR((dk_tcpip_t *t));



/**	Shut down endpoint.
	Orderly release (shutdown for writing, reading until no more data)
	for TCP connections, close file descriptor.
	@param	t	TCP/IP support structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_down DK_PR((dk_tcpip_t *t));



/**	Receive data.
	@param	t	TCP/IP support structure.
	@param	b	Buffer to receive data.
	@param	l	Pointer to size variable
			(in: length of \a l in bytes, out: number of bytes
			received).
	@return	Flag to indicate success. The function indicates success
			if the lower-level functions for the endpoint
			did not indicate errors. If the function returns
			successfully check the size variable whether or not
			any bytes were received.
*/
EXTERN int
dktcpip_read DK_PR((dk_tcpip_t *t, char *b, size_t *l));



/**	Send data.
	@param	t	TCP/IP support structure.
	@param	b	Buffer containing the data to write.
	@param	l	Pointer to length variable
			(in: size of \a b, out: number of bytes written)
	@return	Flag to indicate success. The operation succeeds if the
			endpoints sending function does not indicate an
			error. Check the number of bytes written and compare
			it against the number of bytes to write to ensure
			all bytes are written properly if the function
			indicates success.
*/
EXTERN int
dktcpip_write DK_PR((dk_tcpip_t *t, char *b, size_t *l));



/**	Check whether the end of data already was found.
	@param	t	TCP/IP support structure.
	@return	Flag to indicate end of data found.
*/
EXTERN int
dktcpip_is_rdclosed DK_PR((dk_tcpip_t *t));



/**	Shutdown endpoint for write operations. This indicates that we
	will not write data to the endpoint. The peer will be notified
	about the end of data when attempting to read from the connection.
	@param	t	TCP/IP support structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_closewrite DK_PR((dk_tcpip_t *t));



/**	Set endpoint to non-blocking mode.
	@param	t	TCP/IP support structure.
	@param	f	Flag, use non-blocking mode.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_nonblock DK_PR((dk_tcpip_t *t, int f));



/**	Set timeout for operations.
	@param	t	TCP/IP support structure.
	@param	o	Timeout in seconds.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_timeout DK_PR((dk_tcpip_t *t, double o));



/**	Set remote wished address to remote found address.
	For UDP endpoints the next datagram will be sent
	to the address the last datagram was received from.
	@param	t	TCP/IP support structure.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_respond DK_PR((dk_tcpip_t *t));



/**	Set reuse flag for endpoint.
	@param	t	TCP/IP support structure.
	@param	f	New flag value.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_reuse DK_PR((dk_tcpip_t *t, int f));



/**	Enable/disable broadcast for endpoint.
	@param	t	TCP/IP support structure.
	@param	f	Flag, enable broadcast.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_broadcast DK_PR((dk_tcpip_t *t, int f));



/**	Set keep-alive flag.
	@param	t	TCP/IP support structure.
	@param	f	New flag value.
	@return	Flag to indicate success.
*/
EXTERN int
dktcpip_set_keepalive DK_PR((dk_tcpip_t *t, int f));



/**	Get last error code, optionally clear error.
	@param	t	TCP/IP support structure.
	@param	c	Flag, clear error code.
	@return	Last error occured with \a t.
*/
EXTERN int
dktcpip_get_error_code DK_PR((dk_tcpip_t *t, int c));



#if defined(__cplusplus)
}
#endif

/** Retrieve address: Remote address wanted. */
#define DK_IP_ADDR_REMOTE_WISHED 0

/** Retrieve address: Remote address found. */
#define DK_IP_ADDR_REMOTE_FOUND  1

/** Retrieve address: Local address wanted. */
#define DK_IP_ADDR_LOCAL_WISHED  2

/** Retrieve address: Local address found. */
#define DK_IP_ADDR_LOCAL_FOUND   3

#endif

