diff options
author | Adam Ierymenko <adam.ierymenko@zerotier.com> | 2018-04-25 06:39:02 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-25 06:39:02 -0700 |
commit | 42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0 (patch) | |
tree | 7bf86c4d92d6a0f77eced79bfc33313c62c7b6dd /attic/historic/anode/libanode | |
parent | 18c9dc8a0649c866eff9f299f20fa5b19c502e52 (diff) | |
parent | 4608880fb06700822d01e9e5d6729fcdeb82b64b (diff) | |
download | infinitytier-42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0.tar.gz infinitytier-42ec780a6f6eedef4d8b1d8218bd72fc6ed75cc0.zip |
Merge branch 'dev' into netbsd-support
Diffstat (limited to 'attic/historic/anode/libanode')
41 files changed, 6236 insertions, 0 deletions
diff --git a/attic/historic/anode/libanode/Makefile b/attic/historic/anode/libanode/Makefile new file mode 100644 index 00000000..088587bd --- /dev/null +++ b/attic/historic/anode/libanode/Makefile @@ -0,0 +1,33 @@ +SYSNAME:=${shell uname} +SYSNAME!=uname +include ../config.mk.${SYSNAME} + +LIBANODE_OBJS= \ + impl/aes.o \ + impl/dictionary.o \ + impl/dns_txt.o \ + impl/ec.o \ + impl/environment.o \ + impl/misc.o \ + impl/thread.o \ + address.o \ + aes_digest.o \ + errors.o \ + identity.o \ + network_address.o \ + secure_random.o \ + system_transport.o \ + uri.o +# zone.o + +all: $(LIBANODE_OBJS) + ar rcs libanode.a $(LIBANODE_OBJS) + ranlib libanode.a + $(CC) $(CFLAGS) -o utils/anode-make-identity utils/anode-make-identity.c $(LIBANODE_OBJS) $(LIBANODE_LIBS) + +clean: force + rm -f $(LIBANODE_OBJS) + rm -f libanode.$(DLLEXT) libanode.a + rm -f utils/anode-make-identity + +force: ; diff --git a/attic/historic/anode/libanode/address.c b/attic/historic/anode/libanode/address.c new file mode 100644 index 00000000..e7ab7837 --- /dev/null +++ b/attic/historic/anode/libanode/address.c @@ -0,0 +1,98 @@ +/* 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/>. */ + +#include "impl/aes.h" +#include "impl/ec.h" +#include "impl/misc.h" +#include "impl/types.h" +#include "anode.h" + +int AnodeAddress_calc_short_id( + const AnodeAddress *address, + AnodeAddressId *short_address_id) +{ + unsigned char digest[16]; + + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + Anode_aes_digest(address->bits,ANODE_ADDRESS_LENGTH_ANODE_256_40,digest); + break; + default: + return ANODE_ERR_ADDRESS_INVALID; + } + + *((uint64_t *)short_address_id->bits) = ((uint64_t *)digest)[0] ^ ((uint64_t *)digest)[1]; + + return 0; +} + +int AnodeAddress_get_zone(const AnodeAddress *address,AnodeZone *zone) +{ + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + *((uint32_t *)&(zone->bits[0])) = *((uint32_t *)&(address->bits[1])); + return 0; + } + return ANODE_ERR_ADDRESS_INVALID; +} + +int AnodeAddress_to_string(const AnodeAddress *address,char *buf,int len) +{ + const unsigned char *inptr; + char *outptr; + unsigned int i; + + switch(AnodeAddress_get_type(address)) { + case ANODE_ADDRESS_ANODE_256_40: + if (len < (((ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5) * 8) + 1)) + return ANODE_ERR_BUFFER_TOO_SMALL; + inptr = (const unsigned char *)address->bits; + outptr = buf; + for(i=0;i<(ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5);++i) { + Anode_base32_5_to_8(inptr,outptr); + inptr += 5; + outptr += 8; + } + *outptr = (char)0; + return ((ANODE_ADDRESS_LENGTH_ANODE_256_40 / 5) * 8); + } + return ANODE_ERR_ADDRESS_INVALID; +} + +int AnodeAddress_from_string(const char *str,AnodeAddress *address) +{ + const char *blk_start = str; + const char *ptr = str; + unsigned int address_len = 0; + + while (*ptr) { + if ((unsigned long)(ptr - blk_start) == 8) { + if ((address_len + 5) > sizeof(address->bits)) + return ANODE_ERR_ADDRESS_INVALID; + Anode_base32_8_to_5(blk_start,(unsigned char *)&(address->bits[address_len])); + address_len += 5; + blk_start = ptr; + } + ++ptr; + } + + if (ptr != blk_start) + return ANODE_ERR_ADDRESS_INVALID; + if (AnodeAddress_get_type(address) != ANODE_ADDRESS_ANODE_256_40) + return ANODE_ERR_ADDRESS_INVALID; + + return 0; +} diff --git a/attic/historic/anode/libanode/aes_digest.c b/attic/historic/anode/libanode/aes_digest.c new file mode 100644 index 00000000..07b0fc7a --- /dev/null +++ b/attic/historic/anode/libanode/aes_digest.c @@ -0,0 +1,85 @@ +/* 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/>. */ + +#include "anode.h" +#include "impl/aes.h" +#include "impl/misc.h" +#include "impl/types.h" + +void Anode_aes_digest(const void *const message,unsigned long message_len,void *const hash) +{ + unsigned char previous_digest[16]; + unsigned char digest[16]; + unsigned char block[32]; + const unsigned char *in = (const unsigned char *)message; + const unsigned char *end = in + message_len; + unsigned long block_counter; + AnodeAesExpandedKey expkey; + + ((uint64_t *)digest)[0] = 0ULL; + ((uint64_t *)digest)[1] = 0ULL; + ((uint64_t *)block)[0] = 0ULL; + ((uint64_t *)block)[1] = 0ULL; + ((uint64_t *)block)[2] = 0ULL; + ((uint64_t *)block)[3] = 0ULL; + + /* Davis-Meyer hash function built from block cipher */ + block_counter = 0; + while (in != end) { + block[block_counter++] = *(in++); + if (block_counter == 32) { + block_counter = 0; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + } + } + + /* Davis-Meyer end marker */ + block[block_counter++] = 0x80; + while (block_counter != 32) block[block_counter++] = 0; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + + /* Merkle-Damgård length padding */ + ((uint64_t *)block)[0] = 0ULL; + if (sizeof(message_len) >= 8) { /* 32/64 bit? this will get optimized out */ + block[8] = (uint8_t)((uint64_t)message_len >> 56); + block[9] = (uint8_t)((uint64_t)message_len >> 48); + block[10] = (uint8_t)((uint64_t)message_len >> 40); + block[11] = (uint8_t)((uint64_t)message_len >> 32); + } else ((uint32_t *)block)[2] = 0; + block[12] = (uint8_t)(message_len >> 24); + block[13] = (uint8_t)(message_len >> 16); + block[14] = (uint8_t)(message_len >> 8); + block[15] = (uint8_t)message_len; + ((uint64_t *)previous_digest)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)previous_digest)[1] = ((uint64_t *)digest)[1]; + Anode_aes256_expand_key(block,&expkey); + Anode_aes256_encrypt(&expkey,digest,digest); + ((uint64_t *)digest)[0] ^= ((uint64_t *)previous_digest)[0]; + ((uint64_t *)digest)[1] ^= ((uint64_t *)previous_digest)[1]; + + ((uint64_t *)hash)[0] = ((uint64_t *)digest)[0]; + ((uint64_t *)hash)[1] = ((uint64_t *)digest)[1]; +} diff --git a/attic/historic/anode/libanode/anode.h b/attic/historic/anode/libanode/anode.h new file mode 100644 index 00000000..e0c51e2e --- /dev/null +++ b/attic/historic/anode/libanode/anode.h @@ -0,0 +1,795 @@ +/* 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 diff --git a/attic/historic/anode/libanode/errors.c b/attic/historic/anode/libanode/errors.c new file mode 100644 index 00000000..6836bdc4 --- /dev/null +++ b/attic/historic/anode/libanode/errors.c @@ -0,0 +1,52 @@ +/* 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/>. */ + +#include "anode.h" + +struct AnodeErrDesc +{ + int code; + const char *desc; +}; + +#define TOTAL_ERRORS 12 +static const struct AnodeErrDesc ANODE_ERRORS[TOTAL_ERRORS] = { + { ANODE_ERR_NONE, "No error (success)" }, + { ANODE_ERR_INVALID_ARGUMENT, "Invalid argument" }, + { ANODE_ERR_OUT_OF_MEMORY, "Out of memory" }, + { ANODE_ERR_INVALID_URI, "Invalid URI" }, + { ANODE_ERR_BUFFER_TOO_SMALL, "Supplied buffer too small" }, + { ANODE_ERR_ADDRESS_INVALID, "Address invalid" }, + { ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED, "Address type not supported"}, + { ANODE_ERR_CONNECTION_CLOSED, "Connection closed"}, + { ANODE_ERR_CONNECT_FAILED, "Connect failed"}, + { ANODE_ERR_UNABLE_TO_BIND, "Unable to bind to address"}, + { ANODE_ERR_TOO_MANY_OPEN_SOCKETS, "Too many open sockets"}, + { ANODE_ERR_DNS_NAME_NOT_FOUND_OR_TIMED_OUT, "DNS name not found or timed out"} +}; + +extern const char *Anode_strerror(int err) +{ + int i; + int negerr = -err; + + for(i=0;i<TOTAL_ERRORS;++i) { + if ((ANODE_ERRORS[i].code == err)||(ANODE_ERRORS[i].code == negerr)) + return ANODE_ERRORS[i].desc; + } + + return "Unknown error"; +} diff --git a/attic/historic/anode/libanode/identity.c b/attic/historic/anode/libanode/identity.c new file mode 100644 index 00000000..a40f6987 --- /dev/null +++ b/attic/historic/anode/libanode/identity.c @@ -0,0 +1,110 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include "impl/types.h" +#include "impl/ec.h" +#include "impl/misc.h" +#include "anode.h" + +int AnodeIdentity_generate(AnodeIdentity *identity,const AnodeZone *zone,enum AnodeAddressType type) +{ + struct AnodeECKeyPair kp; + + switch(type) { + case ANODE_ADDRESS_ANODE_256_40: + if (!AnodeECKeyPair_generate(&kp)) + return ANODE_ERR_OUT_OF_MEMORY; + + identity->address.bits[0] = (unsigned char)ANODE_ADDRESS_ANODE_256_40; + + identity->address.bits[1] = zone->bits[0]; + identity->address.bits[2] = zone->bits[1]; + identity->address.bits[3] = zone->bits[2]; + identity->address.bits[4] = zone->bits[3]; + + identity->address.bits[5] = 0; + identity->address.bits[6] = 0; + + Anode_memcpy((void *)&(identity->address.bits[7]),(const void *)kp.pub.key,ANODE_EC_PUBLIC_KEY_BYTES); + Anode_memcpy((void *)identity->secret,(const void *)kp.priv.key,kp.priv.bytes); + + AnodeAddress_calc_short_id(&identity->address,&identity->address_id); + + AnodeECKeyPair_destroy(&kp); + + return 0; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} + +int AnodeIdentity_to_string(const AnodeIdentity *identity,char *dest,int dest_len) +{ + char hexbuf[128]; + char strbuf[128]; + int n; + + if ((n = AnodeAddress_to_string(&identity->address,strbuf,sizeof(strbuf))) <= 0) + return n; + + switch(AnodeAddress_get_type(&identity->address)) { + case ANODE_ADDRESS_ANODE_256_40: + Anode_to_hex((const unsigned char *)identity->secret,ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40,hexbuf,sizeof(hexbuf)); + n = snprintf(dest,dest_len,"ANODE-256-40:%s:%s",strbuf,hexbuf); + if (n >= dest_len) + return ANODE_ERR_BUFFER_TOO_SMALL; + return n; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} + +int AnodeIdentity_from_string(AnodeIdentity *identity,const char *str) +{ + char buf[1024]; + char *id_name; + char *address; + char *secret; + int ec; + + Anode_str_copy(buf,str,sizeof(buf)); + + id_name = buf; + if (!id_name) return 0; + if (!*id_name) return 0; + address = (char *)Anode_strchr(id_name,':'); + if (!address) return 0; + if (!*address) return 0; + *(address++) = (char)0; + secret = (char *)Anode_strchr(address,':'); + if (!secret) return 0; + if (!*secret) return 0; + *(secret++) = (char)0; + + if (Anode_strcaseeq("ANODE-256-40",id_name)) { + if ((ec = AnodeAddress_from_string(address,&identity->address))) + return ec; + if (Anode_strlen(secret) != (ANODE_ADDRESS_SECRET_LENGTH_ANODE_256_40 * 2)) + return ANODE_ERR_INVALID_ARGUMENT; + Anode_from_hex(secret,(unsigned char *)identity->secret,sizeof(identity->secret)); + AnodeAddress_calc_short_id(&identity->address,&identity->address_id); + return 0; + } + + return ANODE_ERR_INVALID_ARGUMENT; +} diff --git a/attic/historic/anode/libanode/impl/aes.c b/attic/historic/anode/libanode/impl/aes.c new file mode 100644 index 00000000..90e5e23b --- /dev/null +++ b/attic/historic/anode/libanode/impl/aes.c @@ -0,0 +1,72 @@ +/* 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/>. */ + +#include "aes.h" + +void Anode_cmac_aes256( + const AnodeAesExpandedKey *expkey, + const unsigned char *restrict data, + unsigned long data_len, + unsigned char *restrict mac) +{ + unsigned char cbc[16]; + unsigned char pad[16]; + const unsigned char *restrict pos = data; + unsigned long i; + unsigned long remaining = data_len; + unsigned char c; + + ((uint64_t *)((void *)cbc))[0] = 0ULL; + ((uint64_t *)((void *)cbc))[1] = 0ULL; + + while (remaining >= 16) { + ((uint64_t *)((void *)cbc))[0] ^= ((uint64_t *)((void *)pos))[0]; + ((uint64_t *)((void *)cbc))[1] ^= ((uint64_t *)((void *)pos))[1]; + pos += 16; + if (remaining > 16) + Anode_aes256_encrypt(expkey,cbc,cbc); + remaining -= 16; + } + + ((uint64_t *)((void *)pad))[0] = 0ULL; + ((uint64_t *)((void *)pad))[1] = 0ULL; + Anode_aes256_encrypt(expkey,pad,pad); + + c = pad[0] & 0x80; + for(i=0;i<15;++i) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[15] <<= 1; + if (c) + pad[15] ^= 0x87; + + if (remaining||(!data_len)) { + for(i=0;i<remaining;++i) + cbc[i] ^= *(pos++); + cbc[remaining] ^= 0x80; + + c = pad[0] & 0x80; + for(i=0;i<15;++i) + pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7); + pad[15] <<= 1; + if (c) + pad[15] ^= 0x87; + } + + ((uint64_t *)((void *)mac))[0] = ((uint64_t *)((void *)pad))[0] ^ ((uint64_t *)((void *)cbc))[0]; + ((uint64_t *)((void *)mac))[1] = ((uint64_t *)((void *)pad))[1] ^ ((uint64_t *)((void *)cbc))[1]; + + Anode_aes256_encrypt(expkey,mac,mac); +} diff --git a/attic/historic/anode/libanode/impl/aes.h b/attic/historic/anode/libanode/impl/aes.h new file mode 100644 index 00000000..25e33933 --- /dev/null +++ b/attic/historic/anode/libanode/impl/aes.h @@ -0,0 +1,64 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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_AES_H +#define _ANODE_AES_H + +#include <openssl/aes.h> +#include "types.h" + +/* This just glues us to OpenSSL's built-in AES-256 implementation */ + +#define ANODE_AES_BLOCK_SIZE 16 +#define ANODE_AES_KEY_SIZE 32 + +typedef AES_KEY AnodeAesExpandedKey; + +#define Anode_aes256_expand_key(k,ek) AES_set_encrypt_key((const unsigned char *)(k),256,(AES_KEY *)(ek)) + +/* Note: in and out can be the same thing */ +#define Anode_aes256_encrypt(ek,in,out) AES_encrypt((const unsigned char *)(in),(unsigned char *)(out),(const AES_KEY *)(ek)) + +/* Note: iv is modified */ +static inline void Anode_aes256_cfb_encrypt( + const AnodeAesExpandedKey *expkey, + const unsigned char *in, + unsigned char *out, + unsigned char *iv, + unsigned long len) +{ + int tmp = 0; + AES_cfb128_encrypt(in,out,len,(const AES_KEY *)expkey,iv,&tmp,AES_ENCRYPT); +} +static inline void Anode_aes256_cfb_decrypt( + const AnodeAesExpandedKey *expkey, + const unsigned char *in, + unsigned char *out, + unsigned char *iv, + unsigned long len) +{ + int tmp = 0; + AES_cfb128_encrypt(in,out,len,(const AES_KEY *)expkey,iv,&tmp,AES_DECRYPT); +} + +/* CMAC message authentication code */ +void Anode_cmac_aes256( + const AnodeAesExpandedKey *expkey, + const unsigned char *restrict data, + unsigned long data_len, + unsigned char *restrict mac); + +#endif diff --git a/attic/historic/anode/libanode/impl/dictionary.c b/attic/historic/anode/libanode/impl/dictionary.c new file mode 100644 index 00000000..060c3815 --- /dev/null +++ b/attic/historic/anode/libanode/impl/dictionary.c @@ -0,0 +1,239 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include "dictionary.h" + +static const char *EMPTY_STR = ""; + +void AnodeDictionary_clear(struct AnodeDictionary *d) +{ + struct AnodeDictionaryEntry *e,*ne; + int oldcs; + unsigned int i; + + oldcs = d->case_sensitive; + + for(i=0;i<ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE;++i) { + e = d->ht[i]; + while (e) { + ne = e->next; + if ((e->key)&&(e->key != EMPTY_STR)) free((void *)e->key); + if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value); + free((void *)e); + e = ne; + } + } + + Anode_zero((void *)d,sizeof(struct AnodeDictionary)); + + d->case_sensitive = oldcs; +} + +void AnodeDictionary_put(struct AnodeDictionary *d,const char *key,const char *value) +{ + struct AnodeDictionaryEntry *e; + char *p1; + const char *p2; + unsigned int bucket = (d->case_sensitive) ? AnodeDictionary__get_bucket(key) : AnodeDictionary__get_bucket_ci(key); + unsigned int len,i; + + e = d->ht[bucket]; + while (e) { + if (((d->case_sensitive) ? Anode_streq(key,e->key) : Anode_strcaseeq(key,e->key))) { + if (!d->case_sensitive) { + p1 = e->key; + p2 = key; + while (*p2) *(p1++) = *(p2++); + } + + len = 0; + while (value[len]) ++len; + if (len) { + if ((e->value)&&(e->value != EMPTY_STR)) + e->value = (char *)realloc((void *)e->value,len + 1); + else e->value = (char *)malloc(len + 1); + for(i=0;i<len;++i) e->value[i] = value[i]; + e->value[i] = (char)0; + } else { + if ((e->value)&&(e->value != EMPTY_STR)) free((void *)e->value); + e->value = (char *)EMPTY_STR; + } + return; + } + e = e->next; + } + + e = (struct AnodeDictionaryEntry *)malloc(sizeof(struct AnodeDictionaryEntry)); + + len = 0; + while (key[len]) ++len; + if (len) { + e->key = (char *)malloc(len + 1); + for(i=0;i<len;++i) e->key[i] = key[i]; + e->key[i] = (char)0; + } else e->key = (char *)EMPTY_STR; + + len = 0; + while (value[len]) ++len; + if (len) { + e->value = (char *)malloc(len + 1); + for(i=0;i<len;++i) e->value[i] = value[i]; + e->value[i] = (char)0; + } else e->value = (char *)EMPTY_STR; + + e->next = d->ht[bucket]; + d->ht[bucket] = e; + + ++d->size; +} + +void AnodeDictionary_read( + struct AnodeDictionary *d, + char *in, + const char *line_breaks, + const char *kv_breaks, + const char *comment_chars, + char escape_char, + int trim_whitespace_from_keys, + int trim_whitespace_from_values) +{ + char *line = in; + char *key; + char *value; + char *p1,*p2,*p3; + char last = ~escape_char; + int eof_state = 0; + + for(;;) { + if ((!*in)||((Anode_strchr(line_breaks,*in))&&((last != escape_char)||(!escape_char)))) { + if (!*in) + eof_state = 1; + else *in = (char)0; + + if ((*line)&&((comment_chars)&&(!Anode_strchr(comment_chars,*line)))) { + key = line; + + while (*line) { + if ((Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char))) { + *(line++) = (char)0; + break; + } else last = *(line++); + } + while ((*line)&&(Anode_strchr(kv_breaks,*line))&&((last != escape_char)||(!escape_char))) + last = *(line++); + value = line; + + if (escape_char) { + p1 = key; + while (*p1) { + if (*p1 == escape_char) { + p2 = p1; + p3 = p1 + 1; + while (*p3) + *(p2++) = *(p3++); + *p2 = (char)0; + } + ++p1; + } + p1 = value; + while (*p1) { + if (*p1 == escape_char) { + p2 = p1; + p3 = p1 + 1; + while (*p3) + *(p2++) = *(p3++); + *p2 = (char)0; + } + ++p1; + } + } + + if (trim_whitespace_from_keys) + Anode_trim(key); + if (trim_whitespace_from_values) + Anode_trim(value); + + AnodeDictionary_put(d,key,value); + } + + if (eof_state) + break; + else line = in + 1; + } + last = *(in++); + } +} + +long AnodeDictionary_write( + struct AnodeDictionary *d, + char *out, + long out_size, + const char *line_break, + const char *kv_break) +{ + struct AnodeDictionaryEntry *e; + const char *tmp; + long ptr = 0; + unsigned int bucket; + + if (out_size <= 0) + return -1; + + for(bucket=0;bucket<ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE;++bucket) { + e = d->ht[bucket]; + while (e) { + tmp = e->key; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = kv_break; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = e->value; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + tmp = line_break; + if (tmp) { + while (*tmp) { + out[ptr++] = *tmp++; + if (ptr >= (out_size - 1)) return -1; + } + } + + e = e->next; + } + } + + out[ptr] = (char)0; + + return ptr; +} diff --git a/attic/historic/anode/libanode/impl/dictionary.h b/attic/historic/anode/libanode/impl/dictionary.h new file mode 100644 index 00000000..48e1642a --- /dev/null +++ b/attic/historic/anode/libanode/impl/dictionary.h @@ -0,0 +1,126 @@ +/* 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/>. */ + +/* This is a simple string hash table suitable for small tables such as zone + * files or HTTP header lists. */ + +#ifndef _ANODE_DICTIONARY_H +#define _ANODE_DICTIONARY_H + +#include "misc.h" + +/* This is a fixed hash table and is designed for relatively small numbers + * of keys for things like zone files. */ +#define ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE 16 +#define ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK 15 + +/* Computes a hash code for a string and returns the hash bucket */ +static inline unsigned int AnodeDictionary__get_bucket(const char *s) +{ + unsigned int hc = 3; + while (*s) + hc = ((hc << 4) + hc) + (unsigned int)*(s++); + return ((hc ^ (hc >> 4)) & ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK); +} +/* Case insensitive version of get_bucket */ +static inline unsigned int AnodeDictionary__get_bucket_ci(const char *s) +{ + unsigned int hc = 3; + while (*s) + hc = ((hc << 4) + hc) + (unsigned int)Anode_tolower(*(s++)); + return ((hc ^ (hc >> 4)) & ANODE_DICTIONARY_FIXED_HASH_TABLE_MASK); +} + +struct AnodeDictionaryEntry +{ + char *key; + char *value; + struct AnodeDictionaryEntry *next; +}; + +struct AnodeDictionary +{ + struct AnodeDictionaryEntry *ht[ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE]; + unsigned int size; + int case_sensitive; +}; + +static inline void AnodeDictionary_init(struct AnodeDictionary *d,int case_sensitive) +{ + Anode_zero((void *)d,sizeof(struct AnodeDictionary)); + d->case_sensitive = case_sensitive; +} + +void AnodeDictionary_clear(struct AnodeDictionary *d); + +static inline void AnodeDictionary_destroy(struct AnodeDictionary *d) +{ + AnodeDictionary_clear(d); +} + +void AnodeDictionary_put(struct AnodeDictionary *d,const char *key,const char *value); + +static inline const char *AnodeDictionary_get(struct AnodeDictionary *d,const char *key) +{ + struct AnodeDictionaryEntry *e; + unsigned int bucket = (d->case_sensitive) ? AnodeDictionary__get_bucket(key) : AnodeDictionary__get_bucket_ci(key); + + e = d->ht[bucket]; + while (e) { + if ((d->case_sensitive ? Anode_streq(key,e->key) : Anode_strcaseeq(key,e->key))) + return e->value; + e = e->next; + } + + return (const char *)0; +} + +static inline void AnodeDictionary_iterate( + struct AnodeDictionary *d, + void *arg, + int (*func)(void *,const char *,const char *)) +{ + struct AnodeDictionaryEntry *e; + unsigned int bucket; + + for(bucket=0;bucket<ANODE_DICTIONARY_FIXED_HASH_TABLE_SIZE;++bucket) { + e = d->ht[bucket]; + while (e) { + if (!func(arg,e->key,e->value)) + return; + e = e->next; + } + } +} + +void AnodeDictionary_read( + struct AnodeDictionary *d, + char *in, + const char *line_breaks, + const char *kv_breaks, + const char *comment_chars, + char escape_char, + int trim_whitespace_from_keys, + int trim_whitespace_from_values); + +long AnodeDictionary_write( + struct AnodeDictionary *d, + char *out, + long out_size, + const char *line_break, + const char *kv_break); + +#endif diff --git a/attic/historic/anode/libanode/impl/dns_txt.c b/attic/historic/anode/libanode/impl/dns_txt.c new file mode 100644 index 00000000..b5cf1318 --- /dev/null +++ b/attic/historic/anode/libanode/impl/dns_txt.c @@ -0,0 +1,93 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/nameser.h> +#include <resolv.h> +#include <netdb.h> +#include "dns_txt.h" + +#ifndef C_IN +#define C_IN ns_c_in +#endif +#ifndef T_TXT +#define T_TXT ns_t_txt +#endif + +static volatile int Anode_resolver_initialized = 0; + +int Anode_sync_resolve_txt(const char *host,char *txt,unsigned int txt_len) +{ + unsigned char answer[16384],*pptr,*end; + char name[16384]; + int len,explen,i; + + if (!Anode_resolver_initialized) { + Anode_resolver_initialized = 1; + res_init(); + } + + /* Do not taunt happy fun ball. */ + + len = res_search(host,C_IN,T_TXT,answer,sizeof(answer)); + if (len > 12) { + pptr = answer + 12; + end = answer + len; + + explen = dn_expand(answer,end,pptr,name,sizeof(name)); + if (explen > 0) { + pptr += explen; + + if ((pptr + 2) >= end) return 2; + if (ntohs(*((uint16_t *)pptr)) == T_TXT) { + pptr += 4; + if (pptr >= end) return 2; + + explen = dn_expand(answer,end,pptr,name,sizeof(name)); + if (explen > 0) { + pptr += explen; + + if ((pptr + 2) >= end) return 2; + if (ntohs(*((uint16_t *)pptr)) == T_TXT) { + pptr += 10; + if (pptr >= end) return 2; + + len = *(pptr++); + if (len <= 0) return 2; + if ((pptr + len) > end) return 2; + + if (txt_len < (len + 1)) + return 4; + else { + for(i=0;i<len;++i) + txt[i] = pptr[i]; + txt[len] = (char)0; + return 0; + } + } + } + } + } + } + + return 1; +} + diff --git a/attic/historic/anode/libanode/impl/dns_txt.h b/attic/historic/anode/libanode/impl/dns_txt.h new file mode 100644 index 00000000..252865df --- /dev/null +++ b/attic/historic/anode/libanode/impl/dns_txt.h @@ -0,0 +1,37 @@ +/* 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_DNS_TXT_H +#define _ANODE_DNS_TXT_H + +/** + * Synchronous TXT resolver routine + * + * Error codes: + * 1 - I/O error + * 2 - Invalid response + * 3 - TXT record not found + * 4 - Destination buffer too small for result + * + * @param host Host name + * @param txt Buffer to store TXT result + * @param txt_len Size of buffer + * @return Zero on success, special error code on failure + */ +int Anode_sync_resolve_txt(const char *host,char *txt,unsigned int txt_len); + +#endif + diff --git a/attic/historic/anode/libanode/impl/ec.c b/attic/historic/anode/libanode/impl/ec.c new file mode 100644 index 00000000..2604b4a9 --- /dev/null +++ b/attic/historic/anode/libanode/impl/ec.c @@ -0,0 +1,219 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <openssl/bn.h> +#include <openssl/obj_mac.h> +#include <openssl/rand.h> +#include <openssl/ec.h> +#include <openssl/ecdh.h> +#include <openssl/ecdsa.h> +#include "types.h" +#include "misc.h" +#include "ec.h" + +static EC_GROUP *AnodeEC_group = (EC_GROUP *)0; + +static void *AnodeEC_KDF(const void *in,size_t inlen,void *out,size_t *outlen) +{ + unsigned long i,longest_length; + + if (!*outlen) + return out; + + for(i=0;i<(unsigned long)*outlen;++i) + ((unsigned char *)out)[i] = (unsigned char)0; + + longest_length = inlen; + if (longest_length < *outlen) + longest_length = *outlen; + for(i=0;i<longest_length;++i) + ((unsigned char *)out)[i % (unsigned long)*outlen] ^= ((const unsigned char *)in)[i % (unsigned long)inlen]; + + return out; +} + +int AnodeECKeyPair_generate(struct AnodeECKeyPair *pair) +{ + EC_KEY *key; + int len; + +#ifdef HAS_DEV_URANDOM + char buf[128]; + FILE *f = fopen("/dev/urandom","r"); + if (f) { + if (fread(buf,1,sizeof(buf),f) == sizeof(buf)) + RAND_add(buf,sizeof(buf),sizeof(buf)/2); + fclose(f); + } +#endif + + if (!AnodeEC_group) { + AnodeEC_group = EC_GROUP_new_by_curve_name(ANODE_EC_GROUP); + if (!AnodeEC_group) return 0; + } + + key = EC_KEY_new(); + if (!key) return 0; + + if (!EC_KEY_set_group(key,AnodeEC_group)) { + EC_KEY_free(key); + return 0; + } + + if (!EC_KEY_generate_key(key)) { + EC_KEY_free(key); + return 0; + } + + Anode_zero(pair,sizeof(struct AnodeECKeyPair)); + + /* Stuff the private key into priv.key */ + len = BN_num_bytes(EC_KEY_get0_private_key(key)); + if ((len > ANODE_EC_PRIME_BYTES)||(len < 0)) { + EC_KEY_free(key); + return 0; + } + BN_bn2bin(EC_KEY_get0_private_key(key),&(pair->priv.key[ANODE_EC_PRIME_BYTES - len])); + pair->priv.bytes = ANODE_EC_PRIME_BYTES; + + len = EC_POINT_point2oct(AnodeEC_group,EC_KEY_get0_public_key(key),POINT_CONVERSION_COMPRESSED,pair->pub.key,sizeof(pair->pub.key),0); + if (len != ANODE_EC_PUBLIC_KEY_BYTES) { + EC_KEY_free(key); + return 0; + } + pair->pub.bytes = ANODE_EC_PUBLIC_KEY_BYTES; + + /* Keep a copy of OpenSSL's structure around so we don't have to re-init + * it every time we use our key pair structure. */ + pair->internal_key = key; + + return 1; +} + +int AnodeECKeyPair_init(struct AnodeECKeyPair *pair,const struct AnodeECKey *pub,const struct AnodeECKey *priv) +{ + EC_KEY *key; + EC_POINT *kxy; + BIGNUM *pn; + + if (!AnodeEC_group) { + AnodeEC_group = EC_GROUP_new_by_curve_name(ANODE_EC_GROUP); + if (!AnodeEC_group) return 0; + } + + key = EC_KEY_new(); + if (!key) + return 0; + + if (!EC_KEY_set_group(key,AnodeEC_group)) { + EC_KEY_free(key); + return 0; + } + + /* Grab the private key */ + if (priv->bytes != ANODE_EC_PRIME_BYTES) { + EC_KEY_free(key); + return 0; + } + pn = BN_new(); + if (!pn) { + EC_KEY_free(key); + return 0; + } + if (!BN_bin2bn(priv->key,ANODE_EC_PRIME_BYTES,pn)) { + BN_free(pn); + EC_KEY_free(key); + return 0; + } + if (!EC_KEY_set_private_key(key,pn)) { + BN_free(pn); + EC_KEY_free(key); + return 0; + } + BN_free(pn); + + /* Set the public key */ + if (pub->bytes != ANODE_EC_PUBLIC_KEY_BYTES) { + EC_KEY_free(key); + return 0; + } + kxy = EC_POINT_new(AnodeEC_group); + if (!kxy) { + EC_KEY_free(key); + return 0; + } + EC_POINT_oct2point(AnodeEC_group,kxy,pub->key,ANODE_EC_PUBLIC_KEY_BYTES,0); + if (!EC_KEY_set_public_key(key,kxy)) { + EC_POINT_free(kxy); + EC_KEY_free(key); + return 0; + } + EC_POINT_free(kxy); + + Anode_zero(pair,sizeof(struct AnodeECKeyPair)); + Anode_memcpy((void *)&(pair->pub),(const void *)pub,sizeof(struct AnodeECKey)); + Anode_memcpy((void *)&(pair->priv),(const void *)priv,sizeof(struct AnodeECKey)); + pair->internal_key = key; + + return 1; +} + +void AnodeECKeyPair_destroy(struct AnodeECKeyPair *pair) +{ + if (pair) { + if (pair->internal_key) + EC_KEY_free((EC_KEY *)pair->internal_key); + } +} + +int AnodeECKeyPair_agree(const struct AnodeECKeyPair *my_key_pair,const struct AnodeECKey *their_pub_key,unsigned char *key_buf,unsigned int key_len) +{ + EC_POINT *pub; + int i; + + if (!AnodeEC_group) { + AnodeEC_group = EC_GROUP_new_by_curve_name(ANODE_EC_GROUP); + if (!AnodeEC_group) return 0; + } + + if (!my_key_pair->internal_key) + return 0; + + if (their_pub_key->bytes != ANODE_EC_PUBLIC_KEY_BYTES) + return 0; + pub = EC_POINT_new(AnodeEC_group); + if (!pub) + return 0; + EC_POINT_oct2point(AnodeEC_group,pub,their_pub_key->key,ANODE_EC_PUBLIC_KEY_BYTES,0); + + i = ECDH_compute_key(key_buf,key_len,pub,(EC_KEY *)my_key_pair->internal_key,&AnodeEC_KDF); + if (i != (int)key_len) { + EC_POINT_free(pub); + return 0; + } + + EC_POINT_free(pub); + + return 1; +} + +void AnodeEC_random(unsigned char *buf,unsigned int len) +{ + RAND_pseudo_bytes(buf,len); +} diff --git a/attic/historic/anode/libanode/impl/ec.h b/attic/historic/anode/libanode/impl/ec.h new file mode 100644 index 00000000..f1262664 --- /dev/null +++ b/attic/historic/anode/libanode/impl/ec.h @@ -0,0 +1,61 @@ +/* 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/>. */ + +/* Elliptic curve glue -- hides OpenSSL code behind this source module */ + +#ifndef _ANODE_EC_H +#define _ANODE_EC_H + +#include "misc.h" + +/* Right now, only one mode is supported: NIST-P-256. This is the only mode + * supported in the spec as well, and should be good for quite some time. + * If other modes are needed this code will need to be refactored. */ + +/* NIST-P-256 prime size in bytes */ +#define ANODE_EC_PRIME_BYTES 32 + +/* Sizes of key fields */ +#define ANODE_EC_GROUP NID_X9_62_prime256v1 +#define ANODE_EC_PUBLIC_KEY_BYTES (ANODE_EC_PRIME_BYTES + 1) +#define ANODE_EC_PRIVATE_KEY_BYTES ANODE_EC_PRIME_BYTES + +/* Larger of public or private key bytes, used for buffers */ +#define ANODE_EC_MAX_BYTES ANODE_EC_PUBLIC_KEY_BYTES + +struct AnodeECKey +{ + unsigned char key[ANODE_EC_MAX_BYTES]; + unsigned int bytes; +}; + +struct AnodeECKeyPair +{ + struct AnodeECKey pub; + struct AnodeECKey priv; + void *internal_key; +}; + +/* Key management functions */ +int AnodeECKeyPair_generate(struct AnodeECKeyPair *pair); +int AnodeECKeyPair_init(struct AnodeECKeyPair *pair,const struct AnodeECKey *pub,const struct AnodeECKey *priv); +void AnodeECKeyPair_destroy(struct AnodeECKeyPair *pair); +int AnodeECKeyPair_agree(const struct AnodeECKeyPair *my_key_pair,const struct AnodeECKey *their_pub_key,unsigned char *key_buf,unsigned int key_len); + +/* Provides access to the secure PRNG used to generate keys */ +void AnodeEC_random(unsigned char *buf,unsigned int len); + +#endif diff --git a/attic/historic/anode/libanode/impl/environment.c b/attic/historic/anode/libanode/impl/environment.c new file mode 100644 index 00000000..16e8ebe3 --- /dev/null +++ b/attic/historic/anode/libanode/impl/environment.c @@ -0,0 +1,118 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include "environment.h" + +#ifdef WINDOWS +#include <windows.h> +#else +#include <sys/stat.h> +#include <string.h> +#endif + +static char Anode_cache_base[1024] = { 0 }; + +const char *Anode_get_cache() +{ + if (Anode_cache_base[0]) + return Anode_cache_base; + +#ifdef WINDOWS +#else + char tmp[1024]; + char home[1024]; + unsigned int i; + struct stat st; + const char *_home = getenv("HOME"); + + if (!_home) + return (const char *)0; + for(i=0;i<sizeof(home);++i) { + home[i] = _home[i]; + if (!home[i]) { + if (i == 0) + return (const char *)0; + else if (home[i-1] == ANODE_PATH_SEPARATOR) + home[i-1] = (char)0; + break; + } + } + if (i == sizeof(home)) + return (const char *)0; + +#ifdef __APPLE__ + snprintf(tmp,sizeof(tmp),"%s%cLibrary",home,ANODE_PATH_SEPARATOR); + tmp[sizeof(tmp)-1] = (char)0; + if (!stat(tmp,&st)) { + sprintf(tmp,"%s%cLibrary%cCaches",home,ANODE_PATH_SEPARATOR,ANODE_PATH_SEPARATOR); + if (stat(tmp,&st)) { + if (mkdir(tmp,0700)) + return (const char *)0; + } + snprintf(Anode_cache_base,sizeof(Anode_cache_base),"%s%ccom.zerotier.anode",tmp,ANODE_PATH_SEPARATOR); + Anode_cache_base[sizeof(Anode_cache_base)-1] = (char)0; + if (stat(Anode_cache_base,&st)) { + if (mkdir(Anode_cache_base,0700)) { + Anode_cache_base[0] = (char)0; + return (const char *)0; + } + } + return Anode_cache_base; + } +#endif + + snprintf(tmp,sizeof(tmp),"%s%c.anode",home,ANODE_PATH_SEPARATOR); + tmp[sizeof(tmp)-1] = (char)0; + if (stat(tmp,&st)) { + if (mkdir(tmp,0700)) { + Anode_cache_base[0] = (char)0; + return (const char *)0; + } + } + snprintf(Anode_cache_base,sizeof(Anode_cache_base),"%s%ccaches",tmp,ANODE_PATH_SEPARATOR); + Anode_cache_base[sizeof(Anode_cache_base)-1] = (char)0; + if (stat(Anode_cache_base,&st)) { + if (mkdir(Anode_cache_base,0700)) { + Anode_cache_base[0] = (char)0; + return (const char *)0; + } + } + + return Anode_cache_base; +#endif +} + +char *Anode_get_cache_sub(const char *cache_subdir,char *buf,unsigned int len) +{ + struct stat st; + const char *cache_base = Anode_get_cache(); + + if (!len) + return (char *)0; + if (!cache_base) + return (char *)0; + + snprintf(buf,len,"%s%c%s",cache_base,ANODE_PATH_SEPARATOR,cache_subdir); + buf[len-1] = (char)0; + if (stat(buf,&st)) { + if (mkdir(buf,0700)) + return (char *)0; + } + + return buf; +} diff --git a/attic/historic/anode/libanode/impl/environment.h b/attic/historic/anode/libanode/impl/environment.h new file mode 100644 index 00000000..ecebdc11 --- /dev/null +++ b/attic/historic/anode/libanode/impl/environment.h @@ -0,0 +1,30 @@ +/* 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_ENVIRONMENT_H +#define _ANODE_ENVIRONMENT_H + +#ifdef WINDOWS +#define ANODE_PATH_SEPARATOR '\\' +#else +#define ANODE_PATH_SEPARATOR '/' +#endif + +const char *Anode_get_cache(); +char *Anode_get_cache_sub(const char *cache_subdir,char *buf,unsigned int len); + +#endif + diff --git a/attic/historic/anode/libanode/impl/http_client.c b/attic/historic/anode/libanode/impl/http_client.c new file mode 100644 index 00000000..a398a585 --- /dev/null +++ b/attic/historic/anode/libanode/impl/http_client.c @@ -0,0 +1,558 @@ +/* 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/>. */ + +#include <stdio.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include "http_client.h" +#include "misc.h" +#include "types.h" + +/* How much to increment read buffer at each capacity top? */ +#define ANODE_HTTP_CAPACITY_INCREMENT 4096 + +static void AnodeHttpClient_close_and_fail(struct AnodeHttpClient *client) +{ + if (client->impl.tcp_connection) { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + } + + client->response.data_length = 0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + + if (client->handler) + client->handler(client); +} + +static void AnodeHttpClient_do_initiate_client(struct AnodeHttpClient *client) +{ + const char *method = ""; + long l,i; + + switch(client->method) { + case ANODE_HTTP_GET: method = "GET"; break; + case ANODE_HTTP_HEAD: method = "HEAD"; break; + case ANODE_HTTP_POST: method = "POST"; break; + } + client->impl.outbuf_len = snprintf((char *)client->impl.outbuf,sizeof(client->impl.outbuf), + "%s %s%s%s HTTP/1.1\r\nHost: %s:%d\r\n%s", + method, + client->uri.path, + ((client->uri.query[0]) ? "?" : ""), + client->uri.query, + client->uri.host, + ((client->uri.port > 0) ? client->uri.port : 80), + ((client->keepalive) ? "" : "Connection: close\r\n") + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + if (client->method == ANODE_HTTP_POST) { + if ((client->data)&&(client->data_length)) { + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Type: %s\r\n", + (client->data_content_type ? client->data_content_type : "application/x-www-form-urlencoded") + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Length: %u\r\n", + client->data_length + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + } else { + client->impl.outbuf_len += snprintf((char *)client->impl.outbuf + client->impl.outbuf_len,sizeof(client->impl.outbuf) - client->impl.outbuf_len, + "Content-Length: 0\r\n" + ); + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + + l = AnodeDictionary_write(&(client->headers),(char *)client->impl.outbuf + client->impl.outbuf_len,(long)(sizeof(client->impl.outbuf) - client->impl.outbuf_len - 2),"\r\n",": "); + if (l < 0) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + client->impl.outbuf_len += (unsigned int)l; + if (client->impl.outbuf_len >= (sizeof(client->impl.outbuf) - 2)) { /* sanity check */ + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE; + AnodeHttpClient_close_and_fail(client); + return; + } + + client->impl.outbuf[client->impl.outbuf_len++] = '\r'; + client->impl.outbuf[client->impl.outbuf_len++] = '\n'; + + if ((client->method == ANODE_HTTP_POST)&&(client->data)&&(client->data_length)) { + i = sizeof(client->impl.outbuf) - client->impl.outbuf_len; + if (i > client->data_length) + i = client->data_length; + Anode_memcpy((client->impl.outbuf + client->impl.outbuf_len),client->data,i); + client->impl.request_data_ptr += i; + client->impl.outbuf_len += i; + } + + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_SEND; + client->impl.transport_engine->tcp_start_writing(client->impl.transport_engine,client->impl.tcp_connection); +} + +static void AnodeHttpClient_tcp_outgoing_connect_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + int error_code) +{ + struct AnodeHttpClient *client; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + + if ((client->impl.phase == ANODE_HTTP_REQUEST_PHASE_CONNECT)&&(!client->impl.freed)) { + if (error_code) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_CONNECT_FAILED; + AnodeHttpClient_close_and_fail(client); + } else { + client->impl.tcp_connection = connection; + AnodeHttpClient_do_initiate_client(client); + } + } else transport->tcp_close(transport,connection); +} + +static void AnodeHttpClient_tcp_connection_terminated_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + int error_code) +{ + struct AnodeHttpClient *client; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) + return; + + client->response.data_length = 0; + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + if ((client->impl.phase != ANODE_HTTP_REQUEST_PHASE_KEEPALIVE)&&(client->impl.phase != ANODE_HTTP_REQUEST_PHASE_CLOSED)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + AnodeHttpClient_close_and_fail(client); + } else client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; +} + +static void AnodeHttpClient_tcp_receive_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection, + void *data, + unsigned int data_length) +{ + struct AnodeHttpClient *client; + char *p1,*p2; + unsigned int i; + long l; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) { + transport->tcp_close(transport,connection); + return; + } + + if (!client->response.data) + client->response.data = malloc(client->impl.response_data_capacity = ANODE_HTTP_CAPACITY_INCREMENT); + + i = 0; + while (i < data_length) { + switch(client->impl.read_mode) { + case ANODE_HTTP_READ_MODE_WAITING: + for(;i<data_length;++i) { + if (((const char *)data)[i] == '\n') { + ((char *)client->response.data)[client->response.data_length] = (char)0; + client->response.data_length = 0; + + p1 = (char *)Anode_strchr((char *)client->response.data,' '); + if (!p1) + p1 = (char *)Anode_strchr((char *)client->response.data,'\t'); + if (p1) { + while ((*p1 == ' ')||(*p1 == '\t')) ++p1; + if (!*p1) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + p2 = p1 + 1; + while (*p2) { + if ((*p2 == ' ')||(*p2 == '\t')||(*p2 == '\r')||(*p2 == '\n')) { + *p2 = (char)0; + break; + } else ++p2; + } + client->response.code = (int)strtol(p1,(char **)0,10); + client->impl.read_mode = ANODE_HTTP_READ_MODE_HEADERS; + ++i; break; /* Exit inner for() */ + } + } else { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + if (client->response.data_length >= client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity += ANODE_HTTP_CAPACITY_INCREMENT); + } + } + break; + case ANODE_HTTP_READ_MODE_HEADERS: + case ANODE_HTTP_READ_MODE_CHUNKED_FOOTER: + for(;i<data_length;++i) { + if (((const char *)data)[i] == '\n') { + client->impl.header_line_buf[client->impl.header_line_buf_ptr] = (char)0; + client->impl.header_line_buf_ptr = 0; + + if ((!client->impl.header_line_buf[0])||((client->impl.header_line_buf[0] == '\r')&&(!client->impl.header_line_buf[1]))) { + /* If the line is empty (or is empty with \r\n as the + * line terminator), we're at the end. */ + if (client->impl.read_mode == ANODE_HTTP_READ_MODE_CHUNKED_FOOTER) { + /* If this is a chunked footer, we finally end the + * chunked response. */ + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + } else { + /* Otherwise, this is a regular header block */ + if (client->response.code == 100) { + /* Ignore 100 Continue messages */ + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + ++i; break; /* Exit inner for() */ + } else if ((client->response.code == 200)&&(client->method != ANODE_HTTP_HEAD)) { + /* Other messages get their headers parsed to determine + * how to read them. */ + p1 = (char *)AnodeDictionary_get(&(client->response.headers),"transfer-encoding"); + if ((p1)&&(Anode_strcaseeq(p1,"chunked"))) { + /* Chunked encoding enters chunked mode */ + client->impl.header_line_buf_ptr = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE; + ++i; break; /* Exit inner for() */ + } else { + /* Else we must have a Content-Length header */ + p1 = (char *)AnodeDictionary_get(&(client->response.headers),"content-length"); + if (!p1) { + /* No chunked or content length is not supported */ + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } else { + /* Enter block read mode with content length */ + l = strtol(p1,(char **)0,10); + if (l <= 0) { + /* Zero length data is all done... */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + + ++i; break; /* Exit inner for() */ + } else { + /* Else start reading... */ + client->impl.expecting_response_length = (unsigned int)l; + client->impl.read_mode = ANODE_HTTP_READ_MODE_BLOCK; + ++i; break; /* Exit inner for() */ + } + } + } + } else { + /* HEAD clients or non-200 codes get headers only */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + + ++i; break; /* Exit inner for() */ + } + } + } else { + /* Otherwise this is another header, add to dictionary */ + AnodeDictionary_read( + &(client->response.headers), + client->impl.header_line_buf, + "\r\n", + ": \t", + "", + (char)0, + 1, + 1 + ); + } + } else { + client->impl.header_line_buf[client->impl.header_line_buf_ptr++] = ((const char *)data)[i]; + if (client->impl.header_line_buf_ptr >= sizeof(client->impl.header_line_buf)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + break; + case ANODE_HTTP_READ_MODE_BLOCK: + if ((client->response.data_length + client->impl.expecting_response_length) > client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity = (client->response.data_length + client->impl.expecting_response_length)); + + for(;((i<data_length)&&(client->impl.expecting_response_length));++i) { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + --client->impl.expecting_response_length; + } + + if (!client->impl.expecting_response_length) { + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + if (client->keepalive) + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_KEEPALIVE; + else { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CLOSED; + } + + if (client->handler) + client->handler(client); + if (client->impl.freed) + return; + } + break; + case ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE: + for(;i<data_length;++i) { + if (((const char *)data)[i] == '\n') { + client->impl.header_line_buf[client->impl.header_line_buf_ptr] = (char)0; + client->impl.header_line_buf_ptr = 0; + + p1 = client->impl.header_line_buf; + while (*p1) { + if ((*p1 == ';')||(*p1 == ' ')||(*p1 == '\r')||(*p1 == '\n')||(*p1 == '\t')) { + *p1 = (char)0; + break; + } else ++p1; + } + + if (client->impl.header_line_buf[0]) { + l = strtol(client->impl.header_line_buf,(char **)0,16); + if (l <= 0) { + /* Zero length ends chunked and enters footer mode */ + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_FOOTER; + } else { + /* Otherwise the next chunk is to be read */ + client->impl.expecting_response_length = (unsigned int)l; + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_DATA; + } + ++i; break; /* Exit inner for() */ + } + } else { + client->impl.header_line_buf[client->impl.header_line_buf_ptr++] = ((const char *)data)[i]; + if (client->impl.header_line_buf_ptr >= sizeof(client->impl.header_line_buf)) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE; + AnodeHttpClient_close_and_fail(client); + return; + } + } + } + break; + case ANODE_HTTP_READ_MODE_CHUNKED_DATA: + if ((client->response.data_length + client->impl.expecting_response_length) > client->impl.response_data_capacity) + client->response.data = realloc(client->response.data,client->impl.response_data_capacity = (client->response.data_length + client->impl.expecting_response_length)); + + for(;((i<data_length)&&(client->impl.expecting_response_length));++i) { + ((char *)client->response.data)[client->response.data_length++] = ((const char *)data)[i]; + --client->impl.expecting_response_length; + } + + if (!client->impl.expecting_response_length) + client->impl.read_mode = ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE; + break; + } + } +} + +static void AnodeHttpClient_tcp_available_for_write_handler( + AnodeTransportEngine *transport, + AnodeTransportTcpConnection *connection) +{ + struct AnodeHttpClient *client; + unsigned int i,j; + int n; + + if (!(client = (struct AnodeHttpClient *)(connection->ptr))) + return; + if (client->impl.freed) { + transport->tcp_close(transport,connection); + return; + } + + if (client->impl.phase == ANODE_HTTP_REQUEST_PHASE_SEND) { + n = client->impl.transport_engine->tcp_send(client->impl.transport_engine,client->impl.tcp_connection,(const void *)client->impl.outbuf,(int)client->impl.outbuf_len); + if (n < 0) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION; + AnodeHttpClient_close_and_fail(client); + } else if (n > 0) { + for(i=0,j=(client->impl.outbuf_len - (unsigned int)n);i<j;++i) + client->impl.outbuf[i] = client->impl.outbuf[i + (unsigned int)n]; + client->impl.outbuf_len -= (unsigned int)n; + + if ((client->method == ANODE_HTTP_POST)&&(client->data)&&(client->data_length)) { + i = sizeof(client->impl.outbuf) - client->impl.outbuf_len; + j = client->data_length - client->impl.request_data_ptr; + if (i > j) + i = j; + Anode_memcpy((client->impl.outbuf + client->impl.outbuf_len),client->data,i); + client->impl.request_data_ptr += i; + client->impl.outbuf_len += i; + } + + if (!client->impl.outbuf_len) { + client->impl.transport_engine->tcp_stop_writing(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_RECEIVE; + } + } + } else client->impl.transport_engine->tcp_stop_writing(client->impl.transport_engine,client->impl.tcp_connection); +} + +static void AnodeHttpClient_dns_result_handler( + AnodeTransportEngine *transport, + void *ptr, + int error_code, + const char *name, + const AnodeTransportIpAddress *ip_addresses, + unsigned int ip_address_count, + const AnodeAddress *anode_address) +{ + struct AnodeHttpClient *client; + AnodeTransportIpEndpoint to_endpoint; + + if (!(client = (struct AnodeHttpClient *)ptr)) + return; + if (client->impl.freed) + return; + + if ((error_code)||(!ip_address_count)) { + if (client->impl.phase == ANODE_HTTP_REQUEST_PHASE_RESOLVE) { + client->response.code = ANODE_HTTP_SPECIAL_RESPONSE_DNS_RESOLVE_FAILED; + AnodeHttpClient_close_and_fail(client); + } + } else { + client->impl.phase = ANODE_HTTP_REQUEST_PHASE_CONNECT; + Anode_memcpy(&to_endpoint.address,ip_addresses,sizeof(AnodeTransportIpAddress)); + to_endpoint.port = (client->uri.port > 0) ? client->uri.port : 80; + client->impl.transport_engine->tcp_connect( + client->impl.transport_engine, + client, + &AnodeHttpClient_tcp_outgoing_connect_handler, + &AnodeHttpClient_tcp_connection_terminated_handler, + &AnodeHttpClient_tcp_receive_handler, + &AnodeHttpClient_tcp_available_for_write_handler, + &to_endpoint); + } +} + +struct AnodeHttpClient *AnodeHttpClient_new(AnodeTransportEngine *transport_engine) +{ + struct AnodeHttpClient *req = malloc(sizeof(struct AnodeHttpClient)); + Anode_zero(req,sizeof(struct AnodeHttpClient)); + + AnodeDictionary_init(&(req->headers),0); + AnodeDictionary_init(&(req->response.headers),0); + + req->impl.transport_engine = transport_engine; + + return req; +} + +void AnodeHttpClient_send(struct AnodeHttpClient *client) +{ + client->response.code = 0; + client->response.data_length = 0; + AnodeDictionary_clear(&(client->response.headers)); + + client->impl.request_data_ptr = 0; + client->impl.expecting_response_length = 0; + client->impl.read_mode = ANODE_HTTP_READ_MODE_WAITING; + client->impl.outbuf_len = 0; + + if (!client->impl.tcp_connection) { + client->impl.transport_engine->dns_resolve( + client->impl.transport_engine, + &AnodeHttpClient_dns_result_handler, + client, + client->uri.host, + ANODE_TRANSPORT_DNS_QUERY_ALWAYS, + ANODE_TRANSPORT_DNS_QUERY_IF_NO_PREVIOUS, + ANODE_TRANSPORT_DNS_QUERY_NEVER); + } else AnodeHttpClient_do_initiate_client(client); +} + +void AnodeHttpClient_free(struct AnodeHttpClient *client) +{ + AnodeDictionary_destroy(&(client->headers)); + AnodeDictionary_destroy(&(client->response.headers)); + + if (client->impl.tcp_connection) { + client->impl.transport_engine->tcp_close(client->impl.transport_engine,client->impl.tcp_connection); + client->impl.tcp_connection = (AnodeTransportTcpConnection *)0; + } + + if (client->response.data) + free(client->response.data); + + client->impl.freed = 1; + client->impl.transport_engine->run_later(client->impl.transport_engine,client,&free); +} diff --git a/attic/historic/anode/libanode/impl/http_client.h b/attic/historic/anode/libanode/impl/http_client.h new file mode 100644 index 00000000..f1673097 --- /dev/null +++ b/attic/historic/anode/libanode/impl/http_client.h @@ -0,0 +1,200 @@ +/* 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_HTTP_CLIENT_H +#define _ANODE_HTTP_CLIENT_H + +#include <stdio.h> +#include <stdlib.h> +#include "dictionary.h" +#include "../anode.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HTTP request type + */ +enum AnodeHttpClientRequestMethod +{ + ANODE_HTTP_GET = 0, + ANODE_HTTP_HEAD = 1, + ANODE_HTTP_POST = 2 +}; + +/* + * Special response codes to indicate I/O errors + */ +#define ANODE_HTTP_SPECIAL_RESPONSE_DNS_RESOLVE_FAILED -1 +#define ANODE_HTTP_SPECIAL_RESPONSE_CONNECT_FAILED -2 +#define ANODE_HTTP_SPECIAL_RESPONSE_HEADERS_TOO_LARGE -3 +#define ANODE_HTTP_SPECIAL_RESPONSE_SERVER_CLOSED_CONNECTION -4 +#define ANODE_HTTP_SPECIAL_RESPONSE_INVALID_RESPONSE -5 + +/** + * Simple HTTP client + */ +struct AnodeHttpClient +{ + /** + * Request URI + */ + AnodeURI uri; + + /** + * Request method: GET, PUT, HEAD, or POST + */ + enum AnodeHttpClientRequestMethod method; + + /** + * Data for POST requests + * + * It is your responsibility to manage and/or free this pointer. The HTTP + * client only reads from it. + */ + const void *data; + unsigned int data_length; + + /** + * Content type for data, or null for application/x-www-form-urlencoded + */ + const char *data_content_type; + + /** + * Set to non-zero to use HTTP connection keepalive + * + * If keepalive is enabled, this request can be modified and re-used and + * its associated connection will stay open (being reopened if needed) + * until it is freed. + * + * Note that this client is too dumb to pool connections and pick them on + * the basis of host. Keepalive mode should only be set if the next request + * will be from the same host and port, otherwise you will get a '404'. + */ + int keepalive; + + /** + * Function pointer to be called when request is complete (or fails) + */ + void (*handler)(struct AnodeHttpClient *); + + /** + * Two arbitrary pointers that can be stored here for use by the handler. + * These are not accessed or modified by the client. + */ + void *ptr[2]; + + /** + * Request headers + */ + struct AnodeDictionary headers; + + struct { + /** + * Response code, set on completion or failure before handler is called + * + * Also check for the special response codes defined in http_client.h as + * these negative codes indicate network or other errors. + */ + int code; + + /** + * Response data, for GET and POST requests + */ + void *data; + + /** + * Length of response data + */ + unsigned int data_length; + + /** + * Response headers + */ + struct AnodeDictionary headers; + } response; + + /** + * Internal fields used by implementation + */ + struct { + /* Transport engine being used by request */ + AnodeTransportEngine *transport_engine; + + /* Connection to which request has been sent, or null if none */ + struct AnodeHttpConnection *connection; + + /* Buffer for reading chunked mode chunk lines (can't use data buf) */ + char header_line_buf[256]; + unsigned int header_line_buf_ptr; + + /* Where are we in sending request data? */ + unsigned int request_data_ptr; + + /* Capacity of response_data buffer */ + unsigned int response_data_capacity; + + /* How much response data are we currently expecting? */ + /* This is content-length in block mode or chunk length in chunked mode */ + unsigned int expecting_response_length; + + /* Read mode */ + enum { + ANODE_HTTP_READ_MODE_WAITING = 0, + ANODE_HTTP_READ_MODE_HEADERS = 1, + ANODE_HTTP_READ_MODE_BLOCK = 2, + ANODE_HTTP_READ_MODE_CHUNKED_CHUNK_SIZE = 3, + ANODE_HTTP_READ_MODE_CHUNKED_DATA = 4, + ANODE_HTTP_READ_MODE_CHUNKED_FOOTER = 5 + } read_mode; + + /* Connection from transport engine */ + AnodeTransportTcpConnection *tcp_connection; + + /* Write buffer */ + unsigned char outbuf[16384]; + unsigned int outbuf_len; + + /* Phase of request state machine */ + enum { + ANODE_HTTP_REQUEST_PHASE_RESOLVE = 0, + ANODE_HTTP_REQUEST_PHASE_CONNECT = 1, + ANODE_HTTP_REQUEST_PHASE_SEND = 2, + ANODE_HTTP_REQUEST_PHASE_RECEIVE = 3, + ANODE_HTTP_REQUEST_PHASE_KEEPALIVE = 4, + ANODE_HTTP_REQUEST_PHASE_CLOSED = 5 + } phase; + + /* Has request object been freed? */ + int freed; + + /** + * Pointer used internally for putting requests into linked lists + */ + struct AnodeHttpClient *next; + } impl; +}; + +struct AnodeHttpClient *AnodeHttpClient_new(AnodeTransportEngine *transport_engine); +void AnodeHttpClient_send(struct AnodeHttpClient *client); +void AnodeHttpClient_free(struct AnodeHttpClient *client); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/attic/historic/anode/libanode/impl/misc.c b/attic/historic/anode/libanode/impl/misc.c new file mode 100644 index 00000000..edc73978 --- /dev/null +++ b/attic/historic/anode/libanode/impl/misc.c @@ -0,0 +1,190 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "misc.h" +#include "types.h" + +static const char Anode_hex_chars[16] = { + '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' +}; + +static const char Anode_base32_chars[32] = { + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q', + 'r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' +}; +static const unsigned char Anode_base32_bits[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5, + 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,0,1,2, + 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +/* Table for converting ASCII chars to lower case */ +const unsigned char Anode_ascii_tolower_table[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +void Anode_trim(char *s) +{ + char *dest = s; + char *last; + while ((*s)&&((*s == ' ')||(*s == '\t')||(*s == '\r')||(*s == '\n'))) + ++s; + last = s; + while ((*dest = *s)) { + if ((*dest != ' ')&&(*dest != '\t')&&(*dest != '\r')&&(*dest != '\n')) + last = dest; + ++dest; + ++s; + } + if (*last) + *(++last) = (char)0; +} + +unsigned int Anode_rand() +{ + static volatile int need_seed = 1; + + if (need_seed) { + need_seed = 0; + srandom((unsigned long)Anode_time64()); + } + + return (unsigned int)random(); +} + +void Anode_to_hex(const unsigned char *b,unsigned int len,char *h,unsigned int hlen) +{ + unsigned int i; + + if ((len * 2) >= hlen) + len = (hlen - 1) / 2; + + for(i=0;i<len;++i) { + *(h++) = Anode_hex_chars[b[i] >> 4]; + *(h++) = Anode_hex_chars[b[i] & 0xf]; + } + *h = (char)0; +} + +void Anode_from_hex(const char *h,unsigned char *b,unsigned int blen) +{ + unsigned char *end = b + blen; + unsigned char v = (unsigned char)0; + + while (b != end) { + switch(*(h++)) { + case '0': v = 0x00; break; + case '1': v = 0x10; break; + case '2': v = 0x20; break; + case '3': v = 0x30; break; + case '4': v = 0x40; break; + case '5': v = 0x50; break; + case '6': v = 0x60; break; + case '7': v = 0x70; break; + case '8': v = 0x80; break; + case '9': v = 0x90; break; + case 'a': v = 0xa0; break; + case 'b': v = 0xb0; break; + case 'c': v = 0xc0; break; + case 'd': v = 0xd0; break; + case 'e': v = 0xe0; break; + case 'f': v = 0xf0; break; + default: return; + } + + switch(*(h++)) { + case '0': v |= 0x00; break; + case '1': v |= 0x01; break; + case '2': v |= 0x02; break; + case '3': v |= 0x03; break; + case '4': v |= 0x04; break; + case '5': v |= 0x05; break; + case '6': v |= 0x06; break; + case '7': v |= 0x07; break; + case '8': v |= 0x08; break; + case '9': v |= 0x09; break; + case 'a': v |= 0x0a; break; + case 'b': v |= 0x0b; break; + case 'c': v |= 0x0c; break; + case 'd': v |= 0x0d; break; + case 'e': v |= 0x0e; break; + case 'f': v |= 0x0f; break; + default: return; + } + + *(b++) = v; + } +} + +void Anode_base32_5_to_8(const unsigned char *in,char *out) +{ + out[0] = Anode_base32_chars[(in[0]) >> 3]; + out[1] = Anode_base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6]; + out[2] = Anode_base32_chars[(in[1] & 0x3e) >> 1]; + out[3] = Anode_base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4]; + out[4] = Anode_base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7]; + out[5] = Anode_base32_chars[(in[3] & 0x7c) >> 2]; + out[6] = Anode_base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5]; + out[7] = Anode_base32_chars[(in[4] & 0x1f)]; +} + +void Anode_base32_8_to_5(const char *in,unsigned char *out) +{ + out[0] = ((Anode_base32_bits[(unsigned int)in[0]]) << 3) | (Anode_base32_bits[(unsigned int)in[1]] & 0x1C) >> 2; + out[1] = ((Anode_base32_bits[(unsigned int)in[1]] & 0x03) << 6) | (Anode_base32_bits[(unsigned int)in[2]]) << 1 | (Anode_base32_bits[(unsigned int)in[3]] & 0x10) >> 4; + out[2] = ((Anode_base32_bits[(unsigned int)in[3]] & 0x0F) << 4) | (Anode_base32_bits[(unsigned int)in[4]] & 0x1E) >> 1; + out[3] = ((Anode_base32_bits[(unsigned int)in[4]] & 0x01) << 7) | (Anode_base32_bits[(unsigned int)in[5]]) << 2 | (Anode_base32_bits[(unsigned int)in[6]] & 0x18) >> 3; + out[4] = ((Anode_base32_bits[(unsigned int)in[6]] & 0x07) << 5) | (Anode_base32_bits[(unsigned int)in[7]]); +} diff --git a/attic/historic/anode/libanode/impl/misc.h b/attic/historic/anode/libanode/impl/misc.h new file mode 100644 index 00000000..38ddea7c --- /dev/null +++ b/attic/historic/anode/libanode/impl/misc.h @@ -0,0 +1,193 @@ +/* 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/>. */ + +/* This contains miscellaneous functions, including some re-implementations + * of some functions from string.h. This is to help us port to some platforms + * (cough Windows Mobile cough) that lack a lot of the basic C library. */ + +#ifndef _ANODE_MISC_H +#define _ANODE_MISC_H + +#include <time.h> +#include <sys/time.h> +#include "types.h" + +#ifndef ANODE_NO_STRING_H +#include <string.h> +#include <stdlib.h> +#endif + +/* Table mapping ASCII characters to themselves or their lower case */ +extern const unsigned char Anode_ascii_tolower_table[256]; + +/* Get the lower case version of an ASCII char */ +#define Anode_tolower(c) ((char)Anode_ascii_tolower_table[((unsigned long)((unsigned char)(c)))]) + +/* Test strings for equality, return nonzero if equal */ +static inline unsigned int Anode_streq(const char *restrict a,const char *restrict b) +{ + if ((!a)||(!b)) + return 0; + while (*a == *(b++)) { + if (!*(a++)) + return 1; + } + return 0; +} + +/* Equality test ignoring (ASCII) case */ +static inline unsigned int Anode_strcaseeq(const char *restrict a,const char *restrict b) +{ + if ((!a)||(!b)) + return 0; + while (Anode_tolower(*a) == Anode_tolower(*(b++))) { + if (!*(a++)) + return 1; + } + return 0; +} + +/* Safe c-string copy, ensuring that dest[] always ends with zero */ +static inline void Anode_str_copy(char *restrict dest,const char *restrict src,unsigned int dest_size) +{ + char *restrict dest_end = dest + (dest_size - 1); + while ((*src)&&(dest != dest_end)) + *(dest++) = *(src++); + *dest = (char)0; +} + +/* Simple memcpy() */ +#ifdef ANODE_NO_STRING_H +static inline void Anode_memcpy(void *restrict dest,const void *restrict src,unsigned int len) +{ + unsigned int i; + for(i=0;i<len;++i) + ((unsigned char *restrict)dest)[i] = ((const unsigned char *restrict)src)[i]; +} +#else +#define Anode_memcpy(d,s,l) memcpy((d),(s),(l)) +#endif + +/* Memory test for equality */ +#ifdef ANODE_NO_STRING_H +static inline unsigned int Anode_mem_eq(const void *restrict a,const void *restrict b,unsigned int len) +{ + unsigned int i; + for(i=0;i<len;++i) { + if (((const unsigned char *restrict)a)[i] != ((const unsigned char *restrict)b)[i]) + return 0; + } + return 1; +} +#else +#define Anode_mem_eq(a,b,l) (!memcmp((a),(b),(l))) +#endif + +/* Zero memory */ +#ifdef ANODE_NO_STRING_H +static inline void Anode_zero(void *restrict ptr,unsigned int len) +{ + unsigned int i; + for(i=0;i<len;++i) + ((unsigned char *restrict)ptr)[i] = (unsigned char)0; +} +#else +#define Anode_zero(p,l) memset((p),0,(l)) +#endif + +/* Get a pointer to the first occurrance of a character in a string */ +#ifdef ANODE_NO_STRING_H +static inline const char *Anode_strchr(const char *s,char c) +{ + while (*s) { + if (*s == c) + return s; + ++s; + } + return (char *)0; +} +#else +#define Anode_strchr(s,c) strchr((s),(c)) +#endif + +static inline unsigned int Anode_count_char(const char *s,char c) +{ + unsigned int cnt = 0; + while (s) { + if (*s == c) + ++cnt; + ++s; + } + return cnt; +} + +/* Strip all of a given set of characters from a string */ +static inline void Anode_strip_all(char *s,const char *restrict schars) +{ + char *d = s; + + while (*s) { + if (!Anode_strchr(schars,*s)) + *(d++) = *s; + ++s; + } + *d = (char)0; +} + +/* Trim whitespace from beginning and end of string */ +void Anode_trim(char *s); + +/* Get the length of a string */ +#ifdef ANODE_NO_STRING_H +static inline unsigned int Anode_strlen(const char *s) +{ + const char *ptr = s; + while (*ptr) ++ptr; + return (unsigned int)(ptr - s); +} +#else +#define Anode_strlen(s) strlen((s)) +#endif + +/* Returns number of milliseconds since the epoch (Java-style) */ +static inline uint64_t Anode_time64() +{ + struct timeval tv; + gettimeofday(&tv,(void *)0); + return ( (((uint64_t)tv.tv_sec) / 1000ULL) + ((uint64_t)(tv.tv_usec / 1000ULL)) ); +} + +/* Returns number of seconds since the epoch (*nix style) */ +static inline unsigned long Anode_time() +{ + struct timeval tv; + gettimeofday(&tv,(void *)0); + return (unsigned long)tv.tv_sec; +} + +/* Simple random function, not cryptographically safe */ +unsigned int Anode_rand(); + +/* Fast hex/ascii conversion */ +void Anode_to_hex(const unsigned char *b,unsigned int len,char *h,unsigned int hlen); +void Anode_from_hex(const char *h,unsigned char *b,unsigned int blen); + +/* Convert back and forth from base32 encoding */ +/* 5 bytes -> 8 base32 characters and vice versa */ +void Anode_base32_5_to_8(const unsigned char *in,char *out); +void Anode_base32_8_to_5(const char *in,unsigned char *out); + +#endif diff --git a/attic/historic/anode/libanode/impl/mutex.h b/attic/historic/anode/libanode/impl/mutex.h new file mode 100644 index 00000000..b20eb82b --- /dev/null +++ b/attic/historic/anode/libanode/impl/mutex.h @@ -0,0 +1,34 @@ +/* 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_MUTEX_H +#define _ANODE_MUTEX_H + +#ifdef WINDOWS + +#else /* WINDOWS */ + +#include <pthread.h> + +#define AnodeMutex pthread_mutex_t +#define AnodeMutex_init(m) pthread_mutex_init((m),(const pthread_mutexattr_t *)0) +#define AnodeMutex_destroy(m) pthread_mutex_destroy((m)) +#define AnodeMutex_lock(m) pthread_mutex_lock((m)) +#define AnodeMutex_unlock(m) pthread_mutex_unlock((m)) + +#endif /* WINDOWS */ + +#endif diff --git a/attic/historic/anode/libanode/impl/thread.c b/attic/historic/anode/libanode/impl/thread.c new file mode 100644 index 00000000..c2070462 --- /dev/null +++ b/attic/historic/anode/libanode/impl/thread.c @@ -0,0 +1,58 @@ +/* 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/>. */ + +#include "thread.h" +#include <stdlib.h> + +#ifdef WINDOWS + +#else /* not WINDOWS */ + +struct _AnodeThread +{ + void (*func)(void *); + void *arg; + int wait_for_join; + pthread_t thread; +}; + +static void *_AnodeThread_main(void *arg) +{ + ((struct _AnodeThread *)arg)->func(((struct _AnodeThread *)arg)->arg); + if (!((struct _AnodeThread *)arg)->wait_for_join) + free(arg); + return (void *)0; +} + +AnodeThread *AnodeThread_create(void (*func)(void *),void *arg,int wait_for_join) +{ + struct _AnodeThread *t = malloc(sizeof(struct _AnodeThread)); + t->func = func; + t->arg = arg; + t->wait_for_join = wait_for_join; + pthread_create(&t->thread,(const pthread_attr_t *)0,&_AnodeThread_main,(void *)t); + if (!wait_for_join) + pthread_detach(t->thread); + return (AnodeThread *)t; +} + +void AnodeThread_join(AnodeThread *thread) +{ + pthread_join(((struct _AnodeThread *)thread)->thread,(void **)0); + free((void *)thread); +} + +#endif /* WINDOWS / not WINDOWS */ diff --git a/attic/historic/anode/libanode/impl/thread.h b/attic/historic/anode/libanode/impl/thread.h new file mode 100644 index 00000000..accf173a --- /dev/null +++ b/attic/historic/anode/libanode/impl/thread.h @@ -0,0 +1,65 @@ +/* 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_THREAD_H +#define _ANODE_THREAD_H + +#ifdef WINDOWS + +#include <windows.h> +#include <thread.h> +typedef DWORD AnodeThreadId; + +#else /* not WINDOWS */ + +#include <pthread.h> +typedef pthread_t AnodeThreadId; + +#define AnodeThread_self() pthread_self() +#define AnodeThreadId_equal(a,b) pthread_equal((pthread_t)(a),(pthread_t)(b)) + +#endif + +typedef void AnodeThread; + +/** + * Create and launch a new thread + * + * If wait_for_join is true (nonzero), the thread can and must be joined. The + * thread object won't be freed until join is called and returns. If + * wait_for_join is false, the thread object frees itself automatically on + * termination. + * + * If wait_for_join is false (zero), there is really no need to keep track of + * the thread object. + * + * @param func Function to call as thread main + * @param arg Argument to pass to function + * @param wait_for_join If false, thread deletes itself when it terminates + */ +AnodeThread *AnodeThread_create(void (*func)(void *),void *arg,int wait_for_join); + +/** + * Wait for a thread to terminate and delete thread object + * + * This can only be used for threads created with wait_for_join set to true. + * The thread object is no longer valid after this call. + * + * @param thread Thread to wait for termination and delete + */ +void AnodeThread_join(AnodeThread *thread); + +#endif diff --git a/attic/historic/anode/libanode/impl/types.h b/attic/historic/anode/libanode/impl/types.h new file mode 100644 index 00000000..5f070e5a --- /dev/null +++ b/attic/historic/anode/libanode/impl/types.h @@ -0,0 +1,25 @@ +/* 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_TYPES_H +#define _ANODE_TYPES_H + +#ifdef WINDOWS +#else +#include <stdint.h> +#endif + +#endif diff --git a/attic/historic/anode/libanode/network_address.c b/attic/historic/anode/libanode/network_address.c new file mode 100644 index 00000000..86ec054f --- /dev/null +++ b/attic/historic/anode/libanode/network_address.c @@ -0,0 +1,136 @@ +/* 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/>. */ + +#include <netinet/in.h> +#include <arpa/inet.h> +#include "impl/misc.h" +#include "impl/types.h" +#include "anode.h" + +const AnodeNetworkAddress AnodeNetworkAddress_ANY4 = { + ANODE_NETWORK_ADDRESS_IPV4, + { 0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_ANY6 = { + ANODE_NETWORK_ADDRESS_IPV6, + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_LOCAL4 = { + ANODE_NETWORK_ADDRESS_IPV4, + { 127,0,0,1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; +const AnodeNetworkAddress AnodeNetworkAddress_LOCAL6 = { + ANODE_NETWORK_ADDRESS_IPV6, + { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } +}; + +int AnodeNetworkAddress_to_string(const AnodeNetworkAddress *address,char *buf,int len) +{ + const char *s; + + switch(address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + s = inet_ntop(AF_INET,(const void *)address->bits,buf,len); + if (s) + return Anode_strlen(s); + else return ANODE_ERR_INVALID_ARGUMENT; + break; + case ANODE_NETWORK_ADDRESS_IPV6: + s = inet_ntop(AF_INET6,address->bits,buf,len); + if (s) + return Anode_strlen(s); + else return ANODE_ERR_INVALID_ARGUMENT; + /* + case ANODE_NETWORK_ADDRESS_ETHERNET: + break; + case ANODE_NETWORK_ADDRESS_USB: + break; + case ANODE_NETWORK_ADDRESS_BLUETOOTH: + break; + case ANODE_NETWORK_ADDRESS_IPC: + break; + case ANODE_NETWORK_ADDRESS_80211S: + break; + case ANODE_NETWORK_ADDRESS_SERIAL: + break; + */ + case ANODE_NETWORK_ADDRESS_ANODE_256_40: + return AnodeAddress_to_string((const AnodeAddress *)address->bits,buf,len); + default: + return ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + } +} + +int AnodeNetworkAddress_from_string(const char *str,AnodeNetworkAddress *address) +{ + unsigned int dots = Anode_count_char(str,'.'); + unsigned int colons = Anode_count_char(str,':'); + + if ((dots == 3)&&(!colons)) { + address->type = ANODE_NETWORK_ADDRESS_IPV4; + if (inet_pton(AF_INET,str,address->bits) > 0) + return 0; + else return ANODE_ERR_INVALID_ARGUMENT; + } else if ((colons)&&(!dots)) { + address->type = ANODE_NETWORK_ADDRESS_IPV6; + if (inet_pton(AF_INET6,str,address->bits) > 0) + return 0; + else return ANODE_ERR_INVALID_ARGUMENT; + } else { + address->type = ANODE_NETWORK_ADDRESS_ANODE_256_40; + return AnodeAddress_from_string(str,(AnodeAddress *)address->bits); + } +} + +int AnodeNetworkEndpoint_from_sockaddr(const void *sockaddr,AnodeNetworkEndpoint *endpoint) +{ + switch(((struct sockaddr_storage *)sockaddr)->ss_family) { + case AF_INET: + *((uint32_t *)endpoint->address.bits) = (uint32_t)(((struct sockaddr_in *)sockaddr)->sin_addr.s_addr); + endpoint->port = (int)ntohs(((struct sockaddr_in *)sockaddr)->sin_port); + return 0; + case AF_INET6: + Anode_memcpy(endpoint->address.bits,((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr,16); + endpoint->port = (int)ntohs(((struct sockaddr_in6 *)sockaddr)->sin6_port); + return 0; + default: + return ANODE_ERR_INVALID_ARGUMENT; + } +} + +int AnodeNetworkEndpoint_to_sockaddr(const AnodeNetworkEndpoint *endpoint,void *sockaddr,int sockaddr_len) +{ + switch(endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + if (sockaddr_len < (int)sizeof(struct sockaddr_in)) + return ANODE_ERR_BUFFER_TOO_SMALL; + Anode_zero(sockaddr,sizeof(struct sockaddr_in)); + ((struct sockaddr_in *)sockaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)sockaddr)->sin_port = htons((uint16_t)endpoint->port); + ((struct sockaddr_in *)sockaddr)->sin_addr.s_addr = *((uint32_t *)endpoint->address.bits); + return 0; + case ANODE_NETWORK_ADDRESS_IPV6: + if (sockaddr_len < (int)sizeof(struct sockaddr_in6)) + return ANODE_ERR_BUFFER_TOO_SMALL; + Anode_zero(sockaddr,sizeof(struct sockaddr_in6)); + ((struct sockaddr_in6 *)sockaddr)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)sockaddr)->sin6_port = htons((uint16_t)endpoint->port); + Anode_memcpy(((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr,endpoint->address.bits,16); + return 0; + default: + return ANODE_ERR_INVALID_ARGUMENT; + } +} diff --git a/attic/historic/anode/libanode/secure_random.c b/attic/historic/anode/libanode/secure_random.c new file mode 100644 index 00000000..4322d7de --- /dev/null +++ b/attic/historic/anode/libanode/secure_random.c @@ -0,0 +1,88 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include "impl/aes.h" +#include "impl/misc.h" +#include "anode.h" + +#ifdef WINDOWS +#include <windows.h> +#include <wincrypt.h> +#endif + +struct AnodeSecureRandomImpl +{ + AnodeAesExpandedKey key; + unsigned char state[ANODE_AES_BLOCK_SIZE]; + unsigned char block[ANODE_AES_BLOCK_SIZE]; + unsigned int ptr; +}; + +AnodeSecureRandom *AnodeSecureRandom_new() +{ + unsigned char keybuf[ANODE_AES_KEY_SIZE + ANODE_AES_BLOCK_SIZE + ANODE_AES_BLOCK_SIZE]; + unsigned int i; + struct AnodeSecureRandomImpl *srng; + +#ifdef WINDOWS + HCRYPTPROV hProv; + if (CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { + CryptGenRandom(hProv,sizeof(keybuf),keybuf); + CryptReleaseContext(hProv,0); + } +#else + FILE *urandf = fopen("/dev/urandom","rb"); + if (urandf) { + fread((void *)keybuf,sizeof(keybuf),1,urandf); + fclose(urandf); + } +#endif + + for(i=0;i<sizeof(keybuf);++i) + keybuf[i] ^= (unsigned char)(Anode_rand() >> 5); + + srng = malloc(sizeof(struct AnodeSecureRandomImpl)); + Anode_aes256_expand_key(keybuf,&srng->key); + for(i=0;i<ANODE_AES_BLOCK_SIZE;++i) + srng->state[i] = keybuf[ANODE_AES_KEY_SIZE + i]; + for(i=0;i<ANODE_AES_BLOCK_SIZE;++i) + srng->block[i] = keybuf[ANODE_AES_KEY_SIZE + ANODE_AES_KEY_SIZE + i]; + srng->ptr = ANODE_AES_BLOCK_SIZE; + + return (AnodeSecureRandom *)srng; +} + +void AnodeSecureRandom_gen_bytes(AnodeSecureRandom *srng,void *buf,long count) +{ + long i,j; + + for(i=0;i<count;++i) { + if (((struct AnodeSecureRandomImpl *)srng)->ptr == ANODE_AES_BLOCK_SIZE) { + Anode_aes256_encrypt(&((struct AnodeSecureRandomImpl *)srng)->key,((struct AnodeSecureRandomImpl *)srng)->state,((struct AnodeSecureRandomImpl *)srng)->state); + for(j=0;j<ANODE_AES_KEY_SIZE;++j) + ((struct AnodeSecureRandomImpl *)srng)->block[j] ^= ((struct AnodeSecureRandomImpl *)srng)->state[j]; + ((struct AnodeSecureRandomImpl *)srng)->ptr = 0; + } + ((unsigned char *)buf)[i] = ((struct AnodeSecureRandomImpl *)srng)->block[((struct AnodeSecureRandomImpl *)srng)->ptr++]; + } +} + +void AnodeSecureRandom_delete(AnodeSecureRandom *srng) +{ + free(srng); +} diff --git a/attic/historic/anode/libanode/system_transport.c b/attic/historic/anode/libanode/system_transport.c new file mode 100644 index 00000000..4bfb143e --- /dev/null +++ b/attic/historic/anode/libanode/system_transport.c @@ -0,0 +1,948 @@ +/* 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/>. */ + +#include <stdio.h> +#include <netdb.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include "anode.h" +#include "impl/mutex.h" +#include "impl/thread.h" +#include "impl/misc.h" +#include "impl/dns_txt.h" + +#ifdef WINDOWS +#include <windows.h> +#include <winsock2.h> +#define AnodeSystemTransport__close_socket(s) closesocket((s)) +#define ANODE_USE_SELECT 1 +#else +#include <poll.h> +#include <unistd.h> +#define AnodeSystemTransport__close_socket(s) close((s)) +#endif + +static const char *AnodeSystemTransport_CLASS = "SystemTransport"; + +/* ======================================================================== */ + +struct AnodeSystemTransport; + +struct AnodeSystemTransport_AnodeSocket +{ + AnodeSocket base; /* must be first */ + unsigned int entry_idx; +}; + +#define ANODE_SYSTEM_TRANSPORT_DNS_MAX_RESULTS 16 +struct AnodeSystemTransport__dns_request +{ + struct AnodeSystemTransport__dns_request *next; + + AnodeThread *thread; + struct AnodeSystemTransport *owner; + + void (*event_handler)(const AnodeEvent *event); + + char name[256]; + enum AnodeTransportDnsIncludeMode ipv4_include_mode; + enum AnodeTransportDnsIncludeMode ipv6_include_mode; + enum AnodeTransportDnsIncludeMode anode_include_mode; + + AnodeNetworkAddress addresses[ANODE_SYSTEM_TRANSPORT_DNS_MAX_RESULTS]; + unsigned int address_count; + + int error_code; +}; + +#ifdef ANODE_USE_SELECT +typedef int AnodeSystemTransport__poll_fd; /* for select() */ +#else +typedef struct pollfd AnodeSystemTransport__poll_fd; /* for poll() */ +#endif + +struct AnodeSystemTransport +{ + AnodeTransport interface; /* must be first */ + + AnodeTransport *base; + +#ifdef ANODE_USE_SELECT + FD_SET readfds; + FD_SET writefds; +#endif + + void (*default_event_handler)(const AnodeEvent *event); + + AnodeSystemTransport__poll_fd *fds; + struct AnodeSystemTransport_AnodeSocket *sockets; + unsigned int fd_count; + unsigned int fd_capacity; + + struct AnodeSystemTransport__dns_request *pending_dns_requests; + + int invoke_pipe[2]; + AnodeMutex invoke_pipe_m; + void *invoke_pipe_buf[2]; + unsigned int invoke_pipe_buf_ptr; +}; + +/* ======================================================================== */ +/* Internal helper methods */ + +static unsigned int AnodeSystemTransport__add_entry(struct AnodeSystemTransport *transport) +{ + if ((transport->fd_count + 1) > transport->fd_capacity) { + transport->fd_capacity += 8; + transport->fds = realloc(transport->fds,sizeof(AnodeSystemTransport__poll_fd) * transport->fd_capacity); + transport->sockets = realloc(transport->sockets,sizeof(struct AnodeSystemTransport_AnodeSocket) * transport->fd_capacity); + } + return transport->fd_count++; +} + +static void AnodeSystemTransport__remove_entry(struct AnodeSystemTransport *transport,const unsigned int idx) +{ + unsigned int i; + + --transport->fd_count; + for(i=idx;i<transport->fd_count;++i) { + Anode_memcpy(&transport->fds[i],&transport->fds[i+1],sizeof(AnodeSystemTransport__poll_fd)); + Anode_memcpy(&transport->sockets[i],&transport->sockets[i+1],sizeof(struct AnodeSystemTransport_AnodeSocket)); + } + + if ((transport->fd_capacity - transport->fd_count) > 16) { + transport->fd_capacity -= 16; + transport->fds = realloc(transport->fds,sizeof(AnodeSystemTransport__poll_fd) * transport->fd_capacity); + transport->sockets = realloc(transport->sockets,sizeof(struct AnodeSystemTransport_AnodeSocket) * transport->fd_capacity); + } +} + +static void AnodeSystemTransport__dns_invoke_on_completion(void *_dreq) +{ + struct AnodeSystemTransport__dns_request *dreq = (struct AnodeSystemTransport__dns_request *)_dreq; + struct AnodeSystemTransport__dns_request *ptr,**lastnext; + + AnodeThread_join(dreq->thread); + + ptr = dreq->owner->pending_dns_requests; + lastnext = &dreq->owner->pending_dns_requests; + while (ptr) { + if (ptr == dreq) { + *lastnext = ptr->next; + break; + } else { + lastnext = &ptr->next; + ptr = ptr->next; + } + } + + free(dreq); +} + +static void AnodeSystemTransport__dns_thread_main(void *_dreq) +{ + struct AnodeSystemTransport__dns_request *dreq = (struct AnodeSystemTransport__dns_request *)_dreq; + + dreq->owner->interface.invoke((AnodeTransport *)dreq->owner,dreq,&AnodeSystemTransport__dns_invoke_on_completion); +} + +static void AnodeSystemTransport__do_close(struct AnodeSystemTransport *transport,struct AnodeSystemTransport_AnodeSocket *sock,const int error_code,const int generate_event) +{ + AnodeEvent evbuf; + int fd; + + if (sock->base.class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + fd = (int)(transport->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]); +#else + fd = transport->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd; +#endif + + if ((sock->base.type == ANODE_SOCKET_STREAM_CONNECTION)&&(sock->base.state != ANODE_SOCKET_CLOSED)) { + sock->base.state = ANODE_SOCKET_CLOSED; + + if (generate_event) { + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_CLOSED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = error_code; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } + } + + AnodeSystemTransport__close_socket(fd); + AnodeSystemTransport__remove_entry(transport,((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx); + +#ifdef ANODE_USE_SELECT + FD_CLR(sock,&THIS->readfds); + FD_CLR(sock,&THIS->writefds); +#endif + } else transport->base->close(transport->base,(AnodeSocket *)sock); +} + +static int AnodeSystemTransport__populate_network_endpoint(const struct sockaddr_storage *saddr,AnodeNetworkEndpoint *ep) +{ + switch(saddr->ss_family) { + case AF_INET: + ep->address.type = ANODE_NETWORK_ADDRESS_IPV4; + *((uint32_t *)ep->address.bits) = ((struct sockaddr_in *)saddr)->sin_addr.s_addr; + ep->port = ntohs(((struct sockaddr_in *)saddr)->sin_port); + return 1; + case AF_INET6: + ep->address.type = ANODE_NETWORK_ADDRESS_IPV6; + Anode_memcpy(ep->address.bits,((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr,16); + ep->port = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); + return 1; + } + return 0; +} + +/* ======================================================================== */ + +#ifdef THIS +#undef THIS +#endif +#define THIS ((struct AnodeSystemTransport *)transport) + +static void AnodeSystemTransport_invoke(AnodeTransport *transport, + void *ptr, + void (*func)(void *)) +{ + void *invoke_msg[2]; + + invoke_msg[0] = ptr; + invoke_msg[1] = (void *)func; + + AnodeMutex_lock(&THIS->invoke_pipe_m); + write(THIS->invoke_pipe[1],(void *)(&invoke_msg),sizeof(invoke_msg)); + AnodeMutex_unlock(&THIS->invoke_pipe_m); +} + +static void AnodeSystemTransport_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) +{ + struct AnodeSystemTransport__dns_request *dreq = malloc(sizeof(struct AnodeSystemTransport__dns_request)); + + dreq->owner = THIS; + dreq->event_handler = event_handler; + Anode_str_copy(dreq->name,name,sizeof(dreq->name)); + dreq->ipv4_include_mode = ipv4_include_mode; + dreq->ipv6_include_mode = ipv6_include_mode; + dreq->anode_include_mode = anode_include_mode; + + dreq->address_count = 0; + dreq->error_code = 0; + + dreq->next = THIS->pending_dns_requests; + THIS->pending_dns_requests = dreq; + + dreq->thread = AnodeThread_create(&AnodeSystemTransport__dns_thread_main,dreq,0); +} + +static AnodeSocket *AnodeSystemTransport_datagram_listen(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + int tmp; + + switch(local_address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + fd = socket(AF_INET,SOCK_DGRAM,0); + if (fd <= 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + tmp = 1; + setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&tmp,sizeof(tmp)); + fcntl(fd,F_SETFL,O_NONBLOCK); + + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(local_port); + sin4.sin_addr.s_addr = *((uint32_t *)local_address->bits); + + if (bind(fd,(const struct sockaddr *)&sin4,sizeof(sin4))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + fd = socket(AF_INET6,SOCK_DGRAM,0); + if (fd <= 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + tmp = 1; setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&tmp,sizeof(tmp)); + fcntl(fd,F_SETFL,O_NONBLOCK); +#ifdef IPV6_V6ONLY + tmp = 1; setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&tmp,sizeof(tmp)); +#endif + + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(local_port); + Anode_memcpy(sin6.sin6_addr.s6_addr,local_address->bits,16); + + if (bind(fd,(const struct sockaddr *)&sin6,sizeof(sin6))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + default: + if (THIS->base) + return THIS->base->datagram_listen(THIS->base,local_address,local_port,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_DATAGRAM; + sock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&sock->base.endpoint.address,local_address,sizeof(AnodeNetworkAddress)); + sock->base.endpoint.port = local_port; + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + *error_code = 0; + return (AnodeSocket *)sock; +} + +static AnodeSocket *AnodeSystemTransport_stream_listen(AnodeTransport *transport, + const AnodeNetworkAddress *local_address, + int local_port, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + int tmp; + + switch(local_address->type) { + case ANODE_NETWORK_ADDRESS_IPV4: + fd = socket(AF_INET,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(local_port); + sin4.sin_addr.s_addr = *((uint32_t *)local_address->bits); + + if (bind(fd,(const struct sockaddr *)&sin4,sizeof(sin4))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + if (listen(fd,8)) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + fd = socket(AF_INET6,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); +#ifdef IPV6_V6ONLY + tmp = 1; setsockopt(fd,IPPROTO_IPV6,IPV6_V6ONLY,&tmp,sizeof(tmp)); +#endif + + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(local_port); + Anode_memcpy(sin6.sin6_addr.s6_addr,local_address->bits,16); + + if (bind(fd,(const struct sockaddr *)&sin6,sizeof(sin6))) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + if (listen(fd,8)) { + AnodeSystemTransport__close_socket(fd); + *error_code = ANODE_ERR_UNABLE_TO_BIND; + return (AnodeSocket *)0; + } + break; + default: + if (THIS->base) + return THIS->base->stream_listen(THIS->base,local_address,local_port,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_STREAM_LISTEN; + sock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&sock->base.endpoint.address,local_address,sizeof(AnodeNetworkAddress)); + sock->base.endpoint.port = local_port; + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + *error_code = 0; + return (AnodeSocket *)sock; +} + +static int AnodeSystemTransport_datagram_send(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len, + const AnodeNetworkEndpoint *to_endpoint) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + +#ifdef ANODE_USE_SELECT + const int fd = (int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]); +#else + const int fd = THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd; +#endif + + switch(to_endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons((uint16_t)to_endpoint->port); + sin4.sin_addr.s_addr = *((uint32_t *)to_endpoint->address.bits); + sendto(fd,data,data_len,0,(struct sockaddr *)&sin4,sizeof(sin4)); + return 0; + case ANODE_NETWORK_ADDRESS_IPV6: + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons((uint16_t)to_endpoint->port); + Anode_memcpy(sin6.sin6_addr.s6_addr,to_endpoint->address.bits,16); + sendto(fd,data,data_len,0,(struct sockaddr *)&sin6,sizeof(sin6)); + return 0; + default: + if (THIS->base) + return THIS->base->datagram_send(THIS->base,sock,data,data_len,to_endpoint); + else return ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + } +} + +static AnodeSocket *AnodeSystemTransport_stream_connect(AnodeTransport *transport, + const AnodeNetworkEndpoint *to_endpoint, + int *error_code) +{ + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + struct AnodeSystemTransport_AnodeSocket *sock; + unsigned int entry_idx; + int fd; + + switch(to_endpoint->address.type) { + case ANODE_NETWORK_ADDRESS_IPV4: + Anode_zero(&sin4,sizeof(struct sockaddr_in)); + sin4.sin_family = AF_INET; + sin4.sin_port = htons(to_endpoint->port); + sin4.sin_addr.s_addr = *((uint32_t *)to_endpoint->address.bits); + + fd = socket(AF_INET,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + if (connect(fd,(struct sockaddr *)&sin4,sizeof(sin4))) { + if (errno != EINPROGRESS) { + *error_code = ANODE_ERR_CONNECT_FAILED; + AnodeSystemTransport__close_socket(fd); + return (AnodeSocket *)0; + } + } + break; + case ANODE_NETWORK_ADDRESS_IPV6: + Anode_zero(&sin6,sizeof(struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(to_endpoint->port); + Anode_memcpy(sin6.sin6_addr.s6_addr,to_endpoint->address.bits,16); + + fd = socket(AF_INET6,SOCK_STREAM,0); + if (fd < 0) { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + fcntl(fd,F_SETFL,O_NONBLOCK); + + if (connect(fd,(struct sockaddr *)&sin6,sizeof(sin6))) { + if (errno == EINPROGRESS) { + *error_code = ANODE_ERR_CONNECT_FAILED; + AnodeSystemTransport__close_socket(fd); + return (AnodeSocket *)0; + } + } + break; + default: + if (THIS->base) + return THIS->base->stream_connect(THIS->base,to_endpoint,error_code); + else { + *error_code = ANODE_ERR_ADDRESS_TYPE_NOT_SUPPORTED; + return (AnodeSocket *)0; + } + } + + entry_idx = AnodeSystemTransport__add_entry(THIS); + sock = &(THIS->sockets[entry_idx]); + + sock->base.type = ANODE_SOCKET_STREAM_CONNECTION; + sock->base.state = ANODE_SOCKET_CONNECTING; + Anode_memcpy(&sock->base.endpoint,to_endpoint,sizeof(AnodeNetworkEndpoint)); + sock->base.class_name = AnodeSystemTransport_CLASS; + sock->base.user_ptr[0] = NULL; + sock->base.user_ptr[1] = NULL; + sock->base.event_handler = NULL; + sock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = fd; + THIS->fds[entry_idx].events = POLLIN|POLLOUT; + THIS->fds[entry_idx].revents = 0; + + return (AnodeSocket *)sock; +} + +static void AnodeSystemTransport_stream_start_writing(AnodeTransport *transport, + AnodeSocket *sock) +{ + if ((sock->type == ANODE_SOCKET_STREAM_CONNECTION)&&(((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state == ANODE_SOCKET_OPEN)) { + if (sock->class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + FD_SET((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),&THIS->writefds); +#else + THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].events = (POLLIN|POLLOUT); +#endif + } else THIS->base->stream_start_writing(THIS->base,sock); + } +} + +static void AnodeSystemTransport_stream_stop_writing(AnodeTransport *transport, + AnodeSocket *sock) +{ + if ((sock->type == ANODE_SOCKET_STREAM_CONNECTION)&&(((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state == ANODE_SOCKET_OPEN)) { + if (sock->class_name == AnodeSystemTransport_CLASS) { +#ifdef ANODE_USE_SELECT + FD_CLR((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),&THIS->writefds); +#else + THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].events = POLLIN; +#endif + } else THIS->base->stream_stop_writing(THIS->base,sock); + } +} + +static int AnodeSystemTransport_stream_send(AnodeTransport *transport, + AnodeSocket *sock, + const void *data, + int data_len) +{ + int result; + + if (sock->type == ANODE_SOCKET_STREAM_CONNECTION) { + if (sock->class_name == AnodeSystemTransport_CLASS) { + if (((struct AnodeSystemTransport_AnodeSocket *)sock)->base.state != ANODE_SOCKET_OPEN) + return ANODE_ERR_CONNECTION_CLOSED; + +#ifdef ANODE_USE_SELECT + result = send((int)(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx]),data,data_len,0); +#else + result = send(THIS->fds[((struct AnodeSystemTransport_AnodeSocket *)sock)->entry_idx].fd,data,data_len,0); +#endif + + if (result >= 0) + return result; + else { + AnodeSystemTransport__do_close(THIS,(struct AnodeSystemTransport_AnodeSocket *)sock,ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); + return ANODE_ERR_CONNECTION_CLOSED; + } + } else return THIS->base->stream_send(THIS->base,sock,data,data_len); + } else return ANODE_ERR_INVALID_ARGUMENT; +} + +static void AnodeSystemTransport_close(AnodeTransport *transport, + AnodeSocket *sock) +{ + AnodeSystemTransport__do_close(THIS,(struct AnodeSystemTransport_AnodeSocket *)sock,0,1); +} + +static void AnodeSystemTransport__poll_do_read_datagram(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + char buf[16384]; + struct sockaddr_storage fromaddr; + AnodeNetworkEndpoint tmp_ep; + AnodeEvent evbuf; + socklen_t addrlen; + int n; + + addrlen = sizeof(struct sockaddr_storage); + n = recvfrom(fd,buf,sizeof(buf),0,(struct sockaddr *)&fromaddr,&addrlen); + if ((n >= 0)&&(AnodeSystemTransport__populate_network_endpoint(&fromaddr,&tmp_ep))) { + evbuf.type = ANODE_TRANSPORT_EVENT_DATAGRAM_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = &tmp_ep; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = n; + evbuf.data = buf; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } +} + +static void AnodeSystemTransport__poll_do_accept_incoming_connection(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + struct sockaddr_storage fromaddr; + AnodeNetworkEndpoint tmp_ep; + AnodeEvent evbuf; + struct AnodeSystemTransport_AnodeSocket *newsock; + socklen_t addrlen; + int n; + unsigned int entry_idx; + + addrlen = sizeof(struct sockaddr_storage); + n = accept(fd,(struct sockaddr *)&fromaddr,&addrlen); + if ((n >= 0)&&(AnodeSystemTransport__populate_network_endpoint(&fromaddr,&tmp_ep))) { + entry_idx = AnodeSystemTransport__add_entry(transport); + newsock = &(transport->sockets[entry_idx]); + + newsock->base.type = ANODE_SOCKET_STREAM_CONNECTION; + newsock->base.state = ANODE_SOCKET_OPEN; + Anode_memcpy(&newsock->base.endpoint,&tmp_ep,sizeof(AnodeNetworkEndpoint)); + newsock->base.class_name = AnodeSystemTransport_CLASS; + newsock->base.user_ptr[0] = NULL; + newsock->base.user_ptr[1] = NULL; + newsock->base.event_handler = NULL; + newsock->entry_idx = entry_idx; + + THIS->fds[entry_idx].fd = n; + THIS->fds[entry_idx].events = POLLIN; + THIS->fds[entry_idx].revents = 0; + + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_INCOMING_CONNECT; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)newsock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } +} + +static void AnodeSystemTransport__poll_do_read_stream(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + char buf[65536]; + AnodeEvent evbuf; + int n; + + n = recv(fd,buf,sizeof(buf),0); + if (n > 0) { + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = n; + evbuf.data = buf; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); + } else AnodeSystemTransport__do_close(transport,sock,ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); +} + +static void AnodeSystemTransport__poll_do_stream_available_for_write(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + AnodeEvent evbuf; + + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_DATA_RECEIVED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); +} + +static void AnodeSystemTransport__poll_do_outgoing_connect(struct AnodeSystemTransport *transport,int fd,struct AnodeSystemTransport_AnodeSocket *sock) +{ + AnodeEvent evbuf; + int err_code; + socklen_t optlen; + + optlen = sizeof(err_code); + if (getsockopt(fd,SOL_SOCKET,SO_ERROR,(void *)&err_code,&optlen)) { + /* Error getting result, so we assume a failure */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = ANODE_ERR_CONNECT_FAILED; + evbuf.data_length = 0; + evbuf.data = NULL; + + AnodeSystemTransport__do_close(transport,sock,0,0); + } else if (err_code) { + /* Error code is nonzero, so connect failed */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_FAILED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = ANODE_ERR_CONNECT_FAILED; + evbuf.data_length = 0; + evbuf.data = NULL; + + AnodeSystemTransport__do_close(transport,sock,0,0); + } else { + /* Connect succeeded */ + evbuf.type = ANODE_TRANSPORT_EVENT_STREAM_OUTGOING_CONNECT_ESTABLISHED; + evbuf.transport = (AnodeTransport *)transport; + evbuf.sock = (AnodeSocket *)sock; + evbuf.datagram_from = NULL; + evbuf.dns_name = NULL; + evbuf.dns_addresses = NULL; + evbuf.dns_address_count = 0; + evbuf.error_code = 0; + evbuf.data_length = 0; + evbuf.data = NULL; + } + + if (sock->base.event_handler) + sock->base.event_handler(&evbuf); + else if (transport->default_event_handler) + transport->default_event_handler(&evbuf); +} + +static int AnodeSystemTransport_poll(AnodeTransport *transport) +{ + int timeout = -1; + unsigned int fd_idx; + int event_count = 0; + int n; + + if (poll((struct pollfd *)THIS->fds,THIS->fd_count,timeout) > 0) { + for(fd_idx=0;fd_idx<THIS->fd_count;++fd_idx) { + if ((THIS->fds[fd_idx].revents & (POLLERR|POLLHUP|POLLNVAL))) { + if (THIS->sockets[fd_idx].base.type == ANODE_SOCKET_STREAM_CONNECTION) { + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__do_close(THIS,&THIS->sockets[fd_idx],ANODE_ERR_CONNECTION_CLOSED_BY_REMOTE,1); + ++event_count; + } + } else { + if ((THIS->fds[fd_idx].revents & POLLIN)) { + if (THIS->fds[fd_idx].fd == THIS->invoke_pipe[0]) { + n = read(THIS->invoke_pipe[0],&(((unsigned char *)(&(THIS->invoke_pipe_buf)))[THIS->invoke_pipe_buf_ptr]),sizeof(THIS->invoke_pipe_buf) - THIS->invoke_pipe_buf_ptr); + if (n > 0) { + THIS->invoke_pipe_buf_ptr += (unsigned int)n; + if (THIS->invoke_pipe_buf_ptr >= sizeof(THIS->invoke_pipe_buf)) { + THIS->invoke_pipe_buf_ptr -= sizeof(THIS->invoke_pipe_buf); + ((void (*)(void *))(THIS->invoke_pipe_buf[1]))(THIS->invoke_pipe_buf[0]); + } + } + } else { + switch(THIS->sockets[fd_idx].base.type) { + case ANODE_SOCKET_DATAGRAM: + AnodeSystemTransport__poll_do_read_datagram(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + case ANODE_SOCKET_STREAM_LISTEN: + AnodeSystemTransport__poll_do_accept_incoming_connection(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + case ANODE_SOCKET_STREAM_CONNECTION: + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__poll_do_read_stream(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + break; + } + ++event_count; + } + } + + if ((THIS->fds[fd_idx].revents & POLLOUT)) { + if (THIS->sockets[fd_idx].base.state == ANODE_SOCKET_CONNECTING) + AnodeSystemTransport__poll_do_outgoing_connect(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + else AnodeSystemTransport__poll_do_stream_available_for_write(THIS,THIS->fds[fd_idx].fd,&THIS->sockets[fd_idx]); + ++event_count; + } + } + } + } + + return event_count; +} + +static int AnodeSystemTransport_supports_address_type(const AnodeTransport *transport, + enum AnodeNetworkAddressType at) +{ + switch(at) { + case ANODE_NETWORK_ADDRESS_IPV4: + return 1; + case ANODE_NETWORK_ADDRESS_IPV6: + return 1; + default: + if (THIS->base) + return THIS->base->supports_address_type(THIS->base,at); + return 0; + } +} + +static AnodeTransport *AnodeSystemTransport_base_instance(const AnodeTransport *transport) +{ + return THIS->base; +} + +static const char *AnodeSystemTransport_class_name(AnodeTransport *transport) +{ + return AnodeSystemTransport_CLASS; +} + +static void AnodeSystemTransport_delete(AnodeTransport *transport) +{ + close(THIS->invoke_pipe[0]); + close(THIS->invoke_pipe[1]); + + AnodeMutex_destroy(&THIS->invoke_pipe_m); + + if (THIS->fds) free(THIS->fds); + if (THIS->sockets) free(THIS->sockets); + + if (THIS->base) THIS->base->delete(THIS->base); + + free(transport); +} + +/* ======================================================================== */ + +AnodeTransport *AnodeSystemTransport_new(AnodeTransport *base) +{ + struct AnodeSystemTransport *t; + unsigned int entry_idx; + + t = malloc(sizeof(struct AnodeSystemTransport)); + if (!t) return (AnodeTransport *)0; + Anode_zero(t,sizeof(struct AnodeSystemTransport)); + + t->interface.invoke = &AnodeSystemTransport_invoke; + t->interface.dns_resolve = &AnodeSystemTransport_dns_resolve; + t->interface.datagram_listen = &AnodeSystemTransport_datagram_listen; + t->interface.stream_listen = &AnodeSystemTransport_stream_listen; + t->interface.datagram_send = &AnodeSystemTransport_datagram_send; + t->interface.stream_connect = &AnodeSystemTransport_stream_connect; + t->interface.stream_start_writing = &AnodeSystemTransport_stream_start_writing; + t->interface.stream_stop_writing = &AnodeSystemTransport_stream_stop_writing; + t->interface.stream_send = &AnodeSystemTransport_stream_send; + t->interface.close = &AnodeSystemTransport_close; + t->interface.poll = &AnodeSystemTransport_poll; + t->interface.supports_address_type = &AnodeSystemTransport_supports_address_type; + t->interface.base_instance = &AnodeSystemTransport_base_instance; + t->interface.class_name = &AnodeSystemTransport_class_name; + t->interface.delete = &AnodeSystemTransport_delete; + + t->base = base; + + pipe(t->invoke_pipe); + fcntl(t->invoke_pipe[0],F_SETFL,O_NONBLOCK); + entry_idx = AnodeSystemTransport__add_entry(t); + t->fds[entry_idx].fd = t->invoke_pipe[0]; + t->fds[entry_idx].events = POLLIN; + t->fds[entry_idx].revents = 0; + AnodeMutex_init(&t->invoke_pipe_m); + + return (AnodeTransport *)t; +} diff --git a/attic/historic/anode/libanode/tests/Makefile b/attic/historic/anode/libanode/tests/Makefile new file mode 100644 index 00000000..a479092c --- /dev/null +++ b/attic/historic/anode/libanode/tests/Makefile @@ -0,0 +1,25 @@ +all: force clean anode-utils-test anode-zone-test aes-test ec-test + +aes-test: + gcc -Wall -O6 -ftree-vectorize -std=c99 -o aes-test aes-test.c ../aes_digest.c -lcrypto + +http_client-test: + gcc -O0 -g -std=c99 -o http_client-test http_client-test.c ../anode-utils.c ../misc.c ../http_client.c ../dictionary.c ../iptransport.c ../anode-transport.c -lcrypto + +anode-utils-test: + gcc -O0 -g -std=c99 -o anode-utils-test anode-utils-test.c ../anode-utils.c ../misc.c + +ec-test: + gcc -O0 -g -std=c99 -o ec-test ec-test.c ../impl/ec.c ../impl/misc.c -lcrypto + +anode-zone-test: + gcc -O0 -g -std=c99 -o anode-zone-test anode-zone-test.c ../anode-zone.c ../http_client.c ../dictionary.c ../misc.c ../anode-transport.c ../iptransport.c ../environment.c + +system_transport-test: + gcc -O0 -g -std=c99 -o system_transport-test system_transport-test.c ../system_transport.c ../network_address.c ../address.c ../aes_digest.c ../impl/misc.c ../impl/thread.c ../impl/dns_txt.c ../impl/aes.c -lresolv -lcrypto + +clean: force + rm -rf *.dSYM + rm -f http_client-test anode-utils-test anode-zone-test ec-test aes-test system_transport-test + +force: ; diff --git a/attic/historic/anode/libanode/tests/aes-test.c b/attic/historic/anode/libanode/tests/aes-test.c new file mode 100644 index 00000000..bca63b89 --- /dev/null +++ b/attic/historic/anode/libanode/tests/aes-test.c @@ -0,0 +1,191 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <time.h> +#include <sys/time.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "../impl/aes.h" +#include "../anode.h" + +static const unsigned char AES_TEST_KEY[32] = { + 0x08,0x09,0x0A,0x0B,0x0D,0x0E,0x0F,0x10,0x12,0x13,0x14,0x15,0x17,0x18,0x19,0x1A, + 0x1C,0x1D,0x1E,0x1F,0x21,0x22,0x23,0x24,0x26,0x27,0x28,0x29,0x2B,0x2C,0x2D,0x2E +}; +static const unsigned char AES_TEST_IN[16] = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F,0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 +}; +static const unsigned char AES_TEST_OUT[16] = { + 0x08,0x0e,0x95,0x17,0xeb,0x16,0x77,0x71,0x9a,0xcf,0x72,0x80,0x86,0x04,0x0a,0xe3 +}; + +static const unsigned char CMAC_TEST_KEY[32] = { + 0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81, + 0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4 +}; + +static const unsigned char CMAC_TEST1_OUT[16] = { + 0x02,0x89,0x62,0xf6,0x1b,0x7b,0xf8,0x9e,0xfc,0x6b,0x55,0x1f,0x46,0x67,0xd9,0x83 +}; + +static const unsigned char CMAC_TEST2_IN[16] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a +}; +static const unsigned char CMAC_TEST2_OUT[16] = { + 0x28,0xa7,0x02,0x3f,0x45,0x2e,0x8f,0x82,0xbd,0x4b,0xf2,0x8d,0x8c,0x37,0xc3,0x5c +}; + +static const unsigned char CMAC_TEST3_IN[40] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11 +}; +static const unsigned char CMAC_TEST3_OUT[16] = { + 0xaa,0xf3,0xd8,0xf1,0xde,0x56,0x40,0xc2,0x32,0xf5,0xb1,0x69,0xb9,0xc9,0x11,0xe6 +}; + +static const unsigned char CMAC_TEST4_IN[64] = { + 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, + 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, + 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef, + 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10 +}; +static const unsigned char CMAC_TEST4_OUT[16] = { + 0xe1,0x99,0x21,0x90,0x54,0x9f,0x6e,0xd5,0x69,0x6a,0x2c,0x05,0x6c,0x31,0x54,0x10 +}; + +static void test_cmac(const AnodeAesExpandedKey *expkey,const unsigned char *in,unsigned int inlen,const unsigned char *expected) +{ + unsigned int i; + unsigned char out[16]; + + printf("Testing CMAC with %u byte input:\n",inlen); + printf(" IN: "); + for(i=0;i<inlen;++i) + printf("%.2x",(int)in[i]); + printf("\n"); + printf(" EXP: "); + for(i=0;i<16;++i) + printf("%.2x",(int)expected[i]); + printf("\n"); + Anode_cmac_aes256(expkey,in,inlen,out); + printf(" OUT: "); + for(i=0;i<16;++i) + printf("%.2x",(int)out[i]); + printf("\n"); + if (memcmp(expected,out,16)) { + printf("FAILED!\n"); + exit(1); + } else printf("Passed.\n"); +} + +static void test_cfb(const AnodeAesExpandedKey *expkey,const unsigned char *in,unsigned int inlen,unsigned char *iv,const unsigned char *expected) +{ + unsigned char tmp[131072]; + unsigned char tmp2[131072]; + unsigned char tmpiv[16]; + + printf("Testing AES-256 CFB mode with %u bytes: ",inlen); + fflush(stdout); + + memcpy(tmpiv,iv,16); + Anode_aes256_cfb_encrypt(expkey,in,tmp,tmpiv,inlen); + if (!memcmp(tmp,expected,inlen)) { + printf("FAILED (didn't encrypt)!\n"); + exit(1); + } + memcpy(tmpiv,iv,16); + Anode_aes256_cfb_decrypt(expkey,tmp,tmp2,tmpiv,inlen); + if (memcmp(tmp2,expected,inlen)) { + printf("FAILED (didn't encrypt)!\n"); + exit(1); + } else printf("Passed.\n"); +} + +static const char *AES_DIGEST_TEST_1 = "test"; +static const char *AES_DIGEST_TEST_2 = "supercalifragilisticexpealidocious"; +static const char *AES_DIGEST_TEST_3 = "12345678"; +static const char *AES_DIGEST_TEST_4 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + +int main(int argc,char **argv) +{ + AnodeAesExpandedKey expkey; + unsigned int i; + unsigned char aestestbuf[16]; + unsigned char cfbin[131072]; + unsigned char iv[16]; + + printf("Testing AES-256:"); + Anode_aes256_expand_key(AES_TEST_KEY,&expkey); + printf(" IN: "); + for(i=0;i<16;++i) + printf("%.2x",(int)AES_TEST_IN[i]); + printf("\n"); + printf(" EXP: "); + for(i=0;i<16;++i) + printf("%.2x",(int)AES_TEST_OUT[i]); + printf("\n"); + Anode_aes256_encrypt(&expkey,AES_TEST_IN,aestestbuf); + printf(" OUT: "); + for(i=0;i<16;++i) + printf("%.2x",(int)aestestbuf[i]); + printf("\n"); + if (memcmp(AES_TEST_OUT,aestestbuf,16)) { + printf("FAILED!\n"); + return 1; + } else printf("Passed.\n"); + printf("\n"); + + Anode_aes256_expand_key(CMAC_TEST_KEY,&expkey); + test_cmac(&expkey,(unsigned char *)0,0,CMAC_TEST1_OUT); + test_cmac(&expkey,CMAC_TEST2_IN,16,CMAC_TEST2_OUT); + test_cmac(&expkey,CMAC_TEST3_IN,40,CMAC_TEST3_OUT); + test_cmac(&expkey,CMAC_TEST4_IN,64,CMAC_TEST4_OUT); + printf("\n"); + + for(i=0;i<131072;++i) + cfbin[i] = (unsigned char)(i & 0xff); + for(i=0;i<16;++i) + iv[i] = (unsigned char)(i & 0xff); + for(i=12345;i<131072;i+=7777) + test_cfb(&expkey,cfbin,i,iv,cfbin); + + printf("\nTesting AES-DIGEST...\n"); + printf("0 bytes: "); + Anode_aes_digest(cfbin,0,iv); + for(i=0;i<16;++i) printf("%.2x",(unsigned int)iv[i]); + printf("\n"); + printf("%d bytes: ",(int)strlen(AES_DIGEST_TEST_1)); + Anode_aes_digest(AES_DIGEST_TEST_1,strlen(AES_DIGEST_TEST_1),iv); + for(i=0;i<16;++i) printf("%.2x",(unsigned int)iv[i]); + printf("\n"); + printf("%d bytes: ",(int)strlen(AES_DIGEST_TEST_2)); + Anode_aes_digest(AES_DIGEST_TEST_2,strlen(AES_DIGEST_TEST_2),iv); + for(i=0;i<16;++i) printf("%.2x",(unsigned int)iv[i]); + printf("\n"); + printf("%d bytes: ",(int)strlen(AES_DIGEST_TEST_3)); + Anode_aes_digest(AES_DIGEST_TEST_3,strlen(AES_DIGEST_TEST_3),iv); + for(i=0;i<16;++i) printf("%.2x",(unsigned int)iv[i]); + printf("\n"); + printf("%d bytes: ",(int)strlen(AES_DIGEST_TEST_4)); + Anode_aes_digest(AES_DIGEST_TEST_4,strlen(AES_DIGEST_TEST_4),iv); + for(i=0;i<16;++i) printf("%.2x",(unsigned int)iv[i]); + printf("\n"); + + return 0; +} + diff --git a/attic/historic/anode/libanode/tests/anode-secure_random-test.c b/attic/historic/anode/libanode/tests/anode-secure_random-test.c new file mode 100644 index 00000000..a6983653 --- /dev/null +++ b/attic/historic/anode/libanode/tests/anode-secure_random-test.c @@ -0,0 +1,38 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include "../anode.h" +#include "../misc.h" + +int main(int argc,char **argv) +{ + unsigned char test[10005]; + unsigned int i; + AnodeSecureRandom srng; + + AnodeSecureRandom_init(&srng); + + AnodeSecureRandom_gen_bytes(&srng,test,sizeof(test)); + + for(i=0;i<sizeof(test);++i) { + printf("%.2x",(unsigned int)test[i]); + if ((i % 20) == 19) + printf("\n"); + } + printf("\n"); +} diff --git a/attic/historic/anode/libanode/tests/anode-utils-test.c b/attic/historic/anode/libanode/tests/anode-utils-test.c new file mode 100644 index 00000000..85bfe324 --- /dev/null +++ b/attic/historic/anode/libanode/tests/anode-utils-test.c @@ -0,0 +1,75 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include "../anode.h" +#include "../misc.h" + +static const char *testuris[22] = { + "http://www.test.com", + "http://www.test.com/", + "http://www.test.com/path/to/something", + "http://user@www.test.com", + "http://user@www.test.com/path/to/something", + "http://user:password@www.test.com/path/to/something", + "http://www.test.com/path/to/something?query=foo&bar=baz", + "http://www.test.com/path/to/something#fragment", + "http://www.test.com/path/to/something?query=foo&bar=baz#fragment", + "http://user:password@www.test.com/path/to/something#fragment", + "http://user:password@www.test.com/path/to/something?query=foo&bar=baz#fragment", + "http://@www.test.com/", + "http://:@www.test.com/", + "http://www.test.com:8080/path/to/something", + "http://user:password@www.test.com:8080/path/to/something?query=foo#fragment", + "http://", + "http://www.test.com/path/to/something?#", + "http://www.test.com/path/to/something?#fragment", + "http:", + "http", + "mailto:this_is_a_urn@somedomain.com", + "" +}; + +int main(int argc,char **argv) +{ + int i,r; + char reconstbuf[2048]; + char *reconst; + AnodeURI uri; + + for(i=0;i<22;++i) { + printf("\"%s\":\n",testuris[i]); + r = AnodeURI_parse(&uri,testuris[i]); + if (r) { + printf(" error: %d\n",r); + } else { + printf(" scheme: %s\n",uri.scheme); + printf(" username: %s\n",uri.username); + printf(" password: %s\n",uri.password); + printf(" host: %s\n",uri.host); + printf(" port: %d\n",uri.port); + printf(" path: %s\n",uri.path); + printf(" query: %s\n",uri.query); + printf(" fragment: %s\n",uri.fragment); + } + reconst = AnodeURI_to_string(&uri,reconstbuf,sizeof(reconstbuf)); + printf("Reconstituted URI: %s\n",reconst ? reconst : "(null)"); + printf("\n"); + } + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/anode-zone-test.c b/attic/historic/anode/libanode/tests/anode-zone-test.c new file mode 100644 index 00000000..08396716 --- /dev/null +++ b/attic/historic/anode/libanode/tests/anode-zone-test.c @@ -0,0 +1,47 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "../anode.h" +#include "../dictionary.h" + +static int got_it = 0; + +static void zone_lookup_handler(void *ptr,long zone_id,AnodeZone *zone) +{ + if (zone) + printf("got %.8lx: %d entries\n",(unsigned long)zone_id & 0xffffffff,((struct AnodeDictionary *)zone)->size); + else printf("failed.\n"); + got_it = 1; +} + +int main(int argc,char **argv) +{ + AnodeTransportEngine transport; + + Anode_init_ip_transport_engine(&transport); + + AnodeZone_lookup(&transport,0,0,&zone_lookup_handler); + + while (!got_it) + transport.poll(&transport); + + transport.destroy(&transport); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/dictionary-test.c b/attic/historic/anode/libanode/tests/dictionary-test.c new file mode 100644 index 00000000..12a5fb2f --- /dev/null +++ b/attic/historic/anode/libanode/tests/dictionary-test.c @@ -0,0 +1,149 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include "../dictionary.h" + +static const char *HASH_TESTS[16] = { + "test", + "testt", + "", + "foo", + "fooo", + "1", + "2", + "3", + "4", + "11", + "22", + "33", + "44", + "adklfjklejrer", + "erngnetbekjrq", + "erklerqqqqre" +}; + +int diterate(void *arg,const char *key,const char *value) +{ + printf(" %s: %s\n",key ? key : "(null)",value ? value : "(null)"); + return 1; +} + +int main(int argc,char **argv) +{ + char tmp[1024]; + char fuzzparam1[16],fuzzparam2[16],fuzzparam3[16]; + struct AnodeDictionary d; + unsigned int i,j,k,cs; + + srandom(time(0)); + + printf("Trying out hash function a little...\n"); + for(i=0;i<16;++i) + printf(" %s: %u\n",HASH_TESTS[i],(unsigned int)AnodeDictionary__get_bucket(HASH_TESTS[i])); + + for(cs=0;cs<2;++cs) { + printf("\nTesting with case sensitivity = %d\n",cs); + AnodeDictionary_init(&d,cs); + + printf("\nTesting dictionary by adding and retrieving some keys...\n"); + AnodeDictionary_put(&d,"test1","This is the first test"); + AnodeDictionary_put(&d,"test2","This is the second test"); + AnodeDictionary_put(&d,"test3","This is the third test (lower case)"); + AnodeDictionary_put(&d,"TEST3","This is the third test (UPPER CASE)"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + if (d.size != (cs ? 4 : 3)) { + printf("Failed (size).\n"); + return 1; + } + + AnodeDictionary_clear(&d); + if (d.size||(AnodeDictionary_get(&d,"test1"))) { + printf("Failed (clear).\n"); + return 1; + } + + printf("\nTesting read, trial 1: simple key=value with unterminated line\n"); + strcpy(tmp,"foo=bar\nbar=baz\ntest1=Happy happy joyjoy!\ntest2=foobarbaz\nlinewithnocr=thisworked"); + AnodeDictionary_read(&d,tmp,"\r\n","=","",'\\',0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 2: key=value with escape chars, escaped CRs\n"); + strcpy(tmp,"foo=bar\r\nbar==baz\nte\\=st1=\\=Happy happy joyjoy!\ntest2=foobarbaz\\\nfoobarbaz on next line\r\n"); + AnodeDictionary_read(&d,tmp,"\r\n","=","",'\\',0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 3: HTTP header-like dictionary\n"); + strcpy(tmp,"Host: some.host.net\r\nX-Some-Header: foo bar\r\nX-Some-Other-Header: y0y0y0y0y0\r\n"); + AnodeDictionary_read(&d,tmp,"\r\n",": ","",0,0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nTesting read, trial 4: single line key/value\n"); + strcpy(tmp,"Header: one line only"); + AnodeDictionary_read(&d,tmp,"\r\n",": ","",0,0,0); + printf("Results:\n"); + AnodeDictionary_iterate(&d,(void *)0,&diterate); + AnodeDictionary_clear(&d); + + printf("\nFuzzing dictionary reader...\n"); fflush(stdout); + for(i=0;i<200000;++i) { + j = random() % (sizeof(tmp) - 1); + for(k=0;k<j;++k) { + tmp[k] = (char)((unsigned int)random() >> 3); + if (!tmp[k]) tmp[k] = 1; + } + tmp[j] = (char)0; + + j = random() % (sizeof(fuzzparam1) - 1); + for(k=0;k<j;++k) { + fuzzparam1[k] = (char)((unsigned int)random() >> 3); + if (!fuzzparam1[k]) fuzzparam1[k] = 1; + } + fuzzparam1[j] = (char)0; + + j = random() % (sizeof(fuzzparam2) - 1); + for(k=0;k<j;++k) { + fuzzparam1[k] = (char)((unsigned int)random() >> 3); + if (!fuzzparam2[k]) fuzzparam2[k] = 1; + } + fuzzparam2[j] = (char)0; + + j = random() % (sizeof(fuzzparam3) - 1); + for(k=0;k<j;++k) { + fuzzparam3[k] = (char)((unsigned int)random() >> 3); + if (!fuzzparam3[k]) fuzzparam3[k] = 1; + } + fuzzparam3[j] = (char)0; + + AnodeDictionary_read(&d,tmp,fuzzparam1,fuzzparam2,fuzzparam3,random() & 3,random() & 1,random() & 1); + AnodeDictionary_clear(&d); + } + + AnodeDictionary_destroy(&d); + } + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/ec-test.c b/attic/historic/anode/libanode/tests/ec-test.c new file mode 100644 index 00000000..49f04265 --- /dev/null +++ b/attic/historic/anode/libanode/tests/ec-test.c @@ -0,0 +1,97 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "../impl/ec.h" +#include "../impl/misc.h" + +#define TEST_KEY_LEN 128 +#define AnodeEC_key_to_hex(k,b,l) Anode_to_hex((k)->key,(k)->bytes,(b),l) + +int main(int argc,char **argv) +{ + struct AnodeECKeyPair pair1; + struct AnodeECKeyPair pair2; + struct AnodeECKeyPair pair3; + unsigned char key[TEST_KEY_LEN]; + char str[16384]; + + printf("Creating key pair #1...\n"); + if (!AnodeECKeyPair_generate(&pair1)) { + printf("Could not create key pair.\n"); + return 1; + } + AnodeEC_key_to_hex(&pair1.pub,str,sizeof(str)); + printf("Public: %s\n",str); + AnodeEC_key_to_hex(&pair1.priv,str,sizeof(str)); + printf("Private: %s\n\n",str); + + printf("Creating key pair #2...\n"); + if (!AnodeECKeyPair_generate(&pair2)) { + printf("Could not create key pair.\n"); + return 1; + } + AnodeEC_key_to_hex(&pair2.pub,str,sizeof(str)); + printf("Public: %s\n",str); + AnodeEC_key_to_hex(&pair2.priv,str,sizeof(str)); + printf("Private: %s\n\n",str); + + printf("Key agreement between public #2 and private #1...\n"); + if (!AnodeECKeyPair_agree(&pair1,&pair2.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Key agreement between public #1 and private #2...\n"); + if (!AnodeECKeyPair_agree(&pair2,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Testing key pair init function (init #3 from #2's parts)...\n"); + if (!AnodeECKeyPair_init(&pair3,&(pair2.pub),&(pair2.priv))) { + printf("Init failed.\n"); + return 1; + } + + printf("Key agreement between public #1 and private #3...\n"); + if (!AnodeECKeyPair_agree(&pair3,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret: %s\n\n",str); + + printf("Key agreement between public #1 and private #1...\n"); + if (!AnodeECKeyPair_agree(&pair1,&pair1.pub,key,TEST_KEY_LEN)) { + printf("Agreement failed.\n"); + return 1; + } + Anode_to_hex(key,TEST_KEY_LEN,str,sizeof(str)); + printf("Agreed secret (should not match): %s\n\n",str); + + AnodeECKeyPair_destroy(&pair1); + AnodeECKeyPair_destroy(&pair2); + AnodeECKeyPair_destroy(&pair3); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/environment-test.c b/attic/historic/anode/libanode/tests/environment-test.c new file mode 100644 index 00000000..c481a129 --- /dev/null +++ b/attic/historic/anode/libanode/tests/environment-test.c @@ -0,0 +1,28 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include "../environment.h" + +int main(int argc,char **argv) +{ + const char *cache = Anode_get_cache(); + + printf("Cache folder: %s\n",cache ? cache : "(null)"); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/http_client-test.c b/attic/historic/anode/libanode/tests/http_client-test.c new file mode 100644 index 00000000..e1f93967 --- /dev/null +++ b/attic/historic/anode/libanode/tests/http_client-test.c @@ -0,0 +1,233 @@ +/* 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/>. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <openssl/sha.h> +#include "../anode.h" +#include "../misc.h" +#include "../http_client.h" +#include "../dictionary.h" + +struct TestCase +{ + int method; + AnodeURI uri; + const void *client_data; + unsigned int client_data_len; + const char *expected_sha1; + char actual_sha1[64]; + int got_it; + int keepalive; + struct TestCase *next; +}; + +#define NUM_TEST_CASES 7 +static struct TestCase test_cases[NUM_TEST_CASES]; + +static void init_test_cases(int keepalive) +{ + AnodeURI_parse(&(test_cases[0].uri),"http://zerotier.com/for_unit_tests/test1.txt"); + test_cases[0].method = ANODE_HTTP_GET; + test_cases[0].client_data_len = 0; + test_cases[0].expected_sha1 = "0828324174b10cc867b7255a84a8155cf89e1b8b"; + test_cases[0].actual_sha1[0] = (char)0; + test_cases[0].got_it = 0; + test_cases[0].keepalive = keepalive; + test_cases[0].next = &(test_cases[1]); + + AnodeURI_parse(&(test_cases[1].uri),"http://zerotier.com/for_unit_tests/test2.bin"); + test_cases[1].method = ANODE_HTTP_GET; + test_cases[1].client_data_len = 0; + test_cases[1].expected_sha1 = "6b67c635786ab52666211d02412c0d0f0372980d"; + test_cases[1].actual_sha1[0] = (char)0; + test_cases[1].got_it = 0; + test_cases[1].keepalive = keepalive; + test_cases[1].next = &(test_cases[2]); + + AnodeURI_parse(&(test_cases[2].uri),"http://zerotier.com/for_unit_tests/test3.bin"); + test_cases[2].method = ANODE_HTTP_GET; + test_cases[2].client_data_len = 0; + test_cases[2].expected_sha1 = "efa7722029fdbb6abd0e3ed32a0b44bfb982cff0"; + test_cases[2].actual_sha1[0] = (char)0; + test_cases[2].got_it = 0; + test_cases[2].keepalive = keepalive; + test_cases[2].next = &(test_cases[3]); + + AnodeURI_parse(&(test_cases[3].uri),"http://zerotier.com/for_unit_tests/test4.bin"); + test_cases[3].method = ANODE_HTTP_GET; + test_cases[3].client_data_len = 0; + test_cases[3].expected_sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + test_cases[3].actual_sha1[0] = (char)0; + test_cases[3].got_it = 0; + test_cases[3].keepalive = keepalive; + test_cases[3].next = &(test_cases[4]); + + AnodeURI_parse(&(test_cases[4].uri),"http://zerotier.com/for_unit_tests/echo.php?echo=foobar"); + test_cases[4].method = ANODE_HTTP_GET; + test_cases[4].client_data_len = 0; + test_cases[4].expected_sha1 = "8843d7f92416211de9ebb963ff4ce28125932878"; + test_cases[4].actual_sha1[0] = (char)0; + test_cases[4].got_it = 0; + test_cases[4].keepalive = keepalive; + test_cases[4].next = &(test_cases[5]); + + AnodeURI_parse(&(test_cases[5].uri),"http://zerotier.com/for_unit_tests/echo.php"); + test_cases[5].method = ANODE_HTTP_POST; + test_cases[5].client_data = "echo=foobar"; + test_cases[5].client_data_len = strlen((char *)test_cases[5].client_data); + test_cases[5].expected_sha1 = "8843d7f92416211de9ebb963ff4ce28125932878"; + test_cases[5].actual_sha1[0] = (char)0; + test_cases[5].got_it = 0; + test_cases[5].keepalive = keepalive; + test_cases[5].next = &(test_cases[6]); + + AnodeURI_parse(&(test_cases[6].uri),"http://zerotier.com/for_unit_tests/test3.bin"); + test_cases[6].method = ANODE_HTTP_HEAD; + test_cases[6].client_data_len = 0; + test_cases[6].expected_sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709"; + test_cases[6].actual_sha1[0] = (char)0; + test_cases[6].got_it = 0; + test_cases[6].keepalive = keepalive; + test_cases[6].next = 0; +} + +static int http_handler_dump_headers(void *arg,const char *key,const char *value) +{ + printf(" H %s: %s\n",key,value); + return 1; +} + +static void http_handler(struct AnodeHttpClient *client) +{ + const char *method = "???"; + char buf[1024]; + unsigned char sha[20]; + struct TestCase *test = (struct TestCase *)client->ptr[0]; + + switch(client->method) { + case ANODE_HTTP_GET: + method = "GET"; + break; + case ANODE_HTTP_HEAD: + method = "HEAD"; + break; + case ANODE_HTTP_POST: + method = "POST"; + break; + } + + if (client->response.code == 200) { + SHA1((unsigned char *)client->response.data,client->response.data_length,sha); + Anode_to_hex(sha,20,test->actual_sha1,sizeof(test->actual_sha1)); + printf("%s %s\n * SHA1: %s exp: %s\n",method,AnodeURI_to_string(&(test->uri),buf,sizeof(buf)),test->actual_sha1,test->expected_sha1); + if (strcmp(test->actual_sha1,test->expected_sha1)) + printf(" ! SHA1 MISMATCH!\n"); + AnodeDictionary_iterate(&(client->response.headers),0,&http_handler_dump_headers); + } else printf("%s %s: ERROR: %d\n",method,AnodeURI_to_string(&(test->uri),buf,sizeof(buf)),client->response.code); + + test->got_it = 1; + + if (!test->keepalive) + AnodeHttpClient_free(client); + else { + test = test->next; + if (test) { + memcpy((void *)&(client->uri),(const void *)&(test->uri),sizeof(AnodeURI)); + + client->data = test->client_data; + client->data_length = test->client_data_len; + client->ptr[0] = test; + client->keepalive = test->keepalive; + client->method = test->method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + } else { + AnodeHttpClient_free(client); + } + } +} + +int main(int argc,char **argv) +{ + struct AnodeHttpClient *client; + AnodeTransportEngine transport_engine; + int i; + + if (Anode_init_ip_transport_engine(&transport_engine)) { + printf("Failed (transport engine init)\n"); + return 1; + } + + printf("Testing without keepalive...\n\n"); + init_test_cases(0); + for(i=0;i<NUM_TEST_CASES;++i) { + client = AnodeHttpClient_new(&transport_engine); + + memcpy((void *)&(client->uri),(const void *)&(test_cases[i].uri),sizeof(AnodeURI)); + client->data = test_cases[i].client_data; + client->data_length = test_cases[i].client_data_len; + client->ptr[0] = &test_cases[i]; + client->keepalive = test_cases[i].keepalive; + client->method = test_cases[i].method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + } + + for(;;) { + for(i=0;i<NUM_TEST_CASES;++i) { + if (!test_cases[i].got_it) + break; + } + if (i == NUM_TEST_CASES) + break; + transport_engine.poll(&transport_engine); + } + printf("\n\n"); + + printf("Testing with keepalive...\n\n"); + init_test_cases(1); + + client = AnodeHttpClient_new(&transport_engine); + + i = 0; + memcpy((void *)&(client->uri),(const void *)&(test_cases[i].uri),sizeof(AnodeURI)); + client->data = test_cases[i].client_data; + client->data_length = test_cases[i].client_data_len; + client->ptr[0] = &test_cases[i]; + client->keepalive = test_cases[i].keepalive; + client->method = test_cases[i].method; + client->handler = &http_handler; + + AnodeHttpClient_send(client); + + for(;;) { + for(i=0;i<NUM_TEST_CASES;++i) { + if (!test_cases[i].got_it) + break; + } + if (i == NUM_TEST_CASES) + break; + transport_engine.poll(&transport_engine); + } + + transport_engine.destroy(&transport_engine); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/misc-test.c b/attic/historic/anode/libanode/tests/misc-test.c new file mode 100644 index 00000000..e5b9085f --- /dev/null +++ b/attic/historic/anode/libanode/tests/misc-test.c @@ -0,0 +1,137 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include "../misc.h" + +int main(int argc,char **argv) +{ + const char *base32TestStr = "asdf"; + char *fields[16]; + char buf[1024]; + char buf2[1024]; + char buf3[4096]; + unsigned int i; + unsigned long tmpl,tmpl2; + unsigned long long tmp64; + + srand(time(0)); + + Anode_base32_5_to_8((const unsigned char *)base32TestStr,buf); + printf("Base32 from test string: %s\n",buf); + Anode_base32_8_to_5("MFZWIZQA",(unsigned char *)buf2); + printf("Test string from Base32 (upper case): %s\n",buf2); + Anode_base32_8_to_5("mfzwizqa",(unsigned char *)buf2); + printf("Test string from Base32 (lower case): %s\n",buf2); + printf("Testing variable length encoding/decoded with pad5 functions...\n"); + for(i=0;i<1024;++i) { + tmpl = rand() % (sizeof(buf) - 8); + if (!tmpl) + tmpl = 1; + for(tmpl2=0;tmpl2<tmpl;++tmpl2) + buf[tmpl2] = (buf2[tmpl2] = (char)(rand() >> 3)); + if (!Anode_base32_encode_pad5(buf2,tmpl,buf3,sizeof(buf3))) { + printf("Failed (encode failed).\n"); + return 1; + } + memset(buf2,0,sizeof(buf2)); + if (!Anode_base32_decode_pad5(buf3,buf2,sizeof(buf2))) { + printf("Failed (decode failed).\n"); + return 1; + } + if (memcmp(buf,buf2,tmpl)) { + printf("Failed (compare failed).\n"); + return 1; + } + } + + printf("Anode_htonll(0x0102030405060708) == 0x%.16llx\n",tmp64 = Anode_htonll(0x0102030405060708ULL)); + printf("Anode_ntohll(0x%.16llx) == 0x%.16llx\n",tmp64,Anode_ntohll(tmp64)); + if (Anode_ntohll(tmp64) != 0x0102030405060708ULL) { + printf("Failed.\n"); + return 1; + } + + strcpy(buf,"foo bar baz"); + Anode_trim(buf); + printf("Testing string trim: 'foo bar baz' -> '%s'\n",buf); + strcpy(buf,"foo bar baz "); + Anode_trim(buf); + printf("Testing string trim: 'foo bar baz ' -> '%s'\n",buf); + strcpy(buf," foo bar baz"); + Anode_trim(buf); + printf("Testing string trim: ' foo bar baz' -> '%s'\n",buf); + strcpy(buf," foo bar baz "); + Anode_trim(buf); + printf("Testing string trim: ' foo bar baz ' -> '%s'\n",buf); + strcpy(buf,""); + Anode_trim(buf); + printf("Testing string trim: '' -> '%s'\n",buf); + strcpy(buf," "); + Anode_trim(buf); + printf("Testing string trim: ' ' -> '%s'\n",buf); + + printf("Testing string split.\n"); + strcpy(buf,"66.246.138.121,5323,0"); + i = Anode_split(buf,';',fields,16); + if (i != 1) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s\n",fields[0]); + strcpy(buf,"a;b;c"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,";;"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,"a;b;"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,"a;;c"); + i = Anode_split(buf,';',fields,16); + if (i != 3) { + printf("Failed.\n"); + return 1; + } else printf("Fields: %s %s %s\n",fields[0],fields[1],fields[2]); + strcpy(buf,";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"); + i = Anode_split(buf,';',fields,16); + if (i != 16) { + printf("Failed.\n"); + return 1; + } + strcpy(buf,""); + i = Anode_split(buf,';',fields,16); + if (i != 0) { + printf("Failed.\n"); + return 1; + } + printf("Passed.\n"); + + return 0; +} diff --git a/attic/historic/anode/libanode/tests/system_transport-test.c b/attic/historic/anode/libanode/tests/system_transport-test.c new file mode 100644 index 00000000..bda575ed --- /dev/null +++ b/attic/historic/anode/libanode/tests/system_transport-test.c @@ -0,0 +1,70 @@ +/* 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/>. */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/socket.h> +#include "../anode.h" +#include "../impl/thread.h" + +static int do_client() +{ + AnodeTransport *st; + AnodeSocket *udp_sock; + int run = 1; + + st = AnodeSystemTransport_new(NULL); + if (!st) { + printf("FAILED: unable to construct AnodeSystemTransport.\n"); + return -1; + } + printf("Created AnodeSystemTransport.\n"); + + while (run) + st->poll(st); +} + +static int do_server() +{ + AnodeTransport *st; + AnodeSocket *udp_sock; + AnodeSocket *tcp_sock; + int run = 1; + + st = AnodeSystemTransport_new(NULL); + if (!st) { + printf("FAILED: unable to construct AnodeSystemTransport.\n"); + return -1; + } + printf("Created AnodeSystemTransport.\n"); + + while (run) + st->poll(st); +} + +int main(int argc,char **argv) +{ + if (argc == 2) { + if (!strcmp(argv[1],"client")) + return do_client(); + else if (!strcmp(argv[1],"server")) + return do_server(); + } + + printf("Usage: system_transport-test <client / server>\n"); + return -1; +} diff --git a/attic/historic/anode/libanode/uri.c b/attic/historic/anode/libanode/uri.c new file mode 100644 index 00000000..ca644b6a --- /dev/null +++ b/attic/historic/anode/libanode/uri.c @@ -0,0 +1,185 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include "impl/misc.h" +#include "anode.h" + +int AnodeURI_parse(AnodeURI *parsed_uri,const char *uri_string) +{ + char buf[sizeof(AnodeURI)]; + unsigned long ptr = 0; + char c; + char *p1,*p2; + + Anode_zero((void *)parsed_uri,sizeof(AnodeURI)); + + /* Get the scheme */ + for(;;) { + c = *(uri_string++); + if (!c) { + parsed_uri->scheme[ptr] = (char)0; + return ANODE_ERR_INVALID_URI; + } else if (c == ':') { + parsed_uri->scheme[ptr] = (char)0; + break; + } else { + parsed_uri->scheme[ptr++] = c; + if (ptr == sizeof(parsed_uri->scheme)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + } + + if (*uri_string == '/') { + /* If it starts with /, it's a URL */ + + /* Skip double slash */ + if (!(*(++uri_string))) + return 0; /* Scheme with no path */ + if (*uri_string == '/') { + if (!(*(++uri_string))) + return 0; /* Scheme with no path */ + } + + /* Get the host section and put it in buf[] */ + ptr = 0; + while ((*uri_string)&&(*uri_string != '/')) { + buf[ptr++] = *(uri_string++); + if (ptr == sizeof(buf)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + buf[ptr] = (char)0; + + /* Parse host section for host, username, password, and port */ + if (buf[0]) { + p1 = (char *)Anode_strchr(buf,'@'); + if (p1) { + *(p1++) = (char)0; + if (*p1) { + p2 = (char *)Anode_strchr(buf,':'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->password,p2,sizeof(parsed_uri->password)); + } + Anode_str_copy(parsed_uri->username,buf,sizeof(parsed_uri->username)); + } else return ANODE_ERR_INVALID_URI; + } else p1 = buf; + + p2 = (char *)Anode_strchr(p1,':'); + if (p2) { + *(p2++) = (char)0; + if (*p2) + parsed_uri->port = (int)strtoul(p2,(char **)0,10); + } + Anode_str_copy(parsed_uri->host,p1,sizeof(parsed_uri->host)); + } + + /* Get the path, query, and fragment section and put it in buf[] */ + ptr = 0; + while ((buf[ptr++] = *(uri_string++))) { + if (ptr == sizeof(buf)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + + /* Parse path section for path, query, and fragment */ + if (buf[0]) { + p1 = (char *)Anode_strchr(buf,'?'); + if (p1) { + *(p1++) = (char)0; + p2 = (char *)Anode_strchr(p1,'#'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment)); + } + Anode_str_copy(parsed_uri->query,p1,sizeof(parsed_uri->query)); + } else { + p2 = (char *)Anode_strchr(buf,'#'); + if (p2) { + *(p2++) = (char)0; + Anode_str_copy(parsed_uri->fragment,p2,sizeof(parsed_uri->fragment)); + } + } + Anode_str_copy(parsed_uri->path,buf,sizeof(parsed_uri->path)); + } + } else { + /* Otherwise, it's a URN and what remains is all path */ + ptr = 0; + while ((parsed_uri->path[ptr++] = *(uri_string++))) { + if (ptr == sizeof(parsed_uri->path)) + return ANODE_ERR_BUFFER_TOO_SMALL; + } + } + + return 0; +} + +char *AnodeURI_to_string(const AnodeURI *uri,char *buf,int len) +{ + int i = 0; + char portbuf[16]; + const char *p; + + p = uri->scheme; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + buf[i++] = ':'; if (i >= len) return (char *)0; + + if (uri->host[0]) { + buf[i++] = '/'; if (i >= len) return (char *)0; + buf[i++] = '/'; if (i >= len) return (char *)0; + + if (uri->username[0]) { + p = uri->username; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + if (uri->password[0]) { + buf[i++] = ':'; if (i >= len) return (char *)0; + p = uri->password; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + buf[i++] = '@'; if (i >= len) return (char *)0; + } + + p = uri->host; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + if ((uri->port > 0)&&(uri->port <= 0xffff)) { + buf[i++] = ':'; if (i >= len) return (char *)0; + snprintf(portbuf,sizeof(portbuf),"%d",uri->port); + p = portbuf; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + } + + p = uri->path; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + + if (uri->query[0]) { + buf[i++] = '?'; if (i >= len) return (char *)0; + p = uri->query; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + + if (uri->fragment[0]) { + buf[i++] = '#'; if (i >= len) return (char *)0; + p = uri->fragment; + while (*p) { buf[i++] = *(p++); if (i >= len) return (char *)0; } + } + + buf[i] = (char)0; + + return buf; +} diff --git a/attic/historic/anode/libanode/utils/anode-make-identity.c b/attic/historic/anode/libanode/utils/anode-make-identity.c new file mode 100644 index 00000000..99a3897a --- /dev/null +++ b/attic/historic/anode/libanode/utils/anode-make-identity.c @@ -0,0 +1,50 @@ +/* libanode: the Anode C reference implementation + * Copyright (C) 2009 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include "../anode.h" +#include "../impl/misc.h" +#include "../impl/types.h" + +int main(int argc,char **argv) +{ + char str[1024]; + AnodeZone zone; + AnodeIdentity identity; + + if (argc < 2) { + printf("Usage: anode-make-identity <32-bit zone ID hex>\n"); + return 0; + } + + *((uint32_t *)zone.bits) = htonl((uint32_t)strtoul(argv[1],(char **)0,16)); + + if (AnodeIdentity_generate(&identity,&zone,ANODE_ADDRESS_ANODE_256_40)) { + fprintf(stderr,"Error: identity key pair generation failed (check build settings).\n"); + return 1; + } + if (AnodeIdentity_to_string(&identity,str,sizeof(str)) <= 0) { + fprintf(stderr,"Error: internal error converting identity to string.\n"); + return -1; + } + + printf("%s\n",str); + + return 0; +} diff --git a/attic/historic/anode/libanode/zone.c b/attic/historic/anode/libanode/zone.c new file mode 100644 index 00000000..a6e397ae --- /dev/null +++ b/attic/historic/anode/libanode/zone.c @@ -0,0 +1,184 @@ +/* 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/>. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "impl/types.h" +#include "impl/misc.h" +#include "impl/dictionary.h" +#include "impl/environment.h" +#include "impl/http_client.h" +#include "anode.h" + +static const char *_MONTHS[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; +static const char *_DAYS_OF_WEEK[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" }; +static inline unsigned long get_file_time_for_http(const char *path,char *buf,unsigned int len) +{ + struct stat st; + struct tm *gmt; + + if (!stat(path,(struct stat *)&st)) { + gmt = gmtime(&st.st_mtime); + if (gmt) { + snprintf(buf,len,"%s, %d %s %d %d:%d:%d GMT", + _DAYS_OF_WEEK[gmt->tm_wday], + gmt->tm_mday, + _MONTHS[gmt->tm_mon], + (1900 + gmt->tm_year), + gmt->tm_hour, + gmt->tm_min, + gmt->tm_sec); + buf[len - 1] = (char)0; + return (unsigned long)st.st_size; + } + } + + return 0; +} + +struct AnodeZoneLookupJob +{ + char cached_zone_file[2048]; + struct AnodeDictionary *zone_dict; + AnodeZone zone; + void *ptr; + void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZoneFile *); + int had_cached_zone; +}; + +static void AnodeZone_lookup_http_handler(struct AnodeHttpClient *client) +{ + char *data_tmp; + struct AnodeZoneLookupJob *job = (struct AnodeZoneLookupJob *)client->ptr[0]; + FILE *zf; + + if ((client->response.code == 200)&&(client->response.data_length > 0)) { + zf = fopen(job->cached_zone_file,"w"); + if (zf) { + fwrite(client->response.data,1,client->response.data_length,zf); + fclose(zf); + } + + data_tmp = (char *)malloc(client->response.data_length + 1); + Anode_memcpy((void *)data_tmp,client->response.data,client->response.data_length); + data_tmp[client->response.data_length] = (char)0; + + AnodeDictionary_clear(job->zone_dict); + AnodeDictionary_read( + job->zone_dict, + data_tmp, + "\r\n", + "=", + ";", + '\\', + 1,1); + + free((void *)data_tmp); + + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); + } else if (job->had_cached_zone) + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)job->zone_dict); + else { + AnodeDictionary_destroy(job->zone_dict); + free((void *)job->zone_dict); + job->zone_lookup_handler(job->ptr,&job->zone,(AnodeZoneFile *)0); + } + + free((void *)job); + AnodeHttpClient_free(client); +} + +void AnodeZone_lookup( + AnodeTransportEngine *transport, + const AnodeZone *zone, + void *ptr, + void (*zone_lookup_handler)(void *,const AnodeZone *,AnodeZone *)) +{ + char cached_zones_folder[2048]; + char cached_zone_file[2048]; + char if_modified_since[256]; + unsigned long file_size; + struct AnodeZoneLookupJob *job; + struct AnodeHttpClient *client; + char *file_data; + FILE *zf; + + if (Anode_get_cache_sub("zones",cached_zones_folder,sizeof(cached_zones_folder))) { + snprintf(cached_zone_file,sizeof(cached_zone_file),"%s%c%.2x%.2x%.2x%.2x.z",cached_zones_folder,ANODE_PATH_SEPARATOR,(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); + cached_zone_file[sizeof(cached_zone_file)-1] = (char)0; + + job = (struct AnodeZoneLookupJob *)malloc(sizeof(struct AnodeZoneLookupJob)); + Anode_str_copy(job->cached_zone_file,cached_zone_file,sizeof(job->cached_zone_file)); + job->zone_dict = (struct AnodeDictionary *)malloc(sizeof(struct AnodeDictionary)); + AnodeDictionary_init(job->zone_dict,0); + job->zone.bits[0] = zone->bits[0]; + job->zone.bits[1] = zone->bits[1]; + job->zone.bits[2] = zone->bits[2]; + job->zone.bits[3] = zone->bits[3]; + job->ptr = ptr; + job->zone_lookup_handler = zone_lookup_handler; + job->had_cached_zone = 0; + + client = AnodeHttpClient_new(transport); + + Anode_str_copy(client->uri.scheme,"http",sizeof(client->uri.scheme)); + snprintf(client->uri.host,sizeof(client->uri.host),"a--%.2x%.2x%.2x%.2x.net",(unsigned int)zone->bits[0],(unsigned int)zone->bits[1],(unsigned int)zone->bits[2],(unsigned int)zone->bits[3]); + client->uri.host[sizeof(client->uri.host)-1] = (char)0; + Anode_str_copy(client->uri.path,"/z",sizeof(client->uri.path)); + + client->handler = &AnodeZone_lookup_http_handler; + client->ptr[0] = job; + + if ((file_size = get_file_time_for_http(cached_zone_file,if_modified_since,sizeof(if_modified_since)))) { + zf = fopen(cached_zone_file,"r"); + if (zf) { + AnodeDictionary_put(&client->headers,"If-Modified-Since",if_modified_since); + file_data = (char *)malloc(file_size + 1); + if (fread((void *)file_data,1,file_size,zf)) { + file_data[file_size] = (char)0; + AnodeDictionary_read( + job->zone_dict, + file_data, + "\r\n", + "=", + ";", + '\\', + 1,1); + job->had_cached_zone = 1; + } + free((void *)file_data); + fclose(zf); + } + } + + AnodeHttpClient_send(client); + } else zone_lookup_handler(ptr,zone,(AnodeZone *)0); +} + +const char *AnodeZoneFile_get(AnodeZoneFile *zone,const char *key) +{ + return AnodeDictionary_get((struct AnodeDictionary *)zone,key); +} + +void AnodeZoneFile_free(AnodeZoneFile *zone) +{ + AnodeDictionary_destroy((struct AnodeDictionary *)zone); + free((void *)zone); +} |