/* libanode: the Anode C reference implementation
 * Copyright (C) 2009-2010 Adam Ierymenko <adam.ierymenko@gmail.com>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>. */

#ifndef _ANODE_ANODE_H
#define _ANODE_ANODE_H

#ifdef __cplusplus
extern "C" {
#endif

#ifndef NULL
#define NULL ((void *)0)
#endif

#define ANODE_ADDRESS_LENGTH_ANODE_256_40 40
#define ANODE_ADDRESS_MAX_LENGTH 40
#define ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40 32
#define ANODE_ADDRESS_MAX_SECRET_LENGTH 32

#define ANODE_ADDRESS_ID_LENGTH 8
#define ANODE_ZONE_LENGTH 4

#define ANODE_ERR_NONE 0
#define ANODE_ERR_INVALID_ARGUMENT (-10000)
#define ANODE_ERR_OUT_OF_MEMORY (-10001)
#define ANODE_ERR_INVALID_URI (-10002)
#define ANODE_ERR_BUFFER_TOO_SMALL (-10003)
#define ANODE_ERR_ADDRESS_INVALID (-10010)
#define ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED (-10011)
#define ANODE_ERR_CONNECTION_CLOSED (-10012)
#define ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE (-10013)
#define ANODE_ERR_CONNECT_FAILED (-10014)
#define ANODE_ERR_UNABLE_TO_BIND (-10015)
#define ANODE_ERR_TOO_MANY_OPEN_SOCKETS (-10016)
#define ANODE_ERR_DNS_NAME_NOT_FOUND_OR_TIMED_OUT (-10017)

/**
 * Get a human-readable error description for an error code
 *
 * The value of 'err' can be either negative or positive.
 *
 * @param err Error code
 * @return Human-readable description
 */
extern const char *Anode_strerror(int err);

/* ----------------------------------------------------------------------- */
/* Secure random source                                                    */
/* ----------------------------------------------------------------------- */

/**
 * Opaque secure random instance
 */
typedef void AnodeSecureRandom;

/**
 * Initialize a secure random source
 *
 * No cleanup/destructor is necessary.
 *
 * @param srng Random structure to initialize
 */
extern AnodeSecureRandom *AnodeSecureRandom_new();

/**
 * Generate random bytes
 *
 * @param srng Secure random source
 * @param buf Buffer to fill
 * @param count Number of bytes to generate
 */
extern void AnodeSecureRandom_gen_bytes(AnodeSecureRandom *srng,void *buf,long count);

/**
 * Destroy and free a secure random instance
 *
 * @param srng Secure random source
 */
extern void AnodeSecureRandom_delete(AnodeSecureRandom *srng);

/* ----------------------------------------------------------------------- */
/* AES-256 derived Davis-Meyer hash function                               */
/* ----------------------------------------------------------------------- */

/**
 * Digest a message using AES-DIGEST to yield a 16-byte hash code
 *
 * @param message Message to digest
 * @param message_len Length of message in bytes
 * @param hash Buffer to store 16 byte hash code
 */
extern void Anode_aes_digest(
  const void *const message,
  unsigned long message_len,
  void *const hash);

/* ----------------------------------------------------------------------- */
/* Address Types and Components                                            */
/* ----------------------------------------------------------------------- */

/**
 * Anode address
 *
 * The first byte always identifies the address type, which right now can
 * only be type 1 (ANODE-256-40).
 */
typedef struct
{
  char bits[ANODE_ADDRESS_MAX_LENGTH];
} AnodeAddress;

/**
 * 8-byte short Anode address ID
 */
typedef struct
{
  char bits[ANODE_ADDRESS_ID_LENGTH];
} AnodeAddressId;

/**
 * 4-byte Anode zone ID
 */
typedef struct
{
  char bits[ANODE_ZONE_LENGTH];
} AnodeZone;

/**
 * Anode address types
 */
enum AnodeAddressType
{
  ANODE_ADDRESS_ANODE_256_40 = 1
};

/**
 * Get the type of an Anode address
 *
 * This is a shortcut macro for just looking at the first byte and casting
 * it to the AnodeAddressType enum.
 *
 * @param a Pointer to address
 * @return Type as enum AnodeAddressType
 */
#define AnodeAddress_get_type(a) ((enum AnodeAddressType)((a)->bits[0]))

/**
 * Calculate the short 8 byte address ID from an address
 *
 * @param address Binary address
 * @param short_address_id Buffer to store 8-byte short address ID
 * @return 0 on success or error code on failure
 */
extern int AnodeAddress_calc_short_id(
  const AnodeAddress *address,
  AnodeAddressId *short_address_id);

/**
 * Extract the zone from an anode address
 *
 * @param address Binary address
 * @param zone Zone value-result parameter to fill on success
 * @return 0 on success or error code on failure
 */
extern int AnodeAddress_get_zone(const AnodeAddress *address,AnodeZone *zone);

/**
 * Convert an address to an ASCII string
 *
 * Anode addresses are 64 characters in ASCII form, so the buffer should
 * have 65 bytes of space.
 *
 * @param address Address to convert
 * @param buf Buffer to receive address in string form (should have 65 bytes of space)
 * @param len Length of buffer
 * @return Length of resulting string or a negative error code on error
 */
extern int AnodeAddress_to_string(const AnodeAddress *address,char *buf,int len);

/**
 * Convert a string into an address
 *
 * @param str Address in string form
 * @param address Address buffer to receive result
 * @return Zero on sucess or error code on error
 */
extern int AnodeAddress_from_string(const char *str,AnodeAddress *address);

/**
 * Supported network address types
 */
enum AnodeNetworkAddressType
{
  ANODE_NETWORK_ADDRESS_IPV4 = 0,
  ANODE_NETWORK_ADDRESS_IPV6 = 1,
  ANODE_NETWORK_ADDRESS_ETHERNET = 2,  /* reserved but unused */
  ANODE_NETWORK_ADDRESS_USB = 3,       /* reserved but unused */
  ANODE_NETWORK_ADDRESS_BLUETOOTH = 4, /* reserved but unused */
  ANODE_NETWORK_ADDRESS_IPC = 5,       /* reserved but unused */
  ANODE_NETWORK_ADDRESS_80211S = 6,    /* reserved but unused */
  ANODE_NETWORK_ADDRESS_SERIAL = 7,    /* reserved but unused */
  ANODE_NETWORK_ADDRESS_ANODE_256_40 = 8
};

/**
 * Anode network address
 *
 * This can contain an address of any type: IPv4, IPv6, or Anode, and is used
 * with the common transport API.
 *
 * The length of the address stored in bits[] is determined by the type.
 */
typedef struct
{
  enum AnodeNetworkAddressType type;
  char bits[ANODE_ADDRESS_MAX_LENGTH];
} AnodeNetworkAddress;

/**
 * An endpoint with an address and a port
 */
typedef struct
{
  AnodeNetworkAddress address;
  int port;
} AnodeNetworkEndpoint;

/* Constants for binding to any address (v4 or v6) */
extern const AnodeNetworkAddress AnodeNetworkAddress_IP_ANY_V4;
extern const AnodeNetworkAddress AnodeNetworkAddress_IP_ANY_V6;

/* Local host address in v4 and v6 */
extern const AnodeNetworkAddress AnodeNetworkAddress_IP_LOCAL_V4;
extern const AnodeNetworkAddress AnodeNetworkAddress_IP_LOCAL_V6;

/**
 * Convert a network address to an ASCII string
 *
 * The buffer must have room for a 15 character string for IPv4, a 40 byte
 * string for IPv6, and a 64 byte string for Anode addresses. This does not
 * include the trailing null.
 *
 * @param address Address to convert
 * @param buf Buffer to receive address in string form
 * @param len Length of buffer
 * @return Length of resulting string or a negative error code on error
 */
extern int AnodeNetworkAddress_to_string(const AnodeNetworkAddress *address,char *buf,int len);

/**
 * Convert a string into a network address of the correct type
 *
 * @param str Address in string form
 * @param address Address buffer to receive result
 * @return Zero on sucess or error code on error
 */
extern int AnodeNetworkAddress_from_string(const char *str,AnodeNetworkAddress *address);

/**
 * Fill a network endpoint from a C-API sockaddr structure
 *
 * The argument must be struct sockaddr_in for IPv4 or sockaddr_in6 for IPv6.
 * The common sin_family field will be used to differentiate.
 *
 * @param sockaddr Pointer to proper sockaddr structure
 * @param endpoint Endpoint structure to fill
 * @return Zero on success or error on failure
 */
extern int AnodeNetworkEndpoint_from_sockaddr(const void *sockaddr,AnodeNetworkEndpoint *endpoint);

/**
 * Fill a sockaddr from a network endpoint
 *
 * To support either IPv4 or IPv6 addresses, there is a sockaddr_storage
 * structure in most C APIs. If you supply anything other than an IP address
 * such as an Anode address, this will return an error.
 *
 * @param endpoint Endpoint structure to convert
 * @param sockaddr Sockaddr structure storage
 * @param sockaddr_len Length of sockaddr structure storage in bytes
 * @return Zero on success or error on failure
 */
extern int AnodeNetworkEndpoint_to_sockaddr(const AnodeNetworkEndpoint *endpoint,void *sockaddr,int sockaddr_len);

/* ----------------------------------------------------------------------- */
/* Identity Generation and Management                                      */
/* ----------------------------------------------------------------------- */

/**
 * Anode identity structure containing address and secret key
 *
 * This structure is memcpy-safe, and its members are accessible.
 */
typedef struct
{
  /* The public Anode address */
  AnodeAddress address;

  /* Short address ID */
  AnodeAddressId address_id;

  /* The secret key corresponding with the public address */
  /* Secret length is determined by address type */
  char secret[ANODE_ADDRESS_MAX_SECRET_LENGTH];
} AnodeIdentity;

/**
 * Generate a new identity
 *
 * This generates a public/private key pair and from that generates an
 * identity containing an address and a secret key.
 *
 * @param identity Destination structure to store new identity
 * @param zone Zone ID
 * @param type Type of identity to generate
 * @return Zero on success, error on failure
 */
extern int AnodeIdentity_generate(
  AnodeIdentity *identity,
  const AnodeZone *zone,
  enum AnodeAddressType type);

/**
 * Convert an Anode identity to a string representation
 *
 * @param identity Identity to convert
 * @param dest String buffer
 * @param dest_len Length of string buffer
 * @return Length of string created or negative error code on failure
 */
extern int AnodeIdentity_to_string(
  const AnodeIdentity *identity,
  char *dest,
  int dest_len);

/**
 * Convert a string representation to an Anode identity structure
 *
 * @param identity Destination structure to fill
 * @param str C-string containing string representation
 * @return Zero on success or negative error code on failure
 */
extern int AnodeIdentity_from_string(
  AnodeIdentity *identity,
  const char *str);

/* ----------------------------------------------------------------------- */
/* Transport API                                                           */
/* ----------------------------------------------------------------------- */

struct _AnodeTransport;
typedef struct _AnodeTransport AnodeTransport;
struct _AnodeEvent;
typedef struct _AnodeEvent AnodeEvent;

/**
 * Anode socket
 */
typedef struct
{
  /* Type of socket (read-only) */
  enum {
    ANODE_SOCKET_DATAGRAM = 1,
    ANODE_SOCKET_STREAM_LISTEN = 2,
    ANODE_SOCKET_STREAM_CONNECTION = 3
  } type;

  /* Socket state */
  enum {
    ANODE_SOCKET_CLOSED = 0,
    ANODE_SOCKET_OPEN = 1,
    ANODE_SOCKET_CONNECTING = 2,
  } state;

  /* Local address or remote address for stream connections (read-only) */
  AnodeNetworkEndpoint endpoint;

  /* Name of owning class (read-only) */
  const char *class_name;

  /* Pointers for end user use (writable) */
  void *user_ptr[2];

  /* Special handler to receive events or null for default (writable) */
  void (*event_handler)(const AnodeEvent *event);
} AnodeSocket;

/**
 * Anode transport I/O event
 */
struct _AnodeEvent
{
  enum {
    ANODE_TRANSPORT_EVENT_DATAGRAM_RECEIVED = 1,
    ANODE_TRANSPORT_EVENT_STREAM_INCOMING_CONNECT = 2,
    ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_ESTABLISHED = 3,
    ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED = 4,
    ANODE_TRANSPORT_EVENT_STREAM_CLOSED = 5,
    ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED = 6,
    ANODE_TRANSPORT_EVENT_STREAM_AVAILABLE_FOR_WRITE = 7,
    ANODE_TRANSPORT_EVENT_DNS_RESULT = 8
  } type;

  AnodeTransport *transport;

  /* Anode socket corresponding to this event */
  AnodeSocket *sock;

  /* Originating endpoint for incoming datagrams */
  AnodeNetworkEndpoint *datagram_from;

  /* DNS lookup results */
  const char *dns_name;
  AnodeNetworkAddress *dns_addresses;
  int dns_address_count;

  /* Error code or 0 for none */
  int error_code;

  /* Data for incoming datagrams and stream received events */
  int data_length;
  char *data;
};

/**
 * Enum used for dns_resolve method in transport to specify query rules
 *
 * This can be specified for ipv4, ipv6, and Anode address types to tell the
 * DNS resolver when to bother querying for addresses of the given type.
 * NEVER means to never query for this type, and ALWAYS means to always
 * query. IF_NO_PREVIOUS means to query for this type if no addresses were
 * found in previous queries. Addresses are queried in the order of ipv4,
 * ipv6, then Anode, so if you specify IF_NO_PREVIOUS for all three you will
 * get addresses in that order of priority.
 */
enum AnodeTransportDnsIncludeMode
{
  ANODE_TRANSPORT_DNS_QUERY_NEVER = 0,
  ANODE_TRANSPORT_DNS_QUERY_ALWAYS = 1,
  ANODE_TRANSPORT_DNS_QUERY_IF_NO_PREVIOUS = 2
};

struct _AnodeTransport
{
  /**
   * Set the default event handler
   *
   * @param transport Transport engine
   * @param event_handler Default event handler
   */
  void (*set_default_event_handler)(AnodeTransport *transport,
    void (*event_handler)(const AnodeEvent *event));

  /**
   * Enqueue a function to be executed during a subsequent call to poll()
   *
   * This can be called from other threads, so it can be used to pass a
   * message to the I/O thread in multithreaded applications.
   *
   * If it is called from the same thread, the function is still queued to be
   * run later rather than being run instantly.
   *
   * The order in which invoked functions are called is undefined.
   *
   * @param transport Transport engine
   * @param ptr Arbitrary pointer to pass to function to be called
   * @param func Function to be called
   */
  void (*invoke)(AnodeTransport *transport,
    void *ptr,
    void (*func)(void *));

  /**
   * Initiate a forward DNS query
   *
   * @param transport Transport instance
   * @param name DNS name to query
   * @param event_handler Event handler or null for default event path
   * @param ipv4_include_mode Inclusion mode for IPv4 addresses
   * @param ipv6_include_mode Inclusion mode for IPv6 addresses
   * @param anode_include_mode Inclusion mode for Anode addresses
   */
  void (*dns_resolve)(AnodeTransport *transport,
    const char *name,
    void (*event_handler)(const AnodeEvent *),
    enum AnodeTransportDnsIncludeMode ipv4_include_mode,
    enum AnodeTransportDnsIncludeMode ipv6_include_mode,
    enum AnodeTransportDnsIncludeMode anode_include_mode);

  /**
   * Open a datagram socket
   *
   * @param transport Transport instance
   * @param local_address Local address to bind
   * @param local_port Local port to bind
   * @param error_code Value-result parameter to receive error code on error
   * @return Listen socket or null if error (check error_code in error case)
   */
  AnodeSocket *(*datagram_listen)(AnodeTransport *transport,
    const AnodeNetworkAddress *local_address,
    int local_port,
    int *error_code);

  /**
   * Open a socket to listen for incoming stream connections
   *
   * @param transport Transport instance
   * @param local_address Local address to bind
   * @param local_port Local port to bind
   * @param error_code Value-result parameter to receive error code on error
   * @return Listen socket or null if error (check error_code in error case)
   */
  AnodeSocket *(*stream_listen)(AnodeTransport *transport,
    const AnodeNetworkAddress *local_address,
    int local_port,
    int *error_code);

  /**
   * Send a datagram to a network endpoint
   *
   * @param transport Transport instance
   * @param socket Originating datagram socket
   * @param data Data to send
   * @param data_len Length of data to send
   * @param to_endpoint Destination endpoint
   * @return Zero on success or error code on error
   */
  int (*datagram_send)(AnodeTransport *transport,
    AnodeSocket *sock,
    const void *data,
    int data_len,
    const AnodeNetworkEndpoint *to_endpoint);

  /**
   * Initiate an outgoing stream connection attempt
   *
   * For IPv4 and IPv6 addresses, this will initiate a TCP connection. For
   * Anode addresses, Anode's internal streaming protocol will be used.
   *
   * @param transport Transport instance
   * @param to_endpoint Destination endpoint
   * @param error_code Error code value-result parameter, filled on error
   * @return Stream socket object or null on error (check error_code)
   */
  AnodeSocket *(*stream_connect)(AnodeTransport *transport,
    const AnodeNetworkEndpoint *to_endpoint,
    int *error_code);

  /**
   * Indicate that you are interested in writing to a stream
   *
   * This does nothing if the socket is not a stream connection or is not
   * connected.
   *
   * @param transport Transport instance
   * @param sock Stream connection
   */
  void (*stream_start_writing)(AnodeTransport *transport,
    AnodeSocket *sock);

  /**
   * Indicate that you are no longer interested in writing to a stream
   *
   * This does nothing if the socket is not a stream connection or is not
   * connected.
   *
   * @param transport Transport instance
   * @param sock Stream connection
   */
  void (*stream_stop_writing)(AnodeTransport *transport,
    AnodeSocket *sock);

  /**
   * Send data to a stream connection
   *
   * This must be called after a stream is indicated to be ready for writing.
   * It returns the number of bytes actually written, or a negative error
   * code on failure.
   *
   * A return value of zero can occur here, and simply indicates that nothing
   * was sent. This may occur with certain network stacks on certain
   * platforms.
   *
   * @param transport Transport engine
   * @param sock Stream socket
   * @param data Data to send
   * @param data_len Maximum data to send in bytes
   * @return Actual data sent or negative error code on error
   */
  int (*stream_send)(AnodeTransport *transport,
    AnodeSocket *sock,
    const void *data,
    int data_len);

  /**
   * Close a socket
   *
   * If the socket is a stream connection in the connected state, this
   * will generate a stream closed event with a zero error_code to indicate
   * a normal close.
   *
   * @param transport Transport engine
   * @param sock Socket object
   */
  void (*close)(AnodeTransport *transport,
    AnodeSocket *sock);

  /**
   * Run main polling loop
   *
   * This should be called repeatedly from the I/O thread of your main
   * process. It blocks until one or more events occur, and then returns
   * the number of events. Error returns here are fatal and indicate
   * serious problems such as build or platform issues or a lack of any
   * network interface.
   *
   * Functions queued with invoke() are also called inside here.
   *
   * @param transport Transport engine
   * @return Number of events handled or negative on (fatal) error
   */
  int (*poll)(AnodeTransport *transport);

  /**
   * Check whether transport supports an address type
   *
   * Inheriting classes should call their base if they do not natively
   * speak the specified type.
   *
   * @param transport Transport engine
   * @param at Address type
   * @return Nonzero if true
   */
  int (*supports_address_type)(const AnodeTransport *transport,
    enum AnodeNetworkAddressType at);

  /**
   * Get the instance of AnodeTransport under this one (if any)
   *
   * @param transport Transport engine
   * @return Base instance or null if none
   */
  AnodeTransport *(*base_instance)(const AnodeTransport *transport);

  /**
   * @param transport Transport engine
   * @return Class name of this instance
   */
  const char *(*class_name)(AnodeTransport *transport);

  /**
   * Delete this transport and its base transports
   *
   * The 'transport' pointer and any streams or sockets it owns are no longer
   * valid after this call.
   *
   * @param transport Transport engine
   */
  void (*delete)(AnodeTransport *transport);
};

/**
 * Construct a new system transport
 *
 * This is the default base for AnodeTransport, and it is constructed
 * automatically if 'base' is null in AnodeTransport_new(). However, it also
 * exposed to the user so that specialized transports (such as those that use
 * proxy servers) can be developed on top of it. These in turn can be supplied
 * as 'base' to AnodeTransport_new() to talk Anode over these transports.
 *
 * The system transport supports IP protocols and possibly others.
 *
 * @param base Base class or null for none (usually null)
 * @return Base transport engine instance
 */
extern AnodeTransport *AnodeSystemTransport_new(AnodeTransport *base);

/**
 * Construct a new Anode core transport
 *
 * This is the transport that talks Anode using the specified base transport.
 * Requests for other address types are passed through to the base. If the
 * base is null, an instance of AnodeSystemTransport is used.
 *
 * Since transport engines inherit their functionality, this transport
 * will also do standard IP and everything else that the system transport
 * supports. Most users will just want to construct this with a null base.
 *
 * @param base Base transport to use, or null to use SystemTransport
 * @return Anode transport engine or null on error
 */
extern AnodeTransport *AnodeCoreTransport_new(AnodeTransport *base);

/* ----------------------------------------------------------------------- */
/* URI Parser                                                              */
/* ----------------------------------------------------------------------- */

/**
 * URI broken down by component
 */
typedef struct
{
  char scheme[8];
  char username[64];
  char password[64];
  char host[128];
  char path[256];
  char query[256];
  char fragment[64];
  int port;
} AnodeURI;

/**
 * URI parser
 *
 * A buffer too small error will occur if any field is too large for the
 * AnodeURI structure.
 *
 * @param parsed_uri Structure to fill with parsed URI data
 * @param uri_string URI in string format
 * @return Zero on success or error on failure
 */
extern int AnodeURI_parse(AnodeURI *parsed_uri,const char *uri_string);

/**
 * Output a URI in string format
 *
 * @param uri URI to output as string
 * @param buf Buffer to store URI string
 * @param len Length of buffer
 * @return Buffer or null on error
 */
extern char *AnodeURI_to_string(const AnodeURI *uri,char *buf,int len);

/* ----------------------------------------------------------------------- */
/* Zone File Lookup and Dictionary                                         */
/* ----------------------------------------------------------------------- */

/**
 * Zone file dictionary
 */
typedef void AnodeZoneFile;

/**
 * Start asynchronous zone fetch
 *
 * When the zone is retrieved, the lookup handler is called. If zone lookup
 * failed, the zone file argument to the handler will be null.
 *
 * @param transport Transport engine
 * @param zone Zone ID
 * @param user_ptr User pointer
 * @param zone_lookup_handler Handler for Anode zone lookup
 */
extern void AnodeZoneFile_lookup(
  AnodeTransport *transport,
  const AnodeZone *zone,
  void *ptr,
  void (*zone_lookup_handler)(const AnodeZone *,AnodeZoneFile *,void *));

/**
 * Look up a key in a zone file
 *
 * @param zone Zone file object
 * @param key Key to get in zone file
 */
extern const char *AnodeZoneFile_get(const AnodeZoneFile *zone,const char *key);

/**
 * Free a zone file
 *
 * @param zone Zone to free
 */
extern void AnodeZoneFile_free(AnodeZoneFile *zone);

/* ----------------------------------------------------------------------- */

#ifdef __cplusplus
}
#endif

#endif