/* libanode: the Anode C reference implementation * Copyright (C) 2009-2010 Adam Ierymenko * * 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 . */ #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