diff --git a/client/address.c b/client/address.c index 87ee056d..615bc954 100644 --- a/client/address.c +++ b/client/address.c @@ -1,69 +1,69 @@ -/* addresses, T13.692-T13.720 $DVS:time$ */ - -#include -#include -#include "address.h" - -static const uint8_t bits2mime[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static uint8_t mime2bits[256]; - -// intializes the address module -int xdag_address_init(void) -{ - int i; - - memset(mime2bits, 0xFF, 256); - - for (i = 0; i < 64; ++i) { - mime2bits[bits2mime[i]] = i; - } - - return 0; -} - -// converts address to hash -int xdag_address2hash(const char *address, xdag_hash_t hash) -{ - uint8_t *fld = (uint8_t*)hash; - int i, c, d, n; - - for (int e = n = i = 0; i < 32; ++i) { - do { - if (!(c = (uint8_t)*address++)) - return -1; - d = mime2bits[c]; - } while (d & 0xC0); - e <<= 6; - e |= d; - n += 6; - - if (n >= 8) { - n -= 8; - *fld++ = e >> n; - } - } - - for (i = 0; i < 8; ++i) { - *fld++ = 0; - } - - return 0; -} - -// converts hash to address -void xdag_hash2address(const xdag_hash_t hash, char *address) -{ - int c, d; - const uint8_t *fld = (const uint8_t*)hash; - - for (int i = c = d = 0; i < 32; ++i) { - if (d < 6) { - d += 8; - c <<= 8; - c |= *fld++; - } - d -= 6; - *address++ = bits2mime[c >> d & 0x3F]; - } - *address = 0; -} +/* addresses, T13.692-T13.720 $DVS:time$ */ + +#include +#include +#include "address.h" + +static const uint8_t bits2mime[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static uint8_t mime2bits[256]; + +// intializes the address module +int xdag_address_init(void) +{ + int i; + + memset(mime2bits, 0xFF, 256); + + for (i = 0; i < 64; ++i) { + mime2bits[bits2mime[i]] = i; + } + + return 0; +} + +// converts address to hash +int xdag_address2hash(const char *address, xdag_hash_t hash) +{ + uint8_t *fld = (uint8_t*)hash; + int i, c, d, n; + + for (int e = n = i = 0; i < 32; ++i) { + do { + if (!(c = (uint8_t)*address++)) + return -1; + d = mime2bits[c]; + } while (d & 0xC0); + e <<= 6; + e |= d; + n += 6; + + if (n >= 8) { + n -= 8; + *fld++ = e >> n; + } + } + + for (i = 0; i < 8; ++i) { + *fld++ = 0; + } + + return 0; +} + +// converts hash to address +void xdag_hash2address(const xdag_hash_t hash, char *address) +{ + int c, d; + const uint8_t *fld = (const uint8_t*)hash; + + for (int i = c = d = 0; i < 32; ++i) { + if (d < 6) { + d += 8; + c <<= 8; + c |= *fld++; + } + d -= 6; + *address++ = bits2mime[c >> d & 0x3F]; + } + *address = 0; +} diff --git a/client/address.h b/client/address.h index ebd94e84..efa0c48d 100644 --- a/client/address.h +++ b/client/address.h @@ -5,6 +5,10 @@ #include "hash.h" +#ifdef __cplusplus +extern "C" { +#endif + /* intializes the addresses module */ extern int xdag_address_init(void); @@ -13,5 +17,9 @@ extern int xdag_address2hash(const char *address, xdag_hash_t hash); /* converts hash to address */ extern void xdag_hash2address(const xdag_hash_t hash, char *address); + +#ifdef __cplusplus +}; +#endif #endif diff --git a/client/block.h b/client/block.h index 57a778f2..2c8caeda 100644 --- a/client/block.h +++ b/client/block.h @@ -1,127 +1,136 @@ -/* block processing, T13.654-T13.836 $DVS:time$ */ - -#ifndef XDAG_BLOCK_H -#define XDAG_BLOCK_H - -#include -#include -#include "hash.h" -#include "system.h" -#include "types.h" - -enum xdag_field_type { - XDAG_FIELD_NONCE, //0 - XDAG_FIELD_HEAD, //1 - XDAG_FIELD_IN, //2 - XDAG_FIELD_OUT, //3 - XDAG_FIELD_SIGN_IN, //4 - XDAG_FIELD_SIGN_OUT, //5 - XDAG_FIELD_PUBLIC_KEY_0, //6 - XDAG_FIELD_PUBLIC_KEY_1, //7 - XDAG_FIELD_HEAD_TEST //8 -}; - -enum xdag_message_type { - XDAG_MESSAGE_BLOCKS_REQUEST, - XDAG_MESSAGE_BLOCKS_REPLY, - XDAG_MESSAGE_SUMS_REQUEST, - XDAG_MESSAGE_SUMS_REPLY, - XDAG_MESSAGE_BLOCKEXT_REQUEST, - XDAG_MESSAGE_BLOCKEXT_REPLY, - XDAG_MESSAGE_BLOCK_REQUEST, -}; - -#define XDAG_BLOCK_FIELDS 16 - -struct xdag_field { - union { - struct { - union { - struct { - uint64_t transport_header; - uint64_t type; - xdag_time_t time; - }; - xdag_hashlow_t hash; - }; - union { - xdag_amount_t amount; - xdag_time_t end_time; - }; - }; - xdag_hash_t data; - }; -}; - -struct xdag_block { - struct xdag_field field[XDAG_BLOCK_FIELDS]; -}; - +/* block processing, T13.654-T13.836 $DVS:time$ */ + +#ifndef XDAG_BLOCK_H +#define XDAG_BLOCK_H + +#include +#include +#include "hash.h" +#include "system.h" +#include "types.h" + +enum xdag_field_type { + XDAG_FIELD_NONCE, //0 + XDAG_FIELD_HEAD, //1 + XDAG_FIELD_IN, //2 + XDAG_FIELD_OUT, //3 + XDAG_FIELD_SIGN_IN, //4 + XDAG_FIELD_SIGN_OUT, //5 + XDAG_FIELD_PUBLIC_KEY_0, //6 + XDAG_FIELD_PUBLIC_KEY_1, //7 + XDAG_FIELD_HEAD_TEST //8 +}; + +enum xdag_message_type { + XDAG_MESSAGE_BLOCKS_REQUEST, + XDAG_MESSAGE_BLOCKS_REPLY, + XDAG_MESSAGE_SUMS_REQUEST, + XDAG_MESSAGE_SUMS_REPLY, + XDAG_MESSAGE_BLOCKEXT_REQUEST, + XDAG_MESSAGE_BLOCKEXT_REPLY, + XDAG_MESSAGE_BLOCK_REQUEST, +}; + +#define XDAG_BLOCK_FIELDS 16 + +struct xdag_field { + union { + struct { + union { + struct { + uint64_t transport_header; + uint64_t type; + xdag_time_t time; + }; + xdag_hashlow_t hash; + }; + union { + xdag_amount_t amount; + xdag_time_t end_time; + }; + }; + xdag_hash_t data; + }; +}; + +struct xdag_block { + struct xdag_field field[XDAG_BLOCK_FIELDS]; +}; + #define xdag_type(b, n) ((b)->field[0].type >> ((n) << 2) & 0xf) +#ifdef __cplusplus +extern "C" { +#endif + // convert cheato to xdag extern long double amount2xdags(xdag_amount_t amount); // contert xdag to cheato extern xdag_amount_t xdags2amount(const char *str); -// start of regular block processing -extern int xdag_blocks_start(int is_pool, int mining_threads_count, int miner_address); - -// checks and adds block to the storage. Returns non-zero value in case of error. -extern int xdag_add_block(struct xdag_block *b); - -// returns our first block. If there is no blocks yet - the first block is created. -extern int xdag_get_our_block(xdag_hash_t hash); - -// calls callback for each own block -extern int xdag_traverse_our_blocks(void *data, - int (*callback)(void*, xdag_hash_t, xdag_amount_t, xdag_time_t, int)); - -// calls callback for each block -extern int xdag_traverse_all_blocks(void *data, int (*callback)(void *data, xdag_hash_t hash, - xdag_amount_t amount, xdag_time_t time)); - -// create and publish a block -extern int xdag_create_block(struct xdag_field *fields, int inputsCount, int outputsCount, xdag_amount_t fee, - xdag_time_t send_time, xdag_hash_t newBlockHashResult); - -// returns current balance for specified address or balance for all addresses if hash == 0 -extern xdag_amount_t xdag_get_balance(xdag_hash_t hash); - -// sets current balance for the specified address -extern int xdag_set_balance(xdag_hash_t hash, xdag_amount_t balance); - -// calculates current supply by specified count of main blocks -extern xdag_amount_t xdag_get_supply(uint64_t nmain); - -// returns position and time of block by hash -extern int64_t xdag_get_block_pos(const xdag_hash_t hash, xdag_time_t *time); - -// returns a number of the current period, period is 64 seconds -extern xdag_time_t xdag_main_time(void); - -// returns the number of the time period corresponding to the start of the network -extern xdag_time_t xdag_start_main_time(void); - -// returns a number of key by hash of block or -1 if block is not ours -extern int xdag_get_key(xdag_hash_t hash); - -// reinitialization of block processing -extern int xdag_blocks_reset(void); - -// prints detailed information about block -extern int xdag_print_block_info(xdag_hash_t hash, FILE *out); - -// prints list of N last main blocks -extern void xdag_list_main_blocks(int count, int print_only_addresses, FILE *out); - -// prints list of N last blocks mined by current pool -extern void xdag_list_mined_blocks(int count, int include_non_payed, FILE *out); - -// calculate difficulty from hash -xdag_diff_t xdag_hash_difficulty(xdag_hash_t hash); +// start of regular block processing +extern int xdag_blocks_start(int is_pool, int mining_threads_count, int miner_address); + +// checks and adds block to the storage. Returns non-zero value in case of error. +extern int xdag_add_block(struct xdag_block *b); + +// returns our first block. If there is no blocks yet - the first block is created. +extern int xdag_get_our_block(xdag_hash_t hash); + +// calls callback for each own block +extern int xdag_traverse_our_blocks(void *data, + int (*callback)(void*, xdag_hash_t, xdag_amount_t, xdag_time_t, int)); + +// calls callback for each block +extern int xdag_traverse_all_blocks(void *data, int (*callback)(void *data, xdag_hash_t hash, + xdag_amount_t amount, xdag_time_t time)); + +// create and publish a block +extern int xdag_create_block(struct xdag_field *fields, int inputsCount, int outputsCount, xdag_amount_t fee, + xdag_time_t send_time, xdag_hash_t newBlockHashResult); + +// returns current balance for specified address or balance for all addresses if hash == 0 +extern xdag_amount_t xdag_get_balance(xdag_hash_t hash); + +// sets current balance for the specified address +extern int xdag_set_balance(xdag_hash_t hash, xdag_amount_t balance); + +// calculates current supply by specified count of main blocks +extern xdag_amount_t xdag_get_supply(uint64_t nmain); + +// returns position and time of block by hash +extern int64_t xdag_get_block_pos(const xdag_hash_t hash, xdag_time_t *time); + +// returns a number of the current period, period is 64 seconds +extern xdag_time_t xdag_main_time(void); + +// returns the number of the time period corresponding to the start of the network +extern xdag_time_t xdag_start_main_time(void); + +// returns a number of key by hash of block or -1 if block is not ours +extern int xdag_get_key(xdag_hash_t hash); + +// reinitialization of block processing +extern int xdag_blocks_reset(void); + +// prints detailed information about block +extern int xdag_print_block_info(xdag_hash_t hash, FILE *out); + +// prints list of N last main blocks +extern void xdag_list_main_blocks(int count, int print_only_addresses, FILE *out); + +// prints list of N last blocks mined by current pool +extern void xdag_list_mined_blocks(int count, int include_non_payed, FILE *out); + +// calculate difficulty from hash +xdag_diff_t xdag_hash_difficulty(xdag_hash_t hash); // get all transactions of specified address, and return total number of transactions extern int xdag_get_transactions(xdag_hash_t hash, void *data, int (*callback)(void*, int, xdag_hash_t, xdag_amount_t, xdag_time_t)); + +#ifdef __cplusplus +}; +#endif + #endif diff --git a/client/crypt.c b/client/crypt.c index 27412116..88f36400 100644 --- a/client/crypt.c +++ b/client/crypt.c @@ -1,428 +1,428 @@ -/* cryptography (ECDSA), T13.654-T13.847 $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "crypt.h" -#include "transport.h" -#include "utils/log.h" -#include "system.h" - -#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 - -#include "../secp256k1/include/secp256k1.h" - -secp256k1_context *ctx_noopenssl; - -#endif - -static EC_GROUP *group; - -extern unsigned int xOPENSSL_ia32cap_P[4]; -extern int xOPENSSL_ia32_cpuid(unsigned int *); - -// initialization of the encryption system -int xdag_crypt_init(int withrandom) -{ - if(withrandom) { - uint64_t buf[64]; - xOPENSSL_ia32_cpuid(xOPENSSL_ia32cap_P); - xdag_generate_random_array(buf, sizeof(buf)); - xdag_debug("Seed : [%s]", xdag_log_array(buf, sizeof(buf))); - RAND_seed(buf, sizeof(buf)); - } - -#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 - ctx_noopenssl = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); -#endif - - group = EC_GROUP_new_by_curve_name(NID_secp256k1); - if(!group) return -1; - - return 0; -} - -/* creates a new pair of private and public keys - * the private key is saved to the 'privkey' array, the public key to the 'pubkey' array, - * the parity of the public key is saved to the variable 'pubkey_bit' - * returns a pointer to its internal representation - */ -void *xdag_create_key(xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit) -{ - uint8_t buf[sizeof(xdag_hash_t) + 1]; - EC_KEY *eckey = 0; - const BIGNUM *priv = 0; - const EC_POINT *pub = 0; - BN_CTX *ctx = 0; - int res = -1; - - if(!group) { - goto fail; - } - - eckey = EC_KEY_new(); - - if(!eckey) { - goto fail; - } - - if(!EC_KEY_set_group(eckey, group)) { - goto fail; - } - - if(!EC_KEY_generate_key(eckey)) { - goto fail; - } - - priv = EC_KEY_get0_private_key(eckey); - if(!priv) { - goto fail; - } - - if(BN_bn2bin(priv, (uint8_t*)privkey) != sizeof(xdag_hash_t)) { - goto fail; - } - - pub = EC_KEY_get0_public_key(eckey); - if(!pub) { - goto fail; - } - - ctx = BN_CTX_new(); - if(!ctx) { - goto fail; - } - - BN_CTX_start(ctx); - if(EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, buf, sizeof(xdag_hash_t) + 1, ctx) != sizeof(xdag_hash_t) + 1) { - goto fail; - } - - memcpy(pubkey, buf + 1, sizeof(xdag_hash_t)); - *pubkey_bit = *buf & 1; - res = 0; - -fail: - if(ctx) { - BN_CTX_free(ctx); - } - - if(res && eckey) { - EC_KEY_free(eckey); - } - - return res ? 0 : eckey; -} - -// returns the internal representation of the key and the public key by the known private key -void *xdag_private_to_key(const xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit) -{ - uint8_t buf[sizeof(xdag_hash_t) + 1]; - EC_KEY *eckey = 0; - BIGNUM *priv = 0; - EC_POINT *pub = 0; - BN_CTX *ctx = 0; - int res = -1; - - if(!group) { - goto fail; - } - - eckey = EC_KEY_new(); - if(!eckey) { - goto fail; - } - - if(!EC_KEY_set_group(eckey, group)) { - goto fail; - } - - priv = BN_new(); - if(!priv) { - goto fail; - } - - // BN_init(priv); - BN_bin2bn((uint8_t*)privkey, sizeof(xdag_hash_t), priv); - EC_KEY_set_private_key(eckey, priv); - - ctx = BN_CTX_new(); - if(!ctx) { - goto fail; - } - - BN_CTX_start(ctx); - - pub = EC_POINT_new(group); - if(!pub) { - goto fail; - } - - EC_POINT_mul(group, pub, priv, NULL, NULL, ctx); - EC_KEY_set_public_key(eckey, pub); - if(EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, buf, sizeof(xdag_hash_t) + 1, ctx) != sizeof(xdag_hash_t) + 1) { - goto fail; - } - - memcpy(pubkey, buf + 1, sizeof(xdag_hash_t)); - *pubkey_bit = *buf & 1; - res = 0; - -fail: - if(ctx) { - BN_CTX_free(ctx); - } - - if(priv) { - BN_free(priv); - } - - if(pub) { - EC_POINT_free(pub); - } - - if(res && eckey) { - EC_KEY_free(eckey); - } - - return res ? 0 : eckey; -} - -// Returns the internal representation of the key by the known public key -void *xdag_public_to_key(const xdag_hash_t pubkey, uint8_t pubkey_bit) -{ - EC_KEY *eckey = 0; - BIGNUM *pub = 0; - EC_POINT *p = 0; - BN_CTX *ctx = 0; - int res = -1; - - if(!group) { - goto fail; - } - - eckey = EC_KEY_new(); - if(!eckey) { - goto fail; - } - - if(!EC_KEY_set_group(eckey, group)) { - goto fail; - } - - pub = BN_new(); - if(!pub) { - goto fail; - } - - // BN_init(pub); - BN_bin2bn((uint8_t*)pubkey, sizeof(xdag_hash_t), pub); - p = EC_POINT_new(group); - if(!p) { - goto fail; - } - - ctx = BN_CTX_new(); - if(!ctx) { - goto fail; - } - - BN_CTX_start(ctx); - if(!EC_POINT_set_compressed_coordinates_GFp(group, p, pub, pubkey_bit, ctx)) { - goto fail; - } - - EC_KEY_set_public_key(eckey, p); - res = 0; - -fail: - if(ctx) { - BN_CTX_free(ctx); - } - - if(pub) { - BN_free(pub); - } - - if(p) { - EC_POINT_free(p); - } - - if(res && eckey) { - EC_KEY_free(eckey); - } - - return res ? 0 : eckey; -} - -// removes the internal key representation -void xdag_free_key(void *key) -{ - EC_KEY_free((EC_KEY*)key); -} - -// sign the hash and put the result in sign_r and sign_s -int xdag_sign(const void *key, const xdag_hash_t hash, xdag_hash_t sign_r, xdag_hash_t sign_s) -{ - uint8_t buf[72], *p; - unsigned sig_len, s; - - if(!ECDSA_sign(0, (const uint8_t*)hash, sizeof(xdag_hash_t), buf, &sig_len, (EC_KEY*)key)) { - return -1; - } - - p = buf + 3, s = *p++; - - if(s >= sizeof(xdag_hash_t)) { - memcpy(sign_r, p + s - sizeof(xdag_hash_t), sizeof(xdag_hash_t)); - } else { - memset(sign_r, 0, sizeof(xdag_hash_t)); - memcpy((uint8_t*)sign_r + sizeof(xdag_hash_t) - s, p, s); - } - - p += s + 1, s = *p++; - - if(s >= sizeof(xdag_hash_t)) { - memcpy(sign_s, p + s - sizeof(xdag_hash_t), sizeof(xdag_hash_t)); - } else { - memset(sign_s, 0, sizeof(xdag_hash_t)); - memcpy((uint8_t*)sign_s + sizeof(xdag_hash_t) - s, p, s); - } - - xdag_debug("Sign : hash=[%s] sign=[%s] r=[%s], s=[%s]", xdag_log_hash(hash), - xdag_log_array(buf, sig_len), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - - return 0; -} - -static uint8_t *add_number_to_sign(uint8_t *sign, const xdag_hash_t num) -{ - uint8_t *n = (uint8_t*)num; - int i, len, leadzero; - - for(i = 0; i < sizeof(xdag_hash_t) && !n[i]; ++i); - - leadzero = (i < sizeof(xdag_hash_t) && n[i] & 0x80); - len = (sizeof(xdag_hash_t) - i) + leadzero; - *sign++ = 0x02; - *sign++ = len; - - if(leadzero) { - *sign++ = 0; - } - - while(i < sizeof(xdag_hash_t)) { - *sign++ = n[i++]; - } - - return sign; -} - -// verify that the signature (sign_r, sign_s) corresponds to a hash 'hash', a version for its own key -// returns 0 on success -int xdag_verify_signature(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s) -{ - uint8_t buf[72], *ptr; - int res; - - ptr = add_number_to_sign(buf + 2, sign_r); - ptr = add_number_to_sign(ptr, sign_s); - buf[0] = 0x30; - buf[1] = ptr - buf - 2; - res = ECDSA_verify(0, (const uint8_t*)hash, sizeof(xdag_hash_t), buf, ptr - buf, (EC_KEY*)key); - - xdag_debug("Verify: res=%2d key=%lx hash=[%s] sign=[%s] r=[%s], s=[%s]", res, (long)key, xdag_log_hash(hash), - xdag_log_array(buf, ptr - buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - - return res != 1; -} - -#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 - -static uint8_t *add_number_to_sign_optimized_ec(uint8_t *sign, const xdag_hash_t num) -{ - uint8_t *n = (uint8_t*)num; - int i, len, leadzero; - - for(i = 0; i < sizeof(xdag_hash_t) && !n[i]; ++i); - - leadzero = (i < sizeof(xdag_hash_t) && n[i] & 0x80); - len = (sizeof(xdag_hash_t) - i) + leadzero; - *sign++ = 0x02; - if(len) - *sign++ = len; - else { - *sign++ = 1; - *sign++ = 0; - return sign; - } - - if(leadzero) { - *sign++ = 0; - } - - while(i < sizeof(xdag_hash_t)) { - *sign++ = n[i++]; - } - - return sign; -} - -// returns 0 on success -int xdag_verify_signature_optimized_ec(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s) -{ - uint8_t buf_pubkey[sizeof(xdag_hash_t) + 1]; - secp256k1_pubkey pubkey_noopenssl; - size_t pubkeylen = sizeof(xdag_hash_t) + 1; - secp256k1_ecdsa_signature sig_noopenssl; - secp256k1_ecdsa_signature sig_noopenssl_normalized; - int res = 0; - - buf_pubkey[0] = 2 + ((uintptr_t)key & 1); - memcpy(&(buf_pubkey[1]), (xdag_hash_t*)((uintptr_t)key & ~1l), sizeof(xdag_hash_t)); - - if((res = secp256k1_ec_pubkey_parse(ctx_noopenssl, &pubkey_noopenssl, buf_pubkey, pubkeylen)) != 1) { - xdag_debug("Public key parsing failed: res=%2d key parity bit = %ld key=[%s] hash=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), - xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - - } - - uint8_t sign_buf[72], *ptr; - - ptr = add_number_to_sign_optimized_ec(sign_buf + 2, sign_r); - ptr = add_number_to_sign_optimized_ec(ptr, sign_s); - sign_buf[0] = 0x30; - sign_buf[1] = ptr - sign_buf - 2; - - - if((res = secp256k1_ecdsa_signature_parse_der(ctx_noopenssl, &sig_noopenssl, sign_buf, ptr - sign_buf)) != 1) { - xdag_debug("Signature parsing failed: res=%2d key parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), - xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), - xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - return 1; - } - - // never fail - secp256k1_ecdsa_signature_normalize(ctx_noopenssl, &sig_noopenssl_normalized, &sig_noopenssl); - - if((res = secp256k1_ecdsa_verify(ctx_noopenssl, &sig_noopenssl_normalized, (unsigned char*)hash, &pubkey_noopenssl)) != 1) { - xdag_debug("Verify failed: res =%2d key parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), - xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), - xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - return 1; - } - - xdag_debug("Verify completed: parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", ((uintptr_t)key & 1), - xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), - xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); - return 0; -} - -#endif +/* cryptography (ECDSA), T13.654-T13.847 $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "crypt.h" +#include "transport.h" +#include "utils/log.h" +#include "system.h" + +#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 + +#include "../secp256k1/include/secp256k1.h" + +secp256k1_context *ctx_noopenssl; + +#endif + +static EC_GROUP *group; + +extern unsigned int xOPENSSL_ia32cap_P[4]; +extern int xOPENSSL_ia32_cpuid(unsigned int *); + +// initialization of the encryption system +int xdag_crypt_init(int withrandom) +{ + if(withrandom) { + uint64_t buf[64]; + xOPENSSL_ia32_cpuid(xOPENSSL_ia32cap_P); + xdag_generate_random_array(buf, sizeof(buf)); + xdag_debug("Seed : [%s]", xdag_log_array(buf, sizeof(buf))); + RAND_seed(buf, sizeof(buf)); + } + +#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 + ctx_noopenssl = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); +#endif + + group = EC_GROUP_new_by_curve_name(NID_secp256k1); + if(!group) return -1; + + return 0; +} + +/* creates a new pair of private and public keys + * the private key is saved to the 'privkey' array, the public key to the 'pubkey' array, + * the parity of the public key is saved to the variable 'pubkey_bit' + * returns a pointer to its internal representation + */ +void *xdag_create_key(xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit) +{ + uint8_t buf[sizeof(xdag_hash_t) + 1]; + EC_KEY *eckey = 0; + const BIGNUM *priv = 0; + const EC_POINT *pub = 0; + BN_CTX *ctx = 0; + int res = -1; + + if(!group) { + goto fail; + } + + eckey = EC_KEY_new(); + + if(!eckey) { + goto fail; + } + + if(!EC_KEY_set_group(eckey, group)) { + goto fail; + } + + if(!EC_KEY_generate_key(eckey)) { + goto fail; + } + + priv = EC_KEY_get0_private_key(eckey); + if(!priv) { + goto fail; + } + + if(BN_bn2bin(priv, (uint8_t*)privkey) != sizeof(xdag_hash_t)) { + goto fail; + } + + pub = EC_KEY_get0_public_key(eckey); + if(!pub) { + goto fail; + } + + ctx = BN_CTX_new(); + if(!ctx) { + goto fail; + } + + BN_CTX_start(ctx); + if(EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, buf, sizeof(xdag_hash_t) + 1, ctx) != sizeof(xdag_hash_t) + 1) { + goto fail; + } + + memcpy(pubkey, buf + 1, sizeof(xdag_hash_t)); + *pubkey_bit = *buf & 1; + res = 0; + +fail: + if(ctx) { + BN_CTX_free(ctx); + } + + if(res && eckey) { + EC_KEY_free(eckey); + } + + return res ? 0 : eckey; +} + +// returns the internal representation of the key and the public key by the known private key +void *xdag_private_to_key(const xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit) +{ + uint8_t buf[sizeof(xdag_hash_t) + 1]; + EC_KEY *eckey = 0; + BIGNUM *priv = 0; + EC_POINT *pub = 0; + BN_CTX *ctx = 0; + int res = -1; + + if(!group) { + goto fail; + } + + eckey = EC_KEY_new(); + if(!eckey) { + goto fail; + } + + if(!EC_KEY_set_group(eckey, group)) { + goto fail; + } + + priv = BN_new(); + if(!priv) { + goto fail; + } + + // BN_init(priv); + BN_bin2bn((uint8_t*)privkey, sizeof(xdag_hash_t), priv); + EC_KEY_set_private_key(eckey, priv); + + ctx = BN_CTX_new(); + if(!ctx) { + goto fail; + } + + BN_CTX_start(ctx); + + pub = EC_POINT_new(group); + if(!pub) { + goto fail; + } + + EC_POINT_mul(group, pub, priv, NULL, NULL, ctx); + EC_KEY_set_public_key(eckey, pub); + if(EC_POINT_point2oct(group, pub, POINT_CONVERSION_COMPRESSED, buf, sizeof(xdag_hash_t) + 1, ctx) != sizeof(xdag_hash_t) + 1) { + goto fail; + } + + memcpy(pubkey, buf + 1, sizeof(xdag_hash_t)); + *pubkey_bit = *buf & 1; + res = 0; + +fail: + if(ctx) { + BN_CTX_free(ctx); + } + + if(priv) { + BN_free(priv); + } + + if(pub) { + EC_POINT_free(pub); + } + + if(res && eckey) { + EC_KEY_free(eckey); + } + + return res ? 0 : eckey; +} + +// Returns the internal representation of the key by the known public key +void *xdag_public_to_key(const xdag_hash_t pubkey, uint8_t pubkey_bit) +{ + EC_KEY *eckey = 0; + BIGNUM *pub = 0; + EC_POINT *p = 0; + BN_CTX *ctx = 0; + int res = -1; + + if(!group) { + goto fail; + } + + eckey = EC_KEY_new(); + if(!eckey) { + goto fail; + } + + if(!EC_KEY_set_group(eckey, group)) { + goto fail; + } + + pub = BN_new(); + if(!pub) { + goto fail; + } + + // BN_init(pub); + BN_bin2bn((uint8_t*)pubkey, sizeof(xdag_hash_t), pub); + p = EC_POINT_new(group); + if(!p) { + goto fail; + } + + ctx = BN_CTX_new(); + if(!ctx) { + goto fail; + } + + BN_CTX_start(ctx); + if(!EC_POINT_set_compressed_coordinates_GFp(group, p, pub, pubkey_bit, ctx)) { + goto fail; + } + + EC_KEY_set_public_key(eckey, p); + res = 0; + +fail: + if(ctx) { + BN_CTX_free(ctx); + } + + if(pub) { + BN_free(pub); + } + + if(p) { + EC_POINT_free(p); + } + + if(res && eckey) { + EC_KEY_free(eckey); + } + + return res ? 0 : eckey; +} + +// removes the internal key representation +void xdag_free_key(void *key) +{ + EC_KEY_free((EC_KEY*)key); +} + +// sign the hash and put the result in sign_r and sign_s +int xdag_sign(const void *key, const xdag_hash_t hash, xdag_hash_t sign_r, xdag_hash_t sign_s) +{ + uint8_t buf[72], *p; + unsigned sig_len, s; + + if(!ECDSA_sign(0, (const uint8_t*)hash, sizeof(xdag_hash_t), buf, &sig_len, (EC_KEY*)key)) { + return -1; + } + + p = buf + 3, s = *p++; + + if(s >= sizeof(xdag_hash_t)) { + memcpy(sign_r, p + s - sizeof(xdag_hash_t), sizeof(xdag_hash_t)); + } else { + memset(sign_r, 0, sizeof(xdag_hash_t)); + memcpy((uint8_t*)sign_r + sizeof(xdag_hash_t) - s, p, s); + } + + p += s + 1, s = *p++; + + if(s >= sizeof(xdag_hash_t)) { + memcpy(sign_s, p + s - sizeof(xdag_hash_t), sizeof(xdag_hash_t)); + } else { + memset(sign_s, 0, sizeof(xdag_hash_t)); + memcpy((uint8_t*)sign_s + sizeof(xdag_hash_t) - s, p, s); + } + + xdag_debug("Sign : hash=[%s] sign=[%s] r=[%s], s=[%s]", xdag_log_hash(hash), + xdag_log_array(buf, sig_len), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + + return 0; +} + +static uint8_t *add_number_to_sign(uint8_t *sign, const xdag_hash_t num) +{ + uint8_t *n = (uint8_t*)num; + int i, len, leadzero; + + for(i = 0; i < sizeof(xdag_hash_t) && !n[i]; ++i); + + leadzero = (i < sizeof(xdag_hash_t) && n[i] & 0x80); + len = (sizeof(xdag_hash_t) - i) + leadzero; + *sign++ = 0x02; + *sign++ = len; + + if(leadzero) { + *sign++ = 0; + } + + while(i < sizeof(xdag_hash_t)) { + *sign++ = n[i++]; + } + + return sign; +} + +// verify that the signature (sign_r, sign_s) corresponds to a hash 'hash', a version for its own key +// returns 0 on success +int xdag_verify_signature(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s) +{ + uint8_t buf[72], *ptr; + int res; + + ptr = add_number_to_sign(buf + 2, sign_r); + ptr = add_number_to_sign(ptr, sign_s); + buf[0] = 0x30; + buf[1] = ptr - buf - 2; + res = ECDSA_verify(0, (const uint8_t*)hash, sizeof(xdag_hash_t), buf, ptr - buf, (EC_KEY*)key); + + xdag_debug("Verify: res=%2d key=%lx hash=[%s] sign=[%s] r=[%s], s=[%s]", res, (long)key, xdag_log_hash(hash), + xdag_log_array(buf, ptr - buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + + return res != 1; +} + +#if USE_OPTIMIZED_EC == 1 || USE_OPTIMIZED_EC == 2 + +static uint8_t *add_number_to_sign_optimized_ec(uint8_t *sign, const xdag_hash_t num) +{ + uint8_t *n = (uint8_t*)num; + int i, len, leadzero; + + for(i = 0; i < sizeof(xdag_hash_t) && !n[i]; ++i); + + leadzero = (i < sizeof(xdag_hash_t) && n[i] & 0x80); + len = (sizeof(xdag_hash_t) - i) + leadzero; + *sign++ = 0x02; + if(len) + *sign++ = len; + else { + *sign++ = 1; + *sign++ = 0; + return sign; + } + + if(leadzero) { + *sign++ = 0; + } + + while(i < sizeof(xdag_hash_t)) { + *sign++ = n[i++]; + } + + return sign; +} + +// returns 0 on success +int xdag_verify_signature_optimized_ec(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s) +{ + uint8_t buf_pubkey[sizeof(xdag_hash_t) + 1]; + secp256k1_pubkey pubkey_noopenssl; + size_t pubkeylen = sizeof(xdag_hash_t) + 1; + secp256k1_ecdsa_signature sig_noopenssl; + secp256k1_ecdsa_signature sig_noopenssl_normalized; + int res = 0; + + buf_pubkey[0] = 2 + ((uintptr_t)key & 1); + memcpy(&(buf_pubkey[1]), (xdag_hash_t*)((uintptr_t)key & ~1l), sizeof(xdag_hash_t)); + + if((res = secp256k1_ec_pubkey_parse(ctx_noopenssl, &pubkey_noopenssl, buf_pubkey, pubkeylen)) != 1) { + xdag_debug("Public key parsing failed: res=%2d key parity bit = %ld key=[%s] hash=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), + xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + + } + + uint8_t sign_buf[72], *ptr; + + ptr = add_number_to_sign_optimized_ec(sign_buf + 2, sign_r); + ptr = add_number_to_sign_optimized_ec(ptr, sign_s); + sign_buf[0] = 0x30; + sign_buf[1] = ptr - sign_buf - 2; + + + if((res = secp256k1_ecdsa_signature_parse_der(ctx_noopenssl, &sig_noopenssl, sign_buf, ptr - sign_buf)) != 1) { + xdag_debug("Signature parsing failed: res=%2d key parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), + xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), + xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + return 1; + } + + // never fail + secp256k1_ecdsa_signature_normalize(ctx_noopenssl, &sig_noopenssl_normalized, &sig_noopenssl); + + if((res = secp256k1_ecdsa_verify(ctx_noopenssl, &sig_noopenssl_normalized, (unsigned char*)hash, &pubkey_noopenssl)) != 1) { + xdag_debug("Verify failed: res =%2d key parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", res, ((uintptr_t)key & 1), + xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), + xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + return 1; + } + + xdag_debug("Verify completed: parity bit = %ld key=[%s] hash=[%s] sign=[%s] r=[%s], s=[%s]", ((uintptr_t)key & 1), + xdag_log_hash((uint64_t*)((uintptr_t)key & ~1l)), xdag_log_hash(hash), + xdag_log_array(sign_buf, ptr - sign_buf), xdag_log_hash(sign_r), xdag_log_hash(sign_s)); + return 0; +} + +#endif diff --git a/client/crypt.h b/client/crypt.h index 1582af52..9c295011 100644 --- a/client/crypt.h +++ b/client/crypt.h @@ -1,38 +1,46 @@ -/* cryptography, T13.654-T13.826 $DVS:time$ */ - -#ifndef XDAG_CRYPT_H -#define XDAG_CRYPT_H - -#include -#include "hash.h" +/* cryptography, T13.654-T13.826 $DVS:time$ */ + +#ifndef XDAG_CRYPT_H +#define XDAG_CRYPT_H + +#include +#include "hash.h" #if defined (__MACOS__) || defined (__APPLE__) //no need optimized secp256k1 for mac #else #define USE_OPTIMIZED_EC 1 // 0 disactivate, 1 activated, 2 test openssl vs secp256k1 -#endif - -// initialization of the encryption system -extern int xdag_crypt_init(int withrandom); - -// creates a new pair of private and public keys -extern void *xdag_create_key(xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit); - -// returns the internal representation of the key and the public key by the known private key -extern void *xdag_private_to_key(const xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit); - -// returns the internal representation of the key by the known public key -extern void *xdag_public_to_key(const xdag_hash_t pubkey, uint8_t pubkey_bit); - -// removes the internal key representation -extern void xdag_free_key(void *key); - -// sign the hash and put the result in sign_r and sign_s -extern int xdag_sign(const void *key, const xdag_hash_t hash, xdag_hash_t sign_r, xdag_hash_t sign_s); - -// verify that the signature (sign_r, sign_s) corresponds to a hash 'hash', a version for its own key -extern int xdag_verify_signature(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s); - -extern int xdag_verify_signature_optimized_ec(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s); - -#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// initialization of the encryption system +extern int xdag_crypt_init(int withrandom); + +// creates a new pair of private and public keys +extern void *xdag_create_key(xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit); + +// returns the internal representation of the key and the public key by the known private key +extern void *xdag_private_to_key(const xdag_hash_t privkey, xdag_hash_t pubkey, uint8_t *pubkey_bit); + +// returns the internal representation of the key by the known public key +extern void *xdag_public_to_key(const xdag_hash_t pubkey, uint8_t pubkey_bit); + +// removes the internal key representation +extern void xdag_free_key(void *key); + +// sign the hash and put the result in sign_r and sign_s +extern int xdag_sign(const void *key, const xdag_hash_t hash, xdag_hash_t sign_r, xdag_hash_t sign_s); + +// verify that the signature (sign_r, sign_s) corresponds to a hash 'hash', a version for its own key +extern int xdag_verify_signature(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s); + +extern int xdag_verify_signature_optimized_ec(const void *key, const xdag_hash_t hash, const xdag_hash_t sign_r, const xdag_hash_t sign_s); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/client/hash.c b/client/hash.c index 81ad8ad1..7ec1837c 100644 --- a/client/hash.c +++ b/client/hash.c @@ -1,206 +1,206 @@ -/* hash-function, T13.654-T13.864 $DVS:time$ */ - -#include -#ifdef SHA256_OPENSSL_MBLOCK -#include -#endif -#include "sha256.h" -#include "hash.h" -#include "system.h" - -void xdag_hash(void *data, size_t size, xdag_hash_t hash) -{ - SHA256REF_CTX ctx; - - sha256_init(&ctx); - sha256_update(&ctx, data, size); - sha256_final(&ctx, (uint8_t*)hash); - sha256_init(&ctx); - sha256_update(&ctx, (uint8_t*)hash, sizeof(xdag_hash_t)); - sha256_final(&ctx, (uint8_t*)hash); -} - -unsigned xdag_hash_ctx_size(void) -{ - return sizeof(SHA256REF_CTX); -} - -void xdag_hash_init(void *ctxv) -{ - SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; - - sha256_init(ctx); -} - -void xdag_hash_update(void *ctxv, void *data, size_t size) -{ - SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; - - sha256_update(ctx, data, size); -} - -void xdag_hash_final(void *ctxv, void *data, size_t size, xdag_hash_t hash) -{ - SHA256REF_CTX ctx; - - memcpy(&ctx, ctxv, sizeof(ctx)); - sha256_update(&ctx, (uint8_t*)data, size); - sha256_final(&ctx, (uint8_t*)hash); - sha256_init(&ctx); - sha256_update(&ctx, (uint8_t*)hash, sizeof(xdag_hash_t)); - sha256_final(&ctx, (uint8_t*)hash); -} - -#ifndef SHA256_OPENSSL_MBLOCK - -uint64_t xdag_hash_final_multi(void *ctxv, uint64_t *nonce, int attempts, int step, xdag_hash_t hash) -{ - SHA256REF_CTX ctx; - xdag_hash_t hash0; - uint64_t min_nonce = 0; - int i; - - for (i = 0; i < attempts; ++i) { - memcpy(&ctx, ctxv, sizeof(ctx)); - sha256_update(&ctx, (uint8_t*)nonce, sizeof(uint64_t)); - sha256_final(&ctx, (uint8_t*)hash0); - sha256_init(&ctx); - sha256_update(&ctx, (uint8_t*)hash0, sizeof(xdag_hash_t)); - sha256_final(&ctx, (uint8_t*)hash0); - - if (!i || xdag_cmphash(hash0, hash) < 0) { - memcpy(hash, hash0, sizeof(xdag_hash_t)); - min_nonce = *nonce; - } - - *nonce += step; - } - - return min_nonce; -} - -#else - -#define N 8 - -typedef struct { - unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8]; -} SHA256_MB_CTX; -typedef struct { - const unsigned char *ptr; - int blocks; -} HASH_DESC; - -extern void xsha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int); - -uint64_t xdag_hash_final_multi(void *ctxv, uint64_t *nonce, int attempts, int step, xdag_hash_t hash) -{ - SHA256_MB_CTX mctx1, mctx2, mctx; - SHA256REF_CTX *ctx1 = (SHA256REF_CTX*)ctxv, ctx2[1]; - HASH_DESC desc1[N], desc2[N]; - uint64_t arr1[N * 16], arr2[N * 8]; - uint8_t *array1 = (uint8_t*)arr1, *array2 = (uint8_t*)arr2; - xdag_hash_t hash0; - uint64_t min_nonce = 0, nonce0; - uint32_t *hash032 = (uint32_t*)(uint64_t*)hash0; - int i, j; - - memset(array1, 0, 128); - memcpy(array1, ctx1->data, 56); - array1[64] = 0x80; - array1[126] = 0x10; - - for (i = 1; i < N; ++i) { - memcpy(array1 + i * 128, array1, 128); - } - - for (i = 0; i < N; ++i) { - desc1[i].ptr = array1 + i * 128, desc1[i].blocks = 2; - } - - memset(array2, 0, 64); - array2[32] = 0x80; - array2[62] = 1; - - for (i = 1; i < N; ++i) { - memcpy(array2 + i * 64, array2, 64); - } - - for (i = 0; i < N; ++i) { - desc2[i].ptr = array2 + i * 64, desc2[i].blocks = 1; - } - - sha256_init(ctx2); - - for (i = 0; i < N; ++i) { - mctx1.A[i] = ctx1->state[0]; mctx2.A[i] = ctx2->state[0]; - mctx1.B[i] = ctx1->state[1]; mctx2.B[i] = ctx2->state[1]; - mctx1.C[i] = ctx1->state[2]; mctx2.C[i] = ctx2->state[2]; - mctx1.D[i] = ctx1->state[3]; mctx2.D[i] = ctx2->state[3]; - mctx1.E[i] = ctx1->state[4]; mctx2.E[i] = ctx2->state[4]; - mctx1.F[i] = ctx1->state[5]; mctx2.F[i] = ctx2->state[5]; - mctx1.G[i] = ctx1->state[6]; mctx2.G[i] = ctx2->state[6]; - mctx1.H[i] = ctx1->state[7]; mctx2.H[i] = ctx2->state[7]; - } - - for (j = 0; j < attempts; j += N) { - memcpy(&mctx, &mctx1, 8 * 8 * 4); - nonce0 = *nonce; - - for (i = 0; i < N; ++i) { - memcpy(array1 + i * 128 + 56, nonce, 8); *nonce += step; - } - xsha256_multi_block(&mctx, desc1, N / 4); - - for (i = 0; i < N; ++i) { - ((uint32_t*)array2)[i * 16 + 0] = htonl(mctx.A[i]); - ((uint32_t*)array2)[i * 16 + 1] = htonl(mctx.B[i]); - ((uint32_t*)array2)[i * 16 + 2] = htonl(mctx.C[i]); - ((uint32_t*)array2)[i * 16 + 3] = htonl(mctx.D[i]); - ((uint32_t*)array2)[i * 16 + 4] = htonl(mctx.E[i]); - ((uint32_t*)array2)[i * 16 + 5] = htonl(mctx.F[i]); - ((uint32_t*)array2)[i * 16 + 6] = htonl(mctx.G[i]); - ((uint32_t*)array2)[i * 16 + 7] = htonl(mctx.H[i]); - } - memcpy(&mctx, &mctx2, 8 * 8 * 4); - xsha256_multi_block(&mctx, desc2, N / 4); - - for (i = 0; i < N; ++i, nonce0 += step) { - hash032[0] = htonl(mctx.A[i]); - hash032[1] = htonl(mctx.B[i]); - hash032[2] = htonl(mctx.C[i]); - hash032[3] = htonl(mctx.D[i]); - hash032[4] = htonl(mctx.E[i]); - hash032[5] = htonl(mctx.F[i]); - hash032[6] = htonl(mctx.G[i]); - hash032[7] = htonl(mctx.H[i]); - if ((!i && !j) || xdag_cmphash(hash0, hash) < 0) { - memcpy(hash, hash0, sizeof(xdag_hash_t)); - min_nonce = nonce0; - } - } - } - return min_nonce; -} - -#undef N - -#endif - -void xdag_hash_get_state(void *ctxv, xdag_hash_t state) -{ - SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; - - memcpy(state, ctx->state, sizeof(xdag_hash_t)); -} - -void xdag_hash_set_state(void *ctxv, xdag_hash_t state, size_t size) -{ - SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; - - memcpy(ctx->state, state, sizeof(xdag_hash_t)); - ctx->datalen = 0; - ctx->bitlen = size << 3; - ctx->bitlenH = 0; - ctx->md_len = SHA256_BLOCK_SIZE; -} +/* hash-function, T13.654-T13.864 $DVS:time$ */ + +#include +#ifdef SHA256_OPENSSL_MBLOCK +#include +#endif +#include "sha256.h" +#include "hash.h" +#include "system.h" + +void xdag_hash(void *data, size_t size, xdag_hash_t hash) +{ + SHA256REF_CTX ctx; + + sha256_init(&ctx); + sha256_update(&ctx, data, size); + sha256_final(&ctx, (uint8_t*)hash); + sha256_init(&ctx); + sha256_update(&ctx, (uint8_t*)hash, sizeof(xdag_hash_t)); + sha256_final(&ctx, (uint8_t*)hash); +} + +unsigned xdag_hash_ctx_size(void) +{ + return sizeof(SHA256REF_CTX); +} + +void xdag_hash_init(void *ctxv) +{ + SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; + + sha256_init(ctx); +} + +void xdag_hash_update(void *ctxv, void *data, size_t size) +{ + SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; + + sha256_update(ctx, data, size); +} + +void xdag_hash_final(void *ctxv, void *data, size_t size, xdag_hash_t hash) +{ + SHA256REF_CTX ctx; + + memcpy(&ctx, ctxv, sizeof(ctx)); + sha256_update(&ctx, (uint8_t*)data, size); + sha256_final(&ctx, (uint8_t*)hash); + sha256_init(&ctx); + sha256_update(&ctx, (uint8_t*)hash, sizeof(xdag_hash_t)); + sha256_final(&ctx, (uint8_t*)hash); +} + +#ifndef SHA256_OPENSSL_MBLOCK + +uint64_t xdag_hash_final_multi(void *ctxv, uint64_t *nonce, int attempts, int step, xdag_hash_t hash) +{ + SHA256REF_CTX ctx; + xdag_hash_t hash0; + uint64_t min_nonce = 0; + int i; + + for (i = 0; i < attempts; ++i) { + memcpy(&ctx, ctxv, sizeof(ctx)); + sha256_update(&ctx, (uint8_t*)nonce, sizeof(uint64_t)); + sha256_final(&ctx, (uint8_t*)hash0); + sha256_init(&ctx); + sha256_update(&ctx, (uint8_t*)hash0, sizeof(xdag_hash_t)); + sha256_final(&ctx, (uint8_t*)hash0); + + if (!i || xdag_cmphash(hash0, hash) < 0) { + memcpy(hash, hash0, sizeof(xdag_hash_t)); + min_nonce = *nonce; + } + + *nonce += step; + } + + return min_nonce; +} + +#else + +#define N 8 + +typedef struct { + unsigned int A[8], B[8], C[8], D[8], E[8], F[8], G[8], H[8]; +} SHA256_MB_CTX; +typedef struct { + const unsigned char *ptr; + int blocks; +} HASH_DESC; + +extern void xsha256_multi_block(SHA256_MB_CTX *, const HASH_DESC *, int); + +uint64_t xdag_hash_final_multi(void *ctxv, uint64_t *nonce, int attempts, int step, xdag_hash_t hash) +{ + SHA256_MB_CTX mctx1, mctx2, mctx; + SHA256REF_CTX *ctx1 = (SHA256REF_CTX*)ctxv, ctx2[1]; + HASH_DESC desc1[N], desc2[N]; + uint64_t arr1[N * 16], arr2[N * 8]; + uint8_t *array1 = (uint8_t*)arr1, *array2 = (uint8_t*)arr2; + xdag_hash_t hash0; + uint64_t min_nonce = 0, nonce0; + uint32_t *hash032 = (uint32_t*)(uint64_t*)hash0; + int i, j; + + memset(array1, 0, 128); + memcpy(array1, ctx1->data, 56); + array1[64] = 0x80; + array1[126] = 0x10; + + for (i = 1; i < N; ++i) { + memcpy(array1 + i * 128, array1, 128); + } + + for (i = 0; i < N; ++i) { + desc1[i].ptr = array1 + i * 128, desc1[i].blocks = 2; + } + + memset(array2, 0, 64); + array2[32] = 0x80; + array2[62] = 1; + + for (i = 1; i < N; ++i) { + memcpy(array2 + i * 64, array2, 64); + } + + for (i = 0; i < N; ++i) { + desc2[i].ptr = array2 + i * 64, desc2[i].blocks = 1; + } + + sha256_init(ctx2); + + for (i = 0; i < N; ++i) { + mctx1.A[i] = ctx1->state[0]; mctx2.A[i] = ctx2->state[0]; + mctx1.B[i] = ctx1->state[1]; mctx2.B[i] = ctx2->state[1]; + mctx1.C[i] = ctx1->state[2]; mctx2.C[i] = ctx2->state[2]; + mctx1.D[i] = ctx1->state[3]; mctx2.D[i] = ctx2->state[3]; + mctx1.E[i] = ctx1->state[4]; mctx2.E[i] = ctx2->state[4]; + mctx1.F[i] = ctx1->state[5]; mctx2.F[i] = ctx2->state[5]; + mctx1.G[i] = ctx1->state[6]; mctx2.G[i] = ctx2->state[6]; + mctx1.H[i] = ctx1->state[7]; mctx2.H[i] = ctx2->state[7]; + } + + for (j = 0; j < attempts; j += N) { + memcpy(&mctx, &mctx1, 8 * 8 * 4); + nonce0 = *nonce; + + for (i = 0; i < N; ++i) { + memcpy(array1 + i * 128 + 56, nonce, 8); *nonce += step; + } + xsha256_multi_block(&mctx, desc1, N / 4); + + for (i = 0; i < N; ++i) { + ((uint32_t*)array2)[i * 16 + 0] = htonl(mctx.A[i]); + ((uint32_t*)array2)[i * 16 + 1] = htonl(mctx.B[i]); + ((uint32_t*)array2)[i * 16 + 2] = htonl(mctx.C[i]); + ((uint32_t*)array2)[i * 16 + 3] = htonl(mctx.D[i]); + ((uint32_t*)array2)[i * 16 + 4] = htonl(mctx.E[i]); + ((uint32_t*)array2)[i * 16 + 5] = htonl(mctx.F[i]); + ((uint32_t*)array2)[i * 16 + 6] = htonl(mctx.G[i]); + ((uint32_t*)array2)[i * 16 + 7] = htonl(mctx.H[i]); + } + memcpy(&mctx, &mctx2, 8 * 8 * 4); + xsha256_multi_block(&mctx, desc2, N / 4); + + for (i = 0; i < N; ++i, nonce0 += step) { + hash032[0] = htonl(mctx.A[i]); + hash032[1] = htonl(mctx.B[i]); + hash032[2] = htonl(mctx.C[i]); + hash032[3] = htonl(mctx.D[i]); + hash032[4] = htonl(mctx.E[i]); + hash032[5] = htonl(mctx.F[i]); + hash032[6] = htonl(mctx.G[i]); + hash032[7] = htonl(mctx.H[i]); + if ((!i && !j) || xdag_cmphash(hash0, hash) < 0) { + memcpy(hash, hash0, sizeof(xdag_hash_t)); + min_nonce = nonce0; + } + } + } + return min_nonce; +} + +#undef N + +#endif + +void xdag_hash_get_state(void *ctxv, xdag_hash_t state) +{ + SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; + + memcpy(state, ctx->state, sizeof(xdag_hash_t)); +} + +void xdag_hash_set_state(void *ctxv, xdag_hash_t state, size_t size) +{ + SHA256REF_CTX *ctx = (SHA256REF_CTX*)ctxv; + + memcpy(ctx->state, state, sizeof(xdag_hash_t)); + ctx->datalen = 0; + ctx->bitlen = size << 3; + ctx->bitlenH = 0; + ctx->md_len = SHA256_BLOCK_SIZE; +} diff --git a/client/hash.h b/client/hash.h index 8ad91242..b050f1d3 100644 --- a/client/hash.h +++ b/client/hash.h @@ -9,6 +9,10 @@ typedef uint64_t xdag_hash_t[4]; typedef uint64_t xdag_hashlow_t[3]; +#ifdef __cplusplus +extern "C" { +#endif + extern void xdag_hash(void *data, size_t size, xdag_hash_t hash); static inline int xdag_cmphash(xdag_hash_t l, xdag_hash_t r) @@ -30,5 +34,9 @@ extern uint64_t xdag_hash_final_multi(void *ctxv, uint64_t *nonce, int attempts, extern void xdag_hash_get_state(void *ctxv, xdag_hash_t state); extern void xdag_hash_set_state(void *ctxv, xdag_hash_t state, size_t size); + +#ifdef __cplusplus +}; +#endif #endif diff --git a/client/http/http.h b/client/http/http.h index 54db569b..effaaa15 100644 --- a/client/http/http.h +++ b/client/http/http.h @@ -9,10 +9,18 @@ #ifndef http_h #define http_h +#ifdef __cplusplus +extern "C" { +#endif + // simple http get, pass url, and return the content with malloc. Need free returned value. extern char *http_get(const char* url); extern int test_https(void); extern int test_http(void); + +#ifdef __cplusplus +}; +#endif #endif /* http_h */ diff --git a/client/http/url.h b/client/http/url.h index d735ea74..965e2e9b 100755 --- a/client/http/url.h +++ b/client/http/url.h @@ -42,6 +42,9 @@ typedef struct _url_field char *fragment; } url_field_t; +#ifdef __cplusplus +extern "C" { +#endif extern url_field_t *url_parse(const char *str); @@ -49,4 +52,8 @@ extern void url_free(url_field_t *url); extern void url_field_print(url_field_t *url); +#ifdef __cplusplus +}; +#endif + #endif /* !__URI_H__ */ diff --git a/client/json-rpc/rpc_procedure.h b/client/json-rpc/rpc_procedure.h index 568a418e..88fb0d6d 100644 --- a/client/json-rpc/rpc_procedure.h +++ b/client/json-rpc/rpc_procedure.h @@ -28,6 +28,10 @@ struct xdag_rpc_procedure { void *data; }; +#ifdef __cplusplus +extern "C" { +#endif + /* register procedure */ extern int xdag_rpc_service_register_procedure(xdag_rpc_function function_pointer, char *name, void *data); @@ -37,4 +41,8 @@ extern int xdag_rpc_service_unregister_procedure(char *name); /* handle rpc request */ extern cJSON *xdag_rpc_handle_request(char* buffer); +#ifdef __cplusplus +}; +#endif + #endif //XDAG_RPC_PROCEDURE_H diff --git a/client/json-rpc/rpc_procedures.h b/client/json-rpc/rpc_procedures.h index 9b826694..f1f71e05 100644 --- a/client/json-rpc/rpc_procedures.h +++ b/client/json-rpc/rpc_procedures.h @@ -9,7 +9,15 @@ #ifndef XDAG_RPC_PROCEDURES_H #define XDAG_RPC_PROCEDURES_H +#ifdef __cplusplus +extern "C" { +#endif + /* init rpc procedures */ extern int xdag_rpc_init_procedures(void); +#ifdef __cplusplus +}; +#endif + #endif //XDAG_TERMINAL_H diff --git a/client/json-rpc/rpc_service.h b/client/json-rpc/rpc_service.h index 915cf36d..74127036 100644 --- a/client/json-rpc/rpc_service.h +++ b/client/json-rpc/rpc_service.h @@ -19,10 +19,18 @@ struct xdag_rpc_connection { char * buffer; }; +#ifdef __cplusplus +extern "C" { +#endif + /* init xdag rpc */ extern int xdag_rpc_service_init(int port); /* stop xdag rpc */ extern int xdag_rpc_service_stop(void); + +#ifdef __cplusplus +}; +#endif #endif //XDAG_RPC_SERVICE_H diff --git a/client/json-rpc/rpc_wrapper.h b/client/json-rpc/rpc_wrapper.h index 158af6c7..7891a807 100644 --- a/client/json-rpc/rpc_wrapper.h +++ b/client/json-rpc/rpc_wrapper.h @@ -8,5 +8,15 @@ #ifndef XDAG_RPC_WRAPPER_H #define XDAG_RPC_WRAPPER_H + +#ifdef __cplusplus +extern "C" { +#endif + extern void rpc_call_dnet_command(const char *method, const char *params, char **result); + +#ifdef __cplusplus +}; +#endif + #endif //XDAG_RPC_WRAPPER_H diff --git a/client/memory.h b/client/memory.h index ab2be41c..2416f536 100644 --- a/client/memory.h +++ b/client/memory.h @@ -3,6 +3,10 @@ #ifndef XDAG_MEMORY_H #define XDAG_MEMORY_H +#ifdef __cplusplus +extern "C" { +#endif + extern void xdag_mem_tempfile_path(const char *tempfile_path); extern int xdag_mem_init(size_t size); @@ -18,4 +22,8 @@ extern int xdag_free_all(void); extern char** xdagCreateStringArray(int count, int stringLen); extern void xdagFreeStringArray(char** stringArray, int count); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/client/miner.h b/client/miner.h index 3f8235ad..c58b7a10 100644 --- a/client/miner.h +++ b/client/miner.h @@ -6,6 +6,10 @@ #include #include "block.h" +#ifdef __cplusplus +extern "C" { +#endif + /* a number of mining threads */ extern int g_xdag_mining_threads; @@ -20,4 +24,8 @@ extern void *miner_net_thread(void *arg); /* send block to network via pool */ extern int xdag_send_block_via_pool(struct xdag_block *block); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/client/mining_common.h b/client/mining_common.h index 2c060487..5e825840 100644 --- a/client/mining_common.h +++ b/client/mining_common.h @@ -22,6 +22,10 @@ struct xdag_pool_task { void *ctx0, *ctx; }; +#ifdef __cplusplus +extern "C" { +#endif + extern struct xdag_pool_task g_xdag_pool_task[2]; extern uint64_t g_xdag_pool_task_index; /* global variables are instantiated with 0 */ @@ -44,4 +48,8 @@ extern int xdag_initialize_mining(const char *pool_arg, const char *miner_addres //function sets minimal share for the task extern void xdag_set_min_share(struct xdag_pool_task *task, xdag_hash_t last, xdag_hash_t hash); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/client/netdb-testnet.txt b/client/netdb-testnet.txt index 01892815..0a7235b5 100755 --- a/client/netdb-testnet.txt +++ b/client/netdb-testnet.txt @@ -1,4 +1,4 @@ -213.21.5.18:3366 -77.55.222.85:3366 -87.6.219.5:6667 -195.201.167.125:3366 +213.21.5.18:3366 +77.55.222.85:3366 +87.6.219.5:6667 +195.201.167.125:3366 diff --git a/client/netdb.h b/client/netdb.h index 3b89f57a..f178f466 100644 --- a/client/netdb.h +++ b/client/netdb.h @@ -5,6 +5,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* initialized hosts base, 'our_host_str' - exteranal address of our host (ip:port), * 'addr_port_pairs' - addresses of other 'npairs' hosts in the same format */ @@ -23,4 +27,8 @@ extern void xdag_netdb_finish(void); extern uint32_t *g_xdag_blocked_ips, *g_xdag_white_ips; extern int g_xdag_n_blocked_ips, g_xdag_n_white_ips; +#ifdef __cplusplus +}; +#endif + #endif diff --git a/client/pool.h b/client/pool.h index 7162c21a..944870c0 100644 --- a/client/pool.h +++ b/client/pool.h @@ -1,43 +1,51 @@ -/* pool logic */ - -#ifndef XDAG_POOL_H -#define XDAG_POOL_H - -#include "hash.h" - -#define MAX_CONNECTIONS_COUNT 8192 -#define CONFIRMATIONS_COUNT 16 - -enum disconnect_type -{ - DISCONNECT_BY_ADRESS = 1, - DISCONNECT_BY_IP = 2, - DISCONNECT_ALL = 3 -}; - -extern xdag_hash_t g_xdag_mined_hashes[CONFIRMATIONS_COUNT]; -extern xdag_hash_t g_xdag_mined_nonce[CONFIRMATIONS_COUNT]; - -/* initialization of the pool */ -extern int xdag_initialize_pool(const char *pool_arg); - -/* gets pool parameters as a string, 0 - if the pool is disabled */ -extern char *xdag_pool_get_config(char *buf); - -/* sets pool parameters */ -extern int xdag_pool_set_config(const char *pool_config); - -/* output to the file a list of miners */ -extern int xdag_print_miners(FILE *out, int printOnlyConnections); - -// prints miner's stats -extern int xdag_print_miner_stats(const char* address, FILE *out); - -// disconnect connections by condition -// condition type: all, ip or address -// value: address of ip depending on type -extern void disconnect_connections(enum disconnect_type type, char *value); - -long double diff2log(xdag_diff_t diff); - -#endif +/* pool logic */ + +#ifndef XDAG_POOL_H +#define XDAG_POOL_H + +#include "hash.h" + +#define MAX_CONNECTIONS_COUNT 8192 +#define CONFIRMATIONS_COUNT 16 + +enum disconnect_type +{ + DISCONNECT_BY_ADRESS = 1, + DISCONNECT_BY_IP = 2, + DISCONNECT_ALL = 3 +}; + +extern xdag_hash_t g_xdag_mined_hashes[CONFIRMATIONS_COUNT]; +extern xdag_hash_t g_xdag_mined_nonce[CONFIRMATIONS_COUNT]; + +#ifdef __cplusplus +extern "C" { +#endif + +/* initialization of the pool */ +extern int xdag_initialize_pool(const char *pool_arg); + +/* gets pool parameters as a string, 0 - if the pool is disabled */ +extern char *xdag_pool_get_config(char *buf); + +/* sets pool parameters */ +extern int xdag_pool_set_config(const char *pool_config); + +/* output to the file a list of miners */ +extern int xdag_print_miners(FILE *out, int printOnlyConnections); + +// prints miner's stats +extern int xdag_print_miner_stats(const char* address, FILE *out); + +// disconnect connections by condition +// condition type: all, ip or address +// value: address of ip depending on type +extern void disconnect_connections(enum disconnect_type type, char *value); + +#ifdef __cplusplus +}; +#endif + +long double diff2log(xdag_diff_t diff); + +#endif diff --git a/client/storage.h b/client/storage.h index 9110053d..70a4ec0b 100644 --- a/client/storage.h +++ b/client/storage.h @@ -1,38 +1,46 @@ -/* локальное хранилище, T13.663-T13.788 $DVS:time$ */ - -#ifndef XDAG_STORAGE_H -#define XDAG_STORAGE_H - +/* локальное хранилище, T13.663-T13.788 $DVS:time$ */ + +#ifndef XDAG_STORAGE_H +#define XDAG_STORAGE_H + #include "block.h" -#define MULTI_THREAD_LOADING 0 /* flag to use multi-thread loading for storage files. */ - -struct xdag_storage_sum { - uint64_t sum; - uint64_t size; -}; - -/* Saves the block to local storage, returns its number or -1 in case of error */ -extern int64_t xdag_storage_save(const struct xdag_block *b); +#define MULTI_THREAD_LOADING 0 /* flag to use multi-thread loading for storage files. */ + +struct xdag_storage_sum { + uint64_t sum; + uint64_t size; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Saves the block to local storage, returns its number or -1 in case of error */ +extern int64_t xdag_storage_save(const struct xdag_block *b); /* init storage from hard disk with two threads, one is for preload all blocks, the other one to add blocks to rbtree */ extern void xdag_init_storage(xdag_time_t start_time, xdag_time_t end_time, void *data, void *(*callback)(void *block, void *data)); - -/* reads a block and its number from the local repository; writes it to the buffer or returns a permanent reference, 0 in case of error */ -extern struct xdag_block *xdag_storage_load(xdag_hash_t hash, xdag_time_t time, uint64_t pos, - struct xdag_block *buf); - -/* Calls a callback for all blocks from the repository that are in specified time interval; returns the number of blocks */ -extern uint64_t xdag_load_blocks(xdag_time_t start_time, xdag_time_t end_time, void *data, - void *(*callback)(void *block, void *data)); - -/* places the sums of blocks in 'sums' array, blocks are filtered by interval from start_time to end_time, splitted to 16 parts; - * end - start should be in form 16^k - * (original russian comment is unclear too) */ -extern int xdag_load_sums(xdag_time_t start_time, xdag_time_t end_time, struct xdag_storage_sum sums[16]); - -/* completes work with the storage */ -extern void xdag_storage_finish(void); - -#endif + +/* reads a block and its number from the local repository; writes it to the buffer or returns a permanent reference, 0 in case of error */ +extern struct xdag_block *xdag_storage_load(xdag_hash_t hash, xdag_time_t time, uint64_t pos, + struct xdag_block *buf); + +/* Calls a callback for all blocks from the repository that are in specified time interval; returns the number of blocks */ +extern uint64_t xdag_load_blocks(xdag_time_t start_time, xdag_time_t end_time, void *data, + void *(*callback)(void *block, void *data)); + +/* places the sums of blocks in 'sums' array, blocks are filtered by interval from start_time to end_time, splitted to 16 parts; + * end - start should be in form 16^k + * (original russian comment is unclear too) */ +extern int xdag_load_sums(xdag_time_t start_time, xdag_time_t end_time, struct xdag_storage_sum sums[16]); + +/* completes work with the storage */ +extern void xdag_storage_finish(void); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/client/sync.h b/client/sync.h index e1f1c04f..57152aa9 100644 --- a/client/sync.h +++ b/client/sync.h @@ -5,6 +5,10 @@ #include "block.h" +#ifdef __cplusplus +extern "C" { +#endif + /* checks a block and includes it in the database with synchronization, ruturs non-zero value in case of error */ extern int xdag_sync_add_block(struct xdag_block *b, void *conn); @@ -15,5 +19,9 @@ extern int xdag_sync_pop_block(struct xdag_block *b); extern int xdag_sync_init(void); extern int g_xdag_sync_on; + +#ifdef __cplusplus +}; +#endif #endif diff --git a/client/transport.h b/client/transport.h index 2c1d1b36..5913452f 100644 --- a/client/transport.h +++ b/client/transport.h @@ -1,56 +1,64 @@ -/* транспорт, T13.654-T13.788 $DVS:time$ */ - -#ifndef XDAG_TRANSPORT_H -#define XDAG_TRANSPORT_H - -#include -#include -#include -#include "block.h" -#include "storage.h" - -enum xdag_transport_flags { - XDAG_DAEMON = 1, -}; - -/* starts the transport system; bindto - ip:port for a socket for external connections - * addr-port_pairs - array of pointers to strings with parameters of other host for connection (ip:port), - * npairs - count of the strings - */ -extern int xdag_transport_start(int flags, const char *bindto, int npairs, const char **addr_port_pairs); - -/* generates an array with random data */ -extern int xdag_generate_random_array(void *array, unsigned long size); - -/* sends a new block to network */ -extern int xdag_send_new_block(struct xdag_block *b); - -/* requests all blocks from the remote host, that are in specified time interval; - * calls callback() for each block, callback received the block and data as paramenters; - * return -1 in case of error - */ -extern int xdag_request_blocks(xdag_time_t start_time, xdag_time_t end_time, void *data, - void *(*callback)(void *, void *)); - -/* requests a block by hash from another host */ -extern int xdag_request_block(xdag_hash_t hash, void *conn); - -/* requests a block from a remote host and places sums of blocks into 'sums' array, - * blocks are filtered by interval from start_time to end_time, splitted to 16 parts; - * end - start should be in form 16^k - * (original russian comment is unclear too) */ -extern int xdag_request_sums(xdag_time_t start_time, xdag_time_t end_time, struct xdag_storage_sum sums[16]); - -/* executes transport level command, out - stream to display the result of the command execution */ -extern int xdag_net_command(const char *cmd, void *out); - -/* sends the package, conn is the same as in function dnet_send_xdag_packet */ -extern int xdag_send_packet(struct xdag_block *b, void *conn); - -/* see dnet_user_crypt_action */ -extern int xdag_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action); - -extern pthread_mutex_t g_transport_mutex; -extern time_t g_xdag_last_received; - -#endif +/* транспорт, T13.654-T13.788 $DVS:time$ */ + +#ifndef XDAG_TRANSPORT_H +#define XDAG_TRANSPORT_H + +#include +#include +#include +#include "block.h" +#include "storage.h" + +enum xdag_transport_flags { + XDAG_DAEMON = 1, +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* starts the transport system; bindto - ip:port for a socket for external connections + * addr-port_pairs - array of pointers to strings with parameters of other host for connection (ip:port), + * npairs - count of the strings + */ +extern int xdag_transport_start(int flags, const char *bindto, int npairs, const char **addr_port_pairs); + +/* generates an array with random data */ +extern int xdag_generate_random_array(void *array, unsigned long size); + +/* sends a new block to network */ +extern int xdag_send_new_block(struct xdag_block *b); + +/* requests all blocks from the remote host, that are in specified time interval; + * calls callback() for each block, callback received the block and data as paramenters; + * return -1 in case of error + */ +extern int xdag_request_blocks(xdag_time_t start_time, xdag_time_t end_time, void *data, + void *(*callback)(void *, void *)); + +/* requests a block by hash from another host */ +extern int xdag_request_block(xdag_hash_t hash, void *conn); + +/* requests a block from a remote host and places sums of blocks into 'sums' array, + * blocks are filtered by interval from start_time to end_time, splitted to 16 parts; + * end - start should be in form 16^k + * (original russian comment is unclear too) */ +extern int xdag_request_sums(xdag_time_t start_time, xdag_time_t end_time, struct xdag_storage_sum sums[16]); + +/* executes transport level command, out - stream to display the result of the command execution */ +extern int xdag_net_command(const char *cmd, void *out); + +/* sends the package, conn is the same as in function dnet_send_xdag_packet */ +extern int xdag_send_packet(struct xdag_block *b, void *conn); + +/* see dnet_user_crypt_action */ +extern int xdag_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action); + +extern pthread_mutex_t g_transport_mutex; +extern time_t g_xdag_last_received; + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/client/utils/log.h b/client/utils/log.h index 72eef8ec..5c2c4a46 100644 --- a/client/utils/log.h +++ b/client/utils/log.h @@ -16,6 +16,10 @@ enum xdag_debug_levels { XDAG_TRACE, }; +#ifdef __cplusplus +extern "C" { +#endif + extern int xdag_log(int level, const char *format, ...); extern char *xdag_log_array(const void *arr, unsigned size); @@ -26,6 +30,10 @@ extern int xdag_log_init(void); // sets the maximum error level for output to the log, returns the previous level (0 - do not log anything, 9 - all) extern int xdag_set_log_level(int level); + +#ifdef __cplusplus +}; +#endif #define xdag_fatal(...) xdag_log(XDAG_FATAL , __VA_ARGS__) #define xdag_crit(...) xdag_log(XDAG_CRITICAL, __VA_ARGS__) diff --git a/client/utils/moving_statistics/moving_average.h b/client/utils/moving_statistics/moving_average.h index 6b134fe0..db05005d 100644 --- a/client/utils/moving_statistics/moving_average.h +++ b/client/utils/moving_statistics/moving_average.h @@ -20,8 +20,15 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. #define NSAMPLES_MAX 255 #endif +#ifdef __cplusplus +extern "C" { +#endif + long double moving_average(long double mean, long double sample, uint16_t nsamples); double moving_average_double(double mean, double sample, uint16_t nsamples); +#ifdef __cplusplus +}; +#endif #endif diff --git a/client/utils/utils.h b/client/utils/utils.h index 6d019874..b63ad449 100644 --- a/client/utils/utils.h +++ b/client/utils/utils.h @@ -19,6 +19,10 @@ #define DELIMITER "/" #endif +#ifdef __cplusplus +extern "C" { +#endif + extern uint64_t get_timestamp(void); extern void xdag_init_path(char *base); @@ -72,5 +76,9 @@ void xdag_time_to_string(xdag_time_t time, char *buf); // convert time_t to string representation // minimal length of string buffer `buf` should be 50 void time_to_string(time_t time, char* buf); + +#ifdef __cplusplus +}; +#endif #endif /* utils_h */ diff --git a/client/wallet.h b/client/wallet.h index 93a6b2b8..9019823a 100644 --- a/client/wallet.h +++ b/client/wallet.h @@ -10,6 +10,10 @@ struct xdag_public_key { uint64_t *pub; /* lowest bit contains parity */ }; +#ifdef __cplusplus +extern "C" { +#endif + /* initializes a wallet */ extern int xdag_wallet_init(void); @@ -25,4 +29,8 @@ extern struct xdag_public_key *xdag_wallet_our_keys(int *pnkeys); /* completes work with wallet */ extern void xdag_wallet_finish(void); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/dnet/dnet_command.c b/dnet/dnet_command.c index be2b91cd..c06c1c05 100644 --- a/dnet/dnet_command.c +++ b/dnet/dnet_command.c @@ -1,144 +1,144 @@ -/* dnet: commands; T11.261-T13.808; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#include -#include "dnet_command.h" -#include "dnet_database.h" -#include "dnet_packet.h" -#include "dnet_stream.h" -#include "dnet_files.h" +/* dnet: commands; T11.261-T13.808; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#include +#include "dnet_command.h" +#include "dnet_database.h" +#include "dnet_packet.h" +#include "dnet_stream.h" +#include "dnet_files.h" #include "dnet_main.h" -#include "../client/utils/utils.h" - -#define HISTORY_FILE "dnet_history.txt" - -static char *dnet_strtok_r(char *str, const char *delim, char **lasts) { - char *res0 = 0, *res; - int len = 0; - while ((res = strtok_r(str, delim, lasts))) { - str = 0; - if (res0) { - char *res1 = res0 + len; - while (res1 < res) *res1++ = ' '; - res = res0; - res0 = 0; - } - if (*res != '"') break; - len = strlen(res); - if (len > 1 && res[len - 1] == '"') { - res[len - 1] = 0; - res++; - break; - } - res0 = res; - } - return res ? res : res0; -} - -int dnet_command(const char *in, struct dnet_output *out) { - char *cmd, *lasts, inbuf[DNET_COMMAND_MAX]; - struct dnet_host *host; - FILE *f; +#include "../client/utils/utils.h" + +#define HISTORY_FILE "dnet_history.txt" + +static char *dnet_strtok_r(char *str, const char *delim, char **lasts) { + char *res0 = 0, *res; + int len = 0; + while ((res = strtok_r(str, delim, lasts))) { + str = 0; + if (res0) { + char *res1 = res0 + len; + while (res1 < res) *res1++ = ' '; + res = res0; + res0 = 0; + } + if (*res != '"') break; + len = strlen(res); + if (len > 1 && res[len - 1] == '"') { + res[len - 1] = 0; + res++; + break; + } + res0 = res; + } + return res ? res : res0; +} + +int dnet_command(const char *in, struct dnet_output *out) { + char *cmd, *lasts, inbuf[DNET_COMMAND_MAX]; + struct dnet_host *host; + FILE *f; int len; if (!(in && in[0]) || (strlen(in) >= DNET_COMMAND_MAX - 1)) return 0; - strcpy(inbuf, in); - cmd = inbuf; -begin: - while (*cmd && isspace(*cmd)) ++cmd; - len = strlen(cmd); - while (len && isspace(cmd[len - 1])) cmd[--len] = 0; - if (!*cmd) return 0; - f = xdag_open_file(HISTORY_FILE, "a"); - if (f) { - fprintf(f, "%s\n", cmd); - xdag_close_file(f); - } - cmd = strtok_r(cmd, " \t\r\n", &lasts); - if (!cmd) { - return 0; - } else if (!dnet_limited_version && !strcmp(cmd, "conn")) { - dnet_print_connections(out); - } else if (!dnet_limited_version && !strcmp(cmd, "connect")) { - char *host = dnet_strtok_r(0, " \t\r\n", &lasts); - if (!host) dnet_printf(out, "dnet: host is not given\n"); - else { - struct dnet_thread *thread = malloc(sizeof(struct dnet_thread) + strlen(host) + 1); - int res = 1; - if (thread) { - strcpy((char *)(thread + 1), host); - thread->arg = (char *)(thread + 1); - thread->conn.socket = -1; - thread->type = DNET_THREAD_CLIENT; - res = dnet_thread_create(thread); - if (res) res = res << 4 | 2; - } - if (res) dnet_printf(out, "dnet: can't connect (error %X)\n", res); - } - } else if (!strcmp(cmd, "connlimit")) { - char *str = strtok_r(0, " \t\r\n", &lasts); - if (!str) dnet_printf(out, "Connection limit: %d\n", g_conn_limit); - else if (sscanf(str, "%d", &g_conn_limit) != 1) - dnet_printf(out, "dnet: illegal parameter of the connlimit command\n"); - } else if (!strcmp(cmd, "copy")) { - char *from, *to; - int err = 0; - if (!(from = dnet_strtok_r(0, " \t\r\n", &lasts)) || !(to = dnet_strtok_r(0, " \t\r\n", &lasts)) - || (err = dnet_file_command(from, to, dnet_strtok_r(0, " \t\r\n", &lasts), out))) - dnet_printf(out, "dnet: illegal parameters of copy command (error %X)\n", err); - } else if (!strcmp(cmd, "help") || !strcmp(cmd , "?")) { - dnet_printf(out, - "Commands:\n" - ); - if (!dnet_limited_version) dnet_printf(out, - " conn - list connections\n" - " connect ip:port - connect to this host\n" - " connlimit [] - print of set the inbound connection limit\n" - ); - dnet_printf(out, - " help, ? - print this help\n" - " history [] - print last N commands (20 by default)\n" - " host [] - print brief information about the host (the current host by default)\n" - ); - if (!dnet_limited_version) dnet_printf(out, - " hosts [-a|-d|-h] - list active [all|daily|hourly] hosts\n" - ); - } else if (!strcmp(cmd, "history")) { - char *arg; - int N = 20; - if ((arg = strtok_r(0, " \t\r\n", &lasts))) sscanf(arg, "%d", &N); - sprintf(inbuf, "tail -n %u " HISTORY_FILE, N); - cmd = inbuf; goto begin; - } else if (!strcmp(cmd, "host")) { - char *name; - if ((name = strtok_r(0, " \t\r\n", &lasts))) { - host = dnet_get_host_by_name(name); - if (!host) { - dnet_printf(out, "dnet: unknown host\n"); - return 1; - } - } else host = dnet_get_self_host(); - dnet_print_host_brief(host, out); - } else if (!dnet_limited_version && !strcmp(cmd, "hosts")) { - char *arg; - if ((arg = strtok_r(0, " \t\r\n", &lasts))) { - if (!strcmp(arg, "-a")) dnet_print_hosts(out, LONG_MAX); - else if (!strcmp(arg, "-d")) dnet_print_hosts(out, 3600*24); - else if (!strcmp(arg, "-h")) dnet_print_hosts(out, 3600); - else dnet_printf(out, "dnet: illegal parameter\n"); - } else dnet_print_hosts(out, DNET_ACTIVE_PERIOD); - } - return 0; -} - -int dnet_execute_command(const char *cmd, void *fileout) { - struct dnet_output out; - memset(&out, 0, sizeof(out)); - out.f = (FILE *)fileout; - return dnet_command(cmd, &out); -} + strcpy(inbuf, in); + cmd = inbuf; +begin: + while (*cmd && isspace(*cmd)) ++cmd; + len = strlen(cmd); + while (len && isspace(cmd[len - 1])) cmd[--len] = 0; + if (!*cmd) return 0; + f = xdag_open_file(HISTORY_FILE, "a"); + if (f) { + fprintf(f, "%s\n", cmd); + xdag_close_file(f); + } + cmd = strtok_r(cmd, " \t\r\n", &lasts); + if (!cmd) { + return 0; + } else if (!dnet_limited_version && !strcmp(cmd, "conn")) { + dnet_print_connections(out); + } else if (!dnet_limited_version && !strcmp(cmd, "connect")) { + char *host = dnet_strtok_r(0, " \t\r\n", &lasts); + if (!host) dnet_printf(out, "dnet: host is not given\n"); + else { + struct dnet_thread *thread = malloc(sizeof(struct dnet_thread) + strlen(host) + 1); + int res = 1; + if (thread) { + strcpy((char *)(thread + 1), host); + thread->arg = (char *)(thread + 1); + thread->conn.socket = -1; + thread->type = DNET_THREAD_CLIENT; + res = dnet_thread_create(thread); + if (res) res = res << 4 | 2; + } + if (res) dnet_printf(out, "dnet: can't connect (error %X)\n", res); + } + } else if (!strcmp(cmd, "connlimit")) { + char *str = strtok_r(0, " \t\r\n", &lasts); + if (!str) dnet_printf(out, "Connection limit: %d\n", g_conn_limit); + else if (sscanf(str, "%d", &g_conn_limit) != 1) + dnet_printf(out, "dnet: illegal parameter of the connlimit command\n"); + } else if (!strcmp(cmd, "copy")) { + char *from, *to; + int err = 0; + if (!(from = dnet_strtok_r(0, " \t\r\n", &lasts)) || !(to = dnet_strtok_r(0, " \t\r\n", &lasts)) + || (err = dnet_file_command(from, to, dnet_strtok_r(0, " \t\r\n", &lasts), out))) + dnet_printf(out, "dnet: illegal parameters of copy command (error %X)\n", err); + } else if (!strcmp(cmd, "help") || !strcmp(cmd , "?")) { + dnet_printf(out, + "Commands:\n" + ); + if (!dnet_limited_version) dnet_printf(out, + " conn - list connections\n" + " connect ip:port - connect to this host\n" + " connlimit [] - print of set the inbound connection limit\n" + ); + dnet_printf(out, + " help, ? - print this help\n" + " history [] - print last N commands (20 by default)\n" + " host [] - print brief information about the host (the current host by default)\n" + ); + if (!dnet_limited_version) dnet_printf(out, + " hosts [-a|-d|-h] - list active [all|daily|hourly] hosts\n" + ); + } else if (!strcmp(cmd, "history")) { + char *arg; + int N = 20; + if ((arg = strtok_r(0, " \t\r\n", &lasts))) sscanf(arg, "%d", &N); + sprintf(inbuf, "tail -n %u " HISTORY_FILE, N); + cmd = inbuf; goto begin; + } else if (!strcmp(cmd, "host")) { + char *name; + if ((name = strtok_r(0, " \t\r\n", &lasts))) { + host = dnet_get_host_by_name(name); + if (!host) { + dnet_printf(out, "dnet: unknown host\n"); + return 1; + } + } else host = dnet_get_self_host(); + dnet_print_host_brief(host, out); + } else if (!dnet_limited_version && !strcmp(cmd, "hosts")) { + char *arg; + if ((arg = strtok_r(0, " \t\r\n", &lasts))) { + if (!strcmp(arg, "-a")) dnet_print_hosts(out, LONG_MAX); + else if (!strcmp(arg, "-d")) dnet_print_hosts(out, 3600*24); + else if (!strcmp(arg, "-h")) dnet_print_hosts(out, 3600); + else dnet_printf(out, "dnet: illegal parameter\n"); + } else dnet_print_hosts(out, DNET_ACTIVE_PERIOD); + } + return 0; +} + +int dnet_execute_command(const char *cmd, void *fileout) { + struct dnet_output out; + memset(&out, 0, sizeof(out)); + out.f = (FILE *)fileout; + return dnet_command(cmd, &out); +} diff --git a/dnet/dnet_command.h b/dnet/dnet_command.h index a3c1e9b3..0dbb698b 100644 --- a/dnet/dnet_command.h +++ b/dnet/dnet_command.h @@ -1,21 +1,21 @@ -/* dnet: commands; T11.261-T13.013; $DVS:time$ */ - -#ifndef DNET_COMMAND_H_INCLUDED -#define DNET_COMMAND_H_INCLUDED - -#include "dnet_log.h" -#include "dnet_packet.h" - -#define DNET_COMMAND_MAX DNET_PKT_STREAM_DATA_MAX - -#ifdef __cplusplus -extern "C" { -#endif - -extern int dnet_command(const char *in, struct dnet_output *out); - -#ifdef __cplusplus -} -#endif - -#endif +/* dnet: commands; T11.261-T13.013; $DVS:time$ */ + +#ifndef DNET_COMMAND_H_INCLUDED +#define DNET_COMMAND_H_INCLUDED + +#include "dnet_log.h" +#include "dnet_packet.h" + +#define DNET_COMMAND_MAX DNET_PKT_STREAM_DATA_MAX + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_command(const char *in, struct dnet_output *out); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dnet/dnet_connection.c b/dnet/dnet_connection.c index a582a2c6..218877f8 100644 --- a/dnet/dnet_connection.c +++ b/dnet/dnet_connection.c @@ -1,191 +1,191 @@ -/* dnet: connections; T11.253-T13.852; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#include -#if defined(_WIN32) || defined(_WIN64) -#include -#if defined(_WIN64) -#define poll WSAPoll -#else -#define poll(a,b,c) ((a)->revents = (a)->events, (b)) -#endif -#else -#include -#endif -#include "dnet_connection.h" -#include "dnet_packet.h" -#include "dnet_threads.h" - -static ssize_t dnet_conn_read(void *private_data, void *buf, size_t size) { - struct dnet_connection *conn = (struct dnet_connection *)private_data; - struct dnet_packet *p = (struct dnet_packet *)conn->buf; - ssize_t res = 0; - size_t todo, packet_size; - while (size) { - if (!conn->buf_pos) packet_size = 1; - else if (conn->buf_pos < sizeof(struct dnet_packet_header)) packet_size = sizeof(struct dnet_packet_header); - else packet_size = p->header.length; - todo = packet_size - conn->buf_pos; - if (todo > size) todo = size; - memcpy(conn->buf + conn->buf_pos, buf, todo); - conn->buf_pos += todo; - buf = (uint8_t *)buf + todo; - size -= todo; - res += todo; - if (conn->buf_pos == packet_size) { - if (packet_size == 1) { - if (p->header.type < DNET_PKT_MIN || p->header.type > DNET_PKT_MAX) conn->buf_pos = 0; - } else if (packet_size == sizeof(struct dnet_packet_header)) { - if (p->header.length <= sizeof(struct dnet_packet_header) || p->header.length > sizeof(conn->buf)) conn->buf_pos = 0; - } else { - int err; - conn->counters[DNET_C_IN_PACKETS]++; - if ((err = dnet_process_packet(p, conn))) { - conn->counters[DNET_C_IN_DROPPED]++; - dnet_log_printf("incoming packet (%08X,%08X,%08X,%08X...) dropped, reason = %X\n", - ((uint32_t *)p)[0], ((uint32_t *)p)[1], ((uint32_t *)p)[2], ((uint32_t *)p)[3], err); - } - conn->buf_pos = 0; - } - } - } - return res; -} - -static ssize_t dnet_conn_write(void *private_data, void *buf, size_t size) { - struct dnet_connection *conn = (struct dnet_connection *)private_data; - ssize_t res = 0; - if (conn->socket < 0) return -1l; - while (size) { - struct pollfd fd; - fd.fd = conn->socket; - fd.events = POLLOUT; - fd.revents = 0; - if (poll(&fd, 1, 16000) != 1 || !(fd.revents & POLLOUT)) { - dnet_log_printf("dnet: write poll failed for socket %d\n", conn->socket); - shutdown(conn->socket, SHUT_RDWR); - return -1l; - } - ssize_t done = write(conn->socket, buf, size); - if (done < 0) break; - res += done; - size -= done; - buf = (uint8_t *)buf + done; - conn->counters[DNET_C_OUT_BYTES] += done; - } - return res; -} - -static const struct dnet_session_ops dnet_conn_ops = { - &dnet_conn_read, - &dnet_conn_write, -}; - -static inline ssize_t dnet_socket_read(int fd, void *buf, size_t size) { -#ifdef __LDuS__ - return read(fd, buf, size); -#else - time_t te = time(0) + DNET_UPDATE_PERIOD * 3 / 2, t; - while ((t = time(0)) < te) { - struct pollfd pfd; - pfd.fd = fd; - pfd.events = POLLIN; - if (poll(&pfd, 1, (te - t) * 1000) == 1 && (pfd.revents & POLLIN)) { - return read(fd, buf, size); - } - } - dnet_log_printf("dnet: read poll failed for socket %d\n", fd); - return -1; -#endif -} - -int dnet_connection_main(struct dnet_connection *conn) { - struct dnet_thread *thread = 0; - char buf[0x1000]; - ssize_t size; - int res = 0; - conn->buf_pos = 0; - conn->is_new = 0; - memset(conn->counters, 0, DNET_C_END * sizeof(uint64_t)); - conn->sess = dnet_session_create(conn, &dnet_conn_ops, conn->ipaddr, conn->port); - if (!conn->sess) { res = 1; goto end; } - conn->creation_time = conn->last_active_time = time(0); - res = dnet_session_init(conn->sess); - if (res) { res = res * 10 + 2; goto end; } - while ((size = dnet_socket_read(conn->socket, buf, 0x1000)) > 0) { - conn->last_active_time = time(0); - conn->counters[DNET_C_IN_BYTES] += size; - dnet_session_read(conn->sess, buf, size); - if (conn->counters[DNET_C_IN_BYTES] >= sizeof(struct dnet_key) + 512 - && conn->counters[DNET_C_IN_BYTES] - size < sizeof(struct dnet_key) + 512) { - conn->is_new = 1; - thread = malloc(sizeof(struct dnet_thread)); - if (!thread) { res = 3; goto end; } - thread->arg = (const char *)conn; - thread->conn.socket = -1; - thread->type = DNET_THREAD_EXCHANGER; - res = dnet_thread_create(thread); - if (res) { - thread->to_remove = 1; - res = 4; - goto end; - } - } - } - res = (int)size * 10 + 4; -end: - if (thread) { - thread->arg = 0; - } - if (conn->sess) { - dthread_mutex_lock(&conn->mutex); - if (conn->sess) { - struct dnet_host *host = dnet_session_get_host(conn->sess); - if (host && host->route_type == DNET_ROUTE_IMMEDIATE) - host->route_type = DNET_ROUTE_AUTO; - free(conn->sess); - conn->sess = 0; - } - dthread_mutex_unlock(&conn->mutex); - } - return res; -} - -struct dnet_traverse_conn { - int (*callback)(struct dnet_connection *conn, void *data); - void *data; -}; - -static int dnet_traverse_conn_callback(struct dnet_thread *t, void *data) { - if ((t->type == DNET_THREAD_CLIENT || t->type == DNET_THREAD_ACCEPTED) && t->conn.sess) { - struct dnet_traverse_conn *dtc = (struct dnet_traverse_conn *)data; - return (*dtc->callback)(&t->conn, dtc->data); - } else return 0; -} - -int dnet_traverse_connections(int (*callback)(struct dnet_connection *conn, void *data), void *data) { - struct dnet_traverse_conn dtc; - dtc.callback = callback; - dtc.data = data; - return dnet_traverse_threads(&dnet_traverse_conn_callback, &dtc); -} - -int dnet_print_connection(struct dnet_connection *conn, struct dnet_output *out) { - char buf[32]; - int len; - sprintf(buf, "%d.%d.%d.%d:%d", conn->ipaddr >> 24 & 0xFF, conn->ipaddr >> 16 & 0xFF, conn->ipaddr >> 8 & 0xFF, conn->ipaddr & 0xFF, conn->port); - len = strlen(buf); - dnet_printf(out, " %2d. %s%*d sec, %lld/%lld in/out bytes, %lld/%lld packets, %lld/%lld dropped\n", - out->count, buf, 28 - len, (int)(time(0) - conn->creation_time), - (long long)conn->counters[DNET_C_IN_BYTES], (long long)conn->counters[DNET_C_OUT_BYTES], - (long long)conn->counters[DNET_C_IN_PACKETS], (long long)conn->counters[DNET_C_OUT_PACKETS], - (long long)conn->counters[DNET_C_IN_DROPPED], (long long)conn->counters[DNET_C_OUT_DROPPED] - ); - out->count++; - return 0; -} +/* dnet: connections; T11.253-T13.852; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) || defined(_WIN64) +#include +#if defined(_WIN64) +#define poll WSAPoll +#else +#define poll(a,b,c) ((a)->revents = (a)->events, (b)) +#endif +#else +#include +#endif +#include "dnet_connection.h" +#include "dnet_packet.h" +#include "dnet_threads.h" + +static ssize_t dnet_conn_read(void *private_data, void *buf, size_t size) { + struct dnet_connection *conn = (struct dnet_connection *)private_data; + struct dnet_packet *p = (struct dnet_packet *)conn->buf; + ssize_t res = 0; + size_t todo, packet_size; + while (size) { + if (!conn->buf_pos) packet_size = 1; + else if (conn->buf_pos < sizeof(struct dnet_packet_header)) packet_size = sizeof(struct dnet_packet_header); + else packet_size = p->header.length; + todo = packet_size - conn->buf_pos; + if (todo > size) todo = size; + memcpy(conn->buf + conn->buf_pos, buf, todo); + conn->buf_pos += todo; + buf = (uint8_t *)buf + todo; + size -= todo; + res += todo; + if (conn->buf_pos == packet_size) { + if (packet_size == 1) { + if (p->header.type < DNET_PKT_MIN || p->header.type > DNET_PKT_MAX) conn->buf_pos = 0; + } else if (packet_size == sizeof(struct dnet_packet_header)) { + if (p->header.length <= sizeof(struct dnet_packet_header) || p->header.length > sizeof(conn->buf)) conn->buf_pos = 0; + } else { + int err; + conn->counters[DNET_C_IN_PACKETS]++; + if ((err = dnet_process_packet(p, conn))) { + conn->counters[DNET_C_IN_DROPPED]++; + dnet_log_printf("incoming packet (%08X,%08X,%08X,%08X...) dropped, reason = %X\n", + ((uint32_t *)p)[0], ((uint32_t *)p)[1], ((uint32_t *)p)[2], ((uint32_t *)p)[3], err); + } + conn->buf_pos = 0; + } + } + } + return res; +} + +static ssize_t dnet_conn_write(void *private_data, void *buf, size_t size) { + struct dnet_connection *conn = (struct dnet_connection *)private_data; + ssize_t res = 0; + if (conn->socket < 0) return -1l; + while (size) { + struct pollfd fd; + fd.fd = conn->socket; + fd.events = POLLOUT; + fd.revents = 0; + if (poll(&fd, 1, 16000) != 1 || !(fd.revents & POLLOUT)) { + dnet_log_printf("dnet: write poll failed for socket %d\n", conn->socket); + shutdown(conn->socket, SHUT_RDWR); + return -1l; + } + ssize_t done = write(conn->socket, buf, size); + if (done < 0) break; + res += done; + size -= done; + buf = (uint8_t *)buf + done; + conn->counters[DNET_C_OUT_BYTES] += done; + } + return res; +} + +static const struct dnet_session_ops dnet_conn_ops = { + &dnet_conn_read, + &dnet_conn_write, +}; + +static inline ssize_t dnet_socket_read(int fd, void *buf, size_t size) { +#ifdef __LDuS__ + return read(fd, buf, size); +#else + time_t te = time(0) + DNET_UPDATE_PERIOD * 3 / 2, t; + while ((t = time(0)) < te) { + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + if (poll(&pfd, 1, (te - t) * 1000) == 1 && (pfd.revents & POLLIN)) { + return read(fd, buf, size); + } + } + dnet_log_printf("dnet: read poll failed for socket %d\n", fd); + return -1; +#endif +} + +int dnet_connection_main(struct dnet_connection *conn) { + struct dnet_thread *thread = 0; + char buf[0x1000]; + ssize_t size; + int res = 0; + conn->buf_pos = 0; + conn->is_new = 0; + memset(conn->counters, 0, DNET_C_END * sizeof(uint64_t)); + conn->sess = dnet_session_create(conn, &dnet_conn_ops, conn->ipaddr, conn->port); + if (!conn->sess) { res = 1; goto end; } + conn->creation_time = conn->last_active_time = time(0); + res = dnet_session_init(conn->sess); + if (res) { res = res * 10 + 2; goto end; } + while ((size = dnet_socket_read(conn->socket, buf, 0x1000)) > 0) { + conn->last_active_time = time(0); + conn->counters[DNET_C_IN_BYTES] += size; + dnet_session_read(conn->sess, buf, size); + if (conn->counters[DNET_C_IN_BYTES] >= sizeof(struct dnet_key) + 512 + && conn->counters[DNET_C_IN_BYTES] - size < sizeof(struct dnet_key) + 512) { + conn->is_new = 1; + thread = malloc(sizeof(struct dnet_thread)); + if (!thread) { res = 3; goto end; } + thread->arg = (const char *)conn; + thread->conn.socket = -1; + thread->type = DNET_THREAD_EXCHANGER; + res = dnet_thread_create(thread); + if (res) { + thread->to_remove = 1; + res = 4; + goto end; + } + } + } + res = (int)size * 10 + 4; +end: + if (thread) { + thread->arg = 0; + } + if (conn->sess) { + dthread_mutex_lock(&conn->mutex); + if (conn->sess) { + struct dnet_host *host = dnet_session_get_host(conn->sess); + if (host && host->route_type == DNET_ROUTE_IMMEDIATE) + host->route_type = DNET_ROUTE_AUTO; + free(conn->sess); + conn->sess = 0; + } + dthread_mutex_unlock(&conn->mutex); + } + return res; +} + +struct dnet_traverse_conn { + int (*callback)(struct dnet_connection *conn, void *data); + void *data; +}; + +static int dnet_traverse_conn_callback(struct dnet_thread *t, void *data) { + if ((t->type == DNET_THREAD_CLIENT || t->type == DNET_THREAD_ACCEPTED) && t->conn.sess) { + struct dnet_traverse_conn *dtc = (struct dnet_traverse_conn *)data; + return (*dtc->callback)(&t->conn, dtc->data); + } else return 0; +} + +int dnet_traverse_connections(int (*callback)(struct dnet_connection *conn, void *data), void *data) { + struct dnet_traverse_conn dtc; + dtc.callback = callback; + dtc.data = data; + return dnet_traverse_threads(&dnet_traverse_conn_callback, &dtc); +} + +int dnet_print_connection(struct dnet_connection *conn, struct dnet_output *out) { + char buf[32]; + int len; + sprintf(buf, "%d.%d.%d.%d:%d", conn->ipaddr >> 24 & 0xFF, conn->ipaddr >> 16 & 0xFF, conn->ipaddr >> 8 & 0xFF, conn->ipaddr & 0xFF, conn->port); + len = strlen(buf); + dnet_printf(out, " %2d. %s%*d sec, %lld/%lld in/out bytes, %lld/%lld packets, %lld/%lld dropped\n", + out->count, buf, 28 - len, (int)(time(0) - conn->creation_time), + (long long)conn->counters[DNET_C_IN_BYTES], (long long)conn->counters[DNET_C_OUT_BYTES], + (long long)conn->counters[DNET_C_IN_PACKETS], (long long)conn->counters[DNET_C_OUT_PACKETS], + (long long)conn->counters[DNET_C_IN_DROPPED], (long long)conn->counters[DNET_C_OUT_DROPPED] + ); + out->count++; + return 0; +} diff --git a/dnet/dnet_connection.h b/dnet/dnet_connection.h index b090db92..d2c1ec61 100644 --- a/dnet/dnet_connection.h +++ b/dnet/dnet_connection.h @@ -1,43 +1,51 @@ -/* dnet: connections; T11.253-T13.093; $DVS:time$ */ - -#ifndef DNET_CONNECTION_H_INCLUDED -#define DNET_CONNECTION_H_INCLUDED - -#include -#include "dthread.h" -#include "dnet_crypt.h" -#include "dnet_packet.h" -#include "dnet_log.h" - -enum dnet_counters { - DNET_C_IN_BYTES, - DNET_C_OUT_BYTES, - DNET_C_IN_PACKETS, - DNET_C_OUT_PACKETS, - DNET_C_IN_DROPPED, - DNET_C_OUT_DROPPED, - DNET_C_END, -}; - -#define DNET_CONN_BUF_SIZE (sizeof(struct dnet_packet)) - -struct dnet_connection { - dthread_mutex_t mutex; - struct dnet_session *sess; - int socket; - unsigned buf_pos; - uint32_t ipaddr; - uint16_t port; - uint64_t counters[DNET_C_END]; - char buf[DNET_CONN_BUF_SIZE]; - time_t creation_time; - time_t last_active_time; - time_t last_host_exchange_time; - uint8_t is_new; -}; - -extern int dnet_connection_main(struct dnet_connection *conn); -extern int dnet_traverse_connections(int (*callback)(struct dnet_connection *conn, void *data), void *data); -extern int dnet_print_connection(struct dnet_connection *conn, struct dnet_output *out); - -#endif +/* dnet: connections; T11.253-T13.093; $DVS:time$ */ + +#ifndef DNET_CONNECTION_H_INCLUDED +#define DNET_CONNECTION_H_INCLUDED + +#include +#include "dthread.h" +#include "dnet_crypt.h" +#include "dnet_packet.h" +#include "dnet_log.h" + +enum dnet_counters { + DNET_C_IN_BYTES, + DNET_C_OUT_BYTES, + DNET_C_IN_PACKETS, + DNET_C_OUT_PACKETS, + DNET_C_IN_DROPPED, + DNET_C_OUT_DROPPED, + DNET_C_END, +}; + +#define DNET_CONN_BUF_SIZE (sizeof(struct dnet_packet)) + +struct dnet_connection { + dthread_mutex_t mutex; + struct dnet_session *sess; + int socket; + unsigned buf_pos; + uint32_t ipaddr; + uint16_t port; + uint64_t counters[DNET_C_END]; + char buf[DNET_CONN_BUF_SIZE]; + time_t creation_time; + time_t last_active_time; + time_t last_host_exchange_time; + uint8_t is_new; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_connection_main(struct dnet_connection *conn); +extern int dnet_traverse_connections(int (*callback)(struct dnet_connection *conn, void *data), void *data); +extern int dnet_print_connection(struct dnet_connection *conn, struct dnet_output *out); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_crypt.c b/dnet/dnet_crypt.c index 0c82696e..702988f6 100644 --- a/dnet/dnet_crypt.c +++ b/dnet/dnet_crypt.c @@ -1,413 +1,413 @@ -/* dnet: crypt; T11.231-T13.806; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include "system.h" -#include "../dus/programs/dfstools/source/dfslib/dfslib_random.h" -#include "../dus/programs/dfstools/source/dfslib/dfslib_crypt.h" -#include "../dus/programs/dfstools/source/dfslib/dfslib_string.h" -#include "../dus/programs/dar/source/include/crc.h" -#include "dnet_database.h" -#include "dnet_crypt.h" +/* dnet: crypt; T11.231-T13.806; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include "system.h" +#include "../dus/programs/dfstools/source/dfslib/dfslib_random.h" +#include "../dus/programs/dfstools/source/dfslib/dfslib_crypt.h" +#include "../dus/programs/dfstools/source/dfslib/dfslib_string.h" +#include "../dus/programs/dar/source/include/crc.h" +#include "dnet_database.h" +#include "dnet_crypt.h" #include "dnet_main.h" -#include "../client/utils/utils.h" - -#define KEYFILE "dnet_key.dat" -#define PWDLEN 64 -#define SECTOR_LOG 9 -#define SECTOR_SIZE (1 << SECTOR_LOG) -#define KEYLEN_MIN (DNET_KEYLEN / 4) - -#if !defined(_WIN32) && !defined(_WIN64) -extern int gethostname(char *name, size_t namelen); -extern int getlogin_r(char *name, size_t namesize); -#else -#define gethostname(n, l) strncpy(n, "localhost", l) -#define getlogin_r(n, l) strncpy(n, "Administrator", l) -#endif - -struct dnet_keys { - struct dnet_key priv; - struct dnet_key pub; -}; - -struct dnet_keys *g_dnet_keys; -static struct dfslib_crypt *g_dnet_user_crypt = 0; - -struct dnet_session { - struct dnet_key key; - uint32_t sector_write[SECTOR_SIZE / 4]; - uint32_t sector_read[SECTOR_SIZE / 4]; - struct dfslib_crypt crypt_write; - struct dfslib_crypt crypt_read; - uint64_t pos_write, pos_read; - struct dnet_host *host; - const struct dnet_session_ops *ops; - void *private_data; - uint32_t route_ip; - uint32_t route_port; -}; - -int dnet_limited_version = 0; -static int g_keylen = 0; - -static int input_password(const char *prompt, char *buf, unsigned len) { - struct termios t[1]; - int noecho = !!strstr(prompt, "assword"); - printf("%s: ", prompt); fflush(stdout); - if (noecho) { - tcgetattr(0, t); - t->c_lflag &= ~ECHO; - tcsetattr(0, TCSANOW, t); - } - fgets(buf, len, stdin); - if (noecho) { - t->c_lflag |= ECHO; - tcsetattr(0, TCSANOW, t); - printf("\n"); - } - len = strlen(buf); - if (len && buf[len - 1] == '\n') buf[len - 1] = 0; - return 0; -} - -static int(*g_input_password)(const char *prompt, char *buf, unsigned size) = &input_password; - -static void dnet_make_key(dfsrsa_t *key, int keylen) { - unsigned i; - for (i = keylen; i < DNET_KEYLEN; i += keylen) - memcpy(key + i, key, keylen * sizeof(dfsrsa_t)); -} - -static int dnet_detect_keylen(dfsrsa_t *key, int keylen) { - if (g_keylen && (key == g_dnet_keys->priv.key || key == g_dnet_keys->pub.key)) - return g_keylen; - while (keylen >= 8) { - if (memcmp(key, key + keylen / 2, keylen * sizeof(dfsrsa_t) / 2)) break; - keylen /= 2; - } - return keylen; -} - -static int dnet_rsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen) { - return dfsrsa_crypt(data, datalen, key, dnet_detect_keylen(key, keylen)); -} - -#define dfsrsa_crypt dnet_rsa_crypt - -static void dnet_sector_to_password(uint32_t sector[SECTOR_SIZE / 4], char password[PWDLEN + 1]) { - int i; - for (i = 0; i < PWDLEN / 8; ++i) { - unsigned crc = crc_of_array((unsigned char *)(sector + i * SECTOR_SIZE / 4 / (PWDLEN / 8)), SECTOR_SIZE / (PWDLEN / 8)); - sprintf(password + 8 * i, "%08X", crc); - } -} - -static void dnet_random_sector(uint32_t sector[SECTOR_SIZE / 4]) { - char password[PWDLEN + 1] = "Iyf&%d#$jhPo_t|3fgd+hf(s@;)F5D7gli^kjtrd%.kflP(7*5gt;Y1sYRC4VGL&"; - int i, j; - for (i = 0; i < 3; ++i) { - struct dfslib_string str; - dfslib_utf8_string(&str, password, PWDLEN); - dfslib_random_sector(sector, 0, &str, &str); - for (j = KEYLEN_MIN / 8; j <= SECTOR_SIZE / 4; j += KEYLEN_MIN / 8) - sector[j - 1] &= 0x7FFFFFFF; - if (i == 2) break; - dfsrsa_crypt((dfsrsa_t *)sector, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN); - dnet_sector_to_password(sector, password); - } -} - -int dnet_generate_random_array(void *array, unsigned long size) { - uint32_t sector[SECTOR_SIZE / 4]; - unsigned long i; - if (size < 4 || size & (size - 1)) return -1; - if (size >= 512) { - for (i = 0; i < size; i += 512) dnet_random_sector((uint32_t *)((uint8_t *)array + i)); - } else { - dnet_random_sector(sector); - for (i = 0; i < size; i += 4) { - *(uint32_t *)((uint8_t *)array + i) = crc_of_array((unsigned char *)sector + i * 512 / size, 512 / size); - } - } - return 0; -} - -void dnet_generate_stream_id(struct dnet_stream_id *id) { - dnet_generate_random_array(id, sizeof(struct dnet_stream_id)); -} - -static int dnet_test_keys(void) { - uint32_t src[SECTOR_SIZE / 4], dest[SECTOR_SIZE / 4]; - dnet_random_sector(src); - memcpy(dest, src, SECTOR_SIZE); - if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN)) return 1; - if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->pub.key, DNET_KEYLEN)) return 2; - if (memcmp(dest, src, SECTOR_SIZE)) return 3; - memcpy(dest, src, SECTOR_SIZE); - if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->pub.key, DNET_KEYLEN)) return 4; - if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN)) return 5; - if (memcmp(dest, src, SECTOR_SIZE)) return 6; - return 0; -} - -static int set_user_crypt(struct dfslib_string *pwd) { - uint32_t sector0[128]; - int i; - g_dnet_user_crypt = malloc(sizeof(struct dfslib_crypt)); - if (!g_dnet_user_crypt) return -1; - memset(g_dnet_user_crypt->pwd, 0, sizeof(g_dnet_user_crypt->pwd)); - dfslib_crypt_set_password(g_dnet_user_crypt, pwd); - for (i = 0; i < 128; ++i) sector0[i] = 0x4ab29f51u + i * 0xc3807e6du; - for (i = 0; i < 128; ++i) { - dfslib_crypt_set_sector0(g_dnet_user_crypt, sector0); - dfslib_encrypt_sector(g_dnet_user_crypt, sector0, 0x3e9c1d624a8b570full + i * 0x9d2e61fc538704abull); - } - return 0; -} - -/* - * 1 - to encode data (data _ id, serial number data and size data measured in 32 - bit words) - * 2 - decode - * 3 - password and check it returns 0 on success - * 4 - password and write print array data of length 16 bytes - * 5 - to verify that the pattern in the data corresponds to the password - * 6 - setup callback function to input password, data is pointer to function - * int (*)(const char *prompt, char *buf, unsigned size); - */ -int dnet_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action) { - if (action != 4 && action != 6 && !g_dnet_user_crypt) return 0; - switch (action) { - case 1: - dfslib_encrypt_array(g_dnet_user_crypt, data, size, data_id); - break; - case 2: - dfslib_uncrypt_array(g_dnet_user_crypt, data, size, data_id); - break; - case 3: - { - struct dfslib_crypt *crypt = malloc(sizeof(struct dfslib_crypt)); - struct dfslib_string str; - char pwd[256]; - int res; - if (!crypt) return -1; - memset(pwd, 0, 256); - memset(&str, 0, sizeof(struct dfslib_string)); - (*g_input_password)("Password", pwd, 256); - dfslib_utf8_string(&str, pwd, strlen(pwd)); - memset(crypt->pwd, 0, sizeof(crypt->pwd)); - crypt->ispwd = 0; - dfslib_crypt_set_password(crypt, &str); - res = (g_dnet_user_crypt->ispwd == crypt->ispwd - && !memcmp(g_dnet_user_crypt->pwd, crypt->pwd, sizeof(crypt->pwd))); - free(crypt); - return res ? 0 : -1; - } - case 4: - { - struct dfslib_crypt *crypt = malloc(sizeof(struct dfslib_crypt)); - struct dfslib_string str; - char pwd[256]; - memset(pwd, 0, 256); - memset(&str, 0, sizeof(struct dfslib_string)); - (*g_input_password)("Password", pwd, 256); - dfslib_utf8_string(&str, pwd, strlen(pwd)); - memset(crypt->pwd, 0, sizeof(crypt->pwd)); - dfslib_crypt_set_password(crypt, &str); - memcpy(data, crypt->pwd, sizeof(crypt->pwd)); - free(crypt); - return 0; - } - case 5: - return memcmp(g_dnet_user_crypt->pwd, data, sizeof(g_dnet_user_crypt->pwd)) ? -1 : 0; - case 6: - g_input_password = (int(*)(const char *, char *, unsigned))(void *)data; - return 0; - default: return -1; - } - return 0; -} - -int dnet_crypt_init(const char *version) { - FILE *f; - struct dnet_keys *keys; - struct dnet_host *host; - int i; - g_dnet_keys = malloc(sizeof(struct dnet_keys)); - if (!g_dnet_keys) return 1; - keys = g_dnet_keys; - dfslib_random_init(); - if (crc_init()) return 2; - f = xdag_open_file(KEYFILE, "rb"); - if (f) { - if (fread(keys, sizeof(struct dnet_keys), 1, f) != 1) xdag_close_file(f), f = 0; - else { - g_keylen = dnet_detect_keylen(keys->pub.key, DNET_KEYLEN); - if (dnet_test_keys()) { - struct dfslib_string str; - char pwd[256]; - (*g_input_password)("Password", pwd, 256); - dfslib_utf8_string(&str, pwd, strlen(pwd)); - set_user_crypt(&str); - if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) - dfslib_uncrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); - g_keylen = 0; - g_keylen = dnet_detect_keylen(keys->pub.key, DNET_KEYLEN); - } - } - } - if (!f) { - char buf[256]; - struct dfslib_string str; - f = xdag_open_file(KEYFILE, "wb"); - if (!f) return 3; -#ifndef QDNET - if (dnet_limited_version) -#endif - { - int len; - memset(buf, 0, 256); -#ifndef __LDuS__ - gethostname(buf, 255); - len = strlen(buf); - buf[len++] = ','; -#if !defined(QDNET) || !defined(__arm__) - getlogin_r(buf + len, 255 - len); - len += strlen(buf + len); - buf[len++] = ','; -#endif -#else - len = 0; -#endif - dfslib_random_fill(buf + len, 255 - len, 0, 0); - for (; len < 255; len++) buf[len] %= (0x80 - ' '), buf[len] += ' '; -#ifndef QDNET - } else { - struct dfslib_string str, str1; - char pwd[256], pwd1[256]; - (*g_input_password)("Set password", pwd, 256); - dfslib_utf8_string(&str, pwd, strlen(pwd)); - (*g_input_password)("Re-type password", pwd1, 256); - dfslib_utf8_string(&str1, pwd1, strlen(pwd1)); - if (str.len != str1.len || memcmp(str.utf8, str1.utf8, str.len)) { - printf("Passwords differ.\n"); return 4; - } - if (str.len) set_user_crypt(&str); - (*g_input_password)("Type random keys", buf, 256); -#endif - } - dfslib_random_fill(keys->pub.key, DNET_KEYLEN * sizeof(dfsrsa_t), 0, dfslib_utf8_string(&str, buf, strlen(buf))); - printf("Generating host keys... "); fflush(stdout); -#ifdef __arm__ - g_keylen = KEYLEN_MIN; -#else - if (dnet_limited_version) g_keylen = DNET_KEYLEN / 2; - else g_keylen = DNET_KEYLEN; -#endif - dfsrsa_keygen(keys->priv.key, keys->pub.key, g_keylen); - dnet_make_key(keys->priv.key, g_keylen); - dnet_make_key(keys->pub.key, g_keylen); - printf("OK.\n"); fflush(stdout); - if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) - dfslib_encrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); - if (fwrite(keys, sizeof(struct dnet_keys), 1, f) != 1) return 5; - if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) - dfslib_uncrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); - } - xdag_close_file(f); - if (!(host = dnet_add_host(&g_dnet_keys->pub, 0, 127 << 24 | 1, 0, DNET_ROUTE_LOCAL))) return 6; - version = strchr(version, '-'); - if (version) dnet_set_host_version(host, version + 1); - return -dnet_test_keys(); -} - -static void dnet_session_init_crypt(struct dfslib_crypt *crypt, uint32_t sector[SECTOR_SIZE / 4]) { - char password[PWDLEN + 1]; - struct dfslib_string str; - dnet_sector_to_password(sector, password); - dfslib_crypt_set_password(crypt, dfslib_utf8_string(&str, password, PWDLEN)); - dfslib_crypt_set_sector0(crypt, sector); -} - -struct dnet_session *dnet_session_create(void *private_data, const struct dnet_session_ops *ops, uint32_t route_ip, uint16_t route_port) { - struct dnet_session *sess = calloc(sizeof(struct dnet_session), 1); - if (sess) { - sess->private_data = private_data; - sess->ops = ops; - sess->route_ip = route_ip; - sess->route_port = route_port; - } - return sess; -} - -int dnet_session_init(struct dnet_session *sess) { - ssize_t res; - dnet_random_sector(sess->sector_write); - dnet_session_init_crypt(&sess->crypt_write, sess->sector_write); - res = (*sess->ops->write)(sess->private_data, &g_dnet_keys->pub, sizeof(struct dnet_key)); - if (res != sizeof(struct dnet_key)) return 1; - sess->pos_write += res; - return 0; -} - -ssize_t dnet_session_write(struct dnet_session *sess, void *buf, size_t size) { - ssize_t res = 0; - if (sess->pos_write < sizeof(struct dnet_key) + SECTOR_SIZE) return 0; - while (size) { - int pos = sess->pos_write & (SECTOR_SIZE - 1); - unsigned todo = SECTOR_SIZE - pos; - if (todo > size) todo = size; - memcpy((uint8_t *)sess->sector_write + pos, buf, todo); - pos += todo; - if (pos == SECTOR_SIZE) { - dfslib_encrypt_sector(&sess->crypt_write, sess->sector_write, (sess->pos_write - sizeof(struct dnet_key)) >> SECTOR_LOG); - (*sess->ops->write)(sess->private_data, sess->sector_write, SECTOR_SIZE); - } - sess->pos_write += todo; - res += todo; - buf = (uint8_t *)buf + todo; - size -= todo; - } - return res; -} - -ssize_t dnet_session_read(struct dnet_session *sess, void *buf, size_t size) { - ssize_t res = 0; - while (size) { - uint32_t *locbuf = (sess->pos_read < sizeof(struct dnet_key) ? (uint32_t *)sess->key.key : sess->sector_read); - int locbuf_size = (sess->pos_read < sizeof(struct dnet_key) ? sizeof(struct dnet_key) : SECTOR_SIZE); - int pos = sess->pos_read & (locbuf_size - 1); - unsigned todo = locbuf_size - pos; - if (todo > size) todo = size; - memcpy((uint8_t *)locbuf + pos, buf, todo); - pos += todo; - if (pos == locbuf_size) { - if (sess->pos_read < sizeof(struct dnet_key)) { - dfsrsa_crypt((dfsrsa_t *)sess->sector_write, SECTOR_SIZE / sizeof(dfsrsa_t), sess->key.key, DNET_KEYLEN); - (*sess->ops->write)(sess->private_data, sess->sector_write, SECTOR_SIZE); - sess->pos_write += SECTOR_SIZE; - } else if (sess->pos_read < sizeof(struct dnet_key) + SECTOR_SIZE) { - dfsrsa_crypt((dfsrsa_t *)sess->sector_read, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN); - dnet_session_init_crypt(&sess->crypt_read, sess->sector_read); - } else { - dfslib_uncrypt_sector(&sess->crypt_read, sess->sector_read, (sess->pos_read - sizeof(struct dnet_key)) >> SECTOR_LOG); - (*sess->ops->read)(sess->private_data, sess->sector_read, SECTOR_SIZE); - } - } - sess->pos_read += todo; - res += todo; - buf = (uint8_t *)buf + todo; - size -= todo; - if (sess->pos_read >= sizeof(struct dnet_key)) - sess->host = dnet_add_host(&sess->key, 0, sess->route_ip, sess->route_port, DNET_ROUTE_IMMEDIATE); - } - return res; - -} - -struct dnet_host *dnet_session_get_host(struct dnet_session *sess) { - return sess ? sess->host : 0; -} +#include "../client/utils/utils.h" + +#define KEYFILE "dnet_key.dat" +#define PWDLEN 64 +#define SECTOR_LOG 9 +#define SECTOR_SIZE (1 << SECTOR_LOG) +#define KEYLEN_MIN (DNET_KEYLEN / 4) + +#if !defined(_WIN32) && !defined(_WIN64) +extern int gethostname(char *name, size_t namelen); +extern int getlogin_r(char *name, size_t namesize); +#else +#define gethostname(n, l) strncpy(n, "localhost", l) +#define getlogin_r(n, l) strncpy(n, "Administrator", l) +#endif + +struct dnet_keys { + struct dnet_key priv; + struct dnet_key pub; +}; + +struct dnet_keys *g_dnet_keys; +static struct dfslib_crypt *g_dnet_user_crypt = 0; + +struct dnet_session { + struct dnet_key key; + uint32_t sector_write[SECTOR_SIZE / 4]; + uint32_t sector_read[SECTOR_SIZE / 4]; + struct dfslib_crypt crypt_write; + struct dfslib_crypt crypt_read; + uint64_t pos_write, pos_read; + struct dnet_host *host; + const struct dnet_session_ops *ops; + void *private_data; + uint32_t route_ip; + uint32_t route_port; +}; + +int dnet_limited_version = 0; +static int g_keylen = 0; + +static int input_password(const char *prompt, char *buf, unsigned len) { + struct termios t[1]; + int noecho = !!strstr(prompt, "assword"); + printf("%s: ", prompt); fflush(stdout); + if (noecho) { + tcgetattr(0, t); + t->c_lflag &= ~ECHO; + tcsetattr(0, TCSANOW, t); + } + fgets(buf, len, stdin); + if (noecho) { + t->c_lflag |= ECHO; + tcsetattr(0, TCSANOW, t); + printf("\n"); + } + len = strlen(buf); + if (len && buf[len - 1] == '\n') buf[len - 1] = 0; + return 0; +} + +static int(*g_input_password)(const char *prompt, char *buf, unsigned size) = &input_password; + +static void dnet_make_key(dfsrsa_t *key, int keylen) { + unsigned i; + for (i = keylen; i < DNET_KEYLEN; i += keylen) + memcpy(key + i, key, keylen * sizeof(dfsrsa_t)); +} + +static int dnet_detect_keylen(dfsrsa_t *key, int keylen) { + if (g_keylen && (key == g_dnet_keys->priv.key || key == g_dnet_keys->pub.key)) + return g_keylen; + while (keylen >= 8) { + if (memcmp(key, key + keylen / 2, keylen * sizeof(dfsrsa_t) / 2)) break; + keylen /= 2; + } + return keylen; +} + +static int dnet_rsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen) { + return dfsrsa_crypt(data, datalen, key, dnet_detect_keylen(key, keylen)); +} + +#define dfsrsa_crypt dnet_rsa_crypt + +static void dnet_sector_to_password(uint32_t sector[SECTOR_SIZE / 4], char password[PWDLEN + 1]) { + int i; + for (i = 0; i < PWDLEN / 8; ++i) { + unsigned crc = crc_of_array((unsigned char *)(sector + i * SECTOR_SIZE / 4 / (PWDLEN / 8)), SECTOR_SIZE / (PWDLEN / 8)); + sprintf(password + 8 * i, "%08X", crc); + } +} + +static void dnet_random_sector(uint32_t sector[SECTOR_SIZE / 4]) { + char password[PWDLEN + 1] = "Iyf&%d#$jhPo_t|3fgd+hf(s@;)F5D7gli^kjtrd%.kflP(7*5gt;Y1sYRC4VGL&"; + int i, j; + for (i = 0; i < 3; ++i) { + struct dfslib_string str; + dfslib_utf8_string(&str, password, PWDLEN); + dfslib_random_sector(sector, 0, &str, &str); + for (j = KEYLEN_MIN / 8; j <= SECTOR_SIZE / 4; j += KEYLEN_MIN / 8) + sector[j - 1] &= 0x7FFFFFFF; + if (i == 2) break; + dfsrsa_crypt((dfsrsa_t *)sector, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN); + dnet_sector_to_password(sector, password); + } +} + +int dnet_generate_random_array(void *array, unsigned long size) { + uint32_t sector[SECTOR_SIZE / 4]; + unsigned long i; + if (size < 4 || size & (size - 1)) return -1; + if (size >= 512) { + for (i = 0; i < size; i += 512) dnet_random_sector((uint32_t *)((uint8_t *)array + i)); + } else { + dnet_random_sector(sector); + for (i = 0; i < size; i += 4) { + *(uint32_t *)((uint8_t *)array + i) = crc_of_array((unsigned char *)sector + i * 512 / size, 512 / size); + } + } + return 0; +} + +void dnet_generate_stream_id(struct dnet_stream_id *id) { + dnet_generate_random_array(id, sizeof(struct dnet_stream_id)); +} + +static int dnet_test_keys(void) { + uint32_t src[SECTOR_SIZE / 4], dest[SECTOR_SIZE / 4]; + dnet_random_sector(src); + memcpy(dest, src, SECTOR_SIZE); + if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN)) return 1; + if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->pub.key, DNET_KEYLEN)) return 2; + if (memcmp(dest, src, SECTOR_SIZE)) return 3; + memcpy(dest, src, SECTOR_SIZE); + if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->pub.key, DNET_KEYLEN)) return 4; + if (dfsrsa_crypt((dfsrsa_t *)dest, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN)) return 5; + if (memcmp(dest, src, SECTOR_SIZE)) return 6; + return 0; +} + +static int set_user_crypt(struct dfslib_string *pwd) { + uint32_t sector0[128]; + int i; + g_dnet_user_crypt = malloc(sizeof(struct dfslib_crypt)); + if (!g_dnet_user_crypt) return -1; + memset(g_dnet_user_crypt->pwd, 0, sizeof(g_dnet_user_crypt->pwd)); + dfslib_crypt_set_password(g_dnet_user_crypt, pwd); + for (i = 0; i < 128; ++i) sector0[i] = 0x4ab29f51u + i * 0xc3807e6du; + for (i = 0; i < 128; ++i) { + dfslib_crypt_set_sector0(g_dnet_user_crypt, sector0); + dfslib_encrypt_sector(g_dnet_user_crypt, sector0, 0x3e9c1d624a8b570full + i * 0x9d2e61fc538704abull); + } + return 0; +} + +/* + * 1 - to encode data (data _ id, serial number data and size data measured in 32 - bit words) + * 2 - decode + * 3 - password and check it returns 0 on success + * 4 - password and write print array data of length 16 bytes + * 5 - to verify that the pattern in the data corresponds to the password + * 6 - setup callback function to input password, data is pointer to function + * int (*)(const char *prompt, char *buf, unsigned size); + */ +int dnet_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action) { + if (action != 4 && action != 6 && !g_dnet_user_crypt) return 0; + switch (action) { + case 1: + dfslib_encrypt_array(g_dnet_user_crypt, data, size, data_id); + break; + case 2: + dfslib_uncrypt_array(g_dnet_user_crypt, data, size, data_id); + break; + case 3: + { + struct dfslib_crypt *crypt = malloc(sizeof(struct dfslib_crypt)); + struct dfslib_string str; + char pwd[256]; + int res; + if (!crypt) return -1; + memset(pwd, 0, 256); + memset(&str, 0, sizeof(struct dfslib_string)); + (*g_input_password)("Password", pwd, 256); + dfslib_utf8_string(&str, pwd, strlen(pwd)); + memset(crypt->pwd, 0, sizeof(crypt->pwd)); + crypt->ispwd = 0; + dfslib_crypt_set_password(crypt, &str); + res = (g_dnet_user_crypt->ispwd == crypt->ispwd + && !memcmp(g_dnet_user_crypt->pwd, crypt->pwd, sizeof(crypt->pwd))); + free(crypt); + return res ? 0 : -1; + } + case 4: + { + struct dfslib_crypt *crypt = malloc(sizeof(struct dfslib_crypt)); + struct dfslib_string str; + char pwd[256]; + memset(pwd, 0, 256); + memset(&str, 0, sizeof(struct dfslib_string)); + (*g_input_password)("Password", pwd, 256); + dfslib_utf8_string(&str, pwd, strlen(pwd)); + memset(crypt->pwd, 0, sizeof(crypt->pwd)); + dfslib_crypt_set_password(crypt, &str); + memcpy(data, crypt->pwd, sizeof(crypt->pwd)); + free(crypt); + return 0; + } + case 5: + return memcmp(g_dnet_user_crypt->pwd, data, sizeof(g_dnet_user_crypt->pwd)) ? -1 : 0; + case 6: + g_input_password = (int(*)(const char *, char *, unsigned))(void *)data; + return 0; + default: return -1; + } + return 0; +} + +int dnet_crypt_init(const char *version) { + FILE *f; + struct dnet_keys *keys; + struct dnet_host *host; + int i; + g_dnet_keys = malloc(sizeof(struct dnet_keys)); + if (!g_dnet_keys) return 1; + keys = g_dnet_keys; + dfslib_random_init(); + if (crc_init()) return 2; + f = xdag_open_file(KEYFILE, "rb"); + if (f) { + if (fread(keys, sizeof(struct dnet_keys), 1, f) != 1) xdag_close_file(f), f = 0; + else { + g_keylen = dnet_detect_keylen(keys->pub.key, DNET_KEYLEN); + if (dnet_test_keys()) { + struct dfslib_string str; + char pwd[256]; + (*g_input_password)("Password", pwd, 256); + dfslib_utf8_string(&str, pwd, strlen(pwd)); + set_user_crypt(&str); + if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) + dfslib_uncrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); + g_keylen = 0; + g_keylen = dnet_detect_keylen(keys->pub.key, DNET_KEYLEN); + } + } + } + if (!f) { + char buf[256]; + struct dfslib_string str; + f = xdag_open_file(KEYFILE, "wb"); + if (!f) return 3; +#ifndef QDNET + if (dnet_limited_version) +#endif + { + int len; + memset(buf, 0, 256); +#ifndef __LDuS__ + gethostname(buf, 255); + len = strlen(buf); + buf[len++] = ','; +#if !defined(QDNET) || !defined(__arm__) + getlogin_r(buf + len, 255 - len); + len += strlen(buf + len); + buf[len++] = ','; +#endif +#else + len = 0; +#endif + dfslib_random_fill(buf + len, 255 - len, 0, 0); + for (; len < 255; len++) buf[len] %= (0x80 - ' '), buf[len] += ' '; +#ifndef QDNET + } else { + struct dfslib_string str, str1; + char pwd[256], pwd1[256]; + (*g_input_password)("Set password", pwd, 256); + dfslib_utf8_string(&str, pwd, strlen(pwd)); + (*g_input_password)("Re-type password", pwd1, 256); + dfslib_utf8_string(&str1, pwd1, strlen(pwd1)); + if (str.len != str1.len || memcmp(str.utf8, str1.utf8, str.len)) { + printf("Passwords differ.\n"); return 4; + } + if (str.len) set_user_crypt(&str); + (*g_input_password)("Type random keys", buf, 256); +#endif + } + dfslib_random_fill(keys->pub.key, DNET_KEYLEN * sizeof(dfsrsa_t), 0, dfslib_utf8_string(&str, buf, strlen(buf))); + printf("Generating host keys... "); fflush(stdout); +#ifdef __arm__ + g_keylen = KEYLEN_MIN; +#else + if (dnet_limited_version) g_keylen = DNET_KEYLEN / 2; + else g_keylen = DNET_KEYLEN; +#endif + dfsrsa_keygen(keys->priv.key, keys->pub.key, g_keylen); + dnet_make_key(keys->priv.key, g_keylen); + dnet_make_key(keys->pub.key, g_keylen); + printf("OK.\n"); fflush(stdout); + if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) + dfslib_encrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); + if (fwrite(keys, sizeof(struct dnet_keys), 1, f) != 1) return 5; + if (g_dnet_user_crypt) for (i = 0; i < (sizeof(struct dnet_keys) >> 9); ++i) + dfslib_uncrypt_sector(g_dnet_user_crypt, (uint32_t *)keys + 128 * i, ~(uint64_t)i); + } + xdag_close_file(f); + if (!(host = dnet_add_host(&g_dnet_keys->pub, 0, 127 << 24 | 1, 0, DNET_ROUTE_LOCAL))) return 6; + version = strchr(version, '-'); + if (version) dnet_set_host_version(host, version + 1); + return -dnet_test_keys(); +} + +static void dnet_session_init_crypt(struct dfslib_crypt *crypt, uint32_t sector[SECTOR_SIZE / 4]) { + char password[PWDLEN + 1]; + struct dfslib_string str; + dnet_sector_to_password(sector, password); + dfslib_crypt_set_password(crypt, dfslib_utf8_string(&str, password, PWDLEN)); + dfslib_crypt_set_sector0(crypt, sector); +} + +struct dnet_session *dnet_session_create(void *private_data, const struct dnet_session_ops *ops, uint32_t route_ip, uint16_t route_port) { + struct dnet_session *sess = calloc(sizeof(struct dnet_session), 1); + if (sess) { + sess->private_data = private_data; + sess->ops = ops; + sess->route_ip = route_ip; + sess->route_port = route_port; + } + return sess; +} + +int dnet_session_init(struct dnet_session *sess) { + ssize_t res; + dnet_random_sector(sess->sector_write); + dnet_session_init_crypt(&sess->crypt_write, sess->sector_write); + res = (*sess->ops->write)(sess->private_data, &g_dnet_keys->pub, sizeof(struct dnet_key)); + if (res != sizeof(struct dnet_key)) return 1; + sess->pos_write += res; + return 0; +} + +ssize_t dnet_session_write(struct dnet_session *sess, void *buf, size_t size) { + ssize_t res = 0; + if (sess->pos_write < sizeof(struct dnet_key) + SECTOR_SIZE) return 0; + while (size) { + int pos = sess->pos_write & (SECTOR_SIZE - 1); + unsigned todo = SECTOR_SIZE - pos; + if (todo > size) todo = size; + memcpy((uint8_t *)sess->sector_write + pos, buf, todo); + pos += todo; + if (pos == SECTOR_SIZE) { + dfslib_encrypt_sector(&sess->crypt_write, sess->sector_write, (sess->pos_write - sizeof(struct dnet_key)) >> SECTOR_LOG); + (*sess->ops->write)(sess->private_data, sess->sector_write, SECTOR_SIZE); + } + sess->pos_write += todo; + res += todo; + buf = (uint8_t *)buf + todo; + size -= todo; + } + return res; +} + +ssize_t dnet_session_read(struct dnet_session *sess, void *buf, size_t size) { + ssize_t res = 0; + while (size) { + uint32_t *locbuf = (sess->pos_read < sizeof(struct dnet_key) ? (uint32_t *)sess->key.key : sess->sector_read); + int locbuf_size = (sess->pos_read < sizeof(struct dnet_key) ? sizeof(struct dnet_key) : SECTOR_SIZE); + int pos = sess->pos_read & (locbuf_size - 1); + unsigned todo = locbuf_size - pos; + if (todo > size) todo = size; + memcpy((uint8_t *)locbuf + pos, buf, todo); + pos += todo; + if (pos == locbuf_size) { + if (sess->pos_read < sizeof(struct dnet_key)) { + dfsrsa_crypt((dfsrsa_t *)sess->sector_write, SECTOR_SIZE / sizeof(dfsrsa_t), sess->key.key, DNET_KEYLEN); + (*sess->ops->write)(sess->private_data, sess->sector_write, SECTOR_SIZE); + sess->pos_write += SECTOR_SIZE; + } else if (sess->pos_read < sizeof(struct dnet_key) + SECTOR_SIZE) { + dfsrsa_crypt((dfsrsa_t *)sess->sector_read, SECTOR_SIZE / sizeof(dfsrsa_t), g_dnet_keys->priv.key, DNET_KEYLEN); + dnet_session_init_crypt(&sess->crypt_read, sess->sector_read); + } else { + dfslib_uncrypt_sector(&sess->crypt_read, sess->sector_read, (sess->pos_read - sizeof(struct dnet_key)) >> SECTOR_LOG); + (*sess->ops->read)(sess->private_data, sess->sector_read, SECTOR_SIZE); + } + } + sess->pos_read += todo; + res += todo; + buf = (uint8_t *)buf + todo; + size -= todo; + if (sess->pos_read >= sizeof(struct dnet_key)) + sess->host = dnet_add_host(&sess->key, 0, sess->route_ip, sess->route_port, DNET_ROUTE_IMMEDIATE); + } + return res; + +} + +struct dnet_host *dnet_session_get_host(struct dnet_session *sess) { + return sess ? sess->host : 0; +} diff --git a/dnet/dnet_crypt.h b/dnet/dnet_crypt.h index ecea6081..b4247a18 100644 --- a/dnet/dnet_crypt.h +++ b/dnet/dnet_crypt.h @@ -1,43 +1,51 @@ -/* dnet: crypt; T11.231-T12.997; $DVS:time$ */ - -#ifndef DNET_CRYPT_H_INCLUDED -#define DNET_CRYPT_H_INCLUDED - -#include -#include "system.h" -#include "../dus/programs/dfstools/source/include/dfsrsa.h" - -#define DNET_KEY_SIZE 4096 -#define DNET_KEYLEN ((DNET_KEY_SIZE * 2) / (sizeof(dfsrsa_t) * 8)) - -struct dnet_key { - dfsrsa_t key[DNET_KEYLEN]; -}; - -struct dnet_stream_id { - uint32_t id[4]; -}; - -#include "dnet_database.h" - -struct dnet_session; - -struct dnet_session_ops { - ssize_t (*read)(void *private_data, void *buf, size_t size); - ssize_t (*write)(void *private_data, void *buf, size_t size); -}; - -extern int dnet_limited_version; - -extern int dnet_crypt_init(const char *version); - -extern struct dnet_session *dnet_session_create(void *private_data, const struct dnet_session_ops *ops, uint32_t route_ip, uint16_t route_port); -extern int dnet_session_init(struct dnet_session *sess); -extern ssize_t dnet_session_write(struct dnet_session *sess, void *buf, size_t size); -extern ssize_t dnet_session_read(struct dnet_session *sess, void *buf, size_t size); -extern struct dnet_host *dnet_session_get_host(struct dnet_session *sess); -extern void dnet_generate_stream_id(struct dnet_stream_id *id); - -#endif - - +/* dnet: crypt; T11.231-T12.997; $DVS:time$ */ + +#ifndef DNET_CRYPT_H_INCLUDED +#define DNET_CRYPT_H_INCLUDED + +#include +#include "system.h" +#include "../dus/programs/dfstools/source/include/dfsrsa.h" + +#define DNET_KEY_SIZE 4096 +#define DNET_KEYLEN ((DNET_KEY_SIZE * 2) / (sizeof(dfsrsa_t) * 8)) + +struct dnet_key { + dfsrsa_t key[DNET_KEYLEN]; +}; + +struct dnet_stream_id { + uint32_t id[4]; +}; + +#include "dnet_database.h" + +struct dnet_session; + +struct dnet_session_ops { + ssize_t (*read)(void *private_data, void *buf, size_t size); + ssize_t (*write)(void *private_data, void *buf, size_t size); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_limited_version; + +extern int dnet_crypt_init(const char *version); + +extern struct dnet_session *dnet_session_create(void *private_data, const struct dnet_session_ops *ops, uint32_t route_ip, uint16_t route_port); +extern int dnet_session_init(struct dnet_session *sess); +extern ssize_t dnet_session_write(struct dnet_session *sess, void *buf, size_t size); +extern ssize_t dnet_session_read(struct dnet_session *sess, void *buf, size_t size); +extern struct dnet_host *dnet_session_get_host(struct dnet_session *sess); +extern void dnet_generate_stream_id(struct dnet_stream_id *id); + +#ifdef __cplusplus +}; +#endif + +#endif + + diff --git a/dnet/dnet_database.c b/dnet/dnet_database.c index 1b30f8b6..35d9854d 100644 --- a/dnet/dnet_database.c +++ b/dnet/dnet_database.c @@ -1,282 +1,282 @@ -/* dnet: database; T11.231-T13.808; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#include -#include "../dus/programs/dar/source/include/crc.h" -#include "dnet_database.h" +/* dnet: database; T11.231-T13.808; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#include +#include "../dus/programs/dar/source/include/crc.h" +#include "dnet_database.h" #include "dnet_main.h" -#include "../client/utils/utils.h" - -#define DNET_HOST_MAX 0x1000 -#define DNET_NEW_HOST_TIMEOUT DNET_ACTIVE_PERIOD -#define DNET_AUTO_ROUTE_TIMEOUT 10 -#define KEYS_FILE "dnet_keys.dat" -#define NAME_FILE "dnet_name.txt" - -static pthread_mutex_t g_host_mutex = PTHREAD_MUTEX_INITIALIZER; -static struct dnet_host *g_dnet_hosts; -static unsigned g_dnet_n_hosts; - -void dnet_update_host(struct dnet_host *host, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type) { - time_t now = time(0); - time_t t = now - active_ago; - if (t > host->last_active + (active_ago >> 7)) { - if (t - host->last_active >= DNET_NEW_HOST_TIMEOUT) host->last_appear = now; - if (route_type >= host->route_type) { - if (route_type != DNET_ROUTE_AUTO || t - host->last_active >= DNET_AUTO_ROUTE_TIMEOUT) host->route_ip = route_ip, host->route_port = route_port; - host->route_type = route_type; - } - host->last_active = t; - host->last_time_changed = now; - } -} - -struct dnet_host *dnet_add_host(const struct dnet_key *key, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type) { - struct dnet_host *host; - time_t now; - unsigned i, n; -begin: - n = g_dnet_n_hosts; - for (i = 0; i < n; ++i) { - host = &g_dnet_hosts[i]; - if (!memcmp(key, host->key.key, sizeof(struct dnet_key))) { - dnet_update_host(host, active_ago, route_ip, route_port, route_type); - return host; - } - } - if (n == DNET_HOST_MAX) return 0; - pthread_mutex_lock(&g_host_mutex); - if (n != g_dnet_n_hosts) { - pthread_mutex_unlock(&g_host_mutex); - goto begin; - } - host = &g_dnet_hosts[n]; - memset(host, 0, sizeof(struct dnet_host)); - memcpy(host->key.key, key, sizeof(struct dnet_key)); - host->crc32 = crc_of_array((unsigned char *)key, sizeof(struct dnet_key)); - now = time(0); - host->last_active = now - active_ago; - host->last_time_changed = now; - host->last_appear = now; - host->route_ip = route_ip; - host->route_port = route_port; - host->route_type = route_type; - if (!n) { - FILE *f = xdag_open_file(NAME_FILE, "rb"); - if (f) { - int len = fread(host->name, 1, DNET_HOST_NAME_MAX, f); - xdag_close_file(f); - if (len > 0) host->name_len = len; - } - host->is_local = 1; - host->is_trusted = 1; - } else { - FILE *f = xdag_open_file(KEYS_FILE, "rb"); - if (!f) host->is_trusted = 1; - else { - struct dnet_key k; - while (fread(&k, sizeof(struct dnet_key), 1, f) == 1) { - if (!memcmp(key, &k, sizeof(struct dnet_key))) { - host->is_trusted = 1; - break; - } - } - xdag_close_file(f); - } - } - g_dnet_n_hosts++; - pthread_mutex_unlock(&g_host_mutex); - return host; -} - -struct dnet_host *dnet_get_self_host(void) { - return g_dnet_hosts; -} - -struct dnet_host *dnet_get_host_by_crc(uint32_t crc) { - unsigned i; - for (i = 0; i < g_dnet_n_hosts; ++i) { - struct dnet_host *host = &g_dnet_hosts[i]; - if (host->crc32 == crc) return host; - } - return 0; -} - -struct dnet_host *dnet_get_host_by_name(const char *name_or_crc) { - uint32_t crc; - unsigned len = strlen(name_or_crc), i; - if (!len) return 0; - for (i = 0; i < g_dnet_n_hosts; ++i) { - struct dnet_host *host = &g_dnet_hosts[i]; - if (len == host->name_len && !memcmp(name_or_crc, host->name, host->name_len)) return host; - } - if (sscanf(name_or_crc, "%x", &crc) != 1) return 0; - return dnet_get_host_by_crc(crc); -} - -static int dnet_hosts_compar_t(struct dnet_host *l, struct dnet_host *r, uint32_t active_time) { - time_t t = time(0); - uint32_t tl = dnet_host_time_ago(l, t), tr; - if (!r) return tl <= active_time ? 0 : -2; - if (l->is_trusted != r->is_trusted) return r->is_trusted - l->is_trusted; - if (l->route_type != r->route_type) return r->route_type - l->route_type; - tr = dnet_host_time_ago(r, t); - if (tl > DNET_ACTIVE_PERIOD || tr > DNET_ACTIVE_PERIOD) return tl < tr ? -1 : 1; - return l < r ? -1 : 1; -} - -int dnet_hosts_compar(struct dnet_host **l, struct dnet_host **r) { - return dnet_hosts_compar_t(*l, *r, DNET_ACTIVE_PERIOD); -} - -int dnet_hosts_compar_hour(struct dnet_host **l, struct dnet_host **r) { - return dnet_hosts_compar_t(*l, *r, 3600); -} - -int dnet_hosts_compar_day(struct dnet_host **l, struct dnet_host **r) { - return dnet_hosts_compar_t(*l, *r, 3600 * 24); -} - -int dnet_hosts_compar_all(struct dnet_host **l, struct dnet_host **r) { - return dnet_hosts_compar_t(*l, *r, UINT_MAX); -} - -int dnet_traverse_hosts(int (*callback)(struct dnet_host *host, void *data), void *data) { - int n = g_dnet_n_hosts, res = 0, i; - for (i = 0; i < n; ++i) { - res = (*callback)(&g_dnet_hosts[i], data); - if (res) break; - } - return res; -} - -int dnet_traverse_filtered_hosts(int (*callback)(struct dnet_host *host, void *data), int (*compar)(struct dnet_host **l, struct dnet_host **r), void *data) { - struct dnet_host *hostrefs[DNET_HOST_MAX]; - int n = g_dnet_n_hosts, res = 0, i, j; - for (i = j = 0; i < n; ++i) { - struct dnet_host *h = &g_dnet_hosts[i], *h0 = 0; - if (!compar(&h, &h0)) - hostrefs[j++] = h; - } - n = j; - qsort(hostrefs, n, sizeof(struct dnet_host *), (int (*)(const void *, const void *))compar); - for (i = 0; i < n; ++i) { - res = (*callback)(hostrefs[i], data); - if (res) break; - } - return res; -} - -int dnet_trust_host(struct dnet_host *host) { - FILE *f; - unsigned i; - if (host == &g_dnet_hosts[0]) return 0; - if (!(f = xdag_open_file(KEYS_FILE, "rb"))) { - f = xdag_open_file(KEYS_FILE, "wb"); - if (!f) return 1; - for (i = 1; i < g_dnet_n_hosts; ++i) { - g_dnet_hosts[i].is_trusted = 0; - } - } - xdag_close_file(f); - if (host->is_trusted) return 0; - f = xdag_open_file(KEYS_FILE, "ab"); - if (!f) return 2; - if (fwrite(&host->key, sizeof(struct dnet_key), 1, f) != 1) { - xdag_close_file(f); - return 3; - } - xdag_close_file(f); - host->is_trusted = 1; - return 0; -} - -int dnet_untrust_host(struct dnet_host *host) { - return -1; -} - -int dnet_set_host_name(struct dnet_host *host, const char *name, size_t len) { - unsigned i; - if (host->name_len == len && !memcmp(host->name, name, len)) return 0; - for (i = 0; i < g_dnet_n_hosts; ++i) { - struct dnet_host *host1 = &g_dnet_hosts[i]; - if (len == host1->name_len && !memcmp(name, host1->name, host1->name_len)) return 1; - } - host->last_appear = time(0); - memcpy(host->name, name, len); - host->name_len = len; - if (host == g_dnet_hosts) { - FILE *f = xdag_open_file(NAME_FILE, "wb"); - if (f) { - fwrite(host->name, 1, host->name_len, f); - xdag_close_file(f); - } - } - return 0; -} - -int dnet_set_host_version(struct dnet_host *host, const char *version) { - if (strlen(version) >= sizeof(host->version)) return -1; - if (!strcmp(host->version, version)) return 0; - if (host == g_dnet_hosts && host->version[0]) return -2; - host->last_appear = time(0); - strcpy(host->version, version); - return 0; -} - -int dnet_set_self_version(const char *version) { - if (!g_dnet_n_hosts || strlen(version) >= sizeof(g_dnet_hosts->version)) return -1; - if (!strcmp(g_dnet_hosts->version, version)) return 0; - g_dnet_hosts->last_appear = time(0); - strcpy(g_dnet_hosts->version, version); - return 0; -} - -static const char *get_host_version(struct dnet_host *host) { - if (host->version[0]) return host->version; - else return "unknown"; -} - -int dnet_print_host_name(struct dnet_host *host, struct dnet_output *out) { - if (host->name_len) dnet_printf(out, "%-15.*s", host->name_len, host->name); - else dnet_printf(out, "%08X ", host->crc32); - return 15; -} - -int dnet_print_host_brief(struct dnet_host *host, struct dnet_output *out) { - int len = dnet_print_host_name(host, out); - dnet_printf(out, "%*u sec, %s%s\n", 28 - len, dnet_host_time_ago(host, time(0)), - get_host_version(host), (host->is_trusted ? ", trust" : "")); - return 0; -} - -int dnet_print_host(struct dnet_host *host, struct dnet_output *out) { - const char *route_type; int len; - dnet_printf(out, " %2d. ", out->count); - len = dnet_print_host_name(host, out); - switch (host->route_type) { - case DNET_ROUTE_NONE: route_type = "none"; break; - case DNET_ROUTE_AUTO: route_type = "auto"; break; - case DNET_ROUTE_IMMEDIATE: route_type = "immediate"; break; - case DNET_ROUTE_LOCAL: route_type = "local"; break; - case DNET_ROUTE_MANUAL: route_type = "manual"; break; - default: return -1; - } - dnet_printf(out, "%*u sec, %s, %-10s%5s %d.%d.%d.%d:%d\n", 28 - len, dnet_host_time_ago(host, time(0)), - get_host_version(host), route_type, (host->is_trusted ? "trust" : ""), - host->route_ip >> 24 & 0xFF, host->route_ip >> 16 & 0xFF, host->route_ip >> 8 & 0xFF, host->route_ip & 0xFF, host->route_port); - out->count++; - return 0; -} - -int dnet_hosts_init(void) { - g_dnet_hosts = malloc(DNET_HOST_MAX * sizeof(struct dnet_host)); - if (!g_dnet_hosts) return -1; - g_dnet_n_hosts = 0; - return 0; -} +#include "../client/utils/utils.h" + +#define DNET_HOST_MAX 0x1000 +#define DNET_NEW_HOST_TIMEOUT DNET_ACTIVE_PERIOD +#define DNET_AUTO_ROUTE_TIMEOUT 10 +#define KEYS_FILE "dnet_keys.dat" +#define NAME_FILE "dnet_name.txt" + +static pthread_mutex_t g_host_mutex = PTHREAD_MUTEX_INITIALIZER; +static struct dnet_host *g_dnet_hosts; +static unsigned g_dnet_n_hosts; + +void dnet_update_host(struct dnet_host *host, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type) { + time_t now = time(0); + time_t t = now - active_ago; + if (t > host->last_active + (active_ago >> 7)) { + if (t - host->last_active >= DNET_NEW_HOST_TIMEOUT) host->last_appear = now; + if (route_type >= host->route_type) { + if (route_type != DNET_ROUTE_AUTO || t - host->last_active >= DNET_AUTO_ROUTE_TIMEOUT) host->route_ip = route_ip, host->route_port = route_port; + host->route_type = route_type; + } + host->last_active = t; + host->last_time_changed = now; + } +} + +struct dnet_host *dnet_add_host(const struct dnet_key *key, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type) { + struct dnet_host *host; + time_t now; + unsigned i, n; +begin: + n = g_dnet_n_hosts; + for (i = 0; i < n; ++i) { + host = &g_dnet_hosts[i]; + if (!memcmp(key, host->key.key, sizeof(struct dnet_key))) { + dnet_update_host(host, active_ago, route_ip, route_port, route_type); + return host; + } + } + if (n == DNET_HOST_MAX) return 0; + pthread_mutex_lock(&g_host_mutex); + if (n != g_dnet_n_hosts) { + pthread_mutex_unlock(&g_host_mutex); + goto begin; + } + host = &g_dnet_hosts[n]; + memset(host, 0, sizeof(struct dnet_host)); + memcpy(host->key.key, key, sizeof(struct dnet_key)); + host->crc32 = crc_of_array((unsigned char *)key, sizeof(struct dnet_key)); + now = time(0); + host->last_active = now - active_ago; + host->last_time_changed = now; + host->last_appear = now; + host->route_ip = route_ip; + host->route_port = route_port; + host->route_type = route_type; + if (!n) { + FILE *f = xdag_open_file(NAME_FILE, "rb"); + if (f) { + int len = fread(host->name, 1, DNET_HOST_NAME_MAX, f); + xdag_close_file(f); + if (len > 0) host->name_len = len; + } + host->is_local = 1; + host->is_trusted = 1; + } else { + FILE *f = xdag_open_file(KEYS_FILE, "rb"); + if (!f) host->is_trusted = 1; + else { + struct dnet_key k; + while (fread(&k, sizeof(struct dnet_key), 1, f) == 1) { + if (!memcmp(key, &k, sizeof(struct dnet_key))) { + host->is_trusted = 1; + break; + } + } + xdag_close_file(f); + } + } + g_dnet_n_hosts++; + pthread_mutex_unlock(&g_host_mutex); + return host; +} + +struct dnet_host *dnet_get_self_host(void) { + return g_dnet_hosts; +} + +struct dnet_host *dnet_get_host_by_crc(uint32_t crc) { + unsigned i; + for (i = 0; i < g_dnet_n_hosts; ++i) { + struct dnet_host *host = &g_dnet_hosts[i]; + if (host->crc32 == crc) return host; + } + return 0; +} + +struct dnet_host *dnet_get_host_by_name(const char *name_or_crc) { + uint32_t crc; + unsigned len = strlen(name_or_crc), i; + if (!len) return 0; + for (i = 0; i < g_dnet_n_hosts; ++i) { + struct dnet_host *host = &g_dnet_hosts[i]; + if (len == host->name_len && !memcmp(name_or_crc, host->name, host->name_len)) return host; + } + if (sscanf(name_or_crc, "%x", &crc) != 1) return 0; + return dnet_get_host_by_crc(crc); +} + +static int dnet_hosts_compar_t(struct dnet_host *l, struct dnet_host *r, uint32_t active_time) { + time_t t = time(0); + uint32_t tl = dnet_host_time_ago(l, t), tr; + if (!r) return tl <= active_time ? 0 : -2; + if (l->is_trusted != r->is_trusted) return r->is_trusted - l->is_trusted; + if (l->route_type != r->route_type) return r->route_type - l->route_type; + tr = dnet_host_time_ago(r, t); + if (tl > DNET_ACTIVE_PERIOD || tr > DNET_ACTIVE_PERIOD) return tl < tr ? -1 : 1; + return l < r ? -1 : 1; +} + +int dnet_hosts_compar(struct dnet_host **l, struct dnet_host **r) { + return dnet_hosts_compar_t(*l, *r, DNET_ACTIVE_PERIOD); +} + +int dnet_hosts_compar_hour(struct dnet_host **l, struct dnet_host **r) { + return dnet_hosts_compar_t(*l, *r, 3600); +} + +int dnet_hosts_compar_day(struct dnet_host **l, struct dnet_host **r) { + return dnet_hosts_compar_t(*l, *r, 3600 * 24); +} + +int dnet_hosts_compar_all(struct dnet_host **l, struct dnet_host **r) { + return dnet_hosts_compar_t(*l, *r, UINT_MAX); +} + +int dnet_traverse_hosts(int (*callback)(struct dnet_host *host, void *data), void *data) { + int n = g_dnet_n_hosts, res = 0, i; + for (i = 0; i < n; ++i) { + res = (*callback)(&g_dnet_hosts[i], data); + if (res) break; + } + return res; +} + +int dnet_traverse_filtered_hosts(int (*callback)(struct dnet_host *host, void *data), int (*compar)(struct dnet_host **l, struct dnet_host **r), void *data) { + struct dnet_host *hostrefs[DNET_HOST_MAX]; + int n = g_dnet_n_hosts, res = 0, i, j; + for (i = j = 0; i < n; ++i) { + struct dnet_host *h = &g_dnet_hosts[i], *h0 = 0; + if (!compar(&h, &h0)) + hostrefs[j++] = h; + } + n = j; + qsort(hostrefs, n, sizeof(struct dnet_host *), (int (*)(const void *, const void *))compar); + for (i = 0; i < n; ++i) { + res = (*callback)(hostrefs[i], data); + if (res) break; + } + return res; +} + +int dnet_trust_host(struct dnet_host *host) { + FILE *f; + unsigned i; + if (host == &g_dnet_hosts[0]) return 0; + if (!(f = xdag_open_file(KEYS_FILE, "rb"))) { + f = xdag_open_file(KEYS_FILE, "wb"); + if (!f) return 1; + for (i = 1; i < g_dnet_n_hosts; ++i) { + g_dnet_hosts[i].is_trusted = 0; + } + } + xdag_close_file(f); + if (host->is_trusted) return 0; + f = xdag_open_file(KEYS_FILE, "ab"); + if (!f) return 2; + if (fwrite(&host->key, sizeof(struct dnet_key), 1, f) != 1) { + xdag_close_file(f); + return 3; + } + xdag_close_file(f); + host->is_trusted = 1; + return 0; +} + +int dnet_untrust_host(struct dnet_host *host) { + return -1; +} + +int dnet_set_host_name(struct dnet_host *host, const char *name, size_t len) { + unsigned i; + if (host->name_len == len && !memcmp(host->name, name, len)) return 0; + for (i = 0; i < g_dnet_n_hosts; ++i) { + struct dnet_host *host1 = &g_dnet_hosts[i]; + if (len == host1->name_len && !memcmp(name, host1->name, host1->name_len)) return 1; + } + host->last_appear = time(0); + memcpy(host->name, name, len); + host->name_len = len; + if (host == g_dnet_hosts) { + FILE *f = xdag_open_file(NAME_FILE, "wb"); + if (f) { + fwrite(host->name, 1, host->name_len, f); + xdag_close_file(f); + } + } + return 0; +} + +int dnet_set_host_version(struct dnet_host *host, const char *version) { + if (strlen(version) >= sizeof(host->version)) return -1; + if (!strcmp(host->version, version)) return 0; + if (host == g_dnet_hosts && host->version[0]) return -2; + host->last_appear = time(0); + strcpy(host->version, version); + return 0; +} + +int dnet_set_self_version(const char *version) { + if (!g_dnet_n_hosts || strlen(version) >= sizeof(g_dnet_hosts->version)) return -1; + if (!strcmp(g_dnet_hosts->version, version)) return 0; + g_dnet_hosts->last_appear = time(0); + strcpy(g_dnet_hosts->version, version); + return 0; +} + +static const char *get_host_version(struct dnet_host *host) { + if (host->version[0]) return host->version; + else return "unknown"; +} + +int dnet_print_host_name(struct dnet_host *host, struct dnet_output *out) { + if (host->name_len) dnet_printf(out, "%-15.*s", host->name_len, host->name); + else dnet_printf(out, "%08X ", host->crc32); + return 15; +} + +int dnet_print_host_brief(struct dnet_host *host, struct dnet_output *out) { + int len = dnet_print_host_name(host, out); + dnet_printf(out, "%*u sec, %s%s\n", 28 - len, dnet_host_time_ago(host, time(0)), + get_host_version(host), (host->is_trusted ? ", trust" : "")); + return 0; +} + +int dnet_print_host(struct dnet_host *host, struct dnet_output *out) { + const char *route_type; int len; + dnet_printf(out, " %2d. ", out->count); + len = dnet_print_host_name(host, out); + switch (host->route_type) { + case DNET_ROUTE_NONE: route_type = "none"; break; + case DNET_ROUTE_AUTO: route_type = "auto"; break; + case DNET_ROUTE_IMMEDIATE: route_type = "immediate"; break; + case DNET_ROUTE_LOCAL: route_type = "local"; break; + case DNET_ROUTE_MANUAL: route_type = "manual"; break; + default: return -1; + } + dnet_printf(out, "%*u sec, %s, %-10s%5s %d.%d.%d.%d:%d\n", 28 - len, dnet_host_time_ago(host, time(0)), + get_host_version(host), route_type, (host->is_trusted ? "trust" : ""), + host->route_ip >> 24 & 0xFF, host->route_ip >> 16 & 0xFF, host->route_ip >> 8 & 0xFF, host->route_ip & 0xFF, host->route_port); + out->count++; + return 0; +} + +int dnet_hosts_init(void) { + g_dnet_hosts = malloc(DNET_HOST_MAX * sizeof(struct dnet_host)); + if (!g_dnet_hosts) return -1; + g_dnet_n_hosts = 0; + return 0; +} diff --git a/dnet/dnet_database.h b/dnet/dnet_database.h index 3f170a71..fbc33517 100644 --- a/dnet/dnet_database.h +++ b/dnet/dnet_database.h @@ -1,61 +1,69 @@ -/* dnet: database; T11.231-T13.410; $DVS:time$ */ - -#ifndef DNET_DATABASE_H_INCLUDED -#define DNET_DATABASE_H_INCLUDED - -#include -#include -#include "dnet_crypt.h" -#include "dnet_log.h" - -#define DNET_HOST_NAME_MAX 256 - -enum dnet_host_route_types { - DNET_ROUTE_NONE, - DNET_ROUTE_AUTO, - DNET_ROUTE_IMMEDIATE, - DNET_ROUTE_LOCAL, - DNET_ROUTE_MANUAL -}; - -struct dnet_host { - struct dnet_key key; - char name[DNET_HOST_NAME_MAX]; - char version[16]; - time_t last_active; - time_t last_appear; - time_t last_time_changed; - uint32_t crc32; - uint32_t route_ip; - unsigned name_len; - uint16_t route_port; - uint8_t is_local; - uint8_t is_trusted; - enum dnet_host_route_types route_type; -}; - -extern void dnet_update_host(struct dnet_host *host, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type); -extern struct dnet_host *dnet_add_host(const struct dnet_key *key, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type); -extern struct dnet_host *dnet_get_self_host(void); -extern struct dnet_host *dnet_get_host_by_name(const char *name_or_crc); -extern struct dnet_host *dnet_get_host_by_crc(uint32_t crc); -extern int dnet_hosts_compar(struct dnet_host **l, struct dnet_host **r); -extern int dnet_hosts_compar_hour(struct dnet_host **l, struct dnet_host **r); -extern int dnet_hosts_compar_day(struct dnet_host **l, struct dnet_host **r); -extern int dnet_hosts_compar_all(struct dnet_host **l, struct dnet_host **r); -extern int dnet_traverse_hosts(int (*callback)(struct dnet_host *host, void *data), void *data); -extern int dnet_traverse_filtered_hosts(int (*callback)(struct dnet_host *host, void *data), int (*compar)(struct dnet_host **l, struct dnet_host **r), void *data); -extern int dnet_trust_host(struct dnet_host *host); -extern int dnet_untrust_host(struct dnet_host *host); -extern int dnet_set_host_name(struct dnet_host *host, const char *name, size_t len); -extern int dnet_set_host_version(struct dnet_host *host, const char *version); -extern int dnet_print_host_name(struct dnet_host *host, struct dnet_output *out); -extern int dnet_print_host_brief(struct dnet_host *host, struct dnet_output *out); -extern int dnet_print_host(struct dnet_host *host, struct dnet_output *out); -extern int dnet_hosts_init(void); - -static inline uint32_t dnet_host_time_ago(struct dnet_host *h, time_t now) { - return h->is_local || now <= h->last_active ? 0 : (uint32_t)(now - h->last_active); -} - -#endif +/* dnet: database; T11.231-T13.410; $DVS:time$ */ + +#ifndef DNET_DATABASE_H_INCLUDED +#define DNET_DATABASE_H_INCLUDED + +#include +#include +#include "dnet_crypt.h" +#include "dnet_log.h" + +#define DNET_HOST_NAME_MAX 256 + +enum dnet_host_route_types { + DNET_ROUTE_NONE, + DNET_ROUTE_AUTO, + DNET_ROUTE_IMMEDIATE, + DNET_ROUTE_LOCAL, + DNET_ROUTE_MANUAL +}; + +struct dnet_host { + struct dnet_key key; + char name[DNET_HOST_NAME_MAX]; + char version[16]; + time_t last_active; + time_t last_appear; + time_t last_time_changed; + uint32_t crc32; + uint32_t route_ip; + unsigned name_len; + uint16_t route_port; + uint8_t is_local; + uint8_t is_trusted; + enum dnet_host_route_types route_type; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern void dnet_update_host(struct dnet_host *host, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type); +extern struct dnet_host *dnet_add_host(const struct dnet_key *key, time_t active_ago, uint32_t route_ip, uint16_t route_port, enum dnet_host_route_types route_type); +extern struct dnet_host *dnet_get_self_host(void); +extern struct dnet_host *dnet_get_host_by_name(const char *name_or_crc); +extern struct dnet_host *dnet_get_host_by_crc(uint32_t crc); +extern int dnet_hosts_compar(struct dnet_host **l, struct dnet_host **r); +extern int dnet_hosts_compar_hour(struct dnet_host **l, struct dnet_host **r); +extern int dnet_hosts_compar_day(struct dnet_host **l, struct dnet_host **r); +extern int dnet_hosts_compar_all(struct dnet_host **l, struct dnet_host **r); +extern int dnet_traverse_hosts(int (*callback)(struct dnet_host *host, void *data), void *data); +extern int dnet_traverse_filtered_hosts(int (*callback)(struct dnet_host *host, void *data), int (*compar)(struct dnet_host **l, struct dnet_host **r), void *data); +extern int dnet_trust_host(struct dnet_host *host); +extern int dnet_untrust_host(struct dnet_host *host); +extern int dnet_set_host_name(struct dnet_host *host, const char *name, size_t len); +extern int dnet_set_host_version(struct dnet_host *host, const char *version); +extern int dnet_print_host_name(struct dnet_host *host, struct dnet_output *out); +extern int dnet_print_host_brief(struct dnet_host *host, struct dnet_output *out); +extern int dnet_print_host(struct dnet_host *host, struct dnet_output *out); +extern int dnet_hosts_init(void); + +static inline uint32_t dnet_host_time_ago(struct dnet_host *h, time_t now) { + return h->is_local || now <= h->last_active ? 0 : (uint32_t)(now - h->last_active); +} + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_files.h b/dnet/dnet_files.h index 22ce3ae0..b27a3a6e 100644 --- a/dnet/dnet_files.h +++ b/dnet/dnet_files.h @@ -6,6 +6,10 @@ #include "dnet_log.h" #include "dnet_threads.h" +#ifdef __cplusplus +extern "C" { +#endif + /* копирование из источника from в назначение to; источник и назначение заданы в формате [host:]port */ extern int dnet_file_command(const char *from, const char *to, const char *param, struct dnet_output *out); @@ -15,4 +19,8 @@ extern int dnet_file_thread(struct dnet_thread *t, struct dnet_packet_stream *st /* обработка принятого файлового пакета */ extern int dnet_process_file_packet(struct dnet_packet_stream *st); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/dnet/dnet_history.h b/dnet/dnet_history.h index 8afa4603..3ae99007 100644 --- a/dnet/dnet_history.h +++ b/dnet/dnet_history.h @@ -1,149 +1,149 @@ -/* dnet: история и версия; */ -#define DNET_VERSION "T11.231-T13.714" /* $DVS:time$ - -T13.714 добавлена команда connect ip:port, закомментирован ненужный в cheatcoin код - -T13.572 потоки открепляются с помощью pthread_detach, а не pthread_join; устранена - проблема в LDuS с зависанием gc при повторном использовании потока - -T13.448 исправлена ошибка, связанная с зависанием потока, читающего из сокета - -T13.428 при копировании файлов введены дополнительные параметры: начальная позиция, максимальная скорость и время её применения - -T13.410 имя локального хоста сохраняется в файл; информация о хостах, не проявлявших - активности больше 2 суток, не пересылается - -T13.375 в LDuS принудительно освобождается порт сервера - -T13.184 теперь номер tap интерфейса может содержать до 4 байт - -T13.178 исправление ошибок в gcc 6 - -T13.142 теперь команды на другом хосте выполняются в отдельном потоке; - добавлена псевдокоманда repeat для повторения команд в командной строке - -T13.138 в версии для LDuS добавлена возможность создания tap интерфейсов - -T13.096 введена история введённых (в том числе присланных команд) и команда history для её показа - -T13.093 введены fifo-мьютексы для отправки пакетов по одному соединению - -T13.064 введена команда untrust, опции -d, -h команды hosts, теперь в сообщении UPDATE (каждые 30 сек) - посылается информация только о хостах, время активности которых менялось за последние 5 мин, - а сообщения EXCHANGE (каждые полчаса) - только о хостах, у которых данные менялись за последний час - -T13.055 исправлена ошибка при копирование файла, в имени которого есть пробелы - -T13.051 в ограниченном режиме разрешено выполнять команды на другом хосте и заходить на него - (нужно для связи с андроидом и для команды copy) - -T13.047 добавлено ослабленное шифрование для ускорения генерации ключей (1024 бит - для андроида, 2048 бит для ограниченного режима) - -T13.042 добавлена команда copy для копирования файлов/каталогов между хостами - -T13.014 сделана программа qdnet на Qt для PC и Android - -T12.999 добавлено перенаправление UDP портов; сделан обмен версиями программ между хостами - -T12.994 исправлен ряд ошибок - -T12.985 игнорирование большего числа сигналов в режиме демона - -T12.975 изменён порядок вывода в команде hosts, сделан полный (-a) и частичный вывод - -T12.965 добавлены: перенаправление TCP портов, доверенные хосты, ограниченный режим - (для программы, запущенной без параметров) - -T12.694 в LDuS убрана перезегрузка системы при обрыве соединения - -T12.677 добавлена команда close для принудительного закрытия потока (stream) - -T12.664 при удалённом подключении к LDuS теперь можно работать в цветном текстовом окне - -T12.617 улучшен роутинг, теперь следующий хост определяется исход из пары ip:port; - при запуске только с параметром -d добаяляются параметры по умолчанию: - -d -s 0.0.0.0:11231 52.5.32.68:11231 - -T12.527 в параметрах программы можно задать команды, которые будут выполнены после её - запуска в формате -c "команда"; теперь при обрыве туннеля с одной стороны - его можно пересоздать с этой стороны и на другой стороне он перезапустится - -T12.405 в Linux добавлена возможность создавать Ethernet-туннели между tap-интерфейсами - на разных машинах - -T12.231 теперь при работе в shell dnet не прерывается по Ctrl-C и посылает байт 3 - -T12.222 в LDuS сделана возможность захода в shell - -T12.172 сборщик мусора теперь вызывается чаще, раз в 5 минут, но каждый поток - уничтожается только на второй проход сборщика мусора - -T12.171 для обмена сообщениями с другими узлами сети dnet теперь заводится свой - поток для каждого соединения - -T12.170 в LDuS теперь вызывается не ldus_reboot, а ldus_shutdown - -T11.765 в LDuS теперь считаются только те соединения, по которым была активность в - последние 45 секунд, если их нет 2 раза, то перезагрузка - -T11.760 число соединений теперь проверяется каждые 30 сек, соединение открывается - заново через 45 сек простоя - -T11.757 добавлена команда log для пересылки логов - -T11.752 размер DNET_COMMAND_MAX увеличен до 0x1000, т. е. до максимального размера - данных в пакете, тем самым доступно выполнение больших команд, - передаваемых через сеть - -T11.736 если при двух подряд выводах информации в лог (происходят раз в 5 минут) - не было ни одного соединения, а при предыдущем выводе были, то программа dnet - перезагружает систему LDuS; скорее всего, нет доступа в сеть - -T11.713 если в течение 1 минуты не было прочитано данных из соединения, то оно - открывается заново; для соектов устанавливается флаг close-on-exec, тем самым - при падении программы dnet открытые сокеты не переходят дочерним программам - -T11.711 теперь в LDuS доступно API выполнения одиночной команды (в том числе удалённого; - функция dnet_command); параллельно может выполняться до 256 команд; в конце - выполнения команды отправляется пустой пакет и принимающая сторона посылает сигнал - SIGCONT ожидающему потоку (чей pid указан в поле output_file->pid) - -T11.665 при удалённом выполнении одиночной команды ответ посылается асинхронно - и может иметь любую длину - -T11.635 интеграция программы в систему LDuS - -T11.310 в сеансе удалённого доступа автоматически устанавливается размер терминала - -T11.280 улучшение сеансов удалённого доступа - -T11.278 исправлена ошибка с удалённым сеансом, улучшено логирование - -T11.275 во время удалённого сеанса работы в shell ввод с терминала делается - посимвольный, отключается эхо, а также символ 10 (\n) меняется на 13 (\r) - -T11.273 реализованы потоки между хостами; добавлена возможность удалённого запуска - сеанса работы в shell - -T11.267 сделан режим демона - -T11.265 команды теперь можно выполнять на удалённом хосте - -T11.264 добавлены пакеты типа UPDATE для быстрого обмена временами последней активности хостов, - для каждого хоста введён параметр route - ip-адрес соединения дял достижения этого хоста - -T11.262 сделана проверка на соответствие закрытого и открытого ключей - -T11.261 сделано логирование, можно давать команды для system shell - -T11.259 добавлены имена хостов, теперь при обмене известными хостами посылаются также и имена - -T11.256 исправление ошибок, защита от падений - -T11.254 работающая версия, позволяющая обмениватьcя открытыми ключами между группой - компьютеров - -T11.231 начало проекта - -*/ +/* dnet: история и версия; */ +#define DNET_VERSION "T11.231-T13.714" /* $DVS:time$ + +T13.714 добавлена команда connect ip:port, закомментирован ненужный в cheatcoin код + +T13.572 потоки открепляются с помощью pthread_detach, а не pthread_join; устранена + проблема в LDuS с зависанием gc при повторном использовании потока + +T13.448 исправлена ошибка, связанная с зависанием потока, читающего из сокета + +T13.428 при копировании файлов введены дополнительные параметры: начальная позиция, максимальная скорость и время её применения + +T13.410 имя локального хоста сохраняется в файл; информация о хостах, не проявлявших + активности больше 2 суток, не пересылается + +T13.375 в LDuS принудительно освобождается порт сервера + +T13.184 теперь номер tap интерфейса может содержать до 4 байт + +T13.178 исправление ошибок в gcc 6 + +T13.142 теперь команды на другом хосте выполняются в отдельном потоке; + добавлена псевдокоманда repeat для повторения команд в командной строке + +T13.138 в версии для LDuS добавлена возможность создания tap интерфейсов + +T13.096 введена история введённых (в том числе присланных команд) и команда history для её показа + +T13.093 введены fifo-мьютексы для отправки пакетов по одному соединению + +T13.064 введена команда untrust, опции -d, -h команды hosts, теперь в сообщении UPDATE (каждые 30 сек) + посылается информация только о хостах, время активности которых менялось за последние 5 мин, + а сообщения EXCHANGE (каждые полчаса) - только о хостах, у которых данные менялись за последний час + +T13.055 исправлена ошибка при копирование файла, в имени которого есть пробелы + +T13.051 в ограниченном режиме разрешено выполнять команды на другом хосте и заходить на него + (нужно для связи с андроидом и для команды copy) + +T13.047 добавлено ослабленное шифрование для ускорения генерации ключей (1024 бит + для андроида, 2048 бит для ограниченного режима) + +T13.042 добавлена команда copy для копирования файлов/каталогов между хостами + +T13.014 сделана программа qdnet на Qt для PC и Android + +T12.999 добавлено перенаправление UDP портов; сделан обмен версиями программ между хостами + +T12.994 исправлен ряд ошибок + +T12.985 игнорирование большего числа сигналов в режиме демона + +T12.975 изменён порядок вывода в команде hosts, сделан полный (-a) и частичный вывод + +T12.965 добавлены: перенаправление TCP портов, доверенные хосты, ограниченный режим + (для программы, запущенной без параметров) + +T12.694 в LDuS убрана перезегрузка системы при обрыве соединения + +T12.677 добавлена команда close для принудительного закрытия потока (stream) + +T12.664 при удалённом подключении к LDuS теперь можно работать в цветном текстовом окне + +T12.617 улучшен роутинг, теперь следующий хост определяется исход из пары ip:port; + при запуске только с параметром -d добаяляются параметры по умолчанию: + -d -s 0.0.0.0:11231 52.5.32.68:11231 + +T12.527 в параметрах программы можно задать команды, которые будут выполнены после её + запуска в формате -c "команда"; теперь при обрыве туннеля с одной стороны + его можно пересоздать с этой стороны и на другой стороне он перезапустится + +T12.405 в Linux добавлена возможность создавать Ethernet-туннели между tap-интерфейсами + на разных машинах + +T12.231 теперь при работе в shell dnet не прерывается по Ctrl-C и посылает байт 3 + +T12.222 в LDuS сделана возможность захода в shell + +T12.172 сборщик мусора теперь вызывается чаще, раз в 5 минут, но каждый поток + уничтожается только на второй проход сборщика мусора + +T12.171 для обмена сообщениями с другими узлами сети dnet теперь заводится свой + поток для каждого соединения + +T12.170 в LDuS теперь вызывается не ldus_reboot, а ldus_shutdown + +T11.765 в LDuS теперь считаются только те соединения, по которым была активность в + последние 45 секунд, если их нет 2 раза, то перезагрузка + +T11.760 число соединений теперь проверяется каждые 30 сек, соединение открывается + заново через 45 сек простоя + +T11.757 добавлена команда log для пересылки логов + +T11.752 размер DNET_COMMAND_MAX увеличен до 0x1000, т. е. до максимального размера + данных в пакете, тем самым доступно выполнение больших команд, + передаваемых через сеть + +T11.736 если при двух подряд выводах информации в лог (происходят раз в 5 минут) + не было ни одного соединения, а при предыдущем выводе были, то программа dnet + перезагружает систему LDuS; скорее всего, нет доступа в сеть + +T11.713 если в течение 1 минуты не было прочитано данных из соединения, то оно + открывается заново; для соектов устанавливается флаг close-on-exec, тем самым + при падении программы dnet открытые сокеты не переходят дочерним программам + +T11.711 теперь в LDuS доступно API выполнения одиночной команды (в том числе удалённого; + функция dnet_command); параллельно может выполняться до 256 команд; в конце + выполнения команды отправляется пустой пакет и принимающая сторона посылает сигнал + SIGCONT ожидающему потоку (чей pid указан в поле output_file->pid) + +T11.665 при удалённом выполнении одиночной команды ответ посылается асинхронно + и может иметь любую длину + +T11.635 интеграция программы в систему LDuS + +T11.310 в сеансе удалённого доступа автоматически устанавливается размер терминала + +T11.280 улучшение сеансов удалённого доступа + +T11.278 исправлена ошибка с удалённым сеансом, улучшено логирование + +T11.275 во время удалённого сеанса работы в shell ввод с терминала делается + посимвольный, отключается эхо, а также символ 10 (\n) меняется на 13 (\r) + +T11.273 реализованы потоки между хостами; добавлена возможность удалённого запуска + сеанса работы в shell + +T11.267 сделан режим демона + +T11.265 команды теперь можно выполнять на удалённом хосте + +T11.264 добавлены пакеты типа UPDATE для быстрого обмена временами последней активности хостов, + для каждого хоста введён параметр route - ip-адрес соединения дял достижения этого хоста + +T11.262 сделана проверка на соответствие закрытого и открытого ключей + +T11.261 сделано логирование, можно давать команды для system shell + +T11.259 добавлены имена хостов, теперь при обмене известными хостами посылаются также и имена + +T11.256 исправление ошибок, защита от падений + +T11.254 работающая версия, позволяющая обмениватьcя открытыми ключами между группой + компьютеров + +T11.231 начало проекта + +*/ diff --git a/dnet/dnet_log.c b/dnet/dnet_log.c index 31686dce..5f766f54 100644 --- a/dnet/dnet_log.c +++ b/dnet/dnet_log.c @@ -1,155 +1,155 @@ -/* dnet: log; T11.261-T13.063; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#ifdef __LDuS__ -#include -#endif -#include "dnet_database.h" -#include "dnet_connection.h" -#include "dnet_stream.h" +/* dnet: log; T11.261-T13.063; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#ifdef __LDuS__ +#include +#endif +#include "dnet_database.h" +#include "dnet_connection.h" +#include "dnet_stream.h" #include "dnet_log.h" -#include "../client/utils/utils.h" - -#define DNET_LOG_PERIOD 300 - -pthread_mutex_t dnet_log_mutex = PTHREAD_MUTEX_INITIALIZER; -time_t dnet_log_t0 = 0; -int g_connections_count[2]; - -static int dnet_vprintf(struct dnet_output *out, const char *format, va_list arg) { - int done; - - if (out->f) done = vfprintf(out->f, format, arg); - else if (out->str && out->len) { - done = vsnprintf(out->str, out->len, format, arg); - if (done >= 0) { - if ((unsigned)done > out->len) done = out->len; - out->len -= done; - out->str += done; - if (out->callback) (*out->callback)(out); - } - } else done = 0; - - return done; -} - -ssize_t dnet_write(struct dnet_output *out, const void *data, size_t size) { - ssize_t done; - - if (out->f) done = fwrite(data, 1, size, out->f); - else if (out->str && out->len) { - done = size; - if ((size_t)done > out->len) done = out->len; - memcpy(out->str, data, done); - out->len -= done; - out->str += done; - if (out->callback) (*out->callback)(out); - } else done = 0; - - return done; -} - -int dnet_printf(struct dnet_output *out, const char *format, ...) { - va_list arg; - int done; - - va_start (arg, format); - done = dnet_vprintf(out, format, arg); - va_end (arg); - - return done; -} - -static void dnet_log_open(struct dnet_output *out) { - time_t t = time(0); - struct tm tm; - char tbuf[64]; - localtime_r(&t, &tm); - strftime(tbuf, 64, "%Y-%m-%d %H:%M:%S ", &tm); - pthread_mutex_lock(&dnet_log_mutex); - out->f = xdag_open_file("dnet.log", "a"); - if (!out->f) out->f = stderr; - dnet_printf(out, "%s", tbuf); -} - -static void dnet_log_close(struct dnet_output *out) { - if (out->f != stderr) xdag_close_file(out->f); - out->f = 0; - pthread_mutex_unlock(&dnet_log_mutex); -} - -void dnet_print_hosts(struct dnet_output *out, long active_time) { - struct dnet_output new_out; - if (!out) dnet_log_open(out = &new_out); - out->count = 0; - dnet_printf(out, "%s hosts:\n", (active_time > 3600*24 ? "All" : active_time > 3600 ? "Daily" : active_time > DNET_ACTIVE_PERIOD ? "Hourly" : "Active")); - dnet_traverse_filtered_hosts((int (*)(struct dnet_host *, void *))&dnet_print_host, - (active_time > 3600*24 ? &dnet_hosts_compar_all : active_time > 3600 ? &dnet_hosts_compar_day - : active_time > DNET_ACTIVE_PERIOD ? &dnet_hosts_compar_hour : &dnet_hosts_compar), out); - if (out == &new_out) dnet_log_close(out); -} - -int dnet_print_connections(struct dnet_output *out) { - struct dnet_output new_out; - int count; - if (!out) dnet_log_open(out = &new_out); - out->count = 0; - dnet_printf(out, "Current connections:\n"); - dnet_traverse_connections((int (*)(struct dnet_connection *, void *))&dnet_print_connection, out); - count = out->count; - if (out == &new_out) dnet_log_close(out); - return count; -} - -void dnet_print_streams(struct dnet_output *out) { - struct dnet_output new_out; - if (!out) dnet_log_open(out = &new_out); - out->count = 0; - dnet_printf(out, "Current streams:\n"); - dnet_traverse_streams((int (*)(struct dnet_stream *, void *))&dnet_print_stream, out); - if (out == &new_out) dnet_log_close(out); -} - -void dnet_log_periodic(void) { -#ifndef QDNET - time_t t = time(0); - if (t - dnet_log_t0 >= DNET_LOG_PERIOD) { - dnet_log_t0 = t; - if (!dnet_limited_version) { - dnet_print_hosts(0, 0); - dnet_print_connections(0); - } - dnet_print_streams(0); - } -#endif -} - -void dnet_log_watchdog(int count) { -#ifdef __LDuS__ - if (g_connections_count[0] && !g_connections_count[1] && !count) { - printf("dnet: connection lost\n"); -// ldus_shutdown(0); - } -#endif - g_connections_count[0] = g_connections_count[1]; - g_connections_count[1] = count; -} - -int dnet_log_printf(const char *format, ...) { - va_list arg; - int done; - struct dnet_output out; - - va_start (arg, format); - dnet_log_open(&out); - done = dnet_vprintf(&out, format, arg); - dnet_log_close(&out); - va_end (arg); - - return done; -} +#include "../client/utils/utils.h" + +#define DNET_LOG_PERIOD 300 + +pthread_mutex_t dnet_log_mutex = PTHREAD_MUTEX_INITIALIZER; +time_t dnet_log_t0 = 0; +int g_connections_count[2]; + +static int dnet_vprintf(struct dnet_output *out, const char *format, va_list arg) { + int done; + + if (out->f) done = vfprintf(out->f, format, arg); + else if (out->str && out->len) { + done = vsnprintf(out->str, out->len, format, arg); + if (done >= 0) { + if ((unsigned)done > out->len) done = out->len; + out->len -= done; + out->str += done; + if (out->callback) (*out->callback)(out); + } + } else done = 0; + + return done; +} + +ssize_t dnet_write(struct dnet_output *out, const void *data, size_t size) { + ssize_t done; + + if (out->f) done = fwrite(data, 1, size, out->f); + else if (out->str && out->len) { + done = size; + if ((size_t)done > out->len) done = out->len; + memcpy(out->str, data, done); + out->len -= done; + out->str += done; + if (out->callback) (*out->callback)(out); + } else done = 0; + + return done; +} + +int dnet_printf(struct dnet_output *out, const char *format, ...) { + va_list arg; + int done; + + va_start (arg, format); + done = dnet_vprintf(out, format, arg); + va_end (arg); + + return done; +} + +static void dnet_log_open(struct dnet_output *out) { + time_t t = time(0); + struct tm tm; + char tbuf[64]; + localtime_r(&t, &tm); + strftime(tbuf, 64, "%Y-%m-%d %H:%M:%S ", &tm); + pthread_mutex_lock(&dnet_log_mutex); + out->f = xdag_open_file("dnet.log", "a"); + if (!out->f) out->f = stderr; + dnet_printf(out, "%s", tbuf); +} + +static void dnet_log_close(struct dnet_output *out) { + if (out->f != stderr) xdag_close_file(out->f); + out->f = 0; + pthread_mutex_unlock(&dnet_log_mutex); +} + +void dnet_print_hosts(struct dnet_output *out, long active_time) { + struct dnet_output new_out; + if (!out) dnet_log_open(out = &new_out); + out->count = 0; + dnet_printf(out, "%s hosts:\n", (active_time > 3600*24 ? "All" : active_time > 3600 ? "Daily" : active_time > DNET_ACTIVE_PERIOD ? "Hourly" : "Active")); + dnet_traverse_filtered_hosts((int (*)(struct dnet_host *, void *))&dnet_print_host, + (active_time > 3600*24 ? &dnet_hosts_compar_all : active_time > 3600 ? &dnet_hosts_compar_day + : active_time > DNET_ACTIVE_PERIOD ? &dnet_hosts_compar_hour : &dnet_hosts_compar), out); + if (out == &new_out) dnet_log_close(out); +} + +int dnet_print_connections(struct dnet_output *out) { + struct dnet_output new_out; + int count; + if (!out) dnet_log_open(out = &new_out); + out->count = 0; + dnet_printf(out, "Current connections:\n"); + dnet_traverse_connections((int (*)(struct dnet_connection *, void *))&dnet_print_connection, out); + count = out->count; + if (out == &new_out) dnet_log_close(out); + return count; +} + +void dnet_print_streams(struct dnet_output *out) { + struct dnet_output new_out; + if (!out) dnet_log_open(out = &new_out); + out->count = 0; + dnet_printf(out, "Current streams:\n"); + dnet_traverse_streams((int (*)(struct dnet_stream *, void *))&dnet_print_stream, out); + if (out == &new_out) dnet_log_close(out); +} + +void dnet_log_periodic(void) { +#ifndef QDNET + time_t t = time(0); + if (t - dnet_log_t0 >= DNET_LOG_PERIOD) { + dnet_log_t0 = t; + if (!dnet_limited_version) { + dnet_print_hosts(0, 0); + dnet_print_connections(0); + } + dnet_print_streams(0); + } +#endif +} + +void dnet_log_watchdog(int count) { +#ifdef __LDuS__ + if (g_connections_count[0] && !g_connections_count[1] && !count) { + printf("dnet: connection lost\n"); +// ldus_shutdown(0); + } +#endif + g_connections_count[0] = g_connections_count[1]; + g_connections_count[1] = count; +} + +int dnet_log_printf(const char *format, ...) { + va_list arg; + int done; + struct dnet_output out; + + va_start (arg, format); + dnet_log_open(&out); + done = dnet_vprintf(&out, format, arg); + dnet_log_close(&out); + va_end (arg); + + return done; +} diff --git a/dnet/dnet_log.h b/dnet/dnet_log.h index 6239a0cb..49f88449 100644 --- a/dnet/dnet_log.h +++ b/dnet/dnet_log.h @@ -1,31 +1,39 @@ -/* dnet: log; T11.261-T13.063; $DVS:time$ */ - -#ifndef DNET_LOG_H_INCLUDED -#define DNET_LOG_H_INCLUDED - -#include -#include -#include "system.h" - -struct dnet_output { - FILE *f; - char *str; - size_t len; - void *data; - void (*callback)(struct dnet_output *out); - int count; - int err; -}; - -#define DNET_ACTIVE_PERIOD 300 - -extern int dnet_printf(struct dnet_output *out, const char *format, ...); -extern ssize_t dnet_write(struct dnet_output *out, const void *data, size_t size); -extern void dnet_print_hosts(struct dnet_output *out, long active_time); -extern int dnet_print_connections(struct dnet_output *out); -extern void dnet_print_streams(struct dnet_output *out); -extern void dnet_log_periodic(void); -extern int dnet_log_printf(const char *format, ...); -extern void dnet_log_watchdog(int count); - -#endif +/* dnet: log; T11.261-T13.063; $DVS:time$ */ + +#ifndef DNET_LOG_H_INCLUDED +#define DNET_LOG_H_INCLUDED + +#include +#include +#include "system.h" + +struct dnet_output { + FILE *f; + char *str; + size_t len; + void *data; + void (*callback)(struct dnet_output *out); + int count; + int err; +}; + +#define DNET_ACTIVE_PERIOD 300 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_printf(struct dnet_output *out, const char *format, ...); +extern ssize_t dnet_write(struct dnet_output *out, const void *data, size_t size); +extern void dnet_print_hosts(struct dnet_output *out, long active_time); +extern int dnet_print_connections(struct dnet_output *out); +extern void dnet_print_streams(struct dnet_output *out); +extern void dnet_log_periodic(void); +extern int dnet_log_printf(const char *format, ...); +extern void dnet_log_watchdog(int count); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_main.c b/dnet/dnet_main.c index 9d08f5a4..d5fc72ef 100644 --- a/dnet/dnet_main.c +++ b/dnet/dnet_main.c @@ -1,175 +1,175 @@ -/* dnet: main file; T11.231-T13.789; $DVS:time$ */ - -#include -#include -#include -#include -#include -#if !defined(_WIN32) && !defined(_WIN64) -#include -#include -#include -#endif -#include "dnet_crypt.h" -#include "dnet_database.h" -#include "dnet_history.h" -#include "dnet_connection.h" -#include "dnet_threads.h" -#include "dnet_log.h" -#include "dnet_command.h" +/* dnet: main file; T11.231-T13.789; $DVS:time$ */ + +#include +#include +#include +#include +#include +#if !defined(_WIN32) && !defined(_WIN64) +#include +#include +#include +#endif +#include "dnet_crypt.h" +#include "dnet_database.h" +#include "dnet_history.h" +#include "dnet_connection.h" +#include "dnet_threads.h" +#include "dnet_log.h" +#include "dnet_command.h" #include "dnet_main.h" #if defined (__MACOS__) || defined (__APPLE__) #define SIGPOLL SIGIO -#endif - -//#define NO_DNET_FORK - -extern int getdtablesize(void); - -#ifdef __LDuS__ -#include -static void catcher(int signum) { - ldus_block_signal(0, signum); /* заблокировать его, чтобы самому повторно не получить */ - ldus_kill_task(0, signum); /* передать сигнал дальше */ -} -#endif - -static void daemonize(void) { -#if !defined(_WIN32) && !defined(_WIN64) && !defined(QDNET) && !defined(NO_DNET_FORK) - int i; -#ifndef __LDuS__ - if (getppid() == 1) exit(0); /* already a daemon */ - i = fork(); - if (i < 0) exit(1); /* fork error */ - if (i > 0) exit(0); /* parent exits */ - - /* child (daemon) continues */ - setsid(); /* obtain a new process group */ - for (i = getdtablesize(); i >= 0; --i) close(i); /* close all descriptors */ - i = open("/dev/null", O_RDWR); dup(i); dup(i); /* handle standard I/O */ - - /* first instance continues */ -#if 0 - signal(SIGCHLD, SIG_IGN); /* ignore child */ -#endif - signal(SIGHUP, SIG_IGN); - signal(SIGPIPE, SIG_IGN); - signal(SIGALRM, SIG_IGN); - signal(SIGUSR1, SIG_IGN); - signal(SIGUSR2, SIG_IGN); - signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ - signal(SIGPOLL, SIG_IGN); - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - signal(SIGVTALRM, SIG_IGN); - signal(SIGPROF, SIG_IGN); -#else - /* перехват всех сигналов */ - for (i = 1; i <= INT_SIG_END - INT_SIG; ++i) if (i != SIGCONT) - signal(i, &catcher); -#endif -#endif -} - -static void angelize(void) { -#if !defined(__LDuS__) && !defined(QDNET) && !defined(_WIN32) && !defined(_WIN64) && !defined(NO_DNET_FORK) - int stat = 0; - pid_t childpid; - while ((childpid = fork())) { - signal(SIGINT, SIG_IGN); - signal(SIGTERM, SIG_IGN); - if (childpid > 0) while (waitpid(childpid, &stat, 0) == -1) { - if (errno != EINTR) { - abort(); - } - } - if (stat >= 0 && stat <= 5) { - exit(stat); - } - sleep(10); - } -#endif -} - -int dnet_init(int argc, char **argv) { - char command[DNET_COMMAND_MAX]; - struct dnet_output out; - struct dnet_thread *thread; - int i = 0, err = 0, res, is_daemon = 0, is_server = 0; - const char *mess = 0; - - if (system_init() || dnet_threads_init() || dnet_hosts_init()) { - err = 4; mess = "initializing error"; goto end; - } - - for (i = 1; i < argc + 2; ++i) { - if (i == 1) { -#if !defined(_WIN32) && !defined(_WIN64) - if (i < argc && !strcmp(argv[i], "-d")) is_daemon = 1; -#endif - printf("%s %s%s.\n", argv[0], DNET_VERSION, (is_daemon ? ", running as daemon" : "")); - if ((err = dnet_crypt_init(DNET_VERSION))) { - sleep(3); printf("Password incorrect.\n"); - return err; - } - work: - if (is_daemon) daemonize(); - angelize(); - dnet_log_printf("%s %s%s.\n", argv[0], DNET_VERSION, (is_daemon ? ", running as daemon" : "")); - if (is_daemon) continue; - } - if (i < argc && !strcmp(argv[i], "-s")) { - is_server = 1; - continue; - } - if (i < argc - 1 && !strcmp(argv[i], "-c")) { - i++; - continue; - } - - thread = malloc(sizeof(struct dnet_thread)); - if (!thread) { err = 2; goto end; } - if (i < argc) { - thread->arg = argv[i]; - thread->conn.socket = -1; - thread->type = (is_server ? DNET_THREAD_SERVER : DNET_THREAD_CLIENT); - } else if (i == argc) { - thread->type = DNET_THREAD_WATCHDOG; - } else { - thread->type = DNET_THREAD_COLLECTOR; - } - res = dnet_thread_create(thread); - if (res) { err = 3; goto end; } - - is_server = 0; - } - - out.f = stdout; - i = 1; - while (1) { - while (i < argc && strcmp(argv[i], "-c")) i++; - if (i + 1 < argc) { - if (!strcmp(argv[++i], "repeat")) { - i = 1; - continue; - } - strcpy(command, argv[i++]); - } else if (is_daemon) { - return 0; - - } else { - return 0; - } - if (dnet_command(command, &out) < 0) break; - } - -end: - if (err) { - if (!mess) mess = strerror(errno); - if (!is_daemon) printf("%s: error %X: %s.\n", argv[0], err, mess); - dnet_log_printf("%s: error %X: %s.\n", argv[0], err, mess); - if (err < 0) goto work; - } - exit(err); -} +#endif + +//#define NO_DNET_FORK + +extern int getdtablesize(void); + +#ifdef __LDuS__ +#include +static void catcher(int signum) { + ldus_block_signal(0, signum); /* заблокировать его, чтобы самому повторно не получить */ + ldus_kill_task(0, signum); /* передать сигнал дальше */ +} +#endif + +static void daemonize(void) { +#if !defined(_WIN32) && !defined(_WIN64) && !defined(QDNET) && !defined(NO_DNET_FORK) + int i; +#ifndef __LDuS__ + if (getppid() == 1) exit(0); /* already a daemon */ + i = fork(); + if (i < 0) exit(1); /* fork error */ + if (i > 0) exit(0); /* parent exits */ + + /* child (daemon) continues */ + setsid(); /* obtain a new process group */ + for (i = getdtablesize(); i >= 0; --i) close(i); /* close all descriptors */ + i = open("/dev/null", O_RDWR); dup(i); dup(i); /* handle standard I/O */ + + /* first instance continues */ +#if 0 + signal(SIGCHLD, SIG_IGN); /* ignore child */ +#endif + signal(SIGHUP, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGALRM, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ + signal(SIGPOLL, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGVTALRM, SIG_IGN); + signal(SIGPROF, SIG_IGN); +#else + /* перехват всех сигналов */ + for (i = 1; i <= INT_SIG_END - INT_SIG; ++i) if (i != SIGCONT) + signal(i, &catcher); +#endif +#endif +} + +static void angelize(void) { +#if !defined(__LDuS__) && !defined(QDNET) && !defined(_WIN32) && !defined(_WIN64) && !defined(NO_DNET_FORK) + int stat = 0; + pid_t childpid; + while ((childpid = fork())) { + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + if (childpid > 0) while (waitpid(childpid, &stat, 0) == -1) { + if (errno != EINTR) { + abort(); + } + } + if (stat >= 0 && stat <= 5) { + exit(stat); + } + sleep(10); + } +#endif +} + +int dnet_init(int argc, char **argv) { + char command[DNET_COMMAND_MAX]; + struct dnet_output out; + struct dnet_thread *thread; + int i = 0, err = 0, res, is_daemon = 0, is_server = 0; + const char *mess = 0; + + if (system_init() || dnet_threads_init() || dnet_hosts_init()) { + err = 4; mess = "initializing error"; goto end; + } + + for (i = 1; i < argc + 2; ++i) { + if (i == 1) { +#if !defined(_WIN32) && !defined(_WIN64) + if (i < argc && !strcmp(argv[i], "-d")) is_daemon = 1; +#endif + printf("%s %s%s.\n", argv[0], DNET_VERSION, (is_daemon ? ", running as daemon" : "")); + if ((err = dnet_crypt_init(DNET_VERSION))) { + sleep(3); printf("Password incorrect.\n"); + return err; + } + work: + if (is_daemon) daemonize(); + angelize(); + dnet_log_printf("%s %s%s.\n", argv[0], DNET_VERSION, (is_daemon ? ", running as daemon" : "")); + if (is_daemon) continue; + } + if (i < argc && !strcmp(argv[i], "-s")) { + is_server = 1; + continue; + } + if (i < argc - 1 && !strcmp(argv[i], "-c")) { + i++; + continue; + } + + thread = malloc(sizeof(struct dnet_thread)); + if (!thread) { err = 2; goto end; } + if (i < argc) { + thread->arg = argv[i]; + thread->conn.socket = -1; + thread->type = (is_server ? DNET_THREAD_SERVER : DNET_THREAD_CLIENT); + } else if (i == argc) { + thread->type = DNET_THREAD_WATCHDOG; + } else { + thread->type = DNET_THREAD_COLLECTOR; + } + res = dnet_thread_create(thread); + if (res) { err = 3; goto end; } + + is_server = 0; + } + + out.f = stdout; + i = 1; + while (1) { + while (i < argc && strcmp(argv[i], "-c")) i++; + if (i + 1 < argc) { + if (!strcmp(argv[++i], "repeat")) { + i = 1; + continue; + } + strcpy(command, argv[i++]); + } else if (is_daemon) { + return 0; + + } else { + return 0; + } + if (dnet_command(command, &out) < 0) break; + } + +end: + if (err) { + if (!mess) mess = strerror(errno); + if (!is_daemon) printf("%s: error %X: %s.\n", argv[0], err, mess); + dnet_log_printf("%s: error %X: %s.\n", argv[0], err, mess); + if (err < 0) goto work; + } + exit(err); +} diff --git a/dnet/dnet_main.h b/dnet/dnet_main.h index 015bf722..0fa09f94 100644 --- a/dnet/dnet_main.h +++ b/dnet/dnet_main.h @@ -1,48 +1,48 @@ -/* dnet: external interface; T13.011-T13.794; $DVS:time$ */ - -#ifndef DNET_MAIN_H_INCLUDED -#define DNET_MAIN_H_INCLUDED - -#ifdef __cplusplus -extern "C" { -#endif - -extern int dnet_init(int argc, char **argv); - -extern int dnet_generate_random_array(void *array, unsigned long size); - -extern int dnet_set_xdag_callback(int (*callback)(void *block, void *connection_from)); - -/* отправить блок по данному соединению или группе соединений в зависимости от ппраметра connection_to: - * 0 - по случайному соединению, возвращает то соединение, по которому был отправлен; - * 1 ... 255 - по всем соединениям; ttl = данное число; - * нечётное - по всем соединениям, кроме (connection_to - 1); - * чётное - по данному соединению; - */ -extern void *dnet_send_xdag_packet(void *block, void *connection_to); - -extern int dnet_execute_command(const char *cmd, void *fileout); - -extern int dnet_set_self_version(const char *version); - -/* возвращает не 0, если данное входящее соединение не разрешается открывать */ -extern int (*dnet_connection_open_check)(void *conn, uint32_t ip, uint16_t port); - -extern void (*dnet_connection_close_notify)(void *conn); - -/* выполнить действие с паролем пользователя: - * 1 - закодировать данные (data_id - порядковый номер данных, size - размер данных, измеряется в 32-битных словах) - * 2 - декодировать -//- - * 3 - ввести пароль и проверить его, возвращает 0 при успехе - * 4 - ввести пароль и записать его отпечаток в массив data длины 16 байт - * 5 - проверить, что отпечаток в массиве data соответствует паролю - * 6 - setup callback function to input password, data is pointer to function - * int (*)(const char *prompt, char *buf, unsigned size); - */ -extern int dnet_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action); - -#ifdef __cplusplus -} -#endif - -#endif +/* dnet: external interface; T13.011-T13.794; $DVS:time$ */ + +#ifndef DNET_MAIN_H_INCLUDED +#define DNET_MAIN_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_init(int argc, char **argv); + +extern int dnet_generate_random_array(void *array, unsigned long size); + +extern int dnet_set_xdag_callback(int (*callback)(void *block, void *connection_from)); + +/* отправить блок по данному соединению или группе соединений в зависимости от ппраметра connection_to: + * 0 - по случайному соединению, возвращает то соединение, по которому был отправлен; + * 1 ... 255 - по всем соединениям; ttl = данное число; + * нечётное - по всем соединениям, кроме (connection_to - 1); + * чётное - по данному соединению; + */ +extern void *dnet_send_xdag_packet(void *block, void *connection_to); + +extern int dnet_execute_command(const char *cmd, void *fileout); + +extern int dnet_set_self_version(const char *version); + +/* возвращает не 0, если данное входящее соединение не разрешается открывать */ +extern int (*dnet_connection_open_check)(void *conn, uint32_t ip, uint16_t port); + +extern void (*dnet_connection_close_notify)(void *conn); + +/* выполнить действие с паролем пользователя: + * 1 - закодировать данные (data_id - порядковый номер данных, size - размер данных, измеряется в 32-битных словах) + * 2 - декодировать -//- + * 3 - ввести пароль и проверить его, возвращает 0 при успехе + * 4 - ввести пароль и записать его отпечаток в массив data длины 16 байт + * 5 - проверить, что отпечаток в массиве data соответствует паролю + * 6 - setup callback function to input password, data is pointer to function + * int (*)(const char *prompt, char *buf, unsigned size); + */ +extern int dnet_user_crypt_action(unsigned *data, unsigned long long data_id, unsigned size, int action); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_packet.c b/dnet/dnet_packet.c index 22c922a8..7ad01ee4 100644 --- a/dnet/dnet_packet.c +++ b/dnet/dnet_packet.c @@ -1,191 +1,191 @@ -/* dnet: packets; T11.258-T13.808; $DVS:time$ */ - -#include -#include -#include -#include -#ifdef __LDuS__ -#include -#include -#include -#endif -#include "../dus/programs/dar/source/include/crc.h" -#include "dnet_database.h" -#include "dnet_packet.h" -#include "dnet_connection.h" -#include "dnet_threads.h" -#include "dnet_log.h" -#include "dnet_command.h" -#include "dnet_stream.h" -#include "dnet_files.h" -#include "dnet_main.h" - -#define SENT_COMMANDS_MAX 256 -#define XDAG_PACKET_LEN 512 - -struct dnet_sent_command { - struct dnet_stream_id id; - struct dnet_output out; - char valid; -}; - -struct dnet_stream_id g_last_received_command_id = { { 0, 0, 0, 0} }; -struct dnet_sent_command *g_last_sent_command = 0; -static int (*xdag_callback)(void *packet, void *connection) = 0; - -int dnet_set_xdag_callback(int (*callback)(void *, void *)) { xdag_callback = callback; return 0; } - -int dnet_send_packet(struct dnet_packet *p, struct dnet_connection *conn) { - char buf[512]; - int i, len = (512 - p->header.length) & 511; - p->header.crc32 = 0; - p->header.crc32 = crc_of_array((uint8_t *)p, p->header.length); - for (i = 0; i < len; ++i) buf[i] = rand() % DNET_PKT_MIN; - dthread_mutex_lock(&conn->mutex); - if (conn->sess) { - ssize_t res = dnet_session_write(conn->sess, p, p->header.length); - if (len) dnet_session_write(conn->sess, buf, len); - if (res == p->header.length) conn->counters[DNET_C_OUT_PACKETS]++; - else conn->counters[DNET_C_OUT_DROPPED]++; - } - dthread_mutex_unlock(&conn->mutex); - return 0; -} - -struct xdag_data { - struct dnet_packet *p; - struct dnet_connection *conn; - int nconn; -}; - -static int dnet_send_xdag_callback(struct dnet_connection *conn, void *data) { - struct xdag_data *d = (struct xdag_data *)data; - if (d->nconn < 0) { - if (conn != d->conn) dnet_send_packet(d->p, conn); - } else { - if (!(rand() % ++d->nconn)) d->conn = conn; - } - return 0; -} - -void *dnet_send_xdag_packet(void *block, void *connection_to) { - struct xdag_data d; - d.conn = (struct dnet_connection *)connection_to; - d.p = (struct dnet_packet *)block; - d.p->header.type = DNET_PKT_XDAG; - d.p->header.length = XDAG_PACKET_LEN; - if (!d.conn) { - d.p->header.ttl = 1; - d.nconn = 0; - } else if ((uintptr_t)d.conn < 256) { - d.p->header.ttl = (uint8_t)(uintptr_t)d.conn; - d.conn = 0; - d.nconn = -1; - } else if ((uintptr_t)d.conn & 1) { - if (d.p->header.ttl <= 2) return 0; - d.p->header.ttl--; - d.conn = (struct dnet_connection *)((uintptr_t)d.conn - 1); - d.nconn = -1; - } else { - d.p->header.ttl = 1; - d.nconn = INT_MAX; - } - if (d.nconn <= 0) dnet_traverse_connections(dnet_send_xdag_callback, &d); - if (d.nconn > 0) dnet_send_packet(d.p, d.conn); - return (d.nconn > 0 && d.nconn < INT_MAX ? d.conn : 0); -} - -int dnet_send_command_packet(struct dnet_packet_stream *st, struct dnet_output *output) { - int i; - if (!g_last_sent_command) { - g_last_sent_command = calloc(SENT_COMMANDS_MAX, sizeof(struct dnet_sent_command)); - if (!g_last_sent_command) return 4; - } - for (i = 0; i < SENT_COMMANDS_MAX; ++i) if (!g_last_sent_command[i].valid || - (output->f ? (g_last_sent_command[i].out.f == output->f) : (g_last_sent_command[i].out.str == output->str))) { - g_last_sent_command[i].valid = 1; - memcpy(&g_last_sent_command[i].out, output, sizeof(struct dnet_output)); - memcpy(&g_last_sent_command[i].id, &st->id, sizeof(struct dnet_stream_id)); - return dnet_send_stream_packet(st, 0); - } - return 5; -} - -int dnet_cancel_command(struct dnet_output *output) { - int i; - if (g_last_sent_command) for (i = 0; i < SENT_COMMANDS_MAX; ++i) if (g_last_sent_command[i].valid - && (output->f ? (g_last_sent_command[i].out.f == output->f) : (g_last_sent_command[i].out.str == output->str))) { - g_last_sent_command[i].valid = 0; - return 0; - } - return 1; -} - -int dnet_process_packet(struct dnet_packet *p, struct dnet_connection *conn) { - uint32_t crc = p->header.crc32; - p->header.crc32 = 0; - if (crc_of_array((uint8_t *)p, p->header.length) != crc) return 1; - switch(p->header.type) { - case DNET_PKT_EXCHANGE: - if (p->header.length < DNET_PKT_EXCHANGE_MIN_LEN || p->header.length > DNET_PKT_EXCHANGE_MAX_LEN) return 0x12; - { - struct dnet_host *host = dnet_add_host(&p->ex.pub_key, p->ex.time_ago, conn->ipaddr, conn->port, DNET_ROUTE_AUTO); - if (!host) return 3; - if (p->header.length > DNET_PKT_EXCHANGE_MIN_LEN) { - struct dnet_host *host_from = dnet_session_get_host(conn->sess); - int namelen = p->header.length - DNET_PKT_EXCHANGE_MIN_LEN; - if (namelen && (!host->name_len || (host_from && host_from->is_trusted) || !host->is_trusted)) { - char *version = memchr(p->ex.name, 0, namelen); - dnet_set_host_name(host, p->ex.name, version ? version - p->ex.name : namelen); - if (version) { - namelen -= version - p->ex.name + 1; - if (namelen) { - memmove(version, version + 1, namelen); - version[namelen] = 0; - dnet_set_host_version(host, version); - } - } - } - } - } - break; - case DNET_PKT_UPDATE: - if (p->header.length < DNET_PKT_UPDATE_MIN_LEN || p->header.length > DNET_PKT_UPDATE_MAX_LEN || - (p->header.length - DNET_PKT_UPDATE_MIN_LEN) % sizeof(struct dnet_packet_update_item)) return 0x22; - { - struct dnet_host *host; - int i, nitems = (p->header.length - DNET_PKT_UPDATE_MIN_LEN) / sizeof(struct dnet_packet_update_item); - for (i = 0; i < nitems; ++i) { - host = dnet_get_host_by_crc(p->up.item[i].crc32); - if (host) dnet_update_host(host, p->up.item[i].time_ago, conn->ipaddr, conn->port, DNET_ROUTE_AUTO); - } - } - break; - case DNET_PKT_COMMAND: - case DNET_PKT_COMMAND_OUTPUT: - case DNET_PKT_SHELL_INPUT: - case DNET_PKT_SHELL_OUTPUT: - case DNET_PKT_TUNNELED_MSG: - case DNET_PKT_FORWARDED_TCP: - case DNET_PKT_FORWARDED_UDP: - case DNET_PKT_FILE_OP: - break; - case DNET_PKT_XDAG: - { - uint8_t ttl = p->header.ttl; - int res; - if (p->header.length != XDAG_PACKET_LEN) return 0x19; - if (!xdag_callback) return 0x29; - res = (*xdag_callback)(p, conn); - if (res < 0) return 0x39; - if (res > 0 && ttl > 2) { - p->header.ttl = ttl; - dnet_send_xdag_packet(p, (void *)((uintptr_t)conn | 1)); - } - } - break; - default: - return 9; - } - return 0; -} +/* dnet: packets; T11.258-T13.808; $DVS:time$ */ + +#include +#include +#include +#include +#ifdef __LDuS__ +#include +#include +#include +#endif +#include "../dus/programs/dar/source/include/crc.h" +#include "dnet_database.h" +#include "dnet_packet.h" +#include "dnet_connection.h" +#include "dnet_threads.h" +#include "dnet_log.h" +#include "dnet_command.h" +#include "dnet_stream.h" +#include "dnet_files.h" +#include "dnet_main.h" + +#define SENT_COMMANDS_MAX 256 +#define XDAG_PACKET_LEN 512 + +struct dnet_sent_command { + struct dnet_stream_id id; + struct dnet_output out; + char valid; +}; + +struct dnet_stream_id g_last_received_command_id = { { 0, 0, 0, 0} }; +struct dnet_sent_command *g_last_sent_command = 0; +static int (*xdag_callback)(void *packet, void *connection) = 0; + +int dnet_set_xdag_callback(int (*callback)(void *, void *)) { xdag_callback = callback; return 0; } + +int dnet_send_packet(struct dnet_packet *p, struct dnet_connection *conn) { + char buf[512]; + int i, len = (512 - p->header.length) & 511; + p->header.crc32 = 0; + p->header.crc32 = crc_of_array((uint8_t *)p, p->header.length); + for (i = 0; i < len; ++i) buf[i] = rand() % DNET_PKT_MIN; + dthread_mutex_lock(&conn->mutex); + if (conn->sess) { + ssize_t res = dnet_session_write(conn->sess, p, p->header.length); + if (len) dnet_session_write(conn->sess, buf, len); + if (res == p->header.length) conn->counters[DNET_C_OUT_PACKETS]++; + else conn->counters[DNET_C_OUT_DROPPED]++; + } + dthread_mutex_unlock(&conn->mutex); + return 0; +} + +struct xdag_data { + struct dnet_packet *p; + struct dnet_connection *conn; + int nconn; +}; + +static int dnet_send_xdag_callback(struct dnet_connection *conn, void *data) { + struct xdag_data *d = (struct xdag_data *)data; + if (d->nconn < 0) { + if (conn != d->conn) dnet_send_packet(d->p, conn); + } else { + if (!(rand() % ++d->nconn)) d->conn = conn; + } + return 0; +} + +void *dnet_send_xdag_packet(void *block, void *connection_to) { + struct xdag_data d; + d.conn = (struct dnet_connection *)connection_to; + d.p = (struct dnet_packet *)block; + d.p->header.type = DNET_PKT_XDAG; + d.p->header.length = XDAG_PACKET_LEN; + if (!d.conn) { + d.p->header.ttl = 1; + d.nconn = 0; + } else if ((uintptr_t)d.conn < 256) { + d.p->header.ttl = (uint8_t)(uintptr_t)d.conn; + d.conn = 0; + d.nconn = -1; + } else if ((uintptr_t)d.conn & 1) { + if (d.p->header.ttl <= 2) return 0; + d.p->header.ttl--; + d.conn = (struct dnet_connection *)((uintptr_t)d.conn - 1); + d.nconn = -1; + } else { + d.p->header.ttl = 1; + d.nconn = INT_MAX; + } + if (d.nconn <= 0) dnet_traverse_connections(dnet_send_xdag_callback, &d); + if (d.nconn > 0) dnet_send_packet(d.p, d.conn); + return (d.nconn > 0 && d.nconn < INT_MAX ? d.conn : 0); +} + +int dnet_send_command_packet(struct dnet_packet_stream *st, struct dnet_output *output) { + int i; + if (!g_last_sent_command) { + g_last_sent_command = calloc(SENT_COMMANDS_MAX, sizeof(struct dnet_sent_command)); + if (!g_last_sent_command) return 4; + } + for (i = 0; i < SENT_COMMANDS_MAX; ++i) if (!g_last_sent_command[i].valid || + (output->f ? (g_last_sent_command[i].out.f == output->f) : (g_last_sent_command[i].out.str == output->str))) { + g_last_sent_command[i].valid = 1; + memcpy(&g_last_sent_command[i].out, output, sizeof(struct dnet_output)); + memcpy(&g_last_sent_command[i].id, &st->id, sizeof(struct dnet_stream_id)); + return dnet_send_stream_packet(st, 0); + } + return 5; +} + +int dnet_cancel_command(struct dnet_output *output) { + int i; + if (g_last_sent_command) for (i = 0; i < SENT_COMMANDS_MAX; ++i) if (g_last_sent_command[i].valid + && (output->f ? (g_last_sent_command[i].out.f == output->f) : (g_last_sent_command[i].out.str == output->str))) { + g_last_sent_command[i].valid = 0; + return 0; + } + return 1; +} + +int dnet_process_packet(struct dnet_packet *p, struct dnet_connection *conn) { + uint32_t crc = p->header.crc32; + p->header.crc32 = 0; + if (crc_of_array((uint8_t *)p, p->header.length) != crc) return 1; + switch(p->header.type) { + case DNET_PKT_EXCHANGE: + if (p->header.length < DNET_PKT_EXCHANGE_MIN_LEN || p->header.length > DNET_PKT_EXCHANGE_MAX_LEN) return 0x12; + { + struct dnet_host *host = dnet_add_host(&p->ex.pub_key, p->ex.time_ago, conn->ipaddr, conn->port, DNET_ROUTE_AUTO); + if (!host) return 3; + if (p->header.length > DNET_PKT_EXCHANGE_MIN_LEN) { + struct dnet_host *host_from = dnet_session_get_host(conn->sess); + int namelen = p->header.length - DNET_PKT_EXCHANGE_MIN_LEN; + if (namelen && (!host->name_len || (host_from && host_from->is_trusted) || !host->is_trusted)) { + char *version = memchr(p->ex.name, 0, namelen); + dnet_set_host_name(host, p->ex.name, version ? version - p->ex.name : namelen); + if (version) { + namelen -= version - p->ex.name + 1; + if (namelen) { + memmove(version, version + 1, namelen); + version[namelen] = 0; + dnet_set_host_version(host, version); + } + } + } + } + } + break; + case DNET_PKT_UPDATE: + if (p->header.length < DNET_PKT_UPDATE_MIN_LEN || p->header.length > DNET_PKT_UPDATE_MAX_LEN || + (p->header.length - DNET_PKT_UPDATE_MIN_LEN) % sizeof(struct dnet_packet_update_item)) return 0x22; + { + struct dnet_host *host; + int i, nitems = (p->header.length - DNET_PKT_UPDATE_MIN_LEN) / sizeof(struct dnet_packet_update_item); + for (i = 0; i < nitems; ++i) { + host = dnet_get_host_by_crc(p->up.item[i].crc32); + if (host) dnet_update_host(host, p->up.item[i].time_ago, conn->ipaddr, conn->port, DNET_ROUTE_AUTO); + } + } + break; + case DNET_PKT_COMMAND: + case DNET_PKT_COMMAND_OUTPUT: + case DNET_PKT_SHELL_INPUT: + case DNET_PKT_SHELL_OUTPUT: + case DNET_PKT_TUNNELED_MSG: + case DNET_PKT_FORWARDED_TCP: + case DNET_PKT_FORWARDED_UDP: + case DNET_PKT_FILE_OP: + break; + case DNET_PKT_XDAG: + { + uint8_t ttl = p->header.ttl; + int res; + if (p->header.length != XDAG_PACKET_LEN) return 0x19; + if (!xdag_callback) return 0x29; + res = (*xdag_callback)(p, conn); + if (res < 0) return 0x39; + if (res > 0 && ttl > 2) { + p->header.ttl = ttl; + dnet_send_xdag_packet(p, (void *)((uintptr_t)conn | 1)); + } + } + break; + default: + return 9; + } + return 0; +} diff --git a/dnet/dnet_packet.h b/dnet/dnet_packet.h index 95858f33..0bb8f698 100644 --- a/dnet/dnet_packet.h +++ b/dnet/dnet_packet.h @@ -1,91 +1,99 @@ -/* dnet: packets; T11.258-T13.658; $DVS:time$ */ - -#ifndef DNET_PACKET_H_INCLUDED -#define DNET_PACKET_H_INCLUDED - -#include -#include "dnet_crypt.h" -#include "dnet_database.h" -#include "dnet_log.h" - -#define DNET_PKT_STREAM_DATA_MAX 0x1000 - -enum dnet_packet_types { - DNET_PKT_MIN = 0x80, - DNET_PKT_EXCHANGE = 0x80, - DNET_PKT_UPDATE = 0x81, - DNET_PKT_COMMAND = 0x82, - DNET_PKT_COMMAND_OUTPUT = 0x83, - DNET_PKT_SHELL_INPUT = 0x84, - DNET_PKT_SHELL_OUTPUT = 0x85, - DNET_PKT_TUNNELED_MSG = 0x86, - DNET_PKT_FORWARDED_TCP = 0x87, - DNET_PKT_FORWARDED_UDP = 0x88, - DNET_PKT_FILE_OP = 0x89, - DNET_PKT_CRYPT = 0x8A, - DNET_PKT_XDAG = 0x8B, - DNET_PKT_MAX = 0x8B, -}; - -struct dnet_packet_header { - uint8_t type; - uint8_t ttl; - uint16_t length; - uint32_t crc32; -}; - -struct dnet_packet_exchange { - struct dnet_packet_header header; - struct dnet_key pub_key; - uint32_t time_ago; - char name[DNET_HOST_NAME_MAX]; -}; - -struct dnet_packet_update_item { - uint32_t crc32; - uint32_t time_ago; -}; - -#define DNET_PKT_EXCHANGE_MIN_LEN ((long)((struct dnet_packet_exchange *)0)->name) -#define DNET_PKT_EXCHANGE_MAX_LEN (DNET_PKT_EXCHANGE_MIN_LEN + DNET_HOST_NAME_MAX) - -#define DNET_PKT_UPDATE_ITEMS_MAX (DNET_PKT_STREAM_DATA_MAX / sizeof(struct dnet_packet_update_item) - 1) - -struct dnet_packet_update { - struct dnet_packet_header header; - struct dnet_packet_update_item item[DNET_PKT_UPDATE_ITEMS_MAX]; -}; - -#define DNET_PKT_UPDATE_MIN_LEN ((long)((struct dnet_packet_update *)0)->item) -#define DNET_PKT_UPDATE_MAX_LEN (DNET_PKT_UPDATE_MIN_LEN + DNET_PKT_UPDATE_ITEMS_MAX * sizeof(struct dnet_packet_update_item)) - -struct dnet_packet_stream { - struct dnet_packet_header header; - uint32_t crc_from; - uint32_t crc_to; - uint64_t seq; - uint64_t ack; - struct dnet_stream_id id; - uint8_t data[DNET_PKT_STREAM_DATA_MAX]; -}; - -#define DNET_PKT_STREAM_MIN_LEN ((long)((struct dnet_packet_stream *)0)->data) -#define DNET_PKT_STREAM_MAX_LEN (DNET_PKT_STREAM_MIN_LEN + DNET_PKT_STREAM_DATA_MAX) - -struct dnet_packet { - union { - struct dnet_packet_header header; - struct dnet_packet_exchange ex; - struct dnet_packet_update up; - struct dnet_packet_stream st; - }; -}; - -struct dnet_connection; - -extern int dnet_process_packet(struct dnet_packet *p, struct dnet_connection *conn); -extern int dnet_send_packet(struct dnet_packet *p, struct dnet_connection *conn); -extern int dnet_send_command_packet(struct dnet_packet_stream *st, struct dnet_output *output); -extern int dnet_cancel_command(struct dnet_output *output); - -#endif +/* dnet: packets; T11.258-T13.658; $DVS:time$ */ + +#ifndef DNET_PACKET_H_INCLUDED +#define DNET_PACKET_H_INCLUDED + +#include +#include "dnet_crypt.h" +#include "dnet_database.h" +#include "dnet_log.h" + +#define DNET_PKT_STREAM_DATA_MAX 0x1000 + +enum dnet_packet_types { + DNET_PKT_MIN = 0x80, + DNET_PKT_EXCHANGE = 0x80, + DNET_PKT_UPDATE = 0x81, + DNET_PKT_COMMAND = 0x82, + DNET_PKT_COMMAND_OUTPUT = 0x83, + DNET_PKT_SHELL_INPUT = 0x84, + DNET_PKT_SHELL_OUTPUT = 0x85, + DNET_PKT_TUNNELED_MSG = 0x86, + DNET_PKT_FORWARDED_TCP = 0x87, + DNET_PKT_FORWARDED_UDP = 0x88, + DNET_PKT_FILE_OP = 0x89, + DNET_PKT_CRYPT = 0x8A, + DNET_PKT_XDAG = 0x8B, + DNET_PKT_MAX = 0x8B, +}; + +struct dnet_packet_header { + uint8_t type; + uint8_t ttl; + uint16_t length; + uint32_t crc32; +}; + +struct dnet_packet_exchange { + struct dnet_packet_header header; + struct dnet_key pub_key; + uint32_t time_ago; + char name[DNET_HOST_NAME_MAX]; +}; + +struct dnet_packet_update_item { + uint32_t crc32; + uint32_t time_ago; +}; + +#define DNET_PKT_EXCHANGE_MIN_LEN ((long)((struct dnet_packet_exchange *)0)->name) +#define DNET_PKT_EXCHANGE_MAX_LEN (DNET_PKT_EXCHANGE_MIN_LEN + DNET_HOST_NAME_MAX) + +#define DNET_PKT_UPDATE_ITEMS_MAX (DNET_PKT_STREAM_DATA_MAX / sizeof(struct dnet_packet_update_item) - 1) + +struct dnet_packet_update { + struct dnet_packet_header header; + struct dnet_packet_update_item item[DNET_PKT_UPDATE_ITEMS_MAX]; +}; + +#define DNET_PKT_UPDATE_MIN_LEN ((long)((struct dnet_packet_update *)0)->item) +#define DNET_PKT_UPDATE_MAX_LEN (DNET_PKT_UPDATE_MIN_LEN + DNET_PKT_UPDATE_ITEMS_MAX * sizeof(struct dnet_packet_update_item)) + +struct dnet_packet_stream { + struct dnet_packet_header header; + uint32_t crc_from; + uint32_t crc_to; + uint64_t seq; + uint64_t ack; + struct dnet_stream_id id; + uint8_t data[DNET_PKT_STREAM_DATA_MAX]; +}; + +#define DNET_PKT_STREAM_MIN_LEN ((long)((struct dnet_packet_stream *)0)->data) +#define DNET_PKT_STREAM_MAX_LEN (DNET_PKT_STREAM_MIN_LEN + DNET_PKT_STREAM_DATA_MAX) + +struct dnet_packet { + union { + struct dnet_packet_header header; + struct dnet_packet_exchange ex; + struct dnet_packet_update up; + struct dnet_packet_stream st; + }; +}; + +struct dnet_connection; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_process_packet(struct dnet_packet *p, struct dnet_connection *conn); +extern int dnet_send_packet(struct dnet_packet *p, struct dnet_connection *conn); +extern int dnet_send_command_packet(struct dnet_packet_stream *st, struct dnet_output *output); +extern int dnet_cancel_command(struct dnet_output *output); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_stream.c b/dnet/dnet_stream.c index e329dc6c..c4fee30c 100644 --- a/dnet/dnet_stream.c +++ b/dnet/dnet_stream.c @@ -1,355 +1,355 @@ -/* dnet: streams; T11.270-T13.808; $DVS:time$ */ - -#define _XOPEN_SOURCE 600 -#define _DEFAULT_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __LDuS__ -#include -#include -#include <../config.h> -#define MEM_LIMIT_PERCENT LDUS_CONFIG_MEM_NET_APP -#endif -#include "dnet_packet.h" -#include "dnet_stream.h" -#include "dnet_threads.h" -#include "dnet_database.h" -#include "dnet_connection.h" -#include "dnet_files.h" -#include "dnet_tap.h" - -#define DNET_FORWARD_WAIT 3 /* сколько секунд ждать соединения при проброске порта */ - -#ifdef QDNET -#define posix_openpt(oflag) open("/dev/ptmx", oflag) -#endif - -struct dnet_send_stream_packet_data { - struct dnet_packet_stream *st; - struct dnet_host *host; - struct dnet_connection *conn; - int use_port; - int counter; -}; - -int g_ctrlc_handled = 0; - -static int dnet_send_stream_packet_callback(struct dnet_connection *conn, void *data) { - struct dnet_send_stream_packet_data *d = (struct dnet_send_stream_packet_data *)data; - if (conn != d->conn && conn->ipaddr == d->host->route_ip && (!d->use_port || conn->port == d->host->route_port)) { - dnet_send_packet((struct dnet_packet *)d->st, conn); - d->counter++; - } - return 0; -} - -int dnet_send_stream_packet(struct dnet_packet_stream *st, struct dnet_connection *conn) { - struct dnet_send_stream_packet_data data; - data.host = dnet_get_host_by_crc(st->crc_to); - if (!data.host) return 1; - if (data.host == dnet_get_self_host()) return 2; - data.st = st; - data.conn = conn; - data.counter = 0; - data.use_port = 1; - dnet_traverse_connections(&dnet_send_stream_packet_callback, &data); - if (!data.counter) { - if (st->header.ttl > 3) st->header.ttl = 3; - else if (st->header.ttl <= 1) return 3; - data.use_port = 0; - dnet_traverse_connections(&dnet_send_stream_packet_callback, &data); - if (!data.counter) return 4; - } - return 0; -} - -void *dnet_thread_stream(void *arg) { - struct dnet_thread *t = (struct dnet_thread *)arg; - t->to_remove = 1; - return 0; -} - -int dnet_stream_main(uint32_t crc_to) { - return -1; -} - -static int tunnel_callback(struct dnet_stream *st, void *data) { - struct dnet_stream *st0 = (struct dnet_stream *)data; - if (st->pkt_type == DNET_PKT_TUNNELED_MSG && st->tap_from == st0->tap_from) { - if (st0->tap_to == -1) { - st->crc_to = st0->crc_to; - memcpy(&st->id, &st0->id, sizeof(struct dnet_stream_id)); - st->to_reinit = 1; - } - return 0x12345678; - } - return 0; -} - -int dnet_stream_create_tunnel(uint32_t crc_to, int tap_from, int tap_to, struct dnet_stream_id *id) { - struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); - int res; - if (!t) return 1; - t->type = DNET_THREAD_STREAM; - t->st.pkt_type = DNET_PKT_TUNNELED_MSG; - t->st.crc_to = crc_to; - t->st.to_exit = 0; - t->st.to_reinit = 0; - t->st.tap_from = tap_from; - t->st.tap_to = tap_to; - if (id) memcpy(&t->st.id, id, sizeof(struct dnet_stream_id)); - else dnet_generate_stream_id(&t->st.id); - res = dnet_traverse_streams(&tunnel_callback, &t->st); - if (res) { - if (res == 0x12345678) res = 0; - else res = res << 4 | 2; - free(t); - } else { - res = dnet_thread_create(t); - if (res) { - t->to_remove = 1; - res = res << 4 | 3; - } - } - return res; -} - -int dnet_stream_forward(uint32_t crc_to, int proto, int port_from, uint32_t ip_to, int port_to) { - struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); - int res; - if (!t) return 0; - t->type = DNET_THREAD_FORWARD_FROM; - t->conn.socket = -1; - t->st.crc_to = crc_to; - t->st.ip_to = ip_to; - t->st.port_to = port_to; - t->st.proto = proto; - sprintf(t->argbuf, "any:%u", port_from); - t->arg = t->argbuf; - res = dnet_thread_create(t); - if (res) { - t->to_remove = 1; - res = res << 4 | 1; - } - return res; -} - -struct dnet_traverse_st { - int (*callback)(struct dnet_stream *st, void *data); - void *data; -}; - -static int dnet_traverse_st_callback(struct dnet_thread *t, void *data) { - if (t->type == DNET_THREAD_STREAM) { - struct dnet_traverse_st *dts = (struct dnet_traverse_st *)data; - return (*dts->callback)(&t->st, dts->data); - } else return 0; -} - -int dnet_traverse_streams(int (*callback)(struct dnet_stream *st, void *data), void *data) { - struct dnet_traverse_st dts; - dts.callback = callback; - dts.data = data; - return dnet_traverse_threads(&dnet_traverse_st_callback, &dts); -} - -int dnet_print_stream(struct dnet_stream *st, struct dnet_output *out) { - struct dnet_host *host = dnet_get_host_by_crc(st->crc_to); - const char *stream_type; - int len; - if (!host) return 0; - dnet_printf(out, " %2d. %04x ", out->count, st->id.id[0] & 0xFFFF); - len = dnet_print_host_name(host, out); - switch (st->pkt_type) { - case DNET_PKT_SHELL_INPUT: - stream_type = "shell input"; - break; - case DNET_PKT_SHELL_OUTPUT: - stream_type = "shell output"; - break; - case DNET_PKT_TUNNELED_MSG: - stream_type = "tunnel"; - break; - case DNET_PKT_FORWARDED_TCP: - stream_type = "tcp forward"; - break; - case DNET_PKT_FORWARDED_UDP: - stream_type = "udp forward"; - break; - case DNET_PKT_FILE_OP: - stream_type = "copy files"; - break; - default: - stream_type = "unknown"; - break; - } - dnet_printf(out, "%*d sec, %lld/%lld in/out bytes, %s\n", - 28 - (5 + len), (int)(time(0) - st->creation_time), (long long)st->ack, (long long)st->seq, stream_type - ); - out->count++; - return 0; -} - -struct dnet_find_st { - struct dnet_packet_stream *p; - struct dnet_stream *st; -}; - -static int dnet_find_st_callback(struct dnet_stream *st, void *data) { - struct dnet_find_st *dfs = (struct dnet_find_st *)data; - if (!memcmp(&dfs->p->id, &st->id, sizeof(struct dnet_stream_id))) { - uint64_t stack = (uint64_t)st->ip_to | (uint64_t)(htons(st->port_to)) << 32; - if (dfs->p->header.type == DNET_PKT_FORWARDED_UDP && dfs->p->seq != stack) return 0; - dfs->st = st; - return 1; - } else return 0; -} - -int dnet_process_stream_packet(struct dnet_packet_stream *p) { - struct dnet_find_st dfs; - int data_len; - dfs.p = p; - if (!dnet_traverse_streams(&dnet_find_st_callback, &dfs)) { - if (p->header.type == DNET_PKT_SHELL_INPUT && !p->seq && p->header.length == DNET_PKT_STREAM_MIN_LEN + sizeof(struct dnet_tty_params)) { - struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); - int res; - if (!t) return 1; - t->type = DNET_THREAD_STREAM; - t->st.pkt_type = DNET_PKT_SHELL_OUTPUT; - t->st.crc_to = p->crc_from; - t->st.to_exit = 0; - t->st.to_reinit = 0; - memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); - memcpy(&t->st.tty_params, p->data, sizeof(struct dnet_tty_params)); - res = dnet_thread_create(t); - if (res) { - t->to_remove = 1; - return res << 4 | 2; - } - return 0; - } else if (p->header.type == DNET_PKT_FORWARDED_TCP && !p->seq && p->header.length == DNET_PKT_STREAM_MIN_LEN + sizeof(struct dnet_ipport)) { - struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); - struct dnet_ipport *ipport = (struct dnet_ipport *)p->data; - int res, ip = ipport->ip, port = ipport->port; - if (!t) return 3; - t->type = DNET_THREAD_FORWARD_TO; - t->conn.socket = -1; - t->st.pkt_type = DNET_PKT_FORWARDED_TCP; - t->st.crc_to = p->crc_from; - t->st.proto = DNET_TCP; - t->st.ip_to = ip; - t->st.port_to = port; - t->st.to_exit = 0; - t->st.to_reinit = 0; - t->st.output_tty = -1; - sprintf(t->argbuf, "%u.%u.%u.%u:%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port); - t->arg = t->argbuf; - memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); - res = dnet_thread_create(t); - if (res) { - t->to_remove = 1; - return res << 4 | 4; - } - return 0; - } else if (p->header.type == DNET_PKT_FORWARDED_UDP) { - struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); - int res, ip = (uint32_t)p->seq, port = ntohs((uint16_t)(p->seq >> 32)); - if (!t) return 3; - t->type = DNET_THREAD_FORWARD_TO; - t->conn.socket = -1; - t->st.pkt_type = DNET_PKT_FORWARDED_UDP; - t->st.crc_to = p->crc_from; - t->st.proto = DNET_UDP; - t->st.ip_to = ip; - t->st.port_to = port; - t->st.to_exit = 0; - t->st.to_reinit = 0; - t->st.output_tty = -1; - t->arg = "any:0"; - memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); - res = dnet_thread_create(t); - if (res) { - t->to_remove = 1; - return res << 4 | 5; - } - dfs.st = &t->st; - } else if (p->header.type == DNET_PKT_TUNNELED_MSG && !p->seq - && p->header.length >= DNET_PKT_STREAM_MIN_LEN + 1 && p->header.length <= DNET_PKT_STREAM_MIN_LEN + 4) { - int len = p->header.length - DNET_PKT_STREAM_MIN_LEN; - uint32_t tap_to = 0; - while (len) { - tap_to <<= 8; - tap_to += p->data[--len]; - } - return dnet_stream_create_tunnel(p->crc_from, tap_to, -1, &p->id); - } else if (p->header.type != DNET_PKT_SHELL_INPUT) return p->header.type << 4 | 5; - else if (p->seq) return 6; - else return p->header.length << 4 | 7; - } - data_len = p->header.length - DNET_PKT_STREAM_MIN_LEN; - switch(dfs.st->pkt_type) { - case DNET_PKT_SHELL_INPUT: - if (p->header.type != DNET_PKT_SHELL_OUTPUT) return 0x18; - if (!data_len) { dfs.st->to_exit = 1; return 0; } - break; - case DNET_PKT_SHELL_OUTPUT: - if (p->header.type != DNET_PKT_SHELL_INPUT) return 0x28; - break; - case DNET_PKT_FORWARDED_TCP: - case DNET_PKT_FORWARDED_UDP: - if (p->header.type != dfs.st->pkt_type) return 0x19; - if (!data_len) { dfs.st->to_exit = 1; return 0; } - if (dfs.st->output_tty < 0) { - int i; - for (i = 0; i < DNET_FORWARD_WAIT * 100; i++) { - sched_yield(); - usleep(10000); - if (dfs.st->to_exit) return 0x29; - if (dfs.st->output_tty >= 0) break; - } - if (dfs.st->output_tty < 0) { dfs.st->to_exit = 1; return 0x39; } - } - break; - default: - if (p->header.type != dfs.st->pkt_type) return 0x1A; - break; - } - if (p->header.type == DNET_PKT_FORWARDED_UDP) { - struct sockaddr_in servaddr; - memset(&servaddr, 0, sizeof(struct sockaddr_in)); - servaddr.sin_family = AF_INET; - servaddr.sin_port = (uint16_t)(p->ack >> 32); - servaddr.sin_addr.s_addr = (uint32_t)p->ack; - if (sendto(dfs.st->output_tty, p->data, data_len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) != data_len) return 0x2A; - } else { - if (p->header.type != DNET_PKT_TUNNELED_MSG && p->seq != dfs.st->ack) return 0x3A; - if (write(dfs.st->output_tty, p->data, data_len) != data_len) return 0x4A; - } - dfs.st->ack += data_len; - return 0; -} - -static int dnet_finish_st_callback(struct dnet_stream *st, void *data) { - uint16_t id = *(uint16_t *)data; - if ((uint16_t )st->id.id[0] == id) { - st->to_exit = 1; - return 1; - } - else return 0; -} - -int dnet_finish_stream(uint16_t id) { - return dnet_traverse_streams(&dnet_finish_st_callback, &id); -} +/* dnet: streams; T11.270-T13.808; $DVS:time$ */ + +#define _XOPEN_SOURCE 600 +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __LDuS__ +#include +#include +#include <../config.h> +#define MEM_LIMIT_PERCENT LDUS_CONFIG_MEM_NET_APP +#endif +#include "dnet_packet.h" +#include "dnet_stream.h" +#include "dnet_threads.h" +#include "dnet_database.h" +#include "dnet_connection.h" +#include "dnet_files.h" +#include "dnet_tap.h" + +#define DNET_FORWARD_WAIT 3 /* сколько секунд ждать соединения при проброске порта */ + +#ifdef QDNET +#define posix_openpt(oflag) open("/dev/ptmx", oflag) +#endif + +struct dnet_send_stream_packet_data { + struct dnet_packet_stream *st; + struct dnet_host *host; + struct dnet_connection *conn; + int use_port; + int counter; +}; + +int g_ctrlc_handled = 0; + +static int dnet_send_stream_packet_callback(struct dnet_connection *conn, void *data) { + struct dnet_send_stream_packet_data *d = (struct dnet_send_stream_packet_data *)data; + if (conn != d->conn && conn->ipaddr == d->host->route_ip && (!d->use_port || conn->port == d->host->route_port)) { + dnet_send_packet((struct dnet_packet *)d->st, conn); + d->counter++; + } + return 0; +} + +int dnet_send_stream_packet(struct dnet_packet_stream *st, struct dnet_connection *conn) { + struct dnet_send_stream_packet_data data; + data.host = dnet_get_host_by_crc(st->crc_to); + if (!data.host) return 1; + if (data.host == dnet_get_self_host()) return 2; + data.st = st; + data.conn = conn; + data.counter = 0; + data.use_port = 1; + dnet_traverse_connections(&dnet_send_stream_packet_callback, &data); + if (!data.counter) { + if (st->header.ttl > 3) st->header.ttl = 3; + else if (st->header.ttl <= 1) return 3; + data.use_port = 0; + dnet_traverse_connections(&dnet_send_stream_packet_callback, &data); + if (!data.counter) return 4; + } + return 0; +} + +void *dnet_thread_stream(void *arg) { + struct dnet_thread *t = (struct dnet_thread *)arg; + t->to_remove = 1; + return 0; +} + +int dnet_stream_main(uint32_t crc_to) { + return -1; +} + +static int tunnel_callback(struct dnet_stream *st, void *data) { + struct dnet_stream *st0 = (struct dnet_stream *)data; + if (st->pkt_type == DNET_PKT_TUNNELED_MSG && st->tap_from == st0->tap_from) { + if (st0->tap_to == -1) { + st->crc_to = st0->crc_to; + memcpy(&st->id, &st0->id, sizeof(struct dnet_stream_id)); + st->to_reinit = 1; + } + return 0x12345678; + } + return 0; +} + +int dnet_stream_create_tunnel(uint32_t crc_to, int tap_from, int tap_to, struct dnet_stream_id *id) { + struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); + int res; + if (!t) return 1; + t->type = DNET_THREAD_STREAM; + t->st.pkt_type = DNET_PKT_TUNNELED_MSG; + t->st.crc_to = crc_to; + t->st.to_exit = 0; + t->st.to_reinit = 0; + t->st.tap_from = tap_from; + t->st.tap_to = tap_to; + if (id) memcpy(&t->st.id, id, sizeof(struct dnet_stream_id)); + else dnet_generate_stream_id(&t->st.id); + res = dnet_traverse_streams(&tunnel_callback, &t->st); + if (res) { + if (res == 0x12345678) res = 0; + else res = res << 4 | 2; + free(t); + } else { + res = dnet_thread_create(t); + if (res) { + t->to_remove = 1; + res = res << 4 | 3; + } + } + return res; +} + +int dnet_stream_forward(uint32_t crc_to, int proto, int port_from, uint32_t ip_to, int port_to) { + struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); + int res; + if (!t) return 0; + t->type = DNET_THREAD_FORWARD_FROM; + t->conn.socket = -1; + t->st.crc_to = crc_to; + t->st.ip_to = ip_to; + t->st.port_to = port_to; + t->st.proto = proto; + sprintf(t->argbuf, "any:%u", port_from); + t->arg = t->argbuf; + res = dnet_thread_create(t); + if (res) { + t->to_remove = 1; + res = res << 4 | 1; + } + return res; +} + +struct dnet_traverse_st { + int (*callback)(struct dnet_stream *st, void *data); + void *data; +}; + +static int dnet_traverse_st_callback(struct dnet_thread *t, void *data) { + if (t->type == DNET_THREAD_STREAM) { + struct dnet_traverse_st *dts = (struct dnet_traverse_st *)data; + return (*dts->callback)(&t->st, dts->data); + } else return 0; +} + +int dnet_traverse_streams(int (*callback)(struct dnet_stream *st, void *data), void *data) { + struct dnet_traverse_st dts; + dts.callback = callback; + dts.data = data; + return dnet_traverse_threads(&dnet_traverse_st_callback, &dts); +} + +int dnet_print_stream(struct dnet_stream *st, struct dnet_output *out) { + struct dnet_host *host = dnet_get_host_by_crc(st->crc_to); + const char *stream_type; + int len; + if (!host) return 0; + dnet_printf(out, " %2d. %04x ", out->count, st->id.id[0] & 0xFFFF); + len = dnet_print_host_name(host, out); + switch (st->pkt_type) { + case DNET_PKT_SHELL_INPUT: + stream_type = "shell input"; + break; + case DNET_PKT_SHELL_OUTPUT: + stream_type = "shell output"; + break; + case DNET_PKT_TUNNELED_MSG: + stream_type = "tunnel"; + break; + case DNET_PKT_FORWARDED_TCP: + stream_type = "tcp forward"; + break; + case DNET_PKT_FORWARDED_UDP: + stream_type = "udp forward"; + break; + case DNET_PKT_FILE_OP: + stream_type = "copy files"; + break; + default: + stream_type = "unknown"; + break; + } + dnet_printf(out, "%*d sec, %lld/%lld in/out bytes, %s\n", + 28 - (5 + len), (int)(time(0) - st->creation_time), (long long)st->ack, (long long)st->seq, stream_type + ); + out->count++; + return 0; +} + +struct dnet_find_st { + struct dnet_packet_stream *p; + struct dnet_stream *st; +}; + +static int dnet_find_st_callback(struct dnet_stream *st, void *data) { + struct dnet_find_st *dfs = (struct dnet_find_st *)data; + if (!memcmp(&dfs->p->id, &st->id, sizeof(struct dnet_stream_id))) { + uint64_t stack = (uint64_t)st->ip_to | (uint64_t)(htons(st->port_to)) << 32; + if (dfs->p->header.type == DNET_PKT_FORWARDED_UDP && dfs->p->seq != stack) return 0; + dfs->st = st; + return 1; + } else return 0; +} + +int dnet_process_stream_packet(struct dnet_packet_stream *p) { + struct dnet_find_st dfs; + int data_len; + dfs.p = p; + if (!dnet_traverse_streams(&dnet_find_st_callback, &dfs)) { + if (p->header.type == DNET_PKT_SHELL_INPUT && !p->seq && p->header.length == DNET_PKT_STREAM_MIN_LEN + sizeof(struct dnet_tty_params)) { + struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); + int res; + if (!t) return 1; + t->type = DNET_THREAD_STREAM; + t->st.pkt_type = DNET_PKT_SHELL_OUTPUT; + t->st.crc_to = p->crc_from; + t->st.to_exit = 0; + t->st.to_reinit = 0; + memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); + memcpy(&t->st.tty_params, p->data, sizeof(struct dnet_tty_params)); + res = dnet_thread_create(t); + if (res) { + t->to_remove = 1; + return res << 4 | 2; + } + return 0; + } else if (p->header.type == DNET_PKT_FORWARDED_TCP && !p->seq && p->header.length == DNET_PKT_STREAM_MIN_LEN + sizeof(struct dnet_ipport)) { + struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); + struct dnet_ipport *ipport = (struct dnet_ipport *)p->data; + int res, ip = ipport->ip, port = ipport->port; + if (!t) return 3; + t->type = DNET_THREAD_FORWARD_TO; + t->conn.socket = -1; + t->st.pkt_type = DNET_PKT_FORWARDED_TCP; + t->st.crc_to = p->crc_from; + t->st.proto = DNET_TCP; + t->st.ip_to = ip; + t->st.port_to = port; + t->st.to_exit = 0; + t->st.to_reinit = 0; + t->st.output_tty = -1; + sprintf(t->argbuf, "%u.%u.%u.%u:%u", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, port); + t->arg = t->argbuf; + memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); + res = dnet_thread_create(t); + if (res) { + t->to_remove = 1; + return res << 4 | 4; + } + return 0; + } else if (p->header.type == DNET_PKT_FORWARDED_UDP) { + struct dnet_thread *t = (struct dnet_thread *)malloc(sizeof(struct dnet_thread)); + int res, ip = (uint32_t)p->seq, port = ntohs((uint16_t)(p->seq >> 32)); + if (!t) return 3; + t->type = DNET_THREAD_FORWARD_TO; + t->conn.socket = -1; + t->st.pkt_type = DNET_PKT_FORWARDED_UDP; + t->st.crc_to = p->crc_from; + t->st.proto = DNET_UDP; + t->st.ip_to = ip; + t->st.port_to = port; + t->st.to_exit = 0; + t->st.to_reinit = 0; + t->st.output_tty = -1; + t->arg = "any:0"; + memcpy(&t->st.id, &p->id, sizeof(struct dnet_stream_id)); + res = dnet_thread_create(t); + if (res) { + t->to_remove = 1; + return res << 4 | 5; + } + dfs.st = &t->st; + } else if (p->header.type == DNET_PKT_TUNNELED_MSG && !p->seq + && p->header.length >= DNET_PKT_STREAM_MIN_LEN + 1 && p->header.length <= DNET_PKT_STREAM_MIN_LEN + 4) { + int len = p->header.length - DNET_PKT_STREAM_MIN_LEN; + uint32_t tap_to = 0; + while (len) { + tap_to <<= 8; + tap_to += p->data[--len]; + } + return dnet_stream_create_tunnel(p->crc_from, tap_to, -1, &p->id); + } else if (p->header.type != DNET_PKT_SHELL_INPUT) return p->header.type << 4 | 5; + else if (p->seq) return 6; + else return p->header.length << 4 | 7; + } + data_len = p->header.length - DNET_PKT_STREAM_MIN_LEN; + switch(dfs.st->pkt_type) { + case DNET_PKT_SHELL_INPUT: + if (p->header.type != DNET_PKT_SHELL_OUTPUT) return 0x18; + if (!data_len) { dfs.st->to_exit = 1; return 0; } + break; + case DNET_PKT_SHELL_OUTPUT: + if (p->header.type != DNET_PKT_SHELL_INPUT) return 0x28; + break; + case DNET_PKT_FORWARDED_TCP: + case DNET_PKT_FORWARDED_UDP: + if (p->header.type != dfs.st->pkt_type) return 0x19; + if (!data_len) { dfs.st->to_exit = 1; return 0; } + if (dfs.st->output_tty < 0) { + int i; + for (i = 0; i < DNET_FORWARD_WAIT * 100; i++) { + sched_yield(); + usleep(10000); + if (dfs.st->to_exit) return 0x29; + if (dfs.st->output_tty >= 0) break; + } + if (dfs.st->output_tty < 0) { dfs.st->to_exit = 1; return 0x39; } + } + break; + default: + if (p->header.type != dfs.st->pkt_type) return 0x1A; + break; + } + if (p->header.type == DNET_PKT_FORWARDED_UDP) { + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(struct sockaddr_in)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = (uint16_t)(p->ack >> 32); + servaddr.sin_addr.s_addr = (uint32_t)p->ack; + if (sendto(dfs.st->output_tty, p->data, data_len, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)) != data_len) return 0x2A; + } else { + if (p->header.type != DNET_PKT_TUNNELED_MSG && p->seq != dfs.st->ack) return 0x3A; + if (write(dfs.st->output_tty, p->data, data_len) != data_len) return 0x4A; + } + dfs.st->ack += data_len; + return 0; +} + +static int dnet_finish_st_callback(struct dnet_stream *st, void *data) { + uint16_t id = *(uint16_t *)data; + if ((uint16_t )st->id.id[0] == id) { + st->to_exit = 1; + return 1; + } + else return 0; +} + +int dnet_finish_stream(uint16_t id) { + return dnet_traverse_streams(&dnet_finish_st_callback, &id); +} diff --git a/dnet/dnet_stream.h b/dnet/dnet_stream.h index 96e02a0f..4303d2d0 100644 --- a/dnet/dnet_stream.h +++ b/dnet/dnet_stream.h @@ -1,61 +1,69 @@ -/* dnet: streams; T11.270-T13.426; $DVS:time$ */ - -#ifndef DNET_STREAM_H_INCLUDED -#define DNET_STREAM_H_INCLUDED - -#include -#include -#include -#include "system.h" -#include "dthread.h" -#include "dnet_packet.h" -#include "dnet_log.h" - -struct dnet_tty_params { - uint16_t xwinsize, ywinsize; -}; - -struct dnet_ipport { - uint32_t ip; - uint16_t port; -} __attribute__((packed)); - -enum dnet_proto { - DNET_TCP, - DNET_UDP, -}; - -struct dnet_stream { - dthread_mutex_t mutex; - void *sess_reserved; - int input_tty; - int output_tty; - uint32_t ip_to; - uint16_t port_to; - uint16_t port_from; - struct dnet_stream_id id; - uint64_t seq, ack; - const char *file_from, *file_to, *file_param; - struct dnet_tty_params tty_params; - uint32_t crc_from, crc_to; - time_t creation_time; - pid_t child; - int tap_from; - int tap_to; - uint8_t pkt_type; - uint8_t to_reinit; - uint8_t to_exit; - uint8_t proto; -}; - -extern int dnet_send_stream_packet(struct dnet_packet_stream *st, struct dnet_connection *conn); -extern void *dnet_thread_stream(void *arg); -extern int dnet_stream_main(uint32_t crc_to); -extern int dnet_stream_create_tunnel(uint32_t crc_to, int tap_from, int tap_to, struct dnet_stream_id *id); -extern int dnet_stream_forward(uint32_t crc_to, int proto, int port_from, uint32_t ip_to, int port_to); -extern int dnet_traverse_streams(int (*callback)(struct dnet_stream *st, void *data), void *data); -extern int dnet_print_stream(struct dnet_stream *st, struct dnet_output *out); -extern int dnet_process_stream_packet(struct dnet_packet_stream *p); -extern int dnet_finish_stream(uint16_t id); - -#endif +/* dnet: streams; T11.270-T13.426; $DVS:time$ */ + +#ifndef DNET_STREAM_H_INCLUDED +#define DNET_STREAM_H_INCLUDED + +#include +#include +#include +#include "system.h" +#include "dthread.h" +#include "dnet_packet.h" +#include "dnet_log.h" + +struct dnet_tty_params { + uint16_t xwinsize, ywinsize; +}; + +struct dnet_ipport { + uint32_t ip; + uint16_t port; +} __attribute__((packed)); + +enum dnet_proto { + DNET_TCP, + DNET_UDP, +}; + +struct dnet_stream { + dthread_mutex_t mutex; + void *sess_reserved; + int input_tty; + int output_tty; + uint32_t ip_to; + uint16_t port_to; + uint16_t port_from; + struct dnet_stream_id id; + uint64_t seq, ack; + const char *file_from, *file_to, *file_param; + struct dnet_tty_params tty_params; + uint32_t crc_from, crc_to; + time_t creation_time; + pid_t child; + int tap_from; + int tap_to; + uint8_t pkt_type; + uint8_t to_reinit; + uint8_t to_exit; + uint8_t proto; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_send_stream_packet(struct dnet_packet_stream *st, struct dnet_connection *conn); +extern void *dnet_thread_stream(void *arg); +extern int dnet_stream_main(uint32_t crc_to); +extern int dnet_stream_create_tunnel(uint32_t crc_to, int tap_from, int tap_to, struct dnet_stream_id *id); +extern int dnet_stream_forward(uint32_t crc_to, int proto, int port_from, uint32_t ip_to, int port_to); +extern int dnet_traverse_streams(int (*callback)(struct dnet_stream *st, void *data), void *data); +extern int dnet_print_stream(struct dnet_stream *st, struct dnet_output *out); +extern int dnet_process_stream_packet(struct dnet_packet_stream *p); +extern int dnet_finish_stream(uint16_t id); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dnet/dnet_tap.h b/dnet/dnet_tap.h index 209a9896..1179f879 100644 --- a/dnet/dnet_tap.h +++ b/dnet/dnet_tap.h @@ -3,7 +3,15 @@ #ifndef DNET_TAP_H_INCLUDED #define DNET_TAP_H_INCLUDED +#ifdef __cplusplus +extern "C" { +#endif + /* открывает устройство tap с данным номером, возвращает файловый дескриптор */ extern int dnet_tap_open(int tap_number); +#ifdef __cplusplus +}; +#endif + #endif diff --git a/dnet/dnet_threads.c b/dnet/dnet_threads.c index 3c4ff3df..31b563e0 100644 --- a/dnet/dnet_threads.c +++ b/dnet/dnet_threads.c @@ -1,477 +1,477 @@ -/* dnet: threads; T11.231-T13.808; $DVS:time$ */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __LDuS__ -#include -#endif -#include "system.h" -#include "dnet_threads.h" -#include "dnet_connection.h" -#include "dnet_packet.h" -#include "dnet_database.h" -#include "dnet_log.h" -#include "dnet_stream.h" - -#define CONNECTIONS_MAX 100 -#define MAX_N_INBOUND CONNECTIONS_MAX -#define EXCHANGE_PERIOD 1800 -#define EXCHANGE_MAX_TIME (3600 * 48) -#define LOG_PERIOD 300 -#define GC_PERIOD 60 -#define UPDATE_PERIOD DNET_UPDATE_PERIOD - -struct list *g_threads; -pthread_rwlock_t g_threads_rwlock; -int g_nthread; -int(*dnet_connection_open_check)(void *conn, uint32_t ip, uint16_t port); -void(*dnet_connection_close_notify)(void *conn) = 0; -static int g_n_inbound = 0; -int g_conn_limit = MAX_N_INBOUND; - -static void dnet_thread_work(struct dnet_thread *t) -{ - char buf[0x100]; - const char *mess, *mess1 = ""; - struct sockaddr_in peeraddr; - struct hostent *host; - char *str, *lasts; - int res = 0, ip_to = 0, port_to = 0, crc_to = 0, proto = DNET_TCP, reuseaddr = 1; - - if (t->type == DNET_THREAD_FORWARD_FROM || t->type == DNET_THREAD_STREAM) { - port_to = t->st.port_to; - ip_to = t->st.ip_to; - crc_to = t->st.crc_to; - proto = t->st.proto; - } - - // Create a socket - t->conn.socket = socket(AF_INET, (proto == DNET_TCP ? SOCK_STREAM : SOCK_DGRAM), IPPROTO_TCP); - if (t->conn.socket == INVALID_SOCKET) { - mess = "cannot create a socket"; - goto err; - } - if (fcntl(t->conn.socket, F_SETFD, FD_CLOEXEC) == -1) { - dnet_log_printf("dnet.%d: can't set FD_CLOEXEC flag on socket, %s\n", t->nthread, strerror(errno)); - } - - // Fill in the address of server - memset(&peeraddr, 0, sizeof(peeraddr)); - peeraddr.sin_family = AF_INET; - - // Resolve the server address (convert from symbolic name to IP number) - strcpy(buf, t->arg); - str = strtok_r(buf, " \t\r\n:", &lasts); - if (!str) { mess = "host is not given"; goto err; } - if (!strcmp(str, "any")) { - peeraddr.sin_addr.s_addr = htonl(INADDR_ANY); - } else if (!inet_aton(str, &peeraddr.sin_addr)) { - host = gethostbyname(str); - if (!host || !host->h_addr_list[0]) { - mess = "cannot resolve host ", mess1 = str; res = h_errno; - goto err; - } - // Write resolved IP address of a server to the address structure - memmove(&peeraddr.sin_addr.s_addr, host->h_addr_list[0], 4); - } - t->conn.ipaddr = ntohl(peeraddr.sin_addr.s_addr); - - // Resolve port - str = strtok_r(0, " \t\r\n:", &lasts); - if (!str) { mess = "port is not given"; goto err; } - t->conn.port = atoi(str); - peeraddr.sin_port = htons(t->conn.port); - - if (t->type == DNET_THREAD_SERVER || t->type == DNET_THREAD_FORWARD_FROM || proto == DNET_UDP) { - struct linger linger_opt = { 1, (proto == DNET_UDP ? 5 : 0) }; // Linger active, timeout 5 - socklen_t peeraddr_len = sizeof(peeraddr); - - // Bind a socket to the address -#ifdef __LDuS__ - if (t->type == DNET_THREAD_SERVER) { - int i; - for (i = 0; i < 2; ++i) - ldus_free_network_port(AF_INET, SOCK_STREAM, 0, i, t->conn.port); - } -#endif - res = bind(t->conn.socket, (struct sockaddr*)&peeraddr, sizeof(peeraddr)); - if (res) { - mess = "cannot bind a socket"; - goto err; - } - - // Set the "LINGER" timeout to zero, to close the listen socket - // immediately at program termination. - setsockopt(t->conn.socket, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(linger_opt)); - setsockopt(t->conn.socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(int)); - - if (proto == DNET_UDP) { - if (t->type != DNET_THREAD_STREAM) { - dnet_generate_stream_id(&t->st.id); - t->type = DNET_THREAD_STREAM; - t->st.pkt_type = DNET_PKT_FORWARDED_UDP; - } - t->st.crc_to = crc_to; - t->st.ip_to = ip_to; - t->st.port_to = port_to; - t->st.input_tty = t->st.output_tty = t->conn.socket; - dnet_thread_stream(t); - return; - } - - // Now, listen for a connection - res = listen(t->conn.socket, CONNECTIONS_MAX); // "1" is the maximal length of the queue - if (res) { - mess = "cannot listen"; - goto err; - } - - for (;;) { - struct dnet_thread *t1 = malloc(sizeof(struct dnet_thread)); - if (!t1) { mess = "allocation error"; goto err; } - *t1 = *t; - // Accept a connection (the "accept" command waits for a connection with - // no timeout limit...) -begin: - t1->conn.socket = accept(t->conn.socket, (struct sockaddr*) &peeraddr, &peeraddr_len); - if (t1->conn.socket < 0) { free(t1); mess = "cannot accept"; goto err; } - setsockopt(t1->conn.socket, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(linger_opt)); - setsockopt(t1->conn.socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(int)); - if (fcntl(t1->conn.socket, F_SETFD, FD_CLOEXEC) == -1) { - dnet_log_printf("dnet.%d: can't set FD_CLOEXEC flag on accepted socket, %s\n", t->nthread, strerror(errno)); - } - if (g_n_inbound >= g_conn_limit || (dnet_connection_open_check - && (*dnet_connection_open_check)(&t1->conn, peeraddr.sin_addr.s_addr, ntohs(peeraddr.sin_port)))) { - close(t1->conn.socket); goto begin; - } - if (t->type == DNET_THREAD_FORWARD_FROM) { - t1->type = DNET_THREAD_STREAM; - t1->st.pkt_type = DNET_PKT_FORWARDED_TCP; - t1->st.to_exit = 0; - t1->st.to_reinit = 0; - t1->st.input_tty = t1->st.output_tty = t1->conn.socket; - t1->st.crc_to = crc_to; - t1->st.ip_to = ip_to; - t1->st.port_to = port_to; - dnet_generate_stream_id(&t1->st.id); - } else { - t1->conn.ipaddr = ntohl(peeraddr.sin_addr.s_addr); - t1->conn.port = ntohs(peeraddr.sin_port); - t1->type = DNET_THREAD_ACCEPTED; - } - res = dnet_thread_create(t1); - if (res) { - if (t1->conn.socket >= 0) { - close(t1->conn.socket); t1->conn.socket = -1; - } - //pthread_mutex_lock(&t->conn.mutex); - t1->to_remove = 1; - //pthread_mutex_unlock(&t->conn.mutex); - mess = "can't create new thread"; goto err; - } else { - g_n_inbound++; - } - } - } else { - // Connect to a remote server - res = connect(t->conn.socket, (struct sockaddr*) &peeraddr, sizeof(peeraddr)); - if (res) { - mess = "cannot connect"; - goto err; - } - - if (t->type == DNET_THREAD_STREAM) { - t->st.ip_to = ip_to; - t->st.port_to = port_to; - t->st.input_tty = t->st.output_tty = t->conn.socket; - dnet_thread_stream(t); - } else { - res = dnet_connection_main(&t->conn); - if (res) { - mess = "connection error"; - goto err; - } - } - } - - return; -err: -#ifdef QDNET - if (strcmp(mess, "cannot connect") && strcmp(mess, "connection error")) -#endif - dnet_log_printf("dnet.%d: %s%s (%d), %s\n", t->nthread, mess, mess1, res, strerror(errno)); -} - -static void *dnet_thread_client_server(void *arg) -{ - struct dnet_thread *t = (struct dnet_thread *)arg; - extern int g_xdag_sync_on; - while (!g_xdag_sync_on) sleep(1); - for (;;) { -#ifndef QDNET - if (dnet_limited_version) dnet_log_printf("dnet.%d: starting connection.\n", t->nthread); - else dnet_log_printf("dnet.%d: starting connection with %s.\n", t->nthread, t->arg); -#endif - dnet_thread_work(t); - if (t->conn.socket >= 0) { - close(t->conn.socket); t->conn.socket = -1; - } - if (dnet_connection_close_notify) (*dnet_connection_close_notify)(&t->conn); - t->to_remove = 1; - break; - } - return 0; -} - -static void *dnet_thread_accepted(void *arg) -{ - struct dnet_thread *t = (struct dnet_thread *)arg; - int ip = t->conn.ipaddr, port = t->conn.port; - dnet_log_printf("dnet.%d: received connection from %u.%u.%u.%u:%u\n", t->nthread, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff, port); - int res = dnet_connection_main(&t->conn); - if (res) { - const char *mess = "connection error"; - dnet_log_printf("dnet.%d: %s (%d), %s\n", t->nthread, mess, res, strerror(errno)); - } - close(t->conn.socket); - g_n_inbound--; - t->conn.socket = -1; - //pthread_mutex_lock(&t->conn.mutex); - if (dnet_connection_close_notify) (*dnet_connection_close_notify)(&t->conn); - t->to_remove = 1; - //pthread_mutex_unlock(&t->conn.mutex); - return 0; -} - -int dnet_traverse_threads(int(*callback)(struct dnet_thread *, void *), void *data) -{ - int res = 0; - struct list *l; - pthread_rwlock_rdlock(&g_threads_rwlock); - for (l = g_threads->next; l != g_threads; l = l->next) { - struct dnet_thread *t = container_of(l, struct dnet_thread, threads); - if (!t->to_remove) { - res = (*callback)(t, data); - if (res) break; - } - } - pthread_rwlock_unlock(&g_threads_rwlock); - return res; -} - -static int dnet_garbage_collect(void) -{ - struct list *l, *lnext; - int total = 0, collected = 0; - dnet_log_printf("dnet gc: start to collect\n"); - pthread_rwlock_wrlock(&g_threads_rwlock); - for (l = g_threads->next; l != g_threads; l = lnext) { - struct dnet_thread *t = container_of(l, struct dnet_thread, threads); - lnext = l->next; - total++; - if (t->to_remove == 2) { - list_remove(l); - dthread_mutex_destroy(&t->conn.mutex); - free(t); - collected++; - } else if (t->to_remove) t->to_remove = 2; - } - pthread_rwlock_unlock(&g_threads_rwlock); - dnet_log_printf("dnet gc: %d threads total, %d collected\n", total, collected); - return 0; -} - -static void *dnet_thread_collector(void __attribute__((unused)) *arg) -{ - time_t t = 0, gc_t = 0; - for (;;) { - t = time(0); - if (t - gc_t >= GC_PERIOD) { - gc_t = t; - dnet_garbage_collect(); - } - sleep(GC_PERIOD / 10); - } - return 0; - -} - -static void dnet_fill_exchange_packet(struct dnet_host *host, struct dnet_packet_exchange *ex, time_t now) -{ - ex->header.type = DNET_PKT_EXCHANGE; - ex->header.ttl = 1; - ex->header.length = DNET_PKT_EXCHANGE_MIN_LEN; - memcpy(ex->pub_key.key, host->key.key, sizeof(struct dnet_key)); - ex->time_ago = dnet_host_time_ago(host, now); - if (host->name_len) { - memcpy(ex->name, host->name, host->name_len); - ex->header.length += host->name_len; - } - if (strlen(host->version) && host->name_len + strlen(host->version) + 1 <= DNET_HOST_NAME_MAX) { - ex->name[host->name_len] = 0; - memcpy(ex->name + host->name_len + 1, host->version, strlen(host->version)); - ex->header.length += strlen(host->version) + 1; - } -} - -struct host_exchange_data { - struct dnet_connection *conn; - time_t now; -}; - -static int dnet_host_exchange_callback(struct dnet_host *host, void *data) -{ - struct host_exchange_data *ed = (struct host_exchange_data *)data; - if (host->last_appear >= ed->conn->last_host_exchange_time && dnet_host_time_ago(host, ed->now) <= EXCHANGE_MAX_TIME) { - struct dnet_packet_exchange ex; - dnet_fill_exchange_packet(host, &ex, ed->now); - dnet_send_packet((struct dnet_packet *)&ex, ed->conn); - } - return 0; -} - -struct host_update_data { - struct dnet_packet_update up; - struct dnet_connection *conn; - time_t now; -}; - -static int dnet_host_update_callback(struct dnet_host *host, void *data) -{ - struct host_update_data *ud = (struct host_update_data *)data; - int nitem; - if (!host->is_local && host->last_time_changed + DNET_ACTIVE_PERIOD < ud->now) return 0; - if (ud->up.header.length >= DNET_PKT_UPDATE_MAX_LEN) { - dnet_send_packet((struct dnet_packet *)&ud->up, ud->conn); - ud->up.header.length = DNET_PKT_UPDATE_MIN_LEN; - } - nitem = (ud->up.header.length - DNET_PKT_UPDATE_MIN_LEN) / sizeof(struct dnet_packet_update_item); - ud->up.item[nitem].crc32 = host->crc32; - ud->up.item[nitem].time_ago = dnet_host_time_ago(host, ud->now); - ud->up.header.length += sizeof(struct dnet_packet_update_item); - return 0; -} - -static void *dnet_thread_exchanger(void *arg) -{ - struct dnet_thread *t = (struct dnet_thread *)arg; - struct dnet_connection *conn; - time_t ex_t = 0, up_t = 0; - while ((conn = (struct dnet_connection *)t->arg)) { - time_t now = time(0); - if (conn->is_new || now - ex_t >= EXCHANGE_PERIOD) { - ex_t = now; - conn->last_host_exchange_time = (conn->is_new ? 0 : now - 2 * EXCHANGE_PERIOD); - conn->is_new = 0; - } - if (now > conn->last_host_exchange_time) { - struct host_exchange_data ed; - ed.conn = conn; - ed.now = now; - dnet_traverse_hosts(&dnet_host_exchange_callback, &ed); - conn->last_host_exchange_time = now; - } - if (now - up_t >= UPDATE_PERIOD) { - struct host_update_data ud; - up_t = now; - ud.now = now; - ud.conn = conn; - ud.up.header.type = DNET_PKT_UPDATE; - ud.up.header.ttl = 1; - ud.up.header.length = DNET_PKT_UPDATE_MIN_LEN; - dnet_traverse_hosts(&dnet_host_update_callback, &ud); - dnet_send_packet((struct dnet_packet *)&ud.up, conn); - } - sleep(1); - } - t->to_remove = 1; - return 0; -} - -static int dnet_conn_count_callback(struct dnet_connection *conn, void *data) -{ - if (data && (time(0) - conn->last_active_time) < UPDATE_PERIOD * 3 / 2)++*(int *)data; - return 0; -} - -static void *dnet_thread_watchdog(void __attribute__((unused)) *arg) -{ - time_t log_t = 0, up_t = 0; - for (;;) { - time_t t = time(0); - if (t - up_t >= UPDATE_PERIOD) { - int count = 0; - up_t = t; - dnet_traverse_connections(&dnet_conn_count_callback, &count); - dnet_log_watchdog(count); - } - if (t - log_t >= LOG_PERIOD) { - log_t = t; - dnet_log_periodic(); - } - sleep(1); - } - return 0; -} - -int dnet_thread_create(struct dnet_thread *t) -{ - void *(*run)(void *); - int res; - switch (t->type) { - case DNET_THREAD_FORWARD_TO: - t->type = DNET_THREAD_STREAM; - case DNET_THREAD_CLIENT: - case DNET_THREAD_SERVER: - case DNET_THREAD_FORWARD_FROM: - run = &dnet_thread_client_server; - break; - case DNET_THREAD_ACCEPTED: - run = &dnet_thread_accepted; - break; - case DNET_THREAD_STREAM: - run = &dnet_thread_stream; - break; - case DNET_THREAD_EXCHANGER: - run = &dnet_thread_exchanger; - break; - case DNET_THREAD_WATCHDOG: - run = &dnet_thread_watchdog; - break; - case DNET_THREAD_COLLECTOR: - run = &dnet_thread_collector; - break; - default: - return -1; - } - t->nthread = g_nthread++; - t->conn.sess = 0; - t->to_remove = 0; - t->id = pthread_invalid; - dthread_mutex_init(&t->conn.mutex, 0); - pthread_rwlock_wrlock(&g_threads_rwlock); - list_insert_before(g_threads, &t->threads); - pthread_rwlock_unlock(&g_threads_rwlock); - res = pthread_create(&t->id, NULL, run, t); - if (res) t->id = pthread_invalid; - else pthread_detach(t->id); - return res; -} - -int dnet_threads_init(void) -{ - g_threads = malloc(sizeof(struct list)); - if (!g_threads) return -1; - list_init(g_threads); - pthread_rwlock_init(&g_threads_rwlock, 0); - g_nthread = 0; - return 0; -} +/* dnet: threads; T11.231-T13.808; $DVS:time$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __LDuS__ +#include +#endif +#include "system.h" +#include "dnet_threads.h" +#include "dnet_connection.h" +#include "dnet_packet.h" +#include "dnet_database.h" +#include "dnet_log.h" +#include "dnet_stream.h" + +#define CONNECTIONS_MAX 100 +#define MAX_N_INBOUND CONNECTIONS_MAX +#define EXCHANGE_PERIOD 1800 +#define EXCHANGE_MAX_TIME (3600 * 48) +#define LOG_PERIOD 300 +#define GC_PERIOD 60 +#define UPDATE_PERIOD DNET_UPDATE_PERIOD + +struct list *g_threads; +pthread_rwlock_t g_threads_rwlock; +int g_nthread; +int(*dnet_connection_open_check)(void *conn, uint32_t ip, uint16_t port); +void(*dnet_connection_close_notify)(void *conn) = 0; +static int g_n_inbound = 0; +int g_conn_limit = MAX_N_INBOUND; + +static void dnet_thread_work(struct dnet_thread *t) +{ + char buf[0x100]; + const char *mess, *mess1 = ""; + struct sockaddr_in peeraddr; + struct hostent *host; + char *str, *lasts; + int res = 0, ip_to = 0, port_to = 0, crc_to = 0, proto = DNET_TCP, reuseaddr = 1; + + if (t->type == DNET_THREAD_FORWARD_FROM || t->type == DNET_THREAD_STREAM) { + port_to = t->st.port_to; + ip_to = t->st.ip_to; + crc_to = t->st.crc_to; + proto = t->st.proto; + } + + // Create a socket + t->conn.socket = socket(AF_INET, (proto == DNET_TCP ? SOCK_STREAM : SOCK_DGRAM), IPPROTO_TCP); + if (t->conn.socket == INVALID_SOCKET) { + mess = "cannot create a socket"; + goto err; + } + if (fcntl(t->conn.socket, F_SETFD, FD_CLOEXEC) == -1) { + dnet_log_printf("dnet.%d: can't set FD_CLOEXEC flag on socket, %s\n", t->nthread, strerror(errno)); + } + + // Fill in the address of server + memset(&peeraddr, 0, sizeof(peeraddr)); + peeraddr.sin_family = AF_INET; + + // Resolve the server address (convert from symbolic name to IP number) + strcpy(buf, t->arg); + str = strtok_r(buf, " \t\r\n:", &lasts); + if (!str) { mess = "host is not given"; goto err; } + if (!strcmp(str, "any")) { + peeraddr.sin_addr.s_addr = htonl(INADDR_ANY); + } else if (!inet_aton(str, &peeraddr.sin_addr)) { + host = gethostbyname(str); + if (!host || !host->h_addr_list[0]) { + mess = "cannot resolve host ", mess1 = str; res = h_errno; + goto err; + } + // Write resolved IP address of a server to the address structure + memmove(&peeraddr.sin_addr.s_addr, host->h_addr_list[0], 4); + } + t->conn.ipaddr = ntohl(peeraddr.sin_addr.s_addr); + + // Resolve port + str = strtok_r(0, " \t\r\n:", &lasts); + if (!str) { mess = "port is not given"; goto err; } + t->conn.port = atoi(str); + peeraddr.sin_port = htons(t->conn.port); + + if (t->type == DNET_THREAD_SERVER || t->type == DNET_THREAD_FORWARD_FROM || proto == DNET_UDP) { + struct linger linger_opt = { 1, (proto == DNET_UDP ? 5 : 0) }; // Linger active, timeout 5 + socklen_t peeraddr_len = sizeof(peeraddr); + + // Bind a socket to the address +#ifdef __LDuS__ + if (t->type == DNET_THREAD_SERVER) { + int i; + for (i = 0; i < 2; ++i) + ldus_free_network_port(AF_INET, SOCK_STREAM, 0, i, t->conn.port); + } +#endif + res = bind(t->conn.socket, (struct sockaddr*)&peeraddr, sizeof(peeraddr)); + if (res) { + mess = "cannot bind a socket"; + goto err; + } + + // Set the "LINGER" timeout to zero, to close the listen socket + // immediately at program termination. + setsockopt(t->conn.socket, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(linger_opt)); + setsockopt(t->conn.socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(int)); + + if (proto == DNET_UDP) { + if (t->type != DNET_THREAD_STREAM) { + dnet_generate_stream_id(&t->st.id); + t->type = DNET_THREAD_STREAM; + t->st.pkt_type = DNET_PKT_FORWARDED_UDP; + } + t->st.crc_to = crc_to; + t->st.ip_to = ip_to; + t->st.port_to = port_to; + t->st.input_tty = t->st.output_tty = t->conn.socket; + dnet_thread_stream(t); + return; + } + + // Now, listen for a connection + res = listen(t->conn.socket, CONNECTIONS_MAX); // "1" is the maximal length of the queue + if (res) { + mess = "cannot listen"; + goto err; + } + + for (;;) { + struct dnet_thread *t1 = malloc(sizeof(struct dnet_thread)); + if (!t1) { mess = "allocation error"; goto err; } + *t1 = *t; + // Accept a connection (the "accept" command waits for a connection with + // no timeout limit...) +begin: + t1->conn.socket = accept(t->conn.socket, (struct sockaddr*) &peeraddr, &peeraddr_len); + if (t1->conn.socket < 0) { free(t1); mess = "cannot accept"; goto err; } + setsockopt(t1->conn.socket, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, sizeof(linger_opt)); + setsockopt(t1->conn.socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseaddr, sizeof(int)); + if (fcntl(t1->conn.socket, F_SETFD, FD_CLOEXEC) == -1) { + dnet_log_printf("dnet.%d: can't set FD_CLOEXEC flag on accepted socket, %s\n", t->nthread, strerror(errno)); + } + if (g_n_inbound >= g_conn_limit || (dnet_connection_open_check + && (*dnet_connection_open_check)(&t1->conn, peeraddr.sin_addr.s_addr, ntohs(peeraddr.sin_port)))) { + close(t1->conn.socket); goto begin; + } + if (t->type == DNET_THREAD_FORWARD_FROM) { + t1->type = DNET_THREAD_STREAM; + t1->st.pkt_type = DNET_PKT_FORWARDED_TCP; + t1->st.to_exit = 0; + t1->st.to_reinit = 0; + t1->st.input_tty = t1->st.output_tty = t1->conn.socket; + t1->st.crc_to = crc_to; + t1->st.ip_to = ip_to; + t1->st.port_to = port_to; + dnet_generate_stream_id(&t1->st.id); + } else { + t1->conn.ipaddr = ntohl(peeraddr.sin_addr.s_addr); + t1->conn.port = ntohs(peeraddr.sin_port); + t1->type = DNET_THREAD_ACCEPTED; + } + res = dnet_thread_create(t1); + if (res) { + if (t1->conn.socket >= 0) { + close(t1->conn.socket); t1->conn.socket = -1; + } + //pthread_mutex_lock(&t->conn.mutex); + t1->to_remove = 1; + //pthread_mutex_unlock(&t->conn.mutex); + mess = "can't create new thread"; goto err; + } else { + g_n_inbound++; + } + } + } else { + // Connect to a remote server + res = connect(t->conn.socket, (struct sockaddr*) &peeraddr, sizeof(peeraddr)); + if (res) { + mess = "cannot connect"; + goto err; + } + + if (t->type == DNET_THREAD_STREAM) { + t->st.ip_to = ip_to; + t->st.port_to = port_to; + t->st.input_tty = t->st.output_tty = t->conn.socket; + dnet_thread_stream(t); + } else { + res = dnet_connection_main(&t->conn); + if (res) { + mess = "connection error"; + goto err; + } + } + } + + return; +err: +#ifdef QDNET + if (strcmp(mess, "cannot connect") && strcmp(mess, "connection error")) +#endif + dnet_log_printf("dnet.%d: %s%s (%d), %s\n", t->nthread, mess, mess1, res, strerror(errno)); +} + +static void *dnet_thread_client_server(void *arg) +{ + struct dnet_thread *t = (struct dnet_thread *)arg; + extern int g_xdag_sync_on; + while (!g_xdag_sync_on) sleep(1); + for (;;) { +#ifndef QDNET + if (dnet_limited_version) dnet_log_printf("dnet.%d: starting connection.\n", t->nthread); + else dnet_log_printf("dnet.%d: starting connection with %s.\n", t->nthread, t->arg); +#endif + dnet_thread_work(t); + if (t->conn.socket >= 0) { + close(t->conn.socket); t->conn.socket = -1; + } + if (dnet_connection_close_notify) (*dnet_connection_close_notify)(&t->conn); + t->to_remove = 1; + break; + } + return 0; +} + +static void *dnet_thread_accepted(void *arg) +{ + struct dnet_thread *t = (struct dnet_thread *)arg; + int ip = t->conn.ipaddr, port = t->conn.port; + dnet_log_printf("dnet.%d: received connection from %u.%u.%u.%u:%u\n", t->nthread, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff, port); + int res = dnet_connection_main(&t->conn); + if (res) { + const char *mess = "connection error"; + dnet_log_printf("dnet.%d: %s (%d), %s\n", t->nthread, mess, res, strerror(errno)); + } + close(t->conn.socket); + g_n_inbound--; + t->conn.socket = -1; + //pthread_mutex_lock(&t->conn.mutex); + if (dnet_connection_close_notify) (*dnet_connection_close_notify)(&t->conn); + t->to_remove = 1; + //pthread_mutex_unlock(&t->conn.mutex); + return 0; +} + +int dnet_traverse_threads(int(*callback)(struct dnet_thread *, void *), void *data) +{ + int res = 0; + struct list *l; + pthread_rwlock_rdlock(&g_threads_rwlock); + for (l = g_threads->next; l != g_threads; l = l->next) { + struct dnet_thread *t = container_of(l, struct dnet_thread, threads); + if (!t->to_remove) { + res = (*callback)(t, data); + if (res) break; + } + } + pthread_rwlock_unlock(&g_threads_rwlock); + return res; +} + +static int dnet_garbage_collect(void) +{ + struct list *l, *lnext; + int total = 0, collected = 0; + dnet_log_printf("dnet gc: start to collect\n"); + pthread_rwlock_wrlock(&g_threads_rwlock); + for (l = g_threads->next; l != g_threads; l = lnext) { + struct dnet_thread *t = container_of(l, struct dnet_thread, threads); + lnext = l->next; + total++; + if (t->to_remove == 2) { + list_remove(l); + dthread_mutex_destroy(&t->conn.mutex); + free(t); + collected++; + } else if (t->to_remove) t->to_remove = 2; + } + pthread_rwlock_unlock(&g_threads_rwlock); + dnet_log_printf("dnet gc: %d threads total, %d collected\n", total, collected); + return 0; +} + +static void *dnet_thread_collector(void __attribute__((unused)) *arg) +{ + time_t t = 0, gc_t = 0; + for (;;) { + t = time(0); + if (t - gc_t >= GC_PERIOD) { + gc_t = t; + dnet_garbage_collect(); + } + sleep(GC_PERIOD / 10); + } + return 0; + +} + +static void dnet_fill_exchange_packet(struct dnet_host *host, struct dnet_packet_exchange *ex, time_t now) +{ + ex->header.type = DNET_PKT_EXCHANGE; + ex->header.ttl = 1; + ex->header.length = DNET_PKT_EXCHANGE_MIN_LEN; + memcpy(ex->pub_key.key, host->key.key, sizeof(struct dnet_key)); + ex->time_ago = dnet_host_time_ago(host, now); + if (host->name_len) { + memcpy(ex->name, host->name, host->name_len); + ex->header.length += host->name_len; + } + if (strlen(host->version) && host->name_len + strlen(host->version) + 1 <= DNET_HOST_NAME_MAX) { + ex->name[host->name_len] = 0; + memcpy(ex->name + host->name_len + 1, host->version, strlen(host->version)); + ex->header.length += strlen(host->version) + 1; + } +} + +struct host_exchange_data { + struct dnet_connection *conn; + time_t now; +}; + +static int dnet_host_exchange_callback(struct dnet_host *host, void *data) +{ + struct host_exchange_data *ed = (struct host_exchange_data *)data; + if (host->last_appear >= ed->conn->last_host_exchange_time && dnet_host_time_ago(host, ed->now) <= EXCHANGE_MAX_TIME) { + struct dnet_packet_exchange ex; + dnet_fill_exchange_packet(host, &ex, ed->now); + dnet_send_packet((struct dnet_packet *)&ex, ed->conn); + } + return 0; +} + +struct host_update_data { + struct dnet_packet_update up; + struct dnet_connection *conn; + time_t now; +}; + +static int dnet_host_update_callback(struct dnet_host *host, void *data) +{ + struct host_update_data *ud = (struct host_update_data *)data; + int nitem; + if (!host->is_local && host->last_time_changed + DNET_ACTIVE_PERIOD < ud->now) return 0; + if (ud->up.header.length >= DNET_PKT_UPDATE_MAX_LEN) { + dnet_send_packet((struct dnet_packet *)&ud->up, ud->conn); + ud->up.header.length = DNET_PKT_UPDATE_MIN_LEN; + } + nitem = (ud->up.header.length - DNET_PKT_UPDATE_MIN_LEN) / sizeof(struct dnet_packet_update_item); + ud->up.item[nitem].crc32 = host->crc32; + ud->up.item[nitem].time_ago = dnet_host_time_ago(host, ud->now); + ud->up.header.length += sizeof(struct dnet_packet_update_item); + return 0; +} + +static void *dnet_thread_exchanger(void *arg) +{ + struct dnet_thread *t = (struct dnet_thread *)arg; + struct dnet_connection *conn; + time_t ex_t = 0, up_t = 0; + while ((conn = (struct dnet_connection *)t->arg)) { + time_t now = time(0); + if (conn->is_new || now - ex_t >= EXCHANGE_PERIOD) { + ex_t = now; + conn->last_host_exchange_time = (conn->is_new ? 0 : now - 2 * EXCHANGE_PERIOD); + conn->is_new = 0; + } + if (now > conn->last_host_exchange_time) { + struct host_exchange_data ed; + ed.conn = conn; + ed.now = now; + dnet_traverse_hosts(&dnet_host_exchange_callback, &ed); + conn->last_host_exchange_time = now; + } + if (now - up_t >= UPDATE_PERIOD) { + struct host_update_data ud; + up_t = now; + ud.now = now; + ud.conn = conn; + ud.up.header.type = DNET_PKT_UPDATE; + ud.up.header.ttl = 1; + ud.up.header.length = DNET_PKT_UPDATE_MIN_LEN; + dnet_traverse_hosts(&dnet_host_update_callback, &ud); + dnet_send_packet((struct dnet_packet *)&ud.up, conn); + } + sleep(1); + } + t->to_remove = 1; + return 0; +} + +static int dnet_conn_count_callback(struct dnet_connection *conn, void *data) +{ + if (data && (time(0) - conn->last_active_time) < UPDATE_PERIOD * 3 / 2)++*(int *)data; + return 0; +} + +static void *dnet_thread_watchdog(void __attribute__((unused)) *arg) +{ + time_t log_t = 0, up_t = 0; + for (;;) { + time_t t = time(0); + if (t - up_t >= UPDATE_PERIOD) { + int count = 0; + up_t = t; + dnet_traverse_connections(&dnet_conn_count_callback, &count); + dnet_log_watchdog(count); + } + if (t - log_t >= LOG_PERIOD) { + log_t = t; + dnet_log_periodic(); + } + sleep(1); + } + return 0; +} + +int dnet_thread_create(struct dnet_thread *t) +{ + void *(*run)(void *); + int res; + switch (t->type) { + case DNET_THREAD_FORWARD_TO: + t->type = DNET_THREAD_STREAM; + case DNET_THREAD_CLIENT: + case DNET_THREAD_SERVER: + case DNET_THREAD_FORWARD_FROM: + run = &dnet_thread_client_server; + break; + case DNET_THREAD_ACCEPTED: + run = &dnet_thread_accepted; + break; + case DNET_THREAD_STREAM: + run = &dnet_thread_stream; + break; + case DNET_THREAD_EXCHANGER: + run = &dnet_thread_exchanger; + break; + case DNET_THREAD_WATCHDOG: + run = &dnet_thread_watchdog; + break; + case DNET_THREAD_COLLECTOR: + run = &dnet_thread_collector; + break; + default: + return -1; + } + t->nthread = g_nthread++; + t->conn.sess = 0; + t->to_remove = 0; + t->id = pthread_invalid; + dthread_mutex_init(&t->conn.mutex, 0); + pthread_rwlock_wrlock(&g_threads_rwlock); + list_insert_before(g_threads, &t->threads); + pthread_rwlock_unlock(&g_threads_rwlock); + res = pthread_create(&t->id, NULL, run, t); + if (res) t->id = pthread_invalid; + else pthread_detach(t->id); + return res; +} + +int dnet_threads_init(void) +{ + g_threads = malloc(sizeof(struct list)); + if (!g_threads) return -1; + list_init(g_threads); + pthread_rwlock_init(&g_threads_rwlock, 0); + g_nthread = 0; + return 0; +} diff --git a/dnet/dnet_threads.h b/dnet/dnet_threads.h index dfa82474..f0f7eb02 100644 --- a/dnet/dnet_threads.h +++ b/dnet/dnet_threads.h @@ -1,47 +1,55 @@ -/* dnet: threads; T11.231-T13.781; $DVS:time$ */ - -#ifndef DNET_THREADS_H_INCLUDED -#define DNET_THREADS_H_INCLUDED - -#include -#include -#include "../ldus/source/include/ldus/list.h" -#include "dnet_connection.h" -#include "dnet_stream.h" - -enum dnet_thread_type { - DNET_THREAD_CLIENT, - DNET_THREAD_SERVER, - DNET_THREAD_FORWARD_FROM, - DNET_THREAD_FORWARD_TO, - DNET_THREAD_ACCEPTED, - DNET_THREAD_STREAM, - DNET_THREAD_EXCHANGER, - DNET_THREAD_WATCHDOG, - DNET_THREAD_COLLECTOR, -}; - -struct dnet_thread { - struct list threads; - union { - struct dnet_connection conn; - struct dnet_stream st; - }; - const char *arg; - pthread_t id; - int nthread; - uint8_t to_remove; - enum dnet_thread_type type; - char argbuf[32]; -}; - -#define DNET_UPDATE_PERIOD 30 - -extern int dnet_thread_create(struct dnet_thread *t); -extern int dnet_traverse_threads(int (*callback)(struct dnet_thread *t, void *data), void *data); -extern int dnet_threads_init(void); - -/* maximum allowed number of connections */ -extern int g_conn_limit; - -#endif +/* dnet: threads; T11.231-T13.781; $DVS:time$ */ + +#ifndef DNET_THREADS_H_INCLUDED +#define DNET_THREADS_H_INCLUDED + +#include +#include +#include "../ldus/source/include/ldus/list.h" +#include "dnet_connection.h" +#include "dnet_stream.h" + +enum dnet_thread_type { + DNET_THREAD_CLIENT, + DNET_THREAD_SERVER, + DNET_THREAD_FORWARD_FROM, + DNET_THREAD_FORWARD_TO, + DNET_THREAD_ACCEPTED, + DNET_THREAD_STREAM, + DNET_THREAD_EXCHANGER, + DNET_THREAD_WATCHDOG, + DNET_THREAD_COLLECTOR, +}; + +struct dnet_thread { + struct list threads; + union { + struct dnet_connection conn; + struct dnet_stream st; + }; + const char *arg; + pthread_t id; + int nthread; + uint8_t to_remove; + enum dnet_thread_type type; + char argbuf[32]; +}; + +#define DNET_UPDATE_PERIOD 30 + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dnet_thread_create(struct dnet_thread *t); +extern int dnet_traverse_threads(int (*callback)(struct dnet_thread *t, void *data), void *data); +extern int dnet_threads_init(void); + +/* maximum allowed number of connections */ +extern int g_conn_limit; + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dus/programs/dar/source/include/crc.h b/dus/programs/dar/source/include/crc.h index 548fc3f6..f37dd0d2 100644 --- a/dus/programs/dar/source/include/crc.h +++ b/dus/programs/dar/source/include/crc.h @@ -1,39 +1,39 @@ -#ifndef _DAR_CRC_H_INCLUDED -#define _DAR_CRC_H_INCLUDED - -/* h-файл библиотеки CRC, T4.046-T9.267; $DVS:time$ */ - -#ifdef __DuS__ -#define EXTERN extern "dar/crc_c.o" -#else -#include -#define EXTERN extern -#endif - -/* инициализация внутренней таблицы CRC (с выделением памяти) */ -EXTERN int - crc_init (void), - -/* построение таблицы во внешнем массиве длины 256 двойных слов */ - crc_makeTable (unsigned table[256]); - - -EXTERN unsigned - -/* добавить к накопленному CRC новые данные, содержащиеся в массиве buf - длины len; возвращает новый CRC; начальное значение CRC=0 */ - crc_addArray (unsigned char *buf, unsigned len, unsigned crc), - -/* добавить к накопленному CRC новые данные, содержащиеся в файле f, но не - более len байт; возвращает новый CRC; начальное значение CRC=0 */ - crc_addFile (FILE *f, unsigned len, unsigned crc); - -/* подсчитать CRC массива */ -#define crc_of_array(buf,len) crc_addArray(buf,len,0) - -/* подсчитать CRC файла */ -#define crc_of_file(f) crc_addFile(f,-1,0) - -#undef EXTERN - -#endif +#ifndef _DAR_CRC_H_INCLUDED +#define _DAR_CRC_H_INCLUDED + +/* h-файл библиотеки CRC, T4.046-T9.267; $DVS:time$ */ + +#ifdef __DuS__ +#define EXTERN extern "dar/crc_c.o" +#else +#include +#define EXTERN extern +#endif + +/* инициализация внутренней таблицы CRC (с выделением памяти) */ +EXTERN int + crc_init (void), + +/* построение таблицы во внешнем массиве длины 256 двойных слов */ + crc_makeTable (unsigned table[256]); + + +EXTERN unsigned + +/* добавить к накопленному CRC новые данные, содержащиеся в массиве buf + длины len; возвращает новый CRC; начальное значение CRC=0 */ + crc_addArray (unsigned char *buf, unsigned len, unsigned crc), + +/* добавить к накопленному CRC новые данные, содержащиеся в файле f, но не + более len байт; возвращает новый CRC; начальное значение CRC=0 */ + crc_addFile (FILE *f, unsigned len, unsigned crc); + +/* подсчитать CRC массива */ +#define crc_of_array(buf,len) crc_addArray(buf,len,0) + +/* подсчитать CRC файла */ +#define crc_of_file(f) crc_addFile(f,-1,0) + +#undef EXTERN + +#endif diff --git a/dus/programs/dar/source/lib/crc_c.c b/dus/programs/dar/source/lib/crc_c.c index eff58639..a66b7694 100644 --- a/dus/programs/dar/source/lib/crc_c.c +++ b/dus/programs/dar/source/lib/crc_c.c @@ -1,66 +1,66 @@ -/* Библиотека для вычисления CRC32-кода данной последовательности байт; - исходный текст взят со страницы CRC из wikiпедии (www.wikipedia.ru) -*/ - -/* - Name : CRC-32 - Poly : 0x04C11DB7 x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + - x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 - Init : 0xFFFFFFFF - Revert: true - XorOut: 0xFFFFFFFF - Check : 0xCBF43926 ("123456789") - MaxLen: 268 435 455 байт (2 147 483 647 бит) - обнаружение - одинарных, двойных, пакетных и всех нечетных ошибок -*/ - -#include /* T5.245 */ -#include -#ifdef __DuS__ -#include -#else -#define _errn(n) return ((n) << 1 | 1) -#include "../include/crc.h" -#endif - -static const char version[] = "CRC library, ...-T4.046-T11.609"; /* $DVS:time$ */ - -unsigned *crc_table = NULL; - -int crc_makeTable(unsigned table[256]) -{ - unsigned long crc; int i, j; - for(i = 0; i < 256; i++) { - crc = i; - for(j = 0; j < 8; j++) - crc = (crc >> 1) ^ (crc & 1 ? 0xEDB88320UL : 0); - table[i] = crc; - } - return 0; -} - -int crc_init(void) -{ - if(crc_table) return 0; - crc_table = malloc(256 * sizeof(unsigned)); - if(!crc_table) _errn(0); - crc_makeTable(crc_table); - return 0; -} - -#define crc_addChar(crc,c) ((crc)=crc_table[(unsigned char)(crc)^(c)]^((crc)>>8)) - -unsigned crc_addArray(unsigned char *buf, unsigned len, unsigned crc) -{ - crc = ~crc; - while(len--) crc_addChar(crc, *buf++); - return ~crc; -} - -unsigned crc_addFile(FILE *f, unsigned len, unsigned crc) -{ - int c; - crc = ~crc; - while(len-- && (c = fgetc(f)) != EOF) crc_addChar(crc, c); - return ~crc; -} +/* Библиотека для вычисления CRC32-кода данной последовательности байт; + исходный текст взят со страницы CRC из wikiпедии (www.wikipedia.ru) +*/ + +/* + Name : CRC-32 + Poly : 0x04C11DB7 x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1 + Init : 0xFFFFFFFF + Revert: true + XorOut: 0xFFFFFFFF + Check : 0xCBF43926 ("123456789") + MaxLen: 268 435 455 байт (2 147 483 647 бит) - обнаружение + одинарных, двойных, пакетных и всех нечетных ошибок +*/ + +#include /* T5.245 */ +#include +#ifdef __DuS__ +#include +#else +#define _errn(n) return ((n) << 1 | 1) +#include "../include/crc.h" +#endif + +static const char version[] = "CRC library, ...-T4.046-T11.609"; /* $DVS:time$ */ + +unsigned *crc_table = NULL; + +int crc_makeTable(unsigned table[256]) +{ + unsigned long crc; int i, j; + for(i = 0; i < 256; i++) { + crc = i; + for(j = 0; j < 8; j++) + crc = (crc >> 1) ^ (crc & 1 ? 0xEDB88320UL : 0); + table[i] = crc; + } + return 0; +} + +int crc_init(void) +{ + if(crc_table) return 0; + crc_table = malloc(256 * sizeof(unsigned)); + if(!crc_table) _errn(0); + crc_makeTable(crc_table); + return 0; +} + +#define crc_addChar(crc,c) ((crc)=crc_table[(unsigned char)(crc)^(c)]^((crc)>>8)) + +unsigned crc_addArray(unsigned char *buf, unsigned len, unsigned crc) +{ + crc = ~crc; + while(len--) crc_addChar(crc, *buf++); + return ~crc; +} + +unsigned crc_addFile(FILE *f, unsigned len, unsigned crc) +{ + int c; + crc = ~crc; + while(len-- && (c = fgetc(f)) != EOF) crc_addChar(crc, c); + return ~crc; +} diff --git a/dus/programs/dfstools/source/dfslib/dfslib_crypt.c b/dus/programs/dfstools/source/dfslib/dfslib_crypt.c index 0d0f1c3d..b0646810 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_crypt.c +++ b/dus/programs/dfstools/source/dfslib/dfslib_crypt.c @@ -1,200 +1,200 @@ -/* cryptography engine for dfslib, T4.846-T10.734; $DVS:time$ */ - -#ifdef __LDuS__ -#include -#endif - -#include "dfslib_crypt.h" - -#define DFS_MAGIC0 572035291u -#define DFS_MAGIC1 2626708081u -#define DFS_MAGIC2 2471573851u -#define DFS_MAGIC3 3569250857u -#define DFS_MAGIC4 1971772241u -#define DFS_MAGIC5 1615037507u -#define DFS_MAGIC6 43385317u -#define DFS_MAGIC7 1229426917u -#define DFS_MAGIC8 3433359571u - - -int dfslib_crypt_set_password(struct dfslib_crypt *dfsc, - const struct dfslib_string *password) { - unsigned ptr = 0; - dfsc->ispwd = 0; - dfsc->pwd[0] = DFS_MAGIC0; - dfsc->pwd[1] = DFS_MAGIC1; - dfsc->pwd[2] = DFS_MAGIC2; - dfsc->pwd[3] = DFS_MAGIC3; - if (password) { - dfs64 res; - int i, err; - while ((err = dfslib_unicode_read(password, &ptr)) >= 0) { - for (i = 0, res = err; i < 4; ++i, res >>= 32) - dfsc->pwd[i] = (dfs32)(res += (dfs64)dfsc->pwd[i] * DFS_MAGIC4); - } - if (err != DFSLIB_NAME_TOO_LONG) return err; - } - return dfsc->ispwd = !!ptr; -} - -int dfslib_crypt_copy_password(struct dfslib_crypt *to, - const struct dfslib_crypt *from) { - int i; - for (i = 0; i < DFSLIB_CRYPT_PWDLEN; ++i) - to->pwd[i] = from->pwd[i]; - return to->ispwd = from->ispwd; -} - -int dfslib_crypt_is_password(struct dfslib_crypt *dfsc) { - return dfsc->ispwd; -} - -#define dfs_enmix2(c,d) c = *--d ^= c * DFS_MAGIC6 -#define dfs_enmix4(c,d) dfs_enmix2(c,d),dfs_enmix2(c,d),dfs_enmix2(c,d),dfs_enmix2(c,d) -#define dfs_enmix6(c,d) dfs_enmix4(c,d),dfs_enmix4(c,d),dfs_enmix4(c,d),dfs_enmix4(c,d) - -static inline void dfs_enmixSector(register dfs32 *d) { - int i = 8; register dfs32 c = DFS_MAGIC5; d += 128; - while (i--) dfs_enmix6(c, d); -} - -static inline void dfs_enmixArray(register dfs32 *d, int size) { - register dfs32 c = DFS_MAGIC5; d += size; - while (size--) dfs_enmix2(c, d); -} - -#define dfs_unmix2(c,d) c *= DFS_MAGIC6, c ^= *--d ^= c -#define dfs_unmix4(c,d) dfs_unmix2(c,d),dfs_unmix2(c,d),dfs_unmix2(c,d),dfs_unmix2(c,d) -#define dfs_unmix6(c,d) dfs_unmix4(c,d),dfs_unmix4(c,d),dfs_unmix4(c,d),dfs_unmix4(c,d) - -static inline void dfs_unmixSector(register dfs32 *d) { - int i = 8; register dfs32 c = DFS_MAGIC5; - while (i--) dfs_unmix6(c, d); -} - -static inline void dfs_unmixArray(register dfs32 *d, int size) { - register dfs32 c = DFS_MAGIC5; - while (size--) dfs_unmix2(c, d); -} - -#define dfs_crypt0(a,x,y,z,t) a = ((dfs32)(((dfs64)y * \ - (z + dfsc->regs[x >> 16])) >> 16) ^ dfsc->regs[(dfs16)t]) - -#define dfs_crypt2(a,b,c,d,x,y,z,t) \ - dfs_crypt0(a,x,y,z,t), dfs_crypt0(b,y,z,t,x),\ - dfs_crypt0(c,z,t,x,y), dfs_crypt0(d,t,x,y,z) - -#define dfs_crypt3(a,b,c,d,x,y,z,t) \ - dfs_crypt2(a,b,c,d,x,y,z,t), dfs_crypt2(x,y,z,t,a,b,c,d) - -#define dfs_crypt6(a,b,c,d,x,y,z,t) \ - dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ - dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ - dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ - dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t) - -static inline dfs16 dfs_mod(dfs64 big_, dfs16 small_) { - if ((unsigned long)big_ == big_) return (unsigned long)big_ % small_; - else { - dfs32 tmp = (dfs32)(big_ >> 32) % small_; - tmp <<= 16, tmp |= (dfs32)big_ >> 16, tmp %= small_; - tmp <<= 16, tmp |= (dfs16)big_; return tmp % small_; - } -} - -static void dfs_prepare(struct dfslib_crypt *dfsc, dfs64 sectorNo, - dfs32 *px, dfs32 *py, dfs32 *pz, dfs32 *pt){ - dfs32 a,b,c,d,x,y,z,t; - sectorNo *= (dfs64)DFS_MAGIC7 << 32 | DFS_MAGIC8; - x = dfsc->pwd[0] ^ dfsc->regs[dfs_mod(sectorNo, 65479) + 31]; - y = dfsc->pwd[1] ^ dfsc->regs[dfs_mod(sectorNo, 65497) + 11]; - z = dfsc->pwd[2] ^ dfsc->regs[dfs_mod(sectorNo, 65519) + 5]; - t = dfsc->pwd[3] ^ dfsc->regs[dfs_mod(sectorNo, 65521) + 3]; - dfs_crypt6(a,b,c,d,x,y,z,t); - *px = x, *py = y, *pz = z, *pt = t; -} - -#define dfs_encrypt2(a,b,c,d,x,y,z,t,data) \ - dfs_crypt0(a,x,y,z,t)^~*data, dfs_crypt0(b,y,z,t,x),\ - dfs_crypt0(c,z,t,x,y), *data++-=dfs_crypt0(d,t,x,y,z) - -#define dfs_encrypt3(a,b,c,d,x,y,z,t,data) \ - dfs_encrypt2(a,b,c,d,x,y,z,t,data), dfs_encrypt2(x,y,z,t,a,b,c,d,data) - -#define dfs_encrypt6(a,b,c,d,x,y,z,t,data) \ - dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data) - -int dfslib_encrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo) { - dfs32 a,b,c,d,x,y,z,t; int i = 8; - if (!dfsc->ispwd) return 0; - dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); - dfs_enmixSector(sector); - while(i--) dfs_encrypt6(a,b,c,d,x,y,z,t,sector); - return 1; -} - -int dfslib_encrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, dfs64 sectorNo) { - dfs32 a,b,c,d,x,y,z,t; - if (!dfsc->ispwd || (size & 1)) return 0; - dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); - dfs_enmixArray(data, size); size >>= 1; - while (size--) dfs_encrypt3(a,b,c,d,x,y,z,t,data); - return 1; -} - -#define dfs_uncrypt2(a,b,c,d,x,y,z,t,data) \ - dfs_crypt0(c,z,t,x,y), *data+= dfs_crypt0(d,t,x,y,z),\ - dfs_crypt0(a,x,y,z,t)^~*data++,dfs_crypt0(b,y,z,t,x) - -#define dfs_uncrypt3(a,b,c,d,x,y,z,t,data) \ - dfs_uncrypt2(a,b,c,d,x,y,z,t,data), dfs_uncrypt2(x,y,z,t,a,b,c,d,data) - -#define dfs_uncrypt6(a,b,c,d,x,y,z,t,data) \ - dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ - dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data) - -int dfslib_uncrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo) { - dfs32 a,b,c,d,x,y,z,t; int i = 8; - if (!dfsc->ispwd) return 0; - dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); - while (i--) dfs_uncrypt6(a,b,c,d,x,y,z,t,sector); - dfs_unmixSector(sector); - return 1; -} - -int dfslib_uncrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, - dfs64 sectorNo) { - dfs32 a,b,c,d,x,y,z,t; int size0 = size; - if (!dfsc->ispwd || (size & 1)) return 0; - dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); - size >>= 1; - while (size--) dfs_uncrypt3(a,b,c,d,x,y,z,t,data); - dfs_unmixArray(data, size0); - return 1; -} - -static inline void dfs_memcpy(dfs8 *to, const dfs8 *from, unsigned size) { -#ifdef __LDuS__ - memcpy(to, from, size); -#else - while (size--) *to++ = *from++; -#endif -} - -int dfslib_crypt_set_sector0(struct dfslib_crypt *dfsc, const void *sector) { - const dfs8 *data = (dfs8*)sector; - int i; - if (!dfsc->ispwd) return 0; - for (i = 0; i < 512; ++i) { - dfs_memcpy((dfs8*)dfsc->regs + (i << 9), data + i, 512 - i); - dfs_memcpy((dfs8*)dfsc->regs + ((i + 1) << 9) - i, data , i ); - } - for (i = 0; i < 512; ++i) - dfslib_encrypt_sector(dfsc, dfsc->regs + (i << 7), i); - return 1; -} +/* cryptography engine for dfslib, T4.846-T10.734; $DVS:time$ */ + +#ifdef __LDuS__ +#include +#endif + +#include "dfslib_crypt.h" + +#define DFS_MAGIC0 572035291u +#define DFS_MAGIC1 2626708081u +#define DFS_MAGIC2 2471573851u +#define DFS_MAGIC3 3569250857u +#define DFS_MAGIC4 1971772241u +#define DFS_MAGIC5 1615037507u +#define DFS_MAGIC6 43385317u +#define DFS_MAGIC7 1229426917u +#define DFS_MAGIC8 3433359571u + + +int dfslib_crypt_set_password(struct dfslib_crypt *dfsc, + const struct dfslib_string *password) { + unsigned ptr = 0; + dfsc->ispwd = 0; + dfsc->pwd[0] = DFS_MAGIC0; + dfsc->pwd[1] = DFS_MAGIC1; + dfsc->pwd[2] = DFS_MAGIC2; + dfsc->pwd[3] = DFS_MAGIC3; + if (password) { + dfs64 res; + int i, err; + while ((err = dfslib_unicode_read(password, &ptr)) >= 0) { + for (i = 0, res = err; i < 4; ++i, res >>= 32) + dfsc->pwd[i] = (dfs32)(res += (dfs64)dfsc->pwd[i] * DFS_MAGIC4); + } + if (err != DFSLIB_NAME_TOO_LONG) return err; + } + return dfsc->ispwd = !!ptr; +} + +int dfslib_crypt_copy_password(struct dfslib_crypt *to, + const struct dfslib_crypt *from) { + int i; + for (i = 0; i < DFSLIB_CRYPT_PWDLEN; ++i) + to->pwd[i] = from->pwd[i]; + return to->ispwd = from->ispwd; +} + +int dfslib_crypt_is_password(struct dfslib_crypt *dfsc) { + return dfsc->ispwd; +} + +#define dfs_enmix2(c,d) c = *--d ^= c * DFS_MAGIC6 +#define dfs_enmix4(c,d) dfs_enmix2(c,d),dfs_enmix2(c,d),dfs_enmix2(c,d),dfs_enmix2(c,d) +#define dfs_enmix6(c,d) dfs_enmix4(c,d),dfs_enmix4(c,d),dfs_enmix4(c,d),dfs_enmix4(c,d) + +static inline void dfs_enmixSector(register dfs32 *d) { + int i = 8; register dfs32 c = DFS_MAGIC5; d += 128; + while (i--) dfs_enmix6(c, d); +} + +static inline void dfs_enmixArray(register dfs32 *d, int size) { + register dfs32 c = DFS_MAGIC5; d += size; + while (size--) dfs_enmix2(c, d); +} + +#define dfs_unmix2(c,d) c *= DFS_MAGIC6, c ^= *--d ^= c +#define dfs_unmix4(c,d) dfs_unmix2(c,d),dfs_unmix2(c,d),dfs_unmix2(c,d),dfs_unmix2(c,d) +#define dfs_unmix6(c,d) dfs_unmix4(c,d),dfs_unmix4(c,d),dfs_unmix4(c,d),dfs_unmix4(c,d) + +static inline void dfs_unmixSector(register dfs32 *d) { + int i = 8; register dfs32 c = DFS_MAGIC5; + while (i--) dfs_unmix6(c, d); +} + +static inline void dfs_unmixArray(register dfs32 *d, int size) { + register dfs32 c = DFS_MAGIC5; + while (size--) dfs_unmix2(c, d); +} + +#define dfs_crypt0(a,x,y,z,t) a = ((dfs32)(((dfs64)y * \ + (z + dfsc->regs[x >> 16])) >> 16) ^ dfsc->regs[(dfs16)t]) + +#define dfs_crypt2(a,b,c,d,x,y,z,t) \ + dfs_crypt0(a,x,y,z,t), dfs_crypt0(b,y,z,t,x),\ + dfs_crypt0(c,z,t,x,y), dfs_crypt0(d,t,x,y,z) + +#define dfs_crypt3(a,b,c,d,x,y,z,t) \ + dfs_crypt2(a,b,c,d,x,y,z,t), dfs_crypt2(x,y,z,t,a,b,c,d) + +#define dfs_crypt6(a,b,c,d,x,y,z,t) \ + dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ + dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ + dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t), \ + dfs_crypt3(a,b,c,d,x,y,z,t), dfs_crypt3(a,b,c,d,x,y,z,t) + +static inline dfs16 dfs_mod(dfs64 big_, dfs16 small_) { + if ((unsigned long)big_ == big_) return (unsigned long)big_ % small_; + else { + dfs32 tmp = (dfs32)(big_ >> 32) % small_; + tmp <<= 16, tmp |= (dfs32)big_ >> 16, tmp %= small_; + tmp <<= 16, tmp |= (dfs16)big_; return tmp % small_; + } +} + +static void dfs_prepare(struct dfslib_crypt *dfsc, dfs64 sectorNo, + dfs32 *px, dfs32 *py, dfs32 *pz, dfs32 *pt){ + dfs32 a,b,c,d,x,y,z,t; + sectorNo *= (dfs64)DFS_MAGIC7 << 32 | DFS_MAGIC8; + x = dfsc->pwd[0] ^ dfsc->regs[dfs_mod(sectorNo, 65479) + 31]; + y = dfsc->pwd[1] ^ dfsc->regs[dfs_mod(sectorNo, 65497) + 11]; + z = dfsc->pwd[2] ^ dfsc->regs[dfs_mod(sectorNo, 65519) + 5]; + t = dfsc->pwd[3] ^ dfsc->regs[dfs_mod(sectorNo, 65521) + 3]; + dfs_crypt6(a,b,c,d,x,y,z,t); + *px = x, *py = y, *pz = z, *pt = t; +} + +#define dfs_encrypt2(a,b,c,d,x,y,z,t,data) \ + dfs_crypt0(a,x,y,z,t)^~*data, dfs_crypt0(b,y,z,t,x),\ + dfs_crypt0(c,z,t,x,y), *data++-=dfs_crypt0(d,t,x,y,z) + +#define dfs_encrypt3(a,b,c,d,x,y,z,t,data) \ + dfs_encrypt2(a,b,c,d,x,y,z,t,data), dfs_encrypt2(x,y,z,t,a,b,c,d,data) + +#define dfs_encrypt6(a,b,c,d,x,y,z,t,data) \ + dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_encrypt3(a,b,c,d,x,y,z,t,data), dfs_encrypt3(a,b,c,d,x,y,z,t,data) + +int dfslib_encrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo) { + dfs32 a,b,c,d,x,y,z,t; int i = 8; + if (!dfsc->ispwd) return 0; + dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); + dfs_enmixSector(sector); + while(i--) dfs_encrypt6(a,b,c,d,x,y,z,t,sector); + return 1; +} + +int dfslib_encrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, dfs64 sectorNo) { + dfs32 a,b,c,d,x,y,z,t; + if (!dfsc->ispwd || (size & 1)) return 0; + dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); + dfs_enmixArray(data, size); size >>= 1; + while (size--) dfs_encrypt3(a,b,c,d,x,y,z,t,data); + return 1; +} + +#define dfs_uncrypt2(a,b,c,d,x,y,z,t,data) \ + dfs_crypt0(c,z,t,x,y), *data+= dfs_crypt0(d,t,x,y,z),\ + dfs_crypt0(a,x,y,z,t)^~*data++,dfs_crypt0(b,y,z,t,x) + +#define dfs_uncrypt3(a,b,c,d,x,y,z,t,data) \ + dfs_uncrypt2(a,b,c,d,x,y,z,t,data), dfs_uncrypt2(x,y,z,t,a,b,c,d,data) + +#define dfs_uncrypt6(a,b,c,d,x,y,z,t,data) \ + dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data), \ + dfs_uncrypt3(a,b,c,d,x,y,z,t,data), dfs_uncrypt3(a,b,c,d,x,y,z,t,data) + +int dfslib_uncrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo) { + dfs32 a,b,c,d,x,y,z,t; int i = 8; + if (!dfsc->ispwd) return 0; + dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); + while (i--) dfs_uncrypt6(a,b,c,d,x,y,z,t,sector); + dfs_unmixSector(sector); + return 1; +} + +int dfslib_uncrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, + dfs64 sectorNo) { + dfs32 a,b,c,d,x,y,z,t; int size0 = size; + if (!dfsc->ispwd || (size & 1)) return 0; + dfs_prepare(dfsc, sectorNo, &x, &y, &z, &t); + size >>= 1; + while (size--) dfs_uncrypt3(a,b,c,d,x,y,z,t,data); + dfs_unmixArray(data, size0); + return 1; +} + +static inline void dfs_memcpy(dfs8 *to, const dfs8 *from, unsigned size) { +#ifdef __LDuS__ + memcpy(to, from, size); +#else + while (size--) *to++ = *from++; +#endif +} + +int dfslib_crypt_set_sector0(struct dfslib_crypt *dfsc, const void *sector) { + const dfs8 *data = (dfs8*)sector; + int i; + if (!dfsc->ispwd) return 0; + for (i = 0; i < 512; ++i) { + dfs_memcpy((dfs8*)dfsc->regs + (i << 9), data + i, 512 - i); + dfs_memcpy((dfs8*)dfsc->regs + ((i + 1) << 9) - i, data , i ); + } + for (i = 0; i < 512; ++i) + dfslib_encrypt_sector(dfsc, dfsc->regs + (i << 7), i); + return 1; +} diff --git a/dus/programs/dfstools/source/dfslib/dfslib_crypt.h b/dus/programs/dfstools/source/dfslib/dfslib_crypt.h index 8c0f61a3..8869c51f 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_crypt.h +++ b/dus/programs/dfstools/source/dfslib/dfslib_crypt.h @@ -1,32 +1,33 @@ -/* header for dfslib cryptography engine, T4.846-T10.273; $DVS:time$ */ - -#ifndef DFSLIB_CRYPT_H_INCLUDED -#define DFSLIB_CRYPT_H_INCLUDED - -#include "dfslib_types.h" -#include "dfslib_string.h" - -#define DFSLIB_CRYPT_PWDLEN 4 - -struct dfslib_crypt { - dfs32 regs[0x10000]; - dfs32 pwd[DFSLIB_CRYPT_PWDLEN]; - dfs32 ispwd; -}; - -extern int dfslib_crypt_set_password (struct dfslib_crypt *dfsc, - const struct dfslib_string *password); -extern int dfslib_crypt_copy_password (struct dfslib_crypt *to, - const struct dfslib_crypt *from); -extern int dfslib_crypt_is_password (struct dfslib_crypt *dfsc); -extern int dfslib_crypt_set_sector0 (struct dfslib_crypt *dfsc, const void *sector); -extern int dfslib_encrypt_sector (struct dfslib_crypt *dfsc, - dfs32 *sector, dfs64 sectorNo); -extern int dfslib_uncrypt_sector (struct dfslib_crypt *dfsc, - dfs32 *sector, dfs64 sectorNo); -extern int dfslib_encrypt_array (struct dfslib_crypt *dfsc, - dfs32 *data, unsigned size, dfs64 sectorNo); -extern int dfslib_uncrypt_array (struct dfslib_crypt *dfsc, - dfs32 *data, unsigned size, dfs64 sectorNo); - -#endif +/* header for dfslib cryptography engine, T4.846-T10.273; $DVS:time$ */ + +#ifndef DFSLIB_CRYPT_H_INCLUDED +#define DFSLIB_CRYPT_H_INCLUDED + +#include "dfslib_types.h" +#include "dfslib_string.h" + +#define DFSLIB_CRYPT_PWDLEN 4 + +struct dfslib_crypt { + dfs32 regs[0x10000]; + dfs32 pwd[DFSLIB_CRYPT_PWDLEN]; + dfs32 ispwd; +}; +#ifdef __cplusplus +extern "C" { +#endif + +extern int dfslib_crypt_set_password(struct dfslib_crypt *dfsc, const struct dfslib_string *password); +extern int dfslib_crypt_copy_password(struct dfslib_crypt *to, const struct dfslib_crypt *from); +extern int dfslib_crypt_is_password(struct dfslib_crypt *dfsc); +extern int dfslib_crypt_set_sector0(struct dfslib_crypt *dfsc, const void *sector); +extern int dfslib_encrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo); +extern int dfslib_uncrypt_sector(struct dfslib_crypt *dfsc, dfs32 *sector, dfs64 sectorNo); +extern int dfslib_encrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, dfs64 sectorNo); +extern int dfslib_uncrypt_array(struct dfslib_crypt *dfsc, dfs32 *data, unsigned size, dfs64 sectorNo); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dus/programs/dfstools/source/dfslib/dfslib_random.c b/dus/programs/dfstools/source/dfslib/dfslib_random.c index a1ed493e..446b0d35 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_random.c +++ b/dus/programs/dfstools/source/dfslib/dfslib_random.c @@ -1,114 +1,114 @@ -/* dfslib library for random data generation, T10.273-T10.717; $DVS:time$ */ - -#include -#include -#if !defined(_WIN32) && !defined(_WIN64) -#include -#include -#include -#define USE_RAND48 -#else -#include -#include -#define getpid _getpid -#endif -#include "dfslib_random.h" - -unsigned dfslib_random_get(unsigned limit) { - unsigned res; -#ifdef USE_RAND48 - res = mrand48(); -#else - res = rand(); -#endif - if (limit) res %= limit; - return res; -} - -void dfslib_random_fill(void *buf, unsigned long len, int xor, struct dfslib_string *tip) { - unsigned res = 0, bytes3 = 0, rnd, tmp = 0; - while (len) { - rnd = dfslib_random_get(0); - if (tip) { - int uni = dfslib_unicode_read(tip, &tmp); - if (uni < 0) { - tmp = 0; - uni = dfslib_unicode_read(tip, &tmp); - } - rnd += uni; - } - res *= 41, res += rnd % 41, bytes3 += 2; - if (bytes3 >= 10) { - if (xor) *(unsigned char *)buf ^= (unsigned char)res; - else *(unsigned char *)buf = (unsigned char)res; - res >>= 8, bytes3 -= 3; - buf = (unsigned char *)buf + 1, --len; - } - } -} - -void dfslib_random_sector(dfs32 *sector, struct dfslib_crypt *crypt0, - struct dfslib_string *password, struct dfslib_string *tip) { - struct dfslib_crypt crypt[1]; - struct dfslib_string tip0[1]; - char tips[6 * DFSLIB_CRYPT_PWDLEN]; - dfs64 nsector; - int i; - if (crypt0) dfslib_crypt_copy_password(crypt, crypt0); - else dfslib_crypt_set_password(crypt, password); - if (!tip) { - for (i = 0; i < DFSLIB_CRYPT_PWDLEN; ++i) { - dfs32 res = crypt->pwd[i]; - int j; - for (j = 0; j < 6; ++j) - tips[i * 6 + j] = (res % 41) + 0x21, res /= 41; - } - dfslib_utf8_string(tip0, tips, 6 * DFSLIB_CRYPT_PWDLEN); - tip = tip0; - } - for (i = 0; i < 3; ++i) { - dfslib_random_fill(sector, 512, i, tip); - dfslib_random_fill(&nsector, 8, i, tip); - dfslib_crypt_set_sector0(crypt, sector); - dfslib_encrypt_sector(crypt, sector, nsector); - } -} - -void dfslib_random_init(void) { - dfs64 seed = 0, time1, time2, clock, pid; -#if !defined(_WIN32) && !defined(_WIN64) - struct timeval tv[1]; - struct tms tms[1]; - gettimeofday(tv, NULL); - time1 = tv->tv_sec; - time2 = tv->tv_usec; - clock = times(tms); -#else - FILETIME ft[1]; - GetSystemTimeAsFileTime(ft); - time1 = ft->dwHighDateTime; - time2 = ft->dwLowDateTime; - clock = GetTickCount(); -#endif - pid = getpid(); - seed ^= time1; seed *= 0x8E230615u; - seed ^= time2; seed *= 0x40D95A7Bu; - seed ^= clock; seed *= 0x0EE493B1u; - seed ^= pid; seed *= 0xB8204941u; - dfslib_random_fill(&seed, 8, 1, 0); -#if 0 - printf("dfslib_random: time=(%lX, %lX), times=%lX, pid=%lX, seed=%llX\n", - (long)tv->tv_sec, (long)tv->tv_usec, (long)clock, (long)pid, seed); -#endif -#ifdef USE_RAND48 - { - unsigned short xsubi[3]; - int i; - for (i = 0; i < 3; ++i) - xsubi[i] = seed & 0xFFFF, seed >>= 16; - seed48(xsubi); - } -#else - srand((unsigned)seed); -#endif -} +/* dfslib library for random data generation, T10.273-T10.717; $DVS:time$ */ + +#include +#include +#if !defined(_WIN32) && !defined(_WIN64) +#include +#include +#include +#define USE_RAND48 +#else +#include +#include +#define getpid _getpid +#endif +#include "dfslib_random.h" + +unsigned dfslib_random_get(unsigned limit) { + unsigned res; +#ifdef USE_RAND48 + res = mrand48(); +#else + res = rand(); +#endif + if (limit) res %= limit; + return res; +} + +void dfslib_random_fill(void *buf, unsigned long len, int xor, struct dfslib_string *tip) { + unsigned res = 0, bytes3 = 0, rnd, tmp = 0; + while (len) { + rnd = dfslib_random_get(0); + if (tip) { + int uni = dfslib_unicode_read(tip, &tmp); + if (uni < 0) { + tmp = 0; + uni = dfslib_unicode_read(tip, &tmp); + } + rnd += uni; + } + res *= 41, res += rnd % 41, bytes3 += 2; + if (bytes3 >= 10) { + if (xor) *(unsigned char *)buf ^= (unsigned char)res; + else *(unsigned char *)buf = (unsigned char)res; + res >>= 8, bytes3 -= 3; + buf = (unsigned char *)buf + 1, --len; + } + } +} + +void dfslib_random_sector(dfs32 *sector, struct dfslib_crypt *crypt0, + struct dfslib_string *password, struct dfslib_string *tip) { + struct dfslib_crypt crypt[1]; + struct dfslib_string tip0[1]; + char tips[6 * DFSLIB_CRYPT_PWDLEN]; + dfs64 nsector; + int i; + if (crypt0) dfslib_crypt_copy_password(crypt, crypt0); + else dfslib_crypt_set_password(crypt, password); + if (!tip) { + for (i = 0; i < DFSLIB_CRYPT_PWDLEN; ++i) { + dfs32 res = crypt->pwd[i]; + int j; + for (j = 0; j < 6; ++j) + tips[i * 6 + j] = (res % 41) + 0x21, res /= 41; + } + dfslib_utf8_string(tip0, tips, 6 * DFSLIB_CRYPT_PWDLEN); + tip = tip0; + } + for (i = 0; i < 3; ++i) { + dfslib_random_fill(sector, 512, i, tip); + dfslib_random_fill(&nsector, 8, i, tip); + dfslib_crypt_set_sector0(crypt, sector); + dfslib_encrypt_sector(crypt, sector, nsector); + } +} + +void dfslib_random_init(void) { + dfs64 seed = 0, time1, time2, clock, pid; +#if !defined(_WIN32) && !defined(_WIN64) + struct timeval tv[1]; + struct tms tms[1]; + gettimeofday(tv, NULL); + time1 = tv->tv_sec; + time2 = tv->tv_usec; + clock = times(tms); +#else + FILETIME ft[1]; + GetSystemTimeAsFileTime(ft); + time1 = ft->dwHighDateTime; + time2 = ft->dwLowDateTime; + clock = GetTickCount(); +#endif + pid = getpid(); + seed ^= time1; seed *= 0x8E230615u; + seed ^= time2; seed *= 0x40D95A7Bu; + seed ^= clock; seed *= 0x0EE493B1u; + seed ^= pid; seed *= 0xB8204941u; + dfslib_random_fill(&seed, 8, 1, 0); +#if 0 + printf("dfslib_random: time=(%lX, %lX), times=%lX, pid=%lX, seed=%llX\n", + (long)tv->tv_sec, (long)tv->tv_usec, (long)clock, (long)pid, seed); +#endif +#ifdef USE_RAND48 + { + unsigned short xsubi[3]; + int i; + for (i = 0; i < 3; ++i) + xsubi[i] = seed & 0xFFFF, seed >>= 16; + seed48(xsubi); + } +#else + srand((unsigned)seed); +#endif +} diff --git a/dus/programs/dfstools/source/dfslib/dfslib_random.h b/dus/programs/dfstools/source/dfslib/dfslib_random.h index 50271bfe..2198f241 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_random.h +++ b/dus/programs/dfstools/source/dfslib/dfslib_random.h @@ -1,16 +1,22 @@ -/* header of dfslib library for random data generation, T10.273-T10.273; $DVS:time$ */ - -#ifndef DFSLIB_RANDOM_H_INCLUDED -#define DFSLIB_RANDOM_H_INCLUDED - -#include "dfslib_string.h" -#include "dfslib_crypt.h" - -extern void dfslib_random_init(void); -extern unsigned dfslib_random_get(unsigned limit); -extern void dfslib_random_fill(void *buf, unsigned long len, int xor, - struct dfslib_string *tip); -extern void dfslib_random_sector(dfs32 *sector, struct dfslib_crypt *crypt, - struct dfslib_string *password, struct dfslib_string *tip); - -#endif +/* header of dfslib library for random data generation, T10.273-T10.273; $DVS:time$ */ + +#ifndef DFSLIB_RANDOM_H_INCLUDED +#define DFSLIB_RANDOM_H_INCLUDED + +#include "dfslib_string.h" +#include "dfslib_crypt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern void dfslib_random_init(void); +extern unsigned dfslib_random_get(unsigned limit); +extern void dfslib_random_fill(void *buf, unsigned long len, int xor, struct dfslib_string *tip); +extern void dfslib_random_sector(dfs32 *sector, struct dfslib_crypt *crypt, struct dfslib_string *password, struct dfslib_string *tip); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/dus/programs/dfstools/source/dfslib/dfslib_string.c b/dus/programs/dfstools/source/dfslib/dfslib_string.c index c7df8dee..6de0b15f 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_string.c +++ b/dus/programs/dfstools/source/dfslib/dfslib_string.c @@ -1,147 +1,147 @@ -/* dfslib string functions, T10.259-T13.169; $DVS:time$ */ - -#include "dfslib_string.h" - -int dfslib_unicode_to_utf8(dfs16 uni, char **pbuf, unsigned *psize) { - if (!(uni & ~0x7F)) { - if (!*psize) return DFSLIB_NAME_TOO_LONG; - *(*pbuf)++ = (dfs8)uni, (*psize)--; - } else if (!(uni & ~0x7FF)) { - if (*psize < 2) return DFSLIB_NAME_TOO_LONG; - *(*pbuf)++ = uni >> 6 | 0xC0, *(*pbuf)++ = (uni & 0x3F) | 0x80, *psize -= 2; - } else { - if (*psize < 3) return DFSLIB_NAME_TOO_LONG; - *(*pbuf)++ = uni >> 12 | 0xE0, *(*pbuf)++ = (uni >> 6 & 0x3F) | 0x80, - *(*pbuf)++ = (uni & 0x3F) | 0x80, *psize -= 3; - } - return 0; -} - -int dfslib_utf8_to_unicode(const char **utf, unsigned *plen) { - int c; - if (!*plen) return DFSLIB_NAME_TOO_LONG; - --*plen; - if ((c = (dfs8)*(*utf)++) < 0x80) return c; - if (c < 0xC0) return DFSLIB_INVALID_NAME; - if (c < 0xE0) { - int d; - if (!*plen) return DFSLIB_INVALID_NAME; - c &= 0x1F, c <<= 6; --*plen; - if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; - return c | (d & 0x3F); - } - if (c < 0xF0) { - int d; - if (*plen < 2) return DFSLIB_INVALID_NAME; - c &= 0xF, c <<= 12; --*plen; - if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; - c |= (d & 0x3F) << 6; --*plen; - if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; - return c | (d & 0x3F); - } - return DFSLIB_INVALID_NAME; -} - -int dfslib_unicode_read(const struct dfslib_string *str, unsigned *ptr) { - switch(str->type) { - case DFSLIB_STRING_UTF8: - { - const char *utf = str->utf8 + *ptr; - unsigned size = str->len - *ptr; - int unicode = dfslib_utf8_to_unicode(&utf, &size); - *ptr = utf - str->utf8; - return unicode; - } - case DFSLIB_STRING_UNICODE: - if (*ptr < str->len) { - return str->unicode[(*ptr)++]; - } else return DFSLIB_NAME_TOO_LONG; - } - return DFSLIB_INVALID_NAME; -} - -int dfslib_unicode_cmp(const struct dfslib_string *str, unsigned *ptr, int unicode) { - int res = dfslib_unicode_read(str, ptr); - if (res < 0 && res != DFSLIB_NAME_TOO_LONG) return res; - return (res > unicode) - (res < unicode); -} - -int dfslib_unicode_strlen(const struct dfslib_string *str) { - if (str->type == DFSLIB_STRING_UNICODE) return str->len; - else { - unsigned ptr = 0, count = 0; - int res; - while ((res = dfslib_unicode_read(str, &ptr)) >= 0) ++count; - if (res != DFSLIB_NAME_TOO_LONG) return res; - return count; - } -} - -int dfslib_string_to_unicode(struct dfslib_string *str, dfs16 *buf, unsigned len) { - if (str->type == DFSLIB_STRING_UNICODE) return str->len; - else { - unsigned ptr = 0, count = 0; - int res = 0; - while (count < len && (res = dfslib_unicode_read(str, &ptr)) >= 0) - buf[count++] = res; - if (count == len) return DFSLIB_NAME_TOO_LONG; - if (res != DFSLIB_NAME_TOO_LONG) return res; - dfslib_unicode_string(str, buf, count); - return count; - } -} - -int dfslib_string_to_utf8(struct dfslib_string *str, char *buf, unsigned len) { - switch (str->type) { - case DFSLIB_STRING_UTF8: - return str->len; - case DFSLIB_STRING_UNICODE: - { - int res; unsigned i; - char *ptr = buf; - for (i = 0; i < str->len; ++i) { - res = dfslib_unicode_to_utf8(str->unicode[i], &ptr, &len); - if (res < 0) return res; - } - len = ptr - buf; - dfslib_utf8_string(str, buf, len); - return len; - } - } - return DFSLIB_INVALID_NAME; -} - -int dfslib_substring(const struct dfslib_string *str, struct dfslib_string *substr, - unsigned begin, unsigned end) { - *substr = *str; - substr->len = end - begin; - switch(str->type) { - case DFSLIB_STRING_UTF8: substr->utf8 += begin; break; - case DFSLIB_STRING_UNICODE: substr->unicode += begin; break; - default: return DFSLIB_INVALID_NAME; - } - return 0; -} - -int dfslib_unicode_strchr(const struct dfslib_string *str, int unicode) { - unsigned ptr = 0, ptr0; - int res; - while (ptr0 = ptr, (res = dfslib_unicode_read(str, &ptr)) >= 0) - if (res == unicode) return ptr0; - return res; -} - -int dfslib_unicode_strtok(const struct dfslib_string *str, - struct dfslib_string *token, const struct dfslib_string *limits, - unsigned *ptr) { - unsigned begin, end; - int res; - while (begin = *ptr, (res = dfslib_unicode_read(str, ptr)) >= 0 - && dfslib_unicode_strchr(limits, res) >= 0); - if (res < 0) return res; - while (end = *ptr, (res = dfslib_unicode_read(str, ptr)) >= 0 - && dfslib_unicode_strchr(limits, res) < 0); - if (res < 0 && res != DFSLIB_NAME_TOO_LONG) return res; - dfslib_substring(str, token, begin, end); - return 0; -} +/* dfslib string functions, T10.259-T13.169; $DVS:time$ */ + +#include "dfslib_string.h" + +int dfslib_unicode_to_utf8(dfs16 uni, char **pbuf, unsigned *psize) { + if (!(uni & ~0x7F)) { + if (!*psize) return DFSLIB_NAME_TOO_LONG; + *(*pbuf)++ = (dfs8)uni, (*psize)--; + } else if (!(uni & ~0x7FF)) { + if (*psize < 2) return DFSLIB_NAME_TOO_LONG; + *(*pbuf)++ = uni >> 6 | 0xC0, *(*pbuf)++ = (uni & 0x3F) | 0x80, *psize -= 2; + } else { + if (*psize < 3) return DFSLIB_NAME_TOO_LONG; + *(*pbuf)++ = uni >> 12 | 0xE0, *(*pbuf)++ = (uni >> 6 & 0x3F) | 0x80, + *(*pbuf)++ = (uni & 0x3F) | 0x80, *psize -= 3; + } + return 0; +} + +int dfslib_utf8_to_unicode(const char **utf, unsigned *plen) { + int c; + if (!*plen) return DFSLIB_NAME_TOO_LONG; + --*plen; + if ((c = (dfs8)*(*utf)++) < 0x80) return c; + if (c < 0xC0) return DFSLIB_INVALID_NAME; + if (c < 0xE0) { + int d; + if (!*plen) return DFSLIB_INVALID_NAME; + c &= 0x1F, c <<= 6; --*plen; + if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; + return c | (d & 0x3F); + } + if (c < 0xF0) { + int d; + if (*plen < 2) return DFSLIB_INVALID_NAME; + c &= 0xF, c <<= 12; --*plen; + if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; + c |= (d & 0x3F) << 6; --*plen; + if ((d = (dfs8)*(*utf)++) < 0x80 || d >= 0xC0) return DFSLIB_INVALID_NAME; + return c | (d & 0x3F); + } + return DFSLIB_INVALID_NAME; +} + +int dfslib_unicode_read(const struct dfslib_string *str, unsigned *ptr) { + switch(str->type) { + case DFSLIB_STRING_UTF8: + { + const char *utf = str->utf8 + *ptr; + unsigned size = str->len - *ptr; + int unicode = dfslib_utf8_to_unicode(&utf, &size); + *ptr = utf - str->utf8; + return unicode; + } + case DFSLIB_STRING_UNICODE: + if (*ptr < str->len) { + return str->unicode[(*ptr)++]; + } else return DFSLIB_NAME_TOO_LONG; + } + return DFSLIB_INVALID_NAME; +} + +int dfslib_unicode_cmp(const struct dfslib_string *str, unsigned *ptr, int unicode) { + int res = dfslib_unicode_read(str, ptr); + if (res < 0 && res != DFSLIB_NAME_TOO_LONG) return res; + return (res > unicode) - (res < unicode); +} + +int dfslib_unicode_strlen(const struct dfslib_string *str) { + if (str->type == DFSLIB_STRING_UNICODE) return str->len; + else { + unsigned ptr = 0, count = 0; + int res; + while ((res = dfslib_unicode_read(str, &ptr)) >= 0) ++count; + if (res != DFSLIB_NAME_TOO_LONG) return res; + return count; + } +} + +int dfslib_string_to_unicode(struct dfslib_string *str, dfs16 *buf, unsigned len) { + if (str->type == DFSLIB_STRING_UNICODE) return str->len; + else { + unsigned ptr = 0, count = 0; + int res = 0; + while (count < len && (res = dfslib_unicode_read(str, &ptr)) >= 0) + buf[count++] = res; + if (count == len) return DFSLIB_NAME_TOO_LONG; + if (res != DFSLIB_NAME_TOO_LONG) return res; + dfslib_unicode_string(str, buf, count); + return count; + } +} + +int dfslib_string_to_utf8(struct dfslib_string *str, char *buf, unsigned len) { + switch (str->type) { + case DFSLIB_STRING_UTF8: + return str->len; + case DFSLIB_STRING_UNICODE: + { + int res; unsigned i; + char *ptr = buf; + for (i = 0; i < str->len; ++i) { + res = dfslib_unicode_to_utf8(str->unicode[i], &ptr, &len); + if (res < 0) return res; + } + len = ptr - buf; + dfslib_utf8_string(str, buf, len); + return len; + } + } + return DFSLIB_INVALID_NAME; +} + +int dfslib_substring(const struct dfslib_string *str, struct dfslib_string *substr, + unsigned begin, unsigned end) { + *substr = *str; + substr->len = end - begin; + switch(str->type) { + case DFSLIB_STRING_UTF8: substr->utf8 += begin; break; + case DFSLIB_STRING_UNICODE: substr->unicode += begin; break; + default: return DFSLIB_INVALID_NAME; + } + return 0; +} + +int dfslib_unicode_strchr(const struct dfslib_string *str, int unicode) { + unsigned ptr = 0, ptr0; + int res; + while (ptr0 = ptr, (res = dfslib_unicode_read(str, &ptr)) >= 0) + if (res == unicode) return ptr0; + return res; +} + +int dfslib_unicode_strtok(const struct dfslib_string *str, + struct dfslib_string *token, const struct dfslib_string *limits, + unsigned *ptr) { + unsigned begin, end; + int res; + while (begin = *ptr, (res = dfslib_unicode_read(str, ptr)) >= 0 + && dfslib_unicode_strchr(limits, res) >= 0); + if (res < 0) return res; + while (end = *ptr, (res = dfslib_unicode_read(str, ptr)) >= 0 + && dfslib_unicode_strchr(limits, res) < 0); + if (res < 0 && res != DFSLIB_NAME_TOO_LONG) return res; + dfslib_substring(str, token, begin, end); + return 0; +} diff --git a/dus/programs/dfstools/source/dfslib/dfslib_string.h b/dus/programs/dfstools/source/dfslib/dfslib_string.h index eb0e700e..211e1ee9 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_string.h +++ b/dus/programs/dfstools/source/dfslib/dfslib_string.h @@ -1,56 +1,59 @@ -/* header of dfslib string functions, T10.259-T10.267; $DVS:time$ */ - -#ifndef DFSLIB_STRING_H_INCLUDED -#define DFSLIB_STRING_H_INCLUDED - -#include "dfslib_types.h" - -enum dfslib_string_types { - DFSLIB_STRING_NONE, - DFSLIB_STRING_UTF8, - DFSLIB_STRING_UNICODE, -}; - -/* структура, описывающая строку utf8 или массив символов unicode -*/ -struct dfslib_string { - int type; - unsigned len; - union { - const char *utf8; - const dfs16 *unicode; - }; -}; - -extern int dfslib_unicode_to_utf8(dfs16 uni, char **pbuf, unsigned *psize); -extern int dfslib_utf8_to_unicode(const char **utf, unsigned *plen); - -extern int dfslib_unicode_read(const struct dfslib_string *str, unsigned *ptr); -extern int dfslib_unicode_cmp(const struct dfslib_string *str, unsigned *ptr, int unicode); -extern int dfslib_unicode_strlen(const struct dfslib_string *str); -extern int dfslib_string_to_unicode(struct dfslib_string *str, dfs16 *buf, unsigned len); -extern int dfslib_string_to_utf8(struct dfslib_string *str, char *buf, unsigned len); -extern int dfslib_substring(const struct dfslib_string *str, - struct dfslib_string *substr, unsigned begin, unsigned end); -extern int dfslib_unicode_strchr(const struct dfslib_string *str, int unicode); -extern int dfslib_unicode_strtok(const struct dfslib_string *str, - struct dfslib_string *token, const struct dfslib_string *limits, - unsigned *ptr); - -static inline struct dfslib_string *dfslib_utf8_string(struct dfslib_string *str, - const char *utf8, unsigned len) { - str->type = DFSLIB_STRING_UTF8; - str->len = len; - str->utf8 = utf8; - return str; -} - -static inline struct dfslib_string *dfslib_unicode_string(struct dfslib_string *str, - const dfs16 *unicode, unsigned len) { - str->type = DFSLIB_STRING_UNICODE; - str->len = len; - str->unicode = unicode; - return str; -} - -#endif +/* header of dfslib string functions, T10.259-T10.267; $DVS:time$ */ + +#ifndef DFSLIB_STRING_H_INCLUDED +#define DFSLIB_STRING_H_INCLUDED + +#include "dfslib_types.h" + +enum dfslib_string_types { + DFSLIB_STRING_NONE, + DFSLIB_STRING_UTF8, + DFSLIB_STRING_UNICODE, +}; + +/* структура, описывающая строку utf8 или массив символов unicode +*/ +struct dfslib_string { + int type; + unsigned len; + union { + const char *utf8; + const dfs16 *unicode; + }; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int dfslib_unicode_to_utf8(dfs16 uni, char **pbuf, unsigned *psize); +extern int dfslib_utf8_to_unicode(const char **utf, unsigned *plen); + +extern int dfslib_unicode_read(const struct dfslib_string *str, unsigned *ptr); +extern int dfslib_unicode_cmp(const struct dfslib_string *str, unsigned *ptr, int unicode); +extern int dfslib_unicode_strlen(const struct dfslib_string *str); +extern int dfslib_string_to_unicode(struct dfslib_string *str, dfs16 *buf, unsigned len); +extern int dfslib_string_to_utf8(struct dfslib_string *str, char *buf, unsigned len); +extern int dfslib_substring(const struct dfslib_string *str, struct dfslib_string *substr, unsigned begin, unsigned end); +extern int dfslib_unicode_strchr(const struct dfslib_string *str, int unicode); +extern int dfslib_unicode_strtok(const struct dfslib_string *str, struct dfslib_string *token, const struct dfslib_string *limits, unsigned *ptr); + +static inline struct dfslib_string *dfslib_utf8_string(struct dfslib_string *str, + const char *utf8, unsigned len) { + str->type = DFSLIB_STRING_UTF8; + str->len = len; + str->utf8 = utf8; + return str; +} + +static inline struct dfslib_string *dfslib_unicode_string(struct dfslib_string *str, const dfs16 *unicode, unsigned len) { + str->type = DFSLIB_STRING_UNICODE; + str->len = len; + str->unicode = unicode; + return str; +} + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/dus/programs/dfstools/source/dfslib/dfslib_types.h b/dus/programs/dfstools/source/dfslib/dfslib_types.h index 670f34dd..98eca591 100644 --- a/dus/programs/dfstools/source/dfslib/dfslib_types.h +++ b/dus/programs/dfstools/source/dfslib/dfslib_types.h @@ -1,79 +1,79 @@ -/* basic types for dfslib, T10.090-T13.418; $DVS:time$ */ - -#ifndef DFSLIB_TYPES_H_INCLUDED -#define DFSLIB_TYPES_H_INCLUDED - -#if defined(_WIN32) || defined(_WIN64) -#ifndef inline -#define inline __inline -#endif -#endif - -enum dfslib_errors { - DFSLIB_ERROR_MAX = -2, - DFSLIB_NOT_REALIZED = -2, - DFSLIB_IO_ERROR = -3, - DFSLIB_CORRUPT_DATA = -4, - DFSLIB_INVALID_VOLUME = -5, - DFSLIB_INVALID_TYPE = -6, - DFSLIB_INVALID_VALUE = -7, - DFSLIB_FILE_IS_DIR = -8, - DFSLIB_FILE_IS_NOT_DIR = -9, - DFSLIB_DIR_NOT_EMPTY = -10, - DFSLIB_INVALID_NAME = -11, - DFSLIB_NAME_TOO_LONG = -12, - DFSLIB_NOT_FOUND = -13, - DFSLIB_ACCESS_DENIED = -14, - DFSLIB_READ_ONLY = -15, - DFSLIB_NO_FREE_MEMORY = -16, - DFSLIB_NO_FREE_SPACE = -17, - DFSLIB_TEMP_UNAVAILABLE = -18, - DFSLIB_TOO_MANY_LOCKED = -19, - DFSLIB_INTERNAL_ERROR = -20, - DFSLIB_ERROR_MIN = -20, -}; - -/* the structure of ino: 0 access bits + 4 nnode bits + nsector */ -#define DFSLIB_INO_NNODE_SHIFT 0 -#define DFSLIB_INO_NSECTOR_SHIFT (DFSLIB_INO_NNODE_SHIFT + 4) -#define DFSLIB_SECT_PER_BLOCK_SHIFT 6 -#define DFSLIB_SECT_PER_BLOCK (1 << DFSLIB_SECT_PER_BLOCK_SHIFT) - -typedef unsigned long long dfs64; -typedef unsigned int dfs32; -typedef unsigned short dfs16; -typedef unsigned char dfs8; - -typedef dfs32 dfs_atomic; -typedef dfs64 dfs_atomic64; -typedef void * dfs_mutex; - -/* common platform-dependent operations */ -struct dfslib_platform_op { - void * (*malloc)(unsigned long size); - void (*free)(void *mem); - void (*memcpy)(void *to, const void *from, unsigned long size); - dfs64 (*time)(void); /* current time in nanoseconds since 1.1.1970 UTC */ - void (*pause)(void); /* run another processes */ - void (*alert)(const char *mess, dfs64 arg1, dfs64 arg2); - dfs32 (*div)(dfs64 *n, dfs32 base); /* *n /= base; return *n % base */ - - dfs32 (*atomic_read)(dfs_atomic *ptr); - void (*atomic_set)(dfs_atomic *ptr, dfs32 value); - dfs32 (*atomic_inc_return)(dfs_atomic *ptr); - dfs32 (*atomic_dec_return)(dfs_atomic *ptr); - dfs32 (*atomic_cmpxchg)(dfs_atomic *ptr, dfs32 old_, dfs32 new_); - - dfs64 (*atomic64_read)(dfs_atomic64 *ptr); - void (*atomic64_set)(dfs_atomic64 *ptr, dfs64 value); - dfs64 (*atomic64_inc_return)(dfs_atomic64 *ptr); - dfs64 (*atomic64_dec_return)(dfs_atomic64 *ptr); - dfs64 (*atomic64_cmpxchg)(dfs_atomic64 *ptr, dfs64 old_, dfs64 new_); - - dfs_mutex (*mutex_init)(void); /* allocate and init mutex */ - void (*mutex_lock)(dfs_mutex mutex); - void (*mutex_unlock)(dfs_mutex mutex); - void (*mutex_fini)(dfs_mutex mutex); /* finish and free mutex */ -}; - -#endif +/* basic types for dfslib, T10.090-T13.418; $DVS:time$ */ + +#ifndef DFSLIB_TYPES_H_INCLUDED +#define DFSLIB_TYPES_H_INCLUDED + +#if defined(_WIN32) || defined(_WIN64) +#ifndef inline +#define inline __inline +#endif +#endif + +enum dfslib_errors { + DFSLIB_ERROR_MAX = -2, + DFSLIB_NOT_REALIZED = -2, + DFSLIB_IO_ERROR = -3, + DFSLIB_CORRUPT_DATA = -4, + DFSLIB_INVALID_VOLUME = -5, + DFSLIB_INVALID_TYPE = -6, + DFSLIB_INVALID_VALUE = -7, + DFSLIB_FILE_IS_DIR = -8, + DFSLIB_FILE_IS_NOT_DIR = -9, + DFSLIB_DIR_NOT_EMPTY = -10, + DFSLIB_INVALID_NAME = -11, + DFSLIB_NAME_TOO_LONG = -12, + DFSLIB_NOT_FOUND = -13, + DFSLIB_ACCESS_DENIED = -14, + DFSLIB_READ_ONLY = -15, + DFSLIB_NO_FREE_MEMORY = -16, + DFSLIB_NO_FREE_SPACE = -17, + DFSLIB_TEMP_UNAVAILABLE = -18, + DFSLIB_TOO_MANY_LOCKED = -19, + DFSLIB_INTERNAL_ERROR = -20, + DFSLIB_ERROR_MIN = -20, +}; + +/* the structure of ino: 0 access bits + 4 nnode bits + nsector */ +#define DFSLIB_INO_NNODE_SHIFT 0 +#define DFSLIB_INO_NSECTOR_SHIFT (DFSLIB_INO_NNODE_SHIFT + 4) +#define DFSLIB_SECT_PER_BLOCK_SHIFT 6 +#define DFSLIB_SECT_PER_BLOCK (1 << DFSLIB_SECT_PER_BLOCK_SHIFT) + +typedef unsigned long long dfs64; +typedef unsigned int dfs32; +typedef unsigned short dfs16; +typedef unsigned char dfs8; + +typedef dfs32 dfs_atomic; +typedef dfs64 dfs_atomic64; +typedef void * dfs_mutex; + +/* common platform-dependent operations */ +struct dfslib_platform_op { + void * (*malloc)(unsigned long size); + void (*free)(void *mem); + void (*memcpy)(void *to, const void *from, unsigned long size); + dfs64 (*time)(void); /* current time in nanoseconds since 1.1.1970 UTC */ + void (*pause)(void); /* run another processes */ + void (*alert)(const char *mess, dfs64 arg1, dfs64 arg2); + dfs32 (*div)(dfs64 *n, dfs32 base); /* *n /= base; return *n % base */ + + dfs32 (*atomic_read)(dfs_atomic *ptr); + void (*atomic_set)(dfs_atomic *ptr, dfs32 value); + dfs32 (*atomic_inc_return)(dfs_atomic *ptr); + dfs32 (*atomic_dec_return)(dfs_atomic *ptr); + dfs32 (*atomic_cmpxchg)(dfs_atomic *ptr, dfs32 old_, dfs32 new_); + + dfs64 (*atomic64_read)(dfs_atomic64 *ptr); + void (*atomic64_set)(dfs_atomic64 *ptr, dfs64 value); + dfs64 (*atomic64_inc_return)(dfs_atomic64 *ptr); + dfs64 (*atomic64_dec_return)(dfs_atomic64 *ptr); + dfs64 (*atomic64_cmpxchg)(dfs_atomic64 *ptr, dfs64 old_, dfs64 new_); + + dfs_mutex (*mutex_init)(void); /* allocate and init mutex */ + void (*mutex_lock)(dfs_mutex mutex); + void (*mutex_unlock)(dfs_mutex mutex); + void (*mutex_fini)(dfs_mutex mutex); /* finish and free mutex */ +}; + +#endif diff --git a/dus/programs/dfstools/source/include/dfsrsa.h b/dus/programs/dfstools/source/include/dfsrsa.h index 33ecb96a..feb8d37b 100644 --- a/dus/programs/dfstools/source/include/dfsrsa.h +++ b/dus/programs/dfstools/source/include/dfsrsa.h @@ -1,50 +1,50 @@ -#ifndef DFSTOOLS_DFSRSA_H_INCLUDED -#define DFSTOOLS_DFSRSA_H_INCLUDED - -/* Определения функций для длинной арифметики и криптографии RSA, T8.505-T11.316; $DVS:time$ */ - -#ifdef __DuS__ -#define DFSRSA_EXT extern "dfstools/dfsrsa.o" -#else -#define DFSRSA_EXT extern -#endif - -#include - -#ifdef __DuS__ -typedef uint16_t dfsrsa_t; -typedef uint32_t dfsrsa_long_t; -typedef int32_t dfsrsa_slong_t; -#else -typedef uint32_t dfsrsa_t; -typedef uint64_t dfsrsa_long_t; -typedef int64_t dfsrsa_slong_t; -#endif - -// generates public and private keys of the lengh `keylen` of numbers dfsrsa_t -// `keylen` should be a multiple of 4 -// the pubkey array should be prefilled with random numbers -// the algorithm does not use any other random information -// returns -1 in case of error -DFSRSA_EXT int dfsrsa_keygen(dfsrsa_t *privkey, dfsrsa_t *pubkey, int keylen); - -// encodes/decodes the message using corresponding public/private key -// `datalen` and `keylen` are measured in dfsrsa_t numbers -// key `key` should be generated by function `dfsrsa_keygen` -// `datalen` should be a multiple of half of the `keylen` -// the highest bit should be 0 in each part of message (length `keylen`/2 of dfsrsa_t) -// the result message is placed in the same array as the original -// returns -1 in case of error -DFSRSA_EXT int dfsrsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen); - -// compares two long numbers and return -1, 0, 1 -DFSRSA_EXT int dfsrsa_cmp(dfsrsa_t *left, dfsrsa_t *right, int len); - -// adds two long numbers, carry is returned (0 or 1) -DFSRSA_EXT int dfsrsa_add(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, int len); - -DFSRSA_EXT int dfsrsa_divmod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len, dfsrsa_t *quotient); - -#undef DFSRSA_EXT - -#endif +#ifndef DFSTOOLS_DFSRSA_H_INCLUDED +#define DFSTOOLS_DFSRSA_H_INCLUDED + +/* Определения функций для длинной арифметики и криптографии RSA, T8.505-T11.316; $DVS:time$ */ + +#ifdef __DuS__ +#define DFSRSA_EXT extern "dfstools/dfsrsa.o" +#else +#define DFSRSA_EXT extern +#endif + +#include + +#ifdef __DuS__ +typedef uint16_t dfsrsa_t; +typedef uint32_t dfsrsa_long_t; +typedef int32_t dfsrsa_slong_t; +#else +typedef uint32_t dfsrsa_t; +typedef uint64_t dfsrsa_long_t; +typedef int64_t dfsrsa_slong_t; +#endif + +// generates public and private keys of the lengh `keylen` of numbers dfsrsa_t +// `keylen` should be a multiple of 4 +// the pubkey array should be prefilled with random numbers +// the algorithm does not use any other random information +// returns -1 in case of error +DFSRSA_EXT int dfsrsa_keygen(dfsrsa_t *privkey, dfsrsa_t *pubkey, int keylen); + +// encodes/decodes the message using corresponding public/private key +// `datalen` and `keylen` are measured in dfsrsa_t numbers +// key `key` should be generated by function `dfsrsa_keygen` +// `datalen` should be a multiple of half of the `keylen` +// the highest bit should be 0 in each part of message (length `keylen`/2 of dfsrsa_t) +// the result message is placed in the same array as the original +// returns -1 in case of error +DFSRSA_EXT int dfsrsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen); + +// compares two long numbers and return -1, 0, 1 +DFSRSA_EXT int dfsrsa_cmp(dfsrsa_t *left, dfsrsa_t *right, int len); + +// adds two long numbers, carry is returned (0 or 1) +DFSRSA_EXT int dfsrsa_add(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, int len); + +DFSRSA_EXT int dfsrsa_divmod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len, dfsrsa_t *quotient); + +#undef DFSRSA_EXT + +#endif diff --git a/dus/programs/dfstools/source/lib/dfsrsa.c b/dus/programs/dfstools/source/lib/dfsrsa.c index 45c8c4ca..66d7b590 100644 --- a/dus/programs/dfstools/source/lib/dfsrsa.c +++ b/dus/programs/dfstools/source/lib/dfsrsa.c @@ -1,1230 +1,1230 @@ -/* Functions for long arithmetic and RSA cryptography. */ - -#include -#include -#include -#include "../include/dfsrsa.h" - -const char - DFSRSA_TITLE[] = "DFS RSA library", - DFSRSA_VERSION[] = "T8.505-T13.012", /* $DVS:time$ */ - DFSRSA_COPYRIGHT[] = "(C) 2012-2017 Daniel Cheatoshin (cheatoshin@mailinator.com)"; - -#define USE_MILLER_RABIN -#define USE_MONTGOMERY -#define USE_KARATSUBA - -#if defined(__x86_64__) -# define USE_FAST_MULT -# define USE_FAST_MULT_FIXED -# define KARATSUBA_TRESHOLD 64 -# define TEST_MAX_BITS 4096 -#elif defined(__arm__) -# if defined(__ARM_ARCH_3__) // for D-Link DNS-320 -# define USE_FAST_MULT -# define USE_FAST_MULT_FIXED -# define KARATSUBA_TRESHOLD 64 -# define TEST_MAX_BITS 2048 -# else // for Raspberry Pi -# define KARATSUBA_TRESHOLD 32 -# define TEST_MAX_BITS 1024 -# endif -#else -# define KARATSUBA_TRESHOLD 32 -# define TEST_MAX_BITS 2048 -#endif - - - -/************* - * debugging * - *************/ - - - /* #define DFSRSA_DEBUG */ - -#define DFSRSA_DEBUG_TOP 0x01 -#define DFSRSA_DEBUG_GEN 0x02 -#define DFSRSA_DEBUG_MILLER 0x04 -#define DFSRSA_DEBUG_MONT 0x08 -#define DFSRSA_DEBUG_INV 0x10 -#define DFSRSA_DEBUG_MOD 0x20 -#define DFSRSA_DEBUG_MODLOW 0x40 -#define DFSRSA_DEBUG_KARATSUBA 0x80 - -#define DFSRSA_DEBUG_MODE (0x80) -#define DFSRSA_DEBUG_PRINT_MAX 100 - -#ifdef DFSRSA_DEBUG - -#include - -static int dfsrsa_debug(int mode, char *name, dfsrsa_t *arr, int len) -{ - static int count = 0; - if(!(mode & DFSRSA_DEBUG_MODE)) return -1; - if(count >= DFSRSA_DEBUG_PRINT_MAX) return -1; - count++; - printf("%16s = 0x", name); - while(len--) { - printf("%08X", arr[len]); - } - printf("\n"); - fflush(stdout); - return 0; -} - -#define dfsrsa_debug(mode, name, arr, len) \ - dfsrsa_debug(DFSRSA_DEBUG_##mode, name, arr, len) - -#else - -#define dfsrsa_debug(level, name, arr, len) - -#endif - - - -/********************* - * simple operations * - *********************/ - - // count of bits in number dfsrsa_t -#define DFSRSA_T_BITS (sizeof(dfsrsa_t) << 3) - -// returns the sign of a long number: 1, if < 0; 0, if >= 0 -#define dfsrsa_sign(num, len) ((num)[(len) - 1] >> (DFSRSA_T_BITS - 1)) - -// copies the long number -static void dfsrsa_copy(dfsrsa_t *to, dfsrsa_t *from, int len) -{ - memcpy(to, from, len * sizeof(dfsrsa_t)); -} - -// sets the long number to `value` -static void dfsrsa_set(dfsrsa_t *res, int len, dfsrsa_t value) -{ - if(len > 1) { - memset(res + 1, 0, (len - 1) * sizeof(dfsrsa_t)); - } - *res = value; -} - -// returns count of significant digits (the digit is the number dfsrsa_t), discarding the leading zeros -static int dfsrsa_getlen(dfsrsa_t *num, int len) -{ - num += len; - while(len-- && !*--num); - return len + 1; -} - -// compares two long numbers and return -1, 0, 1 -int dfsrsa_cmp(dfsrsa_t *left, dfsrsa_t *right, int len) -{ - left += len, right += len; - while(len-- && *--left == *--right); - if(len < 0) return 0; - else if(*left < *right) return -1; - else return 1; -} - -// adds short number to the long number, carry is discarded -static void dfsrsa_addeq(dfsrsa_t *sum, dfsrsa_t small, int len) -{ - dfsrsa_long_t res = small; - while(len-- && res) { - res += *sum, *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - } -} - -// adds two long numbers, carry is returned (0 or 1) -int dfsrsa_add(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, int len) -{ - dfsrsa_long_t res = 0; - while(len--) { - res += (dfsrsa_long_t)*add1++ + *add2++; - *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - } - return (int)res; -} - -// adds two long numbers and carry, a new carry is returned -static dfsrsa_t dfsrsa_adc(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, - dfsrsa_t carry, int len) -{ - dfsrsa_long_t res = carry; - while(len--) { - res += (dfsrsa_long_t)*add1++ + *add2++; - *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - } - return (dfsrsa_t)res; -} - -// subtracts one long number from another, carry is returned (0 or -1) -static int dfsrsa_sub(dfsrsa_t *sub, dfsrsa_t *from, dfsrsa_t *to, int len) -{ - dfsrsa_slong_t res = 0; - while(len--) { - res += (dfsrsa_long_t)*from++ - *to++; - *sub++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - } - return (int)res; -} - -// shifts a long number by 1 bit to the right, carry is writed to the highest bit; -// the lowest bit is returned -static int dfsrsa_shr1(dfsrsa_t *num, int len, int carry) -{ - int next_carry; - num += len; - while(len--) { - next_carry = *--num & 1, *num >>= 1; - *num |= (dfsrsa_t)carry << (DFSRSA_T_BITS - 1); - carry = next_carry; - } - return carry; -} - -/***************************** - * methods of multiplication * - *****************************/ - - // multiples the number `big` of the lenght `len` by the number `small` - // and adds the result to the array `sum` of length `len` + 1 - // carry is writed to place number `len` in the `sum` -static void dfsrsa_muladd(dfsrsa_t *sum, dfsrsa_t *big, dfsrsa_t small, int len) -{ - dfsrsa_long_t res = 0; - while(len--) { - res += (dfsrsa_long_t)*big++ * small + *sum; - *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - } - *sum = (dfsrsa_t)res; -} - -// multiplies the number `big` of length `len` by number `small` -// and subtracts the result from the array `sub` of length `len` -// if there is a carry, then subtracts it from the position `len` of the `sub` array -static void dfsrsa_mulsub(dfsrsa_t *sub, dfsrsa_t *big, dfsrsa_t small, int len) -{ - dfsrsa_long_t res = 0; - while(len--) { - res += *sub - (dfsrsa_long_t)*big++ * small; - *sub++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; - if(res) { - res |= (dfsrsa_long_t)0 - ((dfsrsa_long_t)1 << DFSRSA_T_BITS); - } - } - if(res) *sub += (dfsrsa_t)res; -} - -// multiplies two long numbers, the result is written into an array with twice bigger length -static void dfsrsa_mul(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) -{ - int i = len; - dfsrsa_set(prod, len, 0); - while(i--) { - dfsrsa_muladd(prod++, mul1, *mul2++, len); - } -} - -#if defined(USE_FAST_MULT) && defined(__GNUC__) && defined(__x86_64__) - -#define FASTMUL2_X86_64 \ - "lodsq\n" \ - "mulq %%r8\n" \ - "addq (%%rdi), %%rax\n" \ - "adcq $0x0, %%rdx\n" \ - "addq %%r9, %%rax\n" \ - "adcq $0x0, %%rdx\n" \ - "stosq\n" \ - "movq %%rdx, %%r9\n" - -#ifdef USE_FAST_MULT_FIXED - -#define FASTMUL4_X86_64 FASTMUL2_X86_64 FASTMUL2_X86_64 -#define FASTMUL8_X86_64 FASTMUL4_X86_64 FASTMUL4_X86_64 -#define FASTMUL16_X86_64 FASTMUL8_X86_64 FASTMUL8_X86_64 -#define FASTMUL32_X86_64 FASTMUL16_X86_64 FASTMUL16_X86_64 -#define FASTMUL64_X86_64 FASTMUL32_X86_64 FASTMUL32_X86_64 - -static void dfsrsa_fastmul16_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "xorq %%rax, %%rax\n" - "movl $0x08, %%ecx\n" - "rep stosq\n" - "movq %%rdx, %%rbx\n" - "subq $0x40, %%rdi\n" - "movl $0x08, %%ecx\n" - "1: movq (%%rbx), %%r8\n" - "xor %%r9, %%r9\n" - FASTMUL16_X86_64 - "movq %%r9, (%%rdi)\n" - "subq $0x40, %%rsi\n" - "subq $0x38, %%rdi\n" - "addq $0x08, %%rbx\n" - "decl %%ecx\n" - "jnz 1b\n" - : "+D"(prod), "+S"(mul1), "+d"(mul2) : - : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" - ); -} - -static void dfsrsa_fastmul32_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "xorq %%rax, %%rax\n" - "movl $0x10, %%ecx\n" - "rep stosq\n" - "movq %%rdx, %%rbx\n" - "subq $0x80, %%rdi\n" - "movl $0x10, %%ecx\n" - "1: movq (%%rbx), %%r8\n" - "xor %%r9, %%r9\n" - FASTMUL32_X86_64 - "movq %%r9, (%%rdi)\n" - "subq $0x80, %%rsi\n" - "subq $0x78, %%rdi\n" - "addq $0x08, %%rbx\n" - "decl %%ecx\n" - "jnz 1b\n" - : "+D"(prod), "+S"(mul1), "+d"(mul2) : - : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" - ); -} - -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 -static void dfsrsa_fastmul64_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "xorq %%rax, %%rax\n" - "movl $0x20, %%ecx\n" - "rep stosq\n" - "movq %%rdx, %%rbx\n" - "subq $0x100, %%rdi\n" - "movl $0x20, %%ecx\n" - "1: movq (%%rbx), %%r8\n" - "xor %%r9, %%r9\n" - FASTMUL64_X86_64 - "movq %%r9, (%%rdi)\n" - "subq $0x100, %%rsi\n" - "subq $0xF8, %%rdi\n" - "addq $0x08, %%rbx\n" - "decl %%ecx\n" - "jnz 1b\n" - : "+D"(prod), "+S"(mul1), "+d"(mul2) : - : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" - ); -} -#endif - -#endif - -static void dfsrsa_fastmul_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) -{ -#ifdef USE_FAST_MULT_FIXED -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 - if(len == 64) { dfsrsa_fastmul64_x86_64(prod, mul1, mul2); return; } -#endif -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 32 - if(len == 32) { dfsrsa_fastmul32_x86_64(prod, mul1, mul2); return; } -#endif -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 16 - if(len == 16) { dfsrsa_fastmul16_x86_64(prod, mul1, mul2); return; } -#endif -#endif - if(len & 1) { dfsrsa_mul(prod, mul1, mul2, len); return; } - asm volatile( - "shrl $1, %%ecx\n" - "xorq %%rax, %%rax\n" - "movq %%rcx, %%r10\n" - "movq %%rcx, %%r11\n" - "leaq (%%rax,%%rcx,8), %%r12\n" - "rep stosq\n" - "movq %%r10, %%rcx\n" - "subq %%r12, %%rdi\n" - "movq %%rdx, %%rbx\n" - "1: movq (%%rbx), %%r8\n" - "xor %%r9, %%r9\n" - "2: \n" - FASTMUL2_X86_64 - "loop 2b\n" - "movq %%r9, (%%rdi)\n" - "movq %%r11, %%rcx\n" - "subq %%r12, %%rdi\n" - "subq %%r12, %%rsi\n" - "addq $0x8, %%rbx\n" - "addq $0x8, %%rdi\n" - "decq %%r10\n" - "jnz 1b\n" - : "+D"(prod), "+S"(mul1), "+d"(mul2), "+c"(len) : - : "memory", "%rax", "%rbx", "%r8", "%r9", "%r10", "%r11", "%r12", "cc" - ); -} - -#define dfsrsa_mul dfsrsa_fastmul_x86_64 -#endif - -#if defined(USE_FAST_MULT) && defined(__GNUC__) && defined(__arm__) - -#if defined(USE_FAST_MULT_FIXED) - -#if defined(__ARCH_ARM_6__) || defined(__ARCH_ARM_7__) -#define LDRD( r1,r2,raddr) "ldrd " #r1 ", [" #raddr "]\n" -#define LDRDI(r1,r2,raddr) "ldrd " #r1 ", [" #raddr "], #8\n" -#define STRD( r1,r2,raddr) "strd " #r1 ", [" #raddr "]\n" -#define STRDI(r1,r2,raddr) "strd " #r1 ", [" #raddr "], #8\n" -#else -#define LDRD( r1,r2,raddr) "ldmia " #raddr ", {" #r1 ", " #r2 "}\n" -#define LDRDI(r1,r2,raddr) "ldmia " #raddr "!, {" #r1 ", " #r2 "}\n" -#define STRD( r1,r2,raddr) "stmia " #raddr ", {" #r1 ", " #r2 "}\n" -#define STRDI(r1,r2,raddr) "stmia " #raddr "!, {" #r1 ", " #r2 "}\n" -#endif - -#define SETMEM2_ARM STRDI(r6, r7, r4) - -#define SETMEM4_ARM SETMEM2_ARM SETMEM2_ARM -#define SETMEM8_ARM SETMEM4_ARM SETMEM4_ARM -#define SETMEM16_ARM SETMEM8_ARM SETMEM8_ARM -#define SETMEM32_ARM SETMEM16_ARM SETMEM16_ARM -#define SETMEM64_ARM SETMEM32_ARM SETMEM32_ARM - -#define FASTMUL2_ARM \ - "mov r12, #0\n" \ - LDRDI (r8, r9, r2) \ - "mov r10, #0\n" \ - "umlal r6, r12, r8, r4\n" \ - "umlal r7, r10, r9, r4\n" \ - "mov r14, #0\n" \ - "mov r11, #0\n" \ - "umlal r12, r14, r8, r5\n" \ - "umlal r10, r11, r9, r5\n" \ - "adds r7, r7, r12\n" \ - LDRD (r8, r9, r0) \ - "adcs r10, r10, r14\n" \ - "adc r11, r11, #0\n" \ - "adds r8, r6, r8\n" \ - "adcs r9, r7, r9\n" \ - "adcs r6, r10, #0\n" \ - STRDI (r8, r9, r0) \ - "adc r7, r11, #0\n" - -#define FASTMUL4_ARM FASTMUL2_ARM FASTMUL2_ARM -#define FASTMUL8_ARM FASTMUL4_ARM FASTMUL4_ARM -#define FASTMUL16_ARM FASTMUL8_ARM FASTMUL8_ARM -#define FASTMUL32_ARM FASTMUL16_ARM FASTMUL16_ARM -#define FASTMUL64_ARM FASTMUL32_ARM FASTMUL32_ARM - -static void dfsrsa_fastmul16_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "stmfd sp!, {r0-r12, r14}\n" - "mov r0, %0\n" - "mov r1, %1\n" - "mov r2, %2\n" - "mov r6, #0\n" - "mov r7, #0\n" - "mov r4, r0\n" - SETMEM16_ARM - "mov r3, #8\n" - "1:\n" - LDRDI(r4, r5, r1) - "mov r6, #0\n" - "mov r7, #0\n" - FASTMUL16_ARM - STRDI(r6, r7, r0) - "sub r0, r0, #64\n" - "sub r2, r2, #64\n" - "subs r3, r3, #1\n" - "bne 1b\n" - "ldmfd sp!, {r0-r12, r14}\n" - : : "r"(prod), "r"(mul1), "r"(mul2) - : "memory", "cc" - ); -} - -static void dfsrsa_fastmul32_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "stmfd sp!, {r0-r12, r14}\n" - "mov r0, %0\n" - "mov r1, %1\n" - "mov r2, %2\n" - "mov r6, #0\n" - "mov r7, #0\n" - "mov r4, r0\n" - SETMEM32_ARM - "mov r3, #16\n" - "1:\n" - LDRDI(r4, r5, r1) - "mov r6, #0\n" - "mov r7, #0\n" - FASTMUL32_ARM - STRDI(r6, r7, r0) - "sub r0, r0, #128\n" - "sub r2, r2, #128\n" - "subs r3, r3, #1\n" - "bne 1b\n" - "ldmfd sp!, {r0-r12, r14}\n" - : : "r"(prod), "r"(mul1), "r"(mul2) - : "memory", "cc" - ); -} - -static void dfsrsa_fastmul64_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) -{ - asm volatile( - "stmfd sp!, {r0-r12, r14}\n" - "mov r0, %0\n" - "mov r1, %1\n" - "mov r2, %2\n" - "mov r6, #0\n" - "mov r7, #0\n" - "mov r4, r0\n" - SETMEM64_ARM - "mov r3, #32\n" - "1:\n" - LDRDI(r4, r5, r1) - "mov r6, #0\n" - "mov r7, #0\n" - FASTMUL64_ARM - STRDI(r6, r7, r0) - "sub r0, r0, #256\n" - "sub r2, r2, #256\n" - "subs r3, r3, #1\n" - "bne 1b\n" - "ldmfd sp!, {r0-r12, r14}\n" - : : "r"(prod), "r"(mul1), "r"(mul2) - : "memory", "cc" - ); -} - -#endif - -static void dfsrsa_fastmul_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) -{ -#ifdef USE_FAST_MULT_FIXED -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 - if(len == 64) { dfsrsa_fastmul64_arm(prod, mul1, mul2); return; } -#endif -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 32 - if(len == 32) { dfsrsa_fastmul32_arm(prod, mul1, mul2); return; } -#endif -#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 16 - if(len == 16) { dfsrsa_fastmul16_arm(prod, mul1, mul2); return; } -#endif -#endif - asm volatile( - "stmfd sp!, {r0-r9}\n" - "mov r0, %0\n" - "mov r1, %1\n" - "mov r2, %2\n" - "mov r3, %3\n" - "mov r4, #0\n" - "mov r5, r0\n" - "mov r6, r3\n" - "1: str r4, [r5], #4\n" - "subs r6, r6, #1\n" - "bne 1b\n" - "mov r5, r3\n" - "2: mov r6, r3\n" - "ldr r4, [r1], #4\n" - "mov r7, #0\n" - "3: ldr r8, [r2], #4\n" - "mov r9, #0\n" - "umlal r7, r9, r4, r8\n" - "ldr r8, [r0]\n" - "adds r7, r7, r8\n" - "adc r9, r9, #0\n" - "str r7, [r0], #4\n" - "mov r7, r9\n" - "subs r6, r6, #1\n" - "bne 3b\n" - "str r7, [r0], #4\n" - "sub r0, r0, r3, LSL #2\n" - "sub r2, r2, r3, LSL #2\n" - "subs r5, r5, #1\n" - "bne 2b\n" - "ldmfd sp!, {r0-r9}\n" - : : "r"(prod), "r"(mul1), "r"(mul2), "r"(len) - : "memory", "cc" - ); -} - -#define dfsrsa_mul dfsrsa_fastmul_arm -#endif - -#ifdef USE_KARATSUBA - -// Karatsuba's method of multiplication of numbers, `work` - auxiliary array of size 2 * len -static void dfsrsa_karatsuba_mul(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, - int len, dfsrsa_t *work) -{ -#ifdef DFSRSA_DEBUG - dfsrsa_t *m1 = mul1, *m2 = mul2, *p = prod, *w = work; int l = len; -#endif - int r, llen; dfsrsa_long_t rem; - if((len & 1) || len < KARATSUBA_TRESHOLD) { - dfsrsa_mul(prod, mul1, mul2, len); - return; - } - r = 1, llen = len, len >>= 1; - if(dfsrsa_cmp(mul1 + len, mul1, len) >= 0) { - dfsrsa_sub(work, mul1 + len, mul1, len); - } else { - dfsrsa_sub(work, mul1, mul1 + len, len), r = -r; - } - if(dfsrsa_cmp(mul2 + len, mul2, len) >= 0) { - dfsrsa_sub(work + len, mul2 + len, mul2, len); - } else { - dfsrsa_sub(work + len, mul2, mul2 + len, len), r = -r; - } - dfsrsa_karatsuba_mul(work + llen, work, work + len, len, prod); - dfsrsa_karatsuba_mul(prod, mul1, mul2, len, work); - dfsrsa_karatsuba_mul(prod + llen, mul1 + len, mul2 + len, len, work); - dfsrsa_copy(work, prod, llen); - mul1 = prod + llen, mul2 = work, work += llen, prod += len, rem = 0; - if(r > 0) { - while(llen--) { - rem += (dfsrsa_long_t)*prod + (dfsrsa_long_t)*mul1++ - + (dfsrsa_long_t)*mul2++ - (dfsrsa_long_t)*work++; - *prod++ = (dfsrsa_t)rem; - rem = (dfsrsa_slong_t)rem >> DFSRSA_T_BITS; - } - } else { - while(llen--) { - rem += (dfsrsa_long_t)*prod + (dfsrsa_long_t)*mul1++ - + (dfsrsa_long_t)*mul2++ + (dfsrsa_long_t)*work++; - *prod++ = (dfsrsa_t)rem; - rem >>= DFSRSA_T_BITS; - } - } - while(rem) { - rem += *prod, *prod++ = (dfsrsa_t)rem, rem >>= DFSRSA_T_BITS; - } -#ifdef DFSRSA_DEBUG - dfsrsa_mul(w, m1, m2, l); - if(dfsrsa_cmp(p, w, l << 1)) { - dfsrsa_debug(KARATSUBA, "mul1", m1, l); - dfsrsa_debug(KARATSUBA, "mul2", m2, l); - dfsrsa_debug(KARATSUBA, "prod0", w, l << 1); - dfsrsa_debug(KARATSUBA, "prod", p, l << 1); - } -#endif -} - -#ifdef dfsrsa_mul -#undef dfsrsa_mul -#endif -#define dfsrsa_mul(prod,mul1,mul2,len) dfsrsa_karatsuba_mul(prod,mul1,mul2,len,kwork) - -#endif - - -/***************************** - * multiplicative operations * - *****************************/ - - - // calculates the rest of division the number `nul` of length `len` by a short number `mod` -static dfsrsa_t dfsrsa_modsmall(dfsrsa_t *div, int len, dfsrsa_t mod) -{ - dfsrsa_long_t rem = 0; - if(!mod) return 0; - while(len) { - rem <<= DFSRSA_T_BITS, rem |= div[--len], rem %= mod; - } - return rem; -} - -// calculates the rest of division of number `mod` of length `mlen` by number `div` of length `len` -// result is places to array `mod`, returns -1 in case of division by 0 -static int dfsrsa_mod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len) -{ - dfsrsa_long_t div0, div2; - dfsrsa_debug(MOD, "divisor", mod, mlen); - dfsrsa_debug(MOD, "dividend", div, len); - len = dfsrsa_getlen(div, len); - if(!len) return -1; - dfsrsa_long_t div1 = div[len - 1]; - if(len > 1) { - div2 = (div1 << DFSRSA_T_BITS) | div[len - 2]; - ++div1; - if(len > 2) ++div2; - } else div2 = 0; - for(;;) { - mlen = dfsrsa_getlen(mod, mlen); - dfsrsa_debug(MODLOW, "work remainder", mod, mlen); - int offset = mlen - len; - if(offset < 0) break; - int res = dfsrsa_cmp(mod + offset, div, len); - dfsrsa_long_t mod0 = (dfsrsa_long_t)mod[mlen - 1]; - if(res < 0) { - if(!offset--) break; - mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; - div0 = div1; - } else if(len > 1 && div2) { - mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; - div0 = div2; - } else { - div0 = div1; - } - dfsrsa_debug(MODLOW, "mod0", (dfsrsa_t*)&mod0, 2); - dfsrsa_debug(MODLOW, "div0", (dfsrsa_t*)&div0, 2); - mod0 /= div0; - if(!mod0) mod0 = 1; - dfsrsa_debug(MODLOW, "mod0/div0", (dfsrsa_t*)&mod0, 2); - dfsrsa_mulsub(mod + offset, div, (dfsrsa_t)mod0, len); - } - dfsrsa_debug(MOD, "remainder", mod, mlen); - return 0; -} - -// calculates the quotient and rest of division of number `mod` of length `mlen` by number `div` of length `len` -// the quotient is placed to array `quotient` of length `mlen`, the rest - in array `mod` -// return -1 in case of division by 0 -int dfsrsa_divmod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len, - dfsrsa_t *quotient) -{ - int res, offset; dfsrsa_long_t mod0, div0, div1, div2; - dfsrsa_debug(MOD, "divisor", mod, mlen); - dfsrsa_debug(MOD, "dividend", div, len); - len = dfsrsa_getlen(div, len); - if(!len) return -1; - dfsrsa_set(quotient, mlen, 0); - div1 = div[len - 1]; - if(len > 1) { - div2 = (div1 << DFSRSA_T_BITS) | div[len - 2]; - ++div1; - if(len > 2) ++div2; - } else div2 = 0; - for(;;) { - mlen = dfsrsa_getlen(mod, mlen); - dfsrsa_debug(MODLOW, "work remainder", mod, mlen); - offset = mlen - len; - if(offset < 0) break; - res = dfsrsa_cmp(mod + offset, div, len); - mod0 = (dfsrsa_long_t)mod[mlen - 1]; - if(res < 0) { - if(!offset--) break; - mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; - div0 = div1; - } else if(len > 1 && div2) { - mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; - div0 = div2; - } else { - div0 = div1; - } - dfsrsa_debug(MODLOW, "mod0", (dfsrsa_t*)&mod0, 2); - dfsrsa_debug(MODLOW, "div0", (dfsrsa_t*)&div0, 2); - mod0 /= div0; - if(!mod0) mod0 = 1; - dfsrsa_debug(MODLOW, "mod0/div0", (dfsrsa_t*)&mod0, 2); - dfsrsa_mulsub(mod + offset, div, (dfsrsa_t)mod0, len); - dfsrsa_addeq(quotient + offset, (dfsrsa_t)mod0, mlen - offset); - } - dfsrsa_debug(MOD, "quotient", quotient, mlen); - dfsrsa_debug(MOD, "remainder", mod, mlen); - return 0; -} - -// raises to the power by module: res = base^exp (mod mod), all numbers has length `len` -// work - auxiliary array of length 6*len, where are writed the last two results of multiplication -// each has 2*len -static void dfsrsa_powmod(dfsrsa_t *res, dfsrsa_t *base, dfsrsa_t *exp, dfsrsa_t *mod, - dfsrsa_t *work, int len) -{ -#define kwork (work + 4 * len) - dfsrsa_t bits; - int off = 0; - int off1 = len << 1; - int flag = 0; - int i; - dfsrsa_set(work, len, 1); - int explen = dfsrsa_getlen(exp, len); - while(explen--) { - bits = exp[explen], i = DFSRSA_T_BITS; - while(i--) { - if(flag) { - off = off1 - off; - dfsrsa_mul(work + off, work + off1 - off, work + off1 - off, len); - dfsrsa_mod(work + off, len << 1, mod, len); - } - if((bits >> i) & 1) { - off = off1 - off; - dfsrsa_mul(work + off, work + off1 - off, base, len); - dfsrsa_mod(work + off, len << 1, mod, len); - flag = 1; - } - } - } - dfsrsa_copy(res, work + off, len); -#undef kwork -} - -// finds the inverse number `inv` for given `num` by module `mod`, if not return -1 -// The version of Euclid's extended binary algorithm is used -// it is assumed that num = 2k + 1, mod = 2^n (2m + 1), n <= 2 -// work - working array of length 4*len -static int dfsrsa_inverse(dfsrsa_t *inv, dfsrsa_t *num, dfsrsa_t *mod, - dfsrsa_t *work, int len) -{ - dfsrsa_t *pn = work, *px = inv, *qn = work + len, *qx = work + 2 * len, - *mod4 = work + 3 * len, mask = 0; - int carry; - dfsrsa_copy(pn, num, len), dfsrsa_set(px, len, 1); - dfsrsa_copy(mod4, mod, len); - while(!(*mod4 & 1)) dfsrsa_shr1(mod4, len, 0), mask <<= 1, mask |= 1; - dfsrsa_copy(qn, mod4, len), dfsrsa_set(qx, len, 0); - dfsrsa_debug(INV, "inv mod/4", mod4, len); - for(;;) { - dfsrsa_debug(INV, "inv pn", pn, len); - dfsrsa_debug(INV, "inv px", px, len); - dfsrsa_debug(INV, "inv qn", qn, len); - dfsrsa_debug(INV, "inv qx", qx, len); - while(!(*pn & 1)) { - carry = 0; - dfsrsa_shr1(pn, len, 0); - if(*px & 1) carry = dfsrsa_add(px, px, mod4, len); - dfsrsa_shr1(px, len, carry); - } - while(!(*qn & 1)) { - carry = 0; - dfsrsa_shr1(qn, len, 0); - if(*qx & 1) carry = dfsrsa_add(qx, qx, mod4, len); - dfsrsa_shr1(qx, len, carry); - } - dfsrsa_debug(INV, "inv pn", pn, len); - dfsrsa_debug(INV, "inv px", px, len); - dfsrsa_debug(INV, "inv qn", qn, len); - dfsrsa_debug(INV, "inv qx", qx, len); - switch(dfsrsa_cmp(pn, qn, len)) { - case 0: goto fin; - case 1: - dfsrsa_sub(pn, pn, qn, len); - if(dfsrsa_sub(px, px, qx, len)) - dfsrsa_add(px, px, mod4, len); - break; - case -1: - dfsrsa_sub(qn, qn, pn, len); - if(dfsrsa_sub(qx, qx, px, len)) - dfsrsa_add(qx, qx, mod4, len); - break; - } - } -fin: - dfsrsa_set(qn, len, 1); - if(dfsrsa_cmp(pn, qn, len)) return -1; - dfsrsa_debug(INV, "inv mod/4", inv, len); - while((*num ^ *inv) & mask) dfsrsa_add(inv, inv, mod4, len); - dfsrsa_debug(INV, "inv result", inv, len); - return 0; -} - - -/********************* - * Montgomery method * - *********************/ - - -// initializes array of data `madata` of length 6*len for Montgomery method -// by specified module `mod` of length `len` -// uses auxiliary array `work` of length 4*len -// returns -1 in case of error -static int dfsrsa_montgomery_init(dfsrsa_t *mod, dfsrsa_t *mdata, dfsrsa_t *work, - int len) -{ - dfsrsa_debug(MONT, "montgomery N", mod, len); - dfsrsa_set(mdata + 2 * len, len, 0); - dfsrsa_sub(mdata, mdata + 2 * len, mod, len); - //dfsrsa_mod(mdata, len, mod, len); - dfsrsa_debug(MONT, "montgomery R - N", mdata, len); - if(dfsrsa_inverse(mdata + 3 * len, mdata, mod, work, len)) return -1; - dfsrsa_debug(MONT, "montgomery R^-1", mdata + 3 * len, len); - if(dfsrsa_divmod(mdata + 2 * len, 2 * len, mod, len, mdata)) return -1; - dfsrsa_debug(MONT, "montgomery k", mdata, len); - return 0; -} - -// reduces the diven number `num` for usage in for Montgomery method -// num = (num << R) mod mod, num and mod have length `len`, R = len * 8 * sizeof(dfsrsa_t) -// mdata - array, initialized by function dfsrsa_montgomery_init -// returns -1 in case of error -static int dfsrsa_montgomery_reduce(dfsrsa_t *num, dfsrsa_t *mod, dfsrsa_t *mdata, - int len) -{ - dfsrsa_debug(MONT, "montgomery n", num, len); - dfsrsa_set(mdata + 2 * len, len, 0); - dfsrsa_copy(mdata + 3 * len, num, len); - if(dfsrsa_mod(mdata + 2 * len, 2 * len, mod, len)) return -1; - dfsrsa_copy(num, mdata + 2 * len, len); - dfsrsa_debug(MONT, "montgomery nR", num, len); - return 0; -} - -// step of Montgomery method: converts the given number `num` by module `mod` dividing by R -// num has a length 2 * len, mod - len, result `num` has length `len` -// `mdata` - array initialized by function dfsrsa_montgomery_init -static void dfsrsa_montgomery_mod(dfsrsa_t *num, dfsrsa_t *mod, dfsrsa_t *mdata, int len) -{ -#define kwork (mdata + 4 * len) - dfsrsa_debug(MONT, "montgomery n", num, 2 * len); - if(dfsrsa_getlen(num, len)) { - dfsrsa_mul(mdata + len, num, mdata, len); - dfsrsa_mul(mdata + 2 * len, mdata + len, mod, len); - if(dfsrsa_adc(num, num + len, mdata + 3 * len, 1, len) - || dfsrsa_cmp(num, mod, len) >= 0) { - dfsrsa_sub(num, num, mod, len); - } - } else { - dfsrsa_copy(num, num + len, len); - if(dfsrsa_cmp(num, mod, len) >= 0) { - dfsrsa_sub(num, num, mod, len); - } - } - dfsrsa_debug(MONT, "montgomery n/R", num, len); -#undef kwork -} - -// raises to the power by module using Montgomery method -// res = base^exp (mod mod), all numbers have length `len` -// work - auxiliary array of length 12 * len, -// two last results of multiplication (each of length 2*len) are written to the beginning of array `work` -static void dfsrsa_montgomery_powmod(dfsrsa_t *res, dfsrsa_t *base, dfsrsa_t *exp, - dfsrsa_t *mod, dfsrsa_t *work, int len) -{ -#define kwork (work + 8 * len) - dfsrsa_t bits, *mdata = work + 4 * len, *mbase = work + 10 * len; - int off = 0; - int off1 = len << 1; - int flag = 0; - int i; - if(dfsrsa_montgomery_init(mod, mdata, work, len)) goto powmod; - dfsrsa_set(work, len, 1); - if(dfsrsa_montgomery_reduce(work, mod, mdata, len)) goto powmod; - dfsrsa_copy(mbase, base, len); - if(dfsrsa_montgomery_reduce(mbase, mod, mdata, len)) goto powmod; - int explen = dfsrsa_getlen(exp, len); - while(explen--) { - bits = exp[explen], i = DFSRSA_T_BITS; - while(i--) { - if(flag) { - off = off1 - off; - dfsrsa_mul(work + off, work + off1 - off, work + off1 - off, len); - dfsrsa_montgomery_mod(work + off, mod, mdata, len); - } - if((bits >> i) & 1) { - off = off1 - off; - dfsrsa_mul(work + off, work + off1 - off, mbase, len); - dfsrsa_montgomery_mod(work + off, mod, mdata, len); - flag = 1; - } - } - } - dfsrsa_set(work + len, len, 0); - dfsrsa_montgomery_mod(work, mod, mdata, len); - dfsrsa_set(work + off1 + len, len, 0); - dfsrsa_montgomery_mod(work + off1, mod, mdata, len); - dfsrsa_copy(res, work + off, len); - return; -powmod: perror("Montgomery_powmod failed! Using std powmod..."); - dfsrsa_powmod(res, base, exp, mod, work, len); -#undef kwork -} - -#ifdef USE_MONTGOMERY -#define dfsrsa_powmod dfsrsa_montgomery_powmod -#endif - - - -/****************************** - * number-theoretic functions * - ******************************/ - - -// simple simplicity test for small numbers -static int dfsrsa_isprime0(dfsrsa_t n) -{ - dfsrsa_t d; - if(n < 32) return (0xA08A28AC >> n) & 1; - if(!(n & 1)) return 0; - for(d = 3; d * d <= n; d += 2) { - if(!(n % d)) return 0; - } - return 1; -} - -// a simplicity test based on deterministic Miller algorithm -// (under the assumption hypothesis of Riemann) -// works only for numbers of the form 4k + 3 -// work - working array of length 16*len -// algorithm: for each simple a = 2, ..., lim it is verified that: -// a ^ (n - 1) = 1 (mod n) -// and -// a ^ ((n-1)/2) = 1 or -1 (mod n) -// where -// lim = (log_2 (n)) ^ 2 -// (by the result of Eric Bach 1985 it is enought to check up to 2 ln^2(n), -// and it is about 0.96 of out `lim` which is more convenient to calculate) -static int dfsrsa_isprime(dfsrsa_t *n, dfsrsa_t *work, int len) -{ - dfsrsa_t *work2, *res, *a, *nm1, *o, lim, d, i; - dfsrsa_debug(MILLER, "miller n", n, len); - len = dfsrsa_getlen(n, len); - lim = (dfsrsa_t)len * DFSRSA_T_BITS; - for(i = 0, d = 3; i < lim; d += 2) { - if(len <= 1 && d * d > *n) return 1; - if(!dfsrsa_isprime0(d)) continue; - if(!dfsrsa_modsmall(n, len, d)) return 0; - ++i; - } - work2 = work + 2 * len, res = work + 12 * len, a = res + len, - nm1 = a + len, o = nm1 + len; - dfsrsa_set(o, len, 1); dfsrsa_set(a, len, 0); - dfsrsa_copy(nm1, n, len), --*nm1; - dfsrsa_debug(MILLER, "miller n-1", nm1, len); -#ifndef USE_MILLER_RABIN - lim *= lim; -#endif - if(len <= 1 && lim > *n) lim = *n; -#ifdef USE_MILLER_RABIN - for(i = 0, d = 2; i < lim; ++d, d |= 1) -#else - for(d = 2; d < lim; ++d, d |= 1) -#endif - if(dfsrsa_isprime0(d)) { - *a = d; -#ifdef USE_MILLER_RABIN - ++i; -#endif - dfsrsa_debug(MILLER, "miller a", a, len); - dfsrsa_powmod(res, a, nm1, n, work, len); - dfsrsa_debug(MILLER, "miller a^(n-1)", res, len); - dfsrsa_debug(MILLER, "miller work", work, len); - dfsrsa_debug(MILLER, "miller work2", work2, len); - - // it is assumed here that last two result of raising in power - // are contained in `work` and `work2`, no matter in what order - // it will be a ^ ((n-1) / 2) and a ^ (n-1) - if((dfsrsa_cmp(work, o, len) && dfsrsa_cmp(work, nm1, len)) - || (dfsrsa_cmp(work2, o, len) && dfsrsa_cmp(work2, nm1, len))) - return 0; - } - return 1; -} - -// generate prime number with given length based on random information in array n -// work - working array of length 16*len -static void dfsrsa_genprime(dfsrsa_t *n, dfsrsa_t *work, int len) -{ - dfsrsa_debug(GEN, "genprime random", n, len); - *n |= 3, n[len - 1] |= 3 << (DFSRSA_T_BITS - 2); - dfsrsa_debug(GEN, "genprime before", n, len); - while(!dfsrsa_isprime(n, work, len)) { - dfsrsa_addeq(n, 4, len); - } - dfsrsa_debug(GEN, "genprime result", n, len); -} - -// generats mutually-inverse numbers `pubkey` and `privkey` by given module `mod` of the form 8k+4 -// at the entrance `pubkey` is filled with random data, work - a working array of length 4*len -static void dfsrsa_geninv(dfsrsa_t *privkey, dfsrsa_t *pubkey, dfsrsa_t *mod, - dfsrsa_t *work, int len) -{ - dfsrsa_debug(GEN, "e random", pubkey, len); - dfsrsa_mod(pubkey, len, mod, len); - dfsrsa_debug(GEN, "e mod", pubkey, len); - *pubkey |= 1; - dfsrsa_debug(GEN, "e before", pubkey, len); - while(dfsrsa_inverse(privkey, pubkey, mod, work, len)) { - dfsrsa_addeq(pubkey, 2, len); - } - dfsrsa_debug(GEN, "e result", pubkey, len); - dfsrsa_debug(GEN, "d result", privkey, len); -} - - -/****************** - * main functions * - ******************/ - - -// allocates memory for number with specified length -static dfsrsa_t *dfsrsa_alloc(int len) -{ - return (dfsrsa_t *)malloc(len * sizeof(dfsrsa_t)); -} - -// frees number -static void dfsrsa_free(dfsrsa_t *num) -{ - free(num); -} - -// encodes/decodes the message using corresponding public/private key -// `datalen` and `keylen` are measured in dfsrsa_t numbers -// key `key` should be generated by function `dfsrsa_keygen` -// `datalen` should be a multiple of half of the `keylen` -// the highest bit should be 0 in each part of message (length `keylen`/2 of dfsrsa_t) -// the result message is placed in the same array as the original -// returns -1 in case of error -int dfsrsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen) -{ - int len = keylen / 2, i; - dfsrsa_t *work, *mod = key + len; - if(keylen <= 0 || (keylen & 1) || datalen < 0 || datalen % len) return -1; - datalen /= len; - for(i = 0; i < datalen; ++i) { - if(dfsrsa_cmp(data + i * len, mod, len) >= 0) return -1; - } - work = dfsrsa_alloc(len << 4); - if(!work) return -1; - for(i = 0; i < datalen; ++i, data += len) { - dfsrsa_powmod(data, data, key, mod, work, len); - } - dfsrsa_free(work); - return 0; -} - -// generates public and private keys of the lengh `keylen` of numbers dfsrsa_t -// `keylen` should be a multiple of 4 -// the pubkey array should be prefilled with random numbers -// the algorithm does not use any other random information -// returns -1 in case of error -int dfsrsa_keygen(dfsrsa_t *privkey, dfsrsa_t *pubkey, int keylen) -{ -#define kwork work - int len = keylen >> 2; - dfsrsa_t *work, *p = pubkey + len * 2, *q = pubkey + len * 3, - *n = privkey + len * 2, *phin = p, *phin0 = privkey; - if(keylen <= 0 || (keylen & 3)) return -1; - if((dfsrsa_t)len * DFSRSA_T_BITS > (dfsrsa_t)1 << (DFSRSA_T_BITS >> 1)) - return -1; - work = dfsrsa_alloc(len << 4); - if(!work) return -1; - dfsrsa_genprime(p, work, len); - dfsrsa_genprime(q, work, len); - dfsrsa_mul(n, p, q, len); - dfsrsa_debug(GEN, "pq", n, len << 1); - --*p, --*q; - dfsrsa_mul(phin0, p, q, len); - len <<= 1; - dfsrsa_copy(phin, phin0, len); - dfsrsa_debug(GEN, "(p-1)(q-1)", phin, len); - dfsrsa_geninv(privkey, pubkey, phin, work, len); - dfsrsa_copy(phin, n, len); - dfsrsa_free(work); - return 0; -#undef kwork -} - - - -/*********** - * testing * - ***********/ - -#if !defined(DFSTOOLS) && !defined(__DuS__) && !defined(QDNET) -#define DFSRSA_TEST -#endif - -#ifdef DFSRSA_TEST - -#include -#include -#include -#include "../dfslib/dfslib_random.h" - -static void dfsrsa_fillrand(dfsrsa_t *arr, int len) -{ - dfslib_random_fill(arr, len * (DFSRSA_T_BITS >> 3), 0, 0); -} - -#define MINLEN 4 -#define MAXLEN (TEST_MAX_BITS >> 4) -#define MAXDATALEN (TEST_MAX_BITS >> 3) -#define STARTLEN 4 -#define ENDLEN 4 - -int work(int keylen, int datalen) -{ - dfsrsa_t pubkey[MAXLEN], privkey[MAXLEN], data[MAXDATALEN], data0[MAXDATALEN]; - int i; - if(keylen > MAXLEN) return -1; - if(datalen > MAXDATALEN) return -2; - - /* генерация ключей */ - dfsrsa_fillrand(pubkey, keylen); - dfsrsa_debug(TOP, "pubkey random", pubkey, keylen); - dfsrsa_set(privkey, keylen, 0); - if(dfsrsa_keygen(privkey, pubkey, keylen)) return -3; - dfsrsa_debug(TOP, "pubkey", pubkey, keylen); - dfsrsa_debug(TOP, "privkey", privkey, keylen); - - /* генерация данных, старший бит в каждой порции данных должен быть 0 */ - dfsrsa_fillrand(data0, datalen); - for(i = 1; i <= datalen / (keylen / 2); ++i) - data0[i * keylen / 2 - 1] &= ((dfsrsa_t)1 << (DFSRSA_T_BITS - 1)) - 1; - dfsrsa_copy(data, data0, datalen); - dfsrsa_debug(TOP, "data", data, datalen); - - /* кодирование открытым ключом, декодирование закрытым */ - if(dfsrsa_crypt(data, datalen, pubkey, keylen)) return -4; - dfsrsa_debug(TOP, "data+pub", data, datalen); - if(!dfsrsa_cmp(data, data0, datalen)) return -5; - if(dfsrsa_crypt(data, datalen, privkey, keylen)) return -6; - dfsrsa_debug(TOP, "data+pub+priv", data, datalen); - if(dfsrsa_cmp(data, data0, datalen)) return -7; - - /* кодирование закрытым ключом, декодирование открытым */ - if(dfsrsa_crypt(data, datalen, privkey, keylen)) return -8; - dfsrsa_debug(TOP, "data+priv", data, datalen); - if(!dfsrsa_cmp(data, data0, datalen)) return -9; - if(dfsrsa_crypt(data, datalen, pubkey, keylen)) return -10; - dfsrsa_debug(TOP, "data+priv+pub", data, datalen); - if(dfsrsa_cmp(data, data0, datalen)) return -11; - - return 0; -} - -static void miller_test(void) -{ - dfsrsa_t n = 0xCB0DB667, work[16]; int i, res = 0, res1; - for(i = 0; i <= 100 || !res; ++i, n += 4) { - res = dfsrsa_isprime(&n, work, 1); - res1 = dfsrsa_isprime0(n); - if(res != res1) { - printf("Error: %u is %sprime, Miller wrong!\n", n, (res1 ? "" : "not ")); - exit(0); - } - } -} - -int main(int argc, char **argv) -{ - int len, keylen, datalen, res; struct tms t0, t; - printf("%s %s %s\n", DFSRSA_TITLE, DFSRSA_VERSION, DFSRSA_COPYRIGHT); - miller_test(); - for(keylen = MINLEN; keylen <= MAXLEN; keylen <<= 1) { - len = keylen / 2; - for(datalen = STARTLEN * len; datalen <= ENDLEN * len; datalen += len) { - printf("%s test: keylen = %4d bits, datalen = %5d bits, result: ", - argv[0], len * DFSRSA_T_BITS, datalen * DFSRSA_T_BITS); - fflush(stdout); - times(&t0); - res = work(keylen, datalen); - times(&t); - if(res) printf("error %d\n", res); - else printf("OK, time = %8.4lf + %8.4lf s\n", - (double)(t.tms_utime - t0.tms_utime) / sysconf(_SC_CLK_TCK), - (double)(t.tms_stime - t0.tms_stime) / sysconf(_SC_CLK_TCK) - ); - fflush(stdout); - } - } - return 0; -} - -#endif +/* Functions for long arithmetic and RSA cryptography. */ + +#include +#include +#include +#include "../include/dfsrsa.h" + +const char + DFSRSA_TITLE[] = "DFS RSA library", + DFSRSA_VERSION[] = "T8.505-T13.012", /* $DVS:time$ */ + DFSRSA_COPYRIGHT[] = "(C) 2012-2017 Daniel Cheatoshin (cheatoshin@mailinator.com)"; + +#define USE_MILLER_RABIN +#define USE_MONTGOMERY +#define USE_KARATSUBA + +#if defined(__x86_64__) +# define USE_FAST_MULT +# define USE_FAST_MULT_FIXED +# define KARATSUBA_TRESHOLD 64 +# define TEST_MAX_BITS 4096 +#elif defined(__arm__) +# if defined(__ARM_ARCH_3__) // for D-Link DNS-320 +# define USE_FAST_MULT +# define USE_FAST_MULT_FIXED +# define KARATSUBA_TRESHOLD 64 +# define TEST_MAX_BITS 2048 +# else // for Raspberry Pi +# define KARATSUBA_TRESHOLD 32 +# define TEST_MAX_BITS 1024 +# endif +#else +# define KARATSUBA_TRESHOLD 32 +# define TEST_MAX_BITS 2048 +#endif + + + +/************* + * debugging * + *************/ + + + /* #define DFSRSA_DEBUG */ + +#define DFSRSA_DEBUG_TOP 0x01 +#define DFSRSA_DEBUG_GEN 0x02 +#define DFSRSA_DEBUG_MILLER 0x04 +#define DFSRSA_DEBUG_MONT 0x08 +#define DFSRSA_DEBUG_INV 0x10 +#define DFSRSA_DEBUG_MOD 0x20 +#define DFSRSA_DEBUG_MODLOW 0x40 +#define DFSRSA_DEBUG_KARATSUBA 0x80 + +#define DFSRSA_DEBUG_MODE (0x80) +#define DFSRSA_DEBUG_PRINT_MAX 100 + +#ifdef DFSRSA_DEBUG + +#include + +static int dfsrsa_debug(int mode, char *name, dfsrsa_t *arr, int len) +{ + static int count = 0; + if(!(mode & DFSRSA_DEBUG_MODE)) return -1; + if(count >= DFSRSA_DEBUG_PRINT_MAX) return -1; + count++; + printf("%16s = 0x", name); + while(len--) { + printf("%08X", arr[len]); + } + printf("\n"); + fflush(stdout); + return 0; +} + +#define dfsrsa_debug(mode, name, arr, len) \ + dfsrsa_debug(DFSRSA_DEBUG_##mode, name, arr, len) + +#else + +#define dfsrsa_debug(level, name, arr, len) + +#endif + + + +/********************* + * simple operations * + *********************/ + + // count of bits in number dfsrsa_t +#define DFSRSA_T_BITS (sizeof(dfsrsa_t) << 3) + +// returns the sign of a long number: 1, if < 0; 0, if >= 0 +#define dfsrsa_sign(num, len) ((num)[(len) - 1] >> (DFSRSA_T_BITS - 1)) + +// copies the long number +static void dfsrsa_copy(dfsrsa_t *to, dfsrsa_t *from, int len) +{ + memcpy(to, from, len * sizeof(dfsrsa_t)); +} + +// sets the long number to `value` +static void dfsrsa_set(dfsrsa_t *res, int len, dfsrsa_t value) +{ + if(len > 1) { + memset(res + 1, 0, (len - 1) * sizeof(dfsrsa_t)); + } + *res = value; +} + +// returns count of significant digits (the digit is the number dfsrsa_t), discarding the leading zeros +static int dfsrsa_getlen(dfsrsa_t *num, int len) +{ + num += len; + while(len-- && !*--num); + return len + 1; +} + +// compares two long numbers and return -1, 0, 1 +int dfsrsa_cmp(dfsrsa_t *left, dfsrsa_t *right, int len) +{ + left += len, right += len; + while(len-- && *--left == *--right); + if(len < 0) return 0; + else if(*left < *right) return -1; + else return 1; +} + +// adds short number to the long number, carry is discarded +static void dfsrsa_addeq(dfsrsa_t *sum, dfsrsa_t small, int len) +{ + dfsrsa_long_t res = small; + while(len-- && res) { + res += *sum, *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + } +} + +// adds two long numbers, carry is returned (0 or 1) +int dfsrsa_add(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, int len) +{ + dfsrsa_long_t res = 0; + while(len--) { + res += (dfsrsa_long_t)*add1++ + *add2++; + *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + } + return (int)res; +} + +// adds two long numbers and carry, a new carry is returned +static dfsrsa_t dfsrsa_adc(dfsrsa_t *sum, dfsrsa_t *add1, dfsrsa_t *add2, + dfsrsa_t carry, int len) +{ + dfsrsa_long_t res = carry; + while(len--) { + res += (dfsrsa_long_t)*add1++ + *add2++; + *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + } + return (dfsrsa_t)res; +} + +// subtracts one long number from another, carry is returned (0 or -1) +static int dfsrsa_sub(dfsrsa_t *sub, dfsrsa_t *from, dfsrsa_t *to, int len) +{ + dfsrsa_slong_t res = 0; + while(len--) { + res += (dfsrsa_long_t)*from++ - *to++; + *sub++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + } + return (int)res; +} + +// shifts a long number by 1 bit to the right, carry is writed to the highest bit; +// the lowest bit is returned +static int dfsrsa_shr1(dfsrsa_t *num, int len, int carry) +{ + int next_carry; + num += len; + while(len--) { + next_carry = *--num & 1, *num >>= 1; + *num |= (dfsrsa_t)carry << (DFSRSA_T_BITS - 1); + carry = next_carry; + } + return carry; +} + +/***************************** + * methods of multiplication * + *****************************/ + + // multiples the number `big` of the lenght `len` by the number `small` + // and adds the result to the array `sum` of length `len` + 1 + // carry is writed to place number `len` in the `sum` +static void dfsrsa_muladd(dfsrsa_t *sum, dfsrsa_t *big, dfsrsa_t small, int len) +{ + dfsrsa_long_t res = 0; + while(len--) { + res += (dfsrsa_long_t)*big++ * small + *sum; + *sum++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + } + *sum = (dfsrsa_t)res; +} + +// multiplies the number `big` of length `len` by number `small` +// and subtracts the result from the array `sub` of length `len` +// if there is a carry, then subtracts it from the position `len` of the `sub` array +static void dfsrsa_mulsub(dfsrsa_t *sub, dfsrsa_t *big, dfsrsa_t small, int len) +{ + dfsrsa_long_t res = 0; + while(len--) { + res += *sub - (dfsrsa_long_t)*big++ * small; + *sub++ = (dfsrsa_t)res, res >>= DFSRSA_T_BITS; + if(res) { + res |= (dfsrsa_long_t)0 - ((dfsrsa_long_t)1 << DFSRSA_T_BITS); + } + } + if(res) *sub += (dfsrsa_t)res; +} + +// multiplies two long numbers, the result is written into an array with twice bigger length +static void dfsrsa_mul(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) +{ + int i = len; + dfsrsa_set(prod, len, 0); + while(i--) { + dfsrsa_muladd(prod++, mul1, *mul2++, len); + } +} + +#if defined(USE_FAST_MULT) && defined(__GNUC__) && defined(__x86_64__) + +#define FASTMUL2_X86_64 \ + "lodsq\n" \ + "mulq %%r8\n" \ + "addq (%%rdi), %%rax\n" \ + "adcq $0x0, %%rdx\n" \ + "addq %%r9, %%rax\n" \ + "adcq $0x0, %%rdx\n" \ + "stosq\n" \ + "movq %%rdx, %%r9\n" + +#ifdef USE_FAST_MULT_FIXED + +#define FASTMUL4_X86_64 FASTMUL2_X86_64 FASTMUL2_X86_64 +#define FASTMUL8_X86_64 FASTMUL4_X86_64 FASTMUL4_X86_64 +#define FASTMUL16_X86_64 FASTMUL8_X86_64 FASTMUL8_X86_64 +#define FASTMUL32_X86_64 FASTMUL16_X86_64 FASTMUL16_X86_64 +#define FASTMUL64_X86_64 FASTMUL32_X86_64 FASTMUL32_X86_64 + +static void dfsrsa_fastmul16_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "xorq %%rax, %%rax\n" + "movl $0x08, %%ecx\n" + "rep stosq\n" + "movq %%rdx, %%rbx\n" + "subq $0x40, %%rdi\n" + "movl $0x08, %%ecx\n" + "1: movq (%%rbx), %%r8\n" + "xor %%r9, %%r9\n" + FASTMUL16_X86_64 + "movq %%r9, (%%rdi)\n" + "subq $0x40, %%rsi\n" + "subq $0x38, %%rdi\n" + "addq $0x08, %%rbx\n" + "decl %%ecx\n" + "jnz 1b\n" + : "+D"(prod), "+S"(mul1), "+d"(mul2) : + : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" + ); +} + +static void dfsrsa_fastmul32_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "xorq %%rax, %%rax\n" + "movl $0x10, %%ecx\n" + "rep stosq\n" + "movq %%rdx, %%rbx\n" + "subq $0x80, %%rdi\n" + "movl $0x10, %%ecx\n" + "1: movq (%%rbx), %%r8\n" + "xor %%r9, %%r9\n" + FASTMUL32_X86_64 + "movq %%r9, (%%rdi)\n" + "subq $0x80, %%rsi\n" + "subq $0x78, %%rdi\n" + "addq $0x08, %%rbx\n" + "decl %%ecx\n" + "jnz 1b\n" + : "+D"(prod), "+S"(mul1), "+d"(mul2) : + : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" + ); +} + +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 +static void dfsrsa_fastmul64_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "xorq %%rax, %%rax\n" + "movl $0x20, %%ecx\n" + "rep stosq\n" + "movq %%rdx, %%rbx\n" + "subq $0x100, %%rdi\n" + "movl $0x20, %%ecx\n" + "1: movq (%%rbx), %%r8\n" + "xor %%r9, %%r9\n" + FASTMUL64_X86_64 + "movq %%r9, (%%rdi)\n" + "subq $0x100, %%rsi\n" + "subq $0xF8, %%rdi\n" + "addq $0x08, %%rbx\n" + "decl %%ecx\n" + "jnz 1b\n" + : "+D"(prod), "+S"(mul1), "+d"(mul2) : + : "memory", "%rax", "%rbx", "%rcx", "%r8", "%r9", "cc" + ); +} +#endif + +#endif + +static void dfsrsa_fastmul_x86_64(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) +{ +#ifdef USE_FAST_MULT_FIXED +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 + if(len == 64) { dfsrsa_fastmul64_x86_64(prod, mul1, mul2); return; } +#endif +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 32 + if(len == 32) { dfsrsa_fastmul32_x86_64(prod, mul1, mul2); return; } +#endif +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 16 + if(len == 16) { dfsrsa_fastmul16_x86_64(prod, mul1, mul2); return; } +#endif +#endif + if(len & 1) { dfsrsa_mul(prod, mul1, mul2, len); return; } + asm volatile( + "shrl $1, %%ecx\n" + "xorq %%rax, %%rax\n" + "movq %%rcx, %%r10\n" + "movq %%rcx, %%r11\n" + "leaq (%%rax,%%rcx,8), %%r12\n" + "rep stosq\n" + "movq %%r10, %%rcx\n" + "subq %%r12, %%rdi\n" + "movq %%rdx, %%rbx\n" + "1: movq (%%rbx), %%r8\n" + "xor %%r9, %%r9\n" + "2: \n" + FASTMUL2_X86_64 + "loop 2b\n" + "movq %%r9, (%%rdi)\n" + "movq %%r11, %%rcx\n" + "subq %%r12, %%rdi\n" + "subq %%r12, %%rsi\n" + "addq $0x8, %%rbx\n" + "addq $0x8, %%rdi\n" + "decq %%r10\n" + "jnz 1b\n" + : "+D"(prod), "+S"(mul1), "+d"(mul2), "+c"(len) : + : "memory", "%rax", "%rbx", "%r8", "%r9", "%r10", "%r11", "%r12", "cc" + ); +} + +#define dfsrsa_mul dfsrsa_fastmul_x86_64 +#endif + +#if defined(USE_FAST_MULT) && defined(__GNUC__) && defined(__arm__) + +#if defined(USE_FAST_MULT_FIXED) + +#if defined(__ARCH_ARM_6__) || defined(__ARCH_ARM_7__) +#define LDRD( r1,r2,raddr) "ldrd " #r1 ", [" #raddr "]\n" +#define LDRDI(r1,r2,raddr) "ldrd " #r1 ", [" #raddr "], #8\n" +#define STRD( r1,r2,raddr) "strd " #r1 ", [" #raddr "]\n" +#define STRDI(r1,r2,raddr) "strd " #r1 ", [" #raddr "], #8\n" +#else +#define LDRD( r1,r2,raddr) "ldmia " #raddr ", {" #r1 ", " #r2 "}\n" +#define LDRDI(r1,r2,raddr) "ldmia " #raddr "!, {" #r1 ", " #r2 "}\n" +#define STRD( r1,r2,raddr) "stmia " #raddr ", {" #r1 ", " #r2 "}\n" +#define STRDI(r1,r2,raddr) "stmia " #raddr "!, {" #r1 ", " #r2 "}\n" +#endif + +#define SETMEM2_ARM STRDI(r6, r7, r4) + +#define SETMEM4_ARM SETMEM2_ARM SETMEM2_ARM +#define SETMEM8_ARM SETMEM4_ARM SETMEM4_ARM +#define SETMEM16_ARM SETMEM8_ARM SETMEM8_ARM +#define SETMEM32_ARM SETMEM16_ARM SETMEM16_ARM +#define SETMEM64_ARM SETMEM32_ARM SETMEM32_ARM + +#define FASTMUL2_ARM \ + "mov r12, #0\n" \ + LDRDI (r8, r9, r2) \ + "mov r10, #0\n" \ + "umlal r6, r12, r8, r4\n" \ + "umlal r7, r10, r9, r4\n" \ + "mov r14, #0\n" \ + "mov r11, #0\n" \ + "umlal r12, r14, r8, r5\n" \ + "umlal r10, r11, r9, r5\n" \ + "adds r7, r7, r12\n" \ + LDRD (r8, r9, r0) \ + "adcs r10, r10, r14\n" \ + "adc r11, r11, #0\n" \ + "adds r8, r6, r8\n" \ + "adcs r9, r7, r9\n" \ + "adcs r6, r10, #0\n" \ + STRDI (r8, r9, r0) \ + "adc r7, r11, #0\n" + +#define FASTMUL4_ARM FASTMUL2_ARM FASTMUL2_ARM +#define FASTMUL8_ARM FASTMUL4_ARM FASTMUL4_ARM +#define FASTMUL16_ARM FASTMUL8_ARM FASTMUL8_ARM +#define FASTMUL32_ARM FASTMUL16_ARM FASTMUL16_ARM +#define FASTMUL64_ARM FASTMUL32_ARM FASTMUL32_ARM + +static void dfsrsa_fastmul16_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "stmfd sp!, {r0-r12, r14}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r2, %2\n" + "mov r6, #0\n" + "mov r7, #0\n" + "mov r4, r0\n" + SETMEM16_ARM + "mov r3, #8\n" + "1:\n" + LDRDI(r4, r5, r1) + "mov r6, #0\n" + "mov r7, #0\n" + FASTMUL16_ARM + STRDI(r6, r7, r0) + "sub r0, r0, #64\n" + "sub r2, r2, #64\n" + "subs r3, r3, #1\n" + "bne 1b\n" + "ldmfd sp!, {r0-r12, r14}\n" + : : "r"(prod), "r"(mul1), "r"(mul2) + : "memory", "cc" + ); +} + +static void dfsrsa_fastmul32_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "stmfd sp!, {r0-r12, r14}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r2, %2\n" + "mov r6, #0\n" + "mov r7, #0\n" + "mov r4, r0\n" + SETMEM32_ARM + "mov r3, #16\n" + "1:\n" + LDRDI(r4, r5, r1) + "mov r6, #0\n" + "mov r7, #0\n" + FASTMUL32_ARM + STRDI(r6, r7, r0) + "sub r0, r0, #128\n" + "sub r2, r2, #128\n" + "subs r3, r3, #1\n" + "bne 1b\n" + "ldmfd sp!, {r0-r12, r14}\n" + : : "r"(prod), "r"(mul1), "r"(mul2) + : "memory", "cc" + ); +} + +static void dfsrsa_fastmul64_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2) +{ + asm volatile( + "stmfd sp!, {r0-r12, r14}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r2, %2\n" + "mov r6, #0\n" + "mov r7, #0\n" + "mov r4, r0\n" + SETMEM64_ARM + "mov r3, #32\n" + "1:\n" + LDRDI(r4, r5, r1) + "mov r6, #0\n" + "mov r7, #0\n" + FASTMUL64_ARM + STRDI(r6, r7, r0) + "sub r0, r0, #256\n" + "sub r2, r2, #256\n" + "subs r3, r3, #1\n" + "bne 1b\n" + "ldmfd sp!, {r0-r12, r14}\n" + : : "r"(prod), "r"(mul1), "r"(mul2) + : "memory", "cc" + ); +} + +#endif + +static void dfsrsa_fastmul_arm(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, int len) +{ +#ifdef USE_FAST_MULT_FIXED +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 64 + if(len == 64) { dfsrsa_fastmul64_arm(prod, mul1, mul2); return; } +#endif +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 32 + if(len == 32) { dfsrsa_fastmul32_arm(prod, mul1, mul2); return; } +#endif +#if !defined(USE_KARATSUBA) || KARATSUBA_TRESHOLD > 16 + if(len == 16) { dfsrsa_fastmul16_arm(prod, mul1, mul2); return; } +#endif +#endif + asm volatile( + "stmfd sp!, {r0-r9}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r2, %2\n" + "mov r3, %3\n" + "mov r4, #0\n" + "mov r5, r0\n" + "mov r6, r3\n" + "1: str r4, [r5], #4\n" + "subs r6, r6, #1\n" + "bne 1b\n" + "mov r5, r3\n" + "2: mov r6, r3\n" + "ldr r4, [r1], #4\n" + "mov r7, #0\n" + "3: ldr r8, [r2], #4\n" + "mov r9, #0\n" + "umlal r7, r9, r4, r8\n" + "ldr r8, [r0]\n" + "adds r7, r7, r8\n" + "adc r9, r9, #0\n" + "str r7, [r0], #4\n" + "mov r7, r9\n" + "subs r6, r6, #1\n" + "bne 3b\n" + "str r7, [r0], #4\n" + "sub r0, r0, r3, LSL #2\n" + "sub r2, r2, r3, LSL #2\n" + "subs r5, r5, #1\n" + "bne 2b\n" + "ldmfd sp!, {r0-r9}\n" + : : "r"(prod), "r"(mul1), "r"(mul2), "r"(len) + : "memory", "cc" + ); +} + +#define dfsrsa_mul dfsrsa_fastmul_arm +#endif + +#ifdef USE_KARATSUBA + +// Karatsuba's method of multiplication of numbers, `work` - auxiliary array of size 2 * len +static void dfsrsa_karatsuba_mul(dfsrsa_t *prod, dfsrsa_t *mul1, dfsrsa_t *mul2, + int len, dfsrsa_t *work) +{ +#ifdef DFSRSA_DEBUG + dfsrsa_t *m1 = mul1, *m2 = mul2, *p = prod, *w = work; int l = len; +#endif + int r, llen; dfsrsa_long_t rem; + if((len & 1) || len < KARATSUBA_TRESHOLD) { + dfsrsa_mul(prod, mul1, mul2, len); + return; + } + r = 1, llen = len, len >>= 1; + if(dfsrsa_cmp(mul1 + len, mul1, len) >= 0) { + dfsrsa_sub(work, mul1 + len, mul1, len); + } else { + dfsrsa_sub(work, mul1, mul1 + len, len), r = -r; + } + if(dfsrsa_cmp(mul2 + len, mul2, len) >= 0) { + dfsrsa_sub(work + len, mul2 + len, mul2, len); + } else { + dfsrsa_sub(work + len, mul2, mul2 + len, len), r = -r; + } + dfsrsa_karatsuba_mul(work + llen, work, work + len, len, prod); + dfsrsa_karatsuba_mul(prod, mul1, mul2, len, work); + dfsrsa_karatsuba_mul(prod + llen, mul1 + len, mul2 + len, len, work); + dfsrsa_copy(work, prod, llen); + mul1 = prod + llen, mul2 = work, work += llen, prod += len, rem = 0; + if(r > 0) { + while(llen--) { + rem += (dfsrsa_long_t)*prod + (dfsrsa_long_t)*mul1++ + + (dfsrsa_long_t)*mul2++ - (dfsrsa_long_t)*work++; + *prod++ = (dfsrsa_t)rem; + rem = (dfsrsa_slong_t)rem >> DFSRSA_T_BITS; + } + } else { + while(llen--) { + rem += (dfsrsa_long_t)*prod + (dfsrsa_long_t)*mul1++ + + (dfsrsa_long_t)*mul2++ + (dfsrsa_long_t)*work++; + *prod++ = (dfsrsa_t)rem; + rem >>= DFSRSA_T_BITS; + } + } + while(rem) { + rem += *prod, *prod++ = (dfsrsa_t)rem, rem >>= DFSRSA_T_BITS; + } +#ifdef DFSRSA_DEBUG + dfsrsa_mul(w, m1, m2, l); + if(dfsrsa_cmp(p, w, l << 1)) { + dfsrsa_debug(KARATSUBA, "mul1", m1, l); + dfsrsa_debug(KARATSUBA, "mul2", m2, l); + dfsrsa_debug(KARATSUBA, "prod0", w, l << 1); + dfsrsa_debug(KARATSUBA, "prod", p, l << 1); + } +#endif +} + +#ifdef dfsrsa_mul +#undef dfsrsa_mul +#endif +#define dfsrsa_mul(prod,mul1,mul2,len) dfsrsa_karatsuba_mul(prod,mul1,mul2,len,kwork) + +#endif + + +/***************************** + * multiplicative operations * + *****************************/ + + + // calculates the rest of division the number `nul` of length `len` by a short number `mod` +static dfsrsa_t dfsrsa_modsmall(dfsrsa_t *div, int len, dfsrsa_t mod) +{ + dfsrsa_long_t rem = 0; + if(!mod) return 0; + while(len) { + rem <<= DFSRSA_T_BITS, rem |= div[--len], rem %= mod; + } + return rem; +} + +// calculates the rest of division of number `mod` of length `mlen` by number `div` of length `len` +// result is places to array `mod`, returns -1 in case of division by 0 +static int dfsrsa_mod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len) +{ + dfsrsa_long_t div0, div2; + dfsrsa_debug(MOD, "divisor", mod, mlen); + dfsrsa_debug(MOD, "dividend", div, len); + len = dfsrsa_getlen(div, len); + if(!len) return -1; + dfsrsa_long_t div1 = div[len - 1]; + if(len > 1) { + div2 = (div1 << DFSRSA_T_BITS) | div[len - 2]; + ++div1; + if(len > 2) ++div2; + } else div2 = 0; + for(;;) { + mlen = dfsrsa_getlen(mod, mlen); + dfsrsa_debug(MODLOW, "work remainder", mod, mlen); + int offset = mlen - len; + if(offset < 0) break; + int res = dfsrsa_cmp(mod + offset, div, len); + dfsrsa_long_t mod0 = (dfsrsa_long_t)mod[mlen - 1]; + if(res < 0) { + if(!offset--) break; + mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; + div0 = div1; + } else if(len > 1 && div2) { + mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; + div0 = div2; + } else { + div0 = div1; + } + dfsrsa_debug(MODLOW, "mod0", (dfsrsa_t*)&mod0, 2); + dfsrsa_debug(MODLOW, "div0", (dfsrsa_t*)&div0, 2); + mod0 /= div0; + if(!mod0) mod0 = 1; + dfsrsa_debug(MODLOW, "mod0/div0", (dfsrsa_t*)&mod0, 2); + dfsrsa_mulsub(mod + offset, div, (dfsrsa_t)mod0, len); + } + dfsrsa_debug(MOD, "remainder", mod, mlen); + return 0; +} + +// calculates the quotient and rest of division of number `mod` of length `mlen` by number `div` of length `len` +// the quotient is placed to array `quotient` of length `mlen`, the rest - in array `mod` +// return -1 in case of division by 0 +int dfsrsa_divmod(dfsrsa_t *mod, int mlen, dfsrsa_t *div, int len, + dfsrsa_t *quotient) +{ + int res, offset; dfsrsa_long_t mod0, div0, div1, div2; + dfsrsa_debug(MOD, "divisor", mod, mlen); + dfsrsa_debug(MOD, "dividend", div, len); + len = dfsrsa_getlen(div, len); + if(!len) return -1; + dfsrsa_set(quotient, mlen, 0); + div1 = div[len - 1]; + if(len > 1) { + div2 = (div1 << DFSRSA_T_BITS) | div[len - 2]; + ++div1; + if(len > 2) ++div2; + } else div2 = 0; + for(;;) { + mlen = dfsrsa_getlen(mod, mlen); + dfsrsa_debug(MODLOW, "work remainder", mod, mlen); + offset = mlen - len; + if(offset < 0) break; + res = dfsrsa_cmp(mod + offset, div, len); + mod0 = (dfsrsa_long_t)mod[mlen - 1]; + if(res < 0) { + if(!offset--) break; + mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; + div0 = div1; + } else if(len > 1 && div2) { + mod0 = (mod0 << DFSRSA_T_BITS) | mod[mlen - 2]; + div0 = div2; + } else { + div0 = div1; + } + dfsrsa_debug(MODLOW, "mod0", (dfsrsa_t*)&mod0, 2); + dfsrsa_debug(MODLOW, "div0", (dfsrsa_t*)&div0, 2); + mod0 /= div0; + if(!mod0) mod0 = 1; + dfsrsa_debug(MODLOW, "mod0/div0", (dfsrsa_t*)&mod0, 2); + dfsrsa_mulsub(mod + offset, div, (dfsrsa_t)mod0, len); + dfsrsa_addeq(quotient + offset, (dfsrsa_t)mod0, mlen - offset); + } + dfsrsa_debug(MOD, "quotient", quotient, mlen); + dfsrsa_debug(MOD, "remainder", mod, mlen); + return 0; +} + +// raises to the power by module: res = base^exp (mod mod), all numbers has length `len` +// work - auxiliary array of length 6*len, where are writed the last two results of multiplication +// each has 2*len +static void dfsrsa_powmod(dfsrsa_t *res, dfsrsa_t *base, dfsrsa_t *exp, dfsrsa_t *mod, + dfsrsa_t *work, int len) +{ +#define kwork (work + 4 * len) + dfsrsa_t bits; + int off = 0; + int off1 = len << 1; + int flag = 0; + int i; + dfsrsa_set(work, len, 1); + int explen = dfsrsa_getlen(exp, len); + while(explen--) { + bits = exp[explen], i = DFSRSA_T_BITS; + while(i--) { + if(flag) { + off = off1 - off; + dfsrsa_mul(work + off, work + off1 - off, work + off1 - off, len); + dfsrsa_mod(work + off, len << 1, mod, len); + } + if((bits >> i) & 1) { + off = off1 - off; + dfsrsa_mul(work + off, work + off1 - off, base, len); + dfsrsa_mod(work + off, len << 1, mod, len); + flag = 1; + } + } + } + dfsrsa_copy(res, work + off, len); +#undef kwork +} + +// finds the inverse number `inv` for given `num` by module `mod`, if not return -1 +// The version of Euclid's extended binary algorithm is used +// it is assumed that num = 2k + 1, mod = 2^n (2m + 1), n <= 2 +// work - working array of length 4*len +static int dfsrsa_inverse(dfsrsa_t *inv, dfsrsa_t *num, dfsrsa_t *mod, + dfsrsa_t *work, int len) +{ + dfsrsa_t *pn = work, *px = inv, *qn = work + len, *qx = work + 2 * len, + *mod4 = work + 3 * len, mask = 0; + int carry; + dfsrsa_copy(pn, num, len), dfsrsa_set(px, len, 1); + dfsrsa_copy(mod4, mod, len); + while(!(*mod4 & 1)) dfsrsa_shr1(mod4, len, 0), mask <<= 1, mask |= 1; + dfsrsa_copy(qn, mod4, len), dfsrsa_set(qx, len, 0); + dfsrsa_debug(INV, "inv mod/4", mod4, len); + for(;;) { + dfsrsa_debug(INV, "inv pn", pn, len); + dfsrsa_debug(INV, "inv px", px, len); + dfsrsa_debug(INV, "inv qn", qn, len); + dfsrsa_debug(INV, "inv qx", qx, len); + while(!(*pn & 1)) { + carry = 0; + dfsrsa_shr1(pn, len, 0); + if(*px & 1) carry = dfsrsa_add(px, px, mod4, len); + dfsrsa_shr1(px, len, carry); + } + while(!(*qn & 1)) { + carry = 0; + dfsrsa_shr1(qn, len, 0); + if(*qx & 1) carry = dfsrsa_add(qx, qx, mod4, len); + dfsrsa_shr1(qx, len, carry); + } + dfsrsa_debug(INV, "inv pn", pn, len); + dfsrsa_debug(INV, "inv px", px, len); + dfsrsa_debug(INV, "inv qn", qn, len); + dfsrsa_debug(INV, "inv qx", qx, len); + switch(dfsrsa_cmp(pn, qn, len)) { + case 0: goto fin; + case 1: + dfsrsa_sub(pn, pn, qn, len); + if(dfsrsa_sub(px, px, qx, len)) + dfsrsa_add(px, px, mod4, len); + break; + case -1: + dfsrsa_sub(qn, qn, pn, len); + if(dfsrsa_sub(qx, qx, px, len)) + dfsrsa_add(qx, qx, mod4, len); + break; + } + } +fin: + dfsrsa_set(qn, len, 1); + if(dfsrsa_cmp(pn, qn, len)) return -1; + dfsrsa_debug(INV, "inv mod/4", inv, len); + while((*num ^ *inv) & mask) dfsrsa_add(inv, inv, mod4, len); + dfsrsa_debug(INV, "inv result", inv, len); + return 0; +} + + +/********************* + * Montgomery method * + *********************/ + + +// initializes array of data `madata` of length 6*len for Montgomery method +// by specified module `mod` of length `len` +// uses auxiliary array `work` of length 4*len +// returns -1 in case of error +static int dfsrsa_montgomery_init(dfsrsa_t *mod, dfsrsa_t *mdata, dfsrsa_t *work, + int len) +{ + dfsrsa_debug(MONT, "montgomery N", mod, len); + dfsrsa_set(mdata + 2 * len, len, 0); + dfsrsa_sub(mdata, mdata + 2 * len, mod, len); + //dfsrsa_mod(mdata, len, mod, len); + dfsrsa_debug(MONT, "montgomery R - N", mdata, len); + if(dfsrsa_inverse(mdata + 3 * len, mdata, mod, work, len)) return -1; + dfsrsa_debug(MONT, "montgomery R^-1", mdata + 3 * len, len); + if(dfsrsa_divmod(mdata + 2 * len, 2 * len, mod, len, mdata)) return -1; + dfsrsa_debug(MONT, "montgomery k", mdata, len); + return 0; +} + +// reduces the diven number `num` for usage in for Montgomery method +// num = (num << R) mod mod, num and mod have length `len`, R = len * 8 * sizeof(dfsrsa_t) +// mdata - array, initialized by function dfsrsa_montgomery_init +// returns -1 in case of error +static int dfsrsa_montgomery_reduce(dfsrsa_t *num, dfsrsa_t *mod, dfsrsa_t *mdata, + int len) +{ + dfsrsa_debug(MONT, "montgomery n", num, len); + dfsrsa_set(mdata + 2 * len, len, 0); + dfsrsa_copy(mdata + 3 * len, num, len); + if(dfsrsa_mod(mdata + 2 * len, 2 * len, mod, len)) return -1; + dfsrsa_copy(num, mdata + 2 * len, len); + dfsrsa_debug(MONT, "montgomery nR", num, len); + return 0; +} + +// step of Montgomery method: converts the given number `num` by module `mod` dividing by R +// num has a length 2 * len, mod - len, result `num` has length `len` +// `mdata` - array initialized by function dfsrsa_montgomery_init +static void dfsrsa_montgomery_mod(dfsrsa_t *num, dfsrsa_t *mod, dfsrsa_t *mdata, int len) +{ +#define kwork (mdata + 4 * len) + dfsrsa_debug(MONT, "montgomery n", num, 2 * len); + if(dfsrsa_getlen(num, len)) { + dfsrsa_mul(mdata + len, num, mdata, len); + dfsrsa_mul(mdata + 2 * len, mdata + len, mod, len); + if(dfsrsa_adc(num, num + len, mdata + 3 * len, 1, len) + || dfsrsa_cmp(num, mod, len) >= 0) { + dfsrsa_sub(num, num, mod, len); + } + } else { + dfsrsa_copy(num, num + len, len); + if(dfsrsa_cmp(num, mod, len) >= 0) { + dfsrsa_sub(num, num, mod, len); + } + } + dfsrsa_debug(MONT, "montgomery n/R", num, len); +#undef kwork +} + +// raises to the power by module using Montgomery method +// res = base^exp (mod mod), all numbers have length `len` +// work - auxiliary array of length 12 * len, +// two last results of multiplication (each of length 2*len) are written to the beginning of array `work` +static void dfsrsa_montgomery_powmod(dfsrsa_t *res, dfsrsa_t *base, dfsrsa_t *exp, + dfsrsa_t *mod, dfsrsa_t *work, int len) +{ +#define kwork (work + 8 * len) + dfsrsa_t bits, *mdata = work + 4 * len, *mbase = work + 10 * len; + int off = 0; + int off1 = len << 1; + int flag = 0; + int i; + if(dfsrsa_montgomery_init(mod, mdata, work, len)) goto powmod; + dfsrsa_set(work, len, 1); + if(dfsrsa_montgomery_reduce(work, mod, mdata, len)) goto powmod; + dfsrsa_copy(mbase, base, len); + if(dfsrsa_montgomery_reduce(mbase, mod, mdata, len)) goto powmod; + int explen = dfsrsa_getlen(exp, len); + while(explen--) { + bits = exp[explen], i = DFSRSA_T_BITS; + while(i--) { + if(flag) { + off = off1 - off; + dfsrsa_mul(work + off, work + off1 - off, work + off1 - off, len); + dfsrsa_montgomery_mod(work + off, mod, mdata, len); + } + if((bits >> i) & 1) { + off = off1 - off; + dfsrsa_mul(work + off, work + off1 - off, mbase, len); + dfsrsa_montgomery_mod(work + off, mod, mdata, len); + flag = 1; + } + } + } + dfsrsa_set(work + len, len, 0); + dfsrsa_montgomery_mod(work, mod, mdata, len); + dfsrsa_set(work + off1 + len, len, 0); + dfsrsa_montgomery_mod(work + off1, mod, mdata, len); + dfsrsa_copy(res, work + off, len); + return; +powmod: perror("Montgomery_powmod failed! Using std powmod..."); + dfsrsa_powmod(res, base, exp, mod, work, len); +#undef kwork +} + +#ifdef USE_MONTGOMERY +#define dfsrsa_powmod dfsrsa_montgomery_powmod +#endif + + + +/****************************** + * number-theoretic functions * + ******************************/ + + +// simple simplicity test for small numbers +static int dfsrsa_isprime0(dfsrsa_t n) +{ + dfsrsa_t d; + if(n < 32) return (0xA08A28AC >> n) & 1; + if(!(n & 1)) return 0; + for(d = 3; d * d <= n; d += 2) { + if(!(n % d)) return 0; + } + return 1; +} + +// a simplicity test based on deterministic Miller algorithm +// (under the assumption hypothesis of Riemann) +// works only for numbers of the form 4k + 3 +// work - working array of length 16*len +// algorithm: for each simple a = 2, ..., lim it is verified that: +// a ^ (n - 1) = 1 (mod n) +// and +// a ^ ((n-1)/2) = 1 or -1 (mod n) +// where +// lim = (log_2 (n)) ^ 2 +// (by the result of Eric Bach 1985 it is enought to check up to 2 ln^2(n), +// and it is about 0.96 of out `lim` which is more convenient to calculate) +static int dfsrsa_isprime(dfsrsa_t *n, dfsrsa_t *work, int len) +{ + dfsrsa_t *work2, *res, *a, *nm1, *o, lim, d, i; + dfsrsa_debug(MILLER, "miller n", n, len); + len = dfsrsa_getlen(n, len); + lim = (dfsrsa_t)len * DFSRSA_T_BITS; + for(i = 0, d = 3; i < lim; d += 2) { + if(len <= 1 && d * d > *n) return 1; + if(!dfsrsa_isprime0(d)) continue; + if(!dfsrsa_modsmall(n, len, d)) return 0; + ++i; + } + work2 = work + 2 * len, res = work + 12 * len, a = res + len, + nm1 = a + len, o = nm1 + len; + dfsrsa_set(o, len, 1); dfsrsa_set(a, len, 0); + dfsrsa_copy(nm1, n, len), --*nm1; + dfsrsa_debug(MILLER, "miller n-1", nm1, len); +#ifndef USE_MILLER_RABIN + lim *= lim; +#endif + if(len <= 1 && lim > *n) lim = *n; +#ifdef USE_MILLER_RABIN + for(i = 0, d = 2; i < lim; ++d, d |= 1) +#else + for(d = 2; d < lim; ++d, d |= 1) +#endif + if(dfsrsa_isprime0(d)) { + *a = d; +#ifdef USE_MILLER_RABIN + ++i; +#endif + dfsrsa_debug(MILLER, "miller a", a, len); + dfsrsa_powmod(res, a, nm1, n, work, len); + dfsrsa_debug(MILLER, "miller a^(n-1)", res, len); + dfsrsa_debug(MILLER, "miller work", work, len); + dfsrsa_debug(MILLER, "miller work2", work2, len); + + // it is assumed here that last two result of raising in power + // are contained in `work` and `work2`, no matter in what order + // it will be a ^ ((n-1) / 2) and a ^ (n-1) + if((dfsrsa_cmp(work, o, len) && dfsrsa_cmp(work, nm1, len)) + || (dfsrsa_cmp(work2, o, len) && dfsrsa_cmp(work2, nm1, len))) + return 0; + } + return 1; +} + +// generate prime number with given length based on random information in array n +// work - working array of length 16*len +static void dfsrsa_genprime(dfsrsa_t *n, dfsrsa_t *work, int len) +{ + dfsrsa_debug(GEN, "genprime random", n, len); + *n |= 3, n[len - 1] |= 3 << (DFSRSA_T_BITS - 2); + dfsrsa_debug(GEN, "genprime before", n, len); + while(!dfsrsa_isprime(n, work, len)) { + dfsrsa_addeq(n, 4, len); + } + dfsrsa_debug(GEN, "genprime result", n, len); +} + +// generats mutually-inverse numbers `pubkey` and `privkey` by given module `mod` of the form 8k+4 +// at the entrance `pubkey` is filled with random data, work - a working array of length 4*len +static void dfsrsa_geninv(dfsrsa_t *privkey, dfsrsa_t *pubkey, dfsrsa_t *mod, + dfsrsa_t *work, int len) +{ + dfsrsa_debug(GEN, "e random", pubkey, len); + dfsrsa_mod(pubkey, len, mod, len); + dfsrsa_debug(GEN, "e mod", pubkey, len); + *pubkey |= 1; + dfsrsa_debug(GEN, "e before", pubkey, len); + while(dfsrsa_inverse(privkey, pubkey, mod, work, len)) { + dfsrsa_addeq(pubkey, 2, len); + } + dfsrsa_debug(GEN, "e result", pubkey, len); + dfsrsa_debug(GEN, "d result", privkey, len); +} + + +/****************** + * main functions * + ******************/ + + +// allocates memory for number with specified length +static dfsrsa_t *dfsrsa_alloc(int len) +{ + return (dfsrsa_t *)malloc(len * sizeof(dfsrsa_t)); +} + +// frees number +static void dfsrsa_free(dfsrsa_t *num) +{ + free(num); +} + +// encodes/decodes the message using corresponding public/private key +// `datalen` and `keylen` are measured in dfsrsa_t numbers +// key `key` should be generated by function `dfsrsa_keygen` +// `datalen` should be a multiple of half of the `keylen` +// the highest bit should be 0 in each part of message (length `keylen`/2 of dfsrsa_t) +// the result message is placed in the same array as the original +// returns -1 in case of error +int dfsrsa_crypt(dfsrsa_t *data, int datalen, dfsrsa_t *key, int keylen) +{ + int len = keylen / 2, i; + dfsrsa_t *work, *mod = key + len; + if(keylen <= 0 || (keylen & 1) || datalen < 0 || datalen % len) return -1; + datalen /= len; + for(i = 0; i < datalen; ++i) { + if(dfsrsa_cmp(data + i * len, mod, len) >= 0) return -1; + } + work = dfsrsa_alloc(len << 4); + if(!work) return -1; + for(i = 0; i < datalen; ++i, data += len) { + dfsrsa_powmod(data, data, key, mod, work, len); + } + dfsrsa_free(work); + return 0; +} + +// generates public and private keys of the lengh `keylen` of numbers dfsrsa_t +// `keylen` should be a multiple of 4 +// the pubkey array should be prefilled with random numbers +// the algorithm does not use any other random information +// returns -1 in case of error +int dfsrsa_keygen(dfsrsa_t *privkey, dfsrsa_t *pubkey, int keylen) +{ +#define kwork work + int len = keylen >> 2; + dfsrsa_t *work, *p = pubkey + len * 2, *q = pubkey + len * 3, + *n = privkey + len * 2, *phin = p, *phin0 = privkey; + if(keylen <= 0 || (keylen & 3)) return -1; + if((dfsrsa_t)len * DFSRSA_T_BITS > (dfsrsa_t)1 << (DFSRSA_T_BITS >> 1)) + return -1; + work = dfsrsa_alloc(len << 4); + if(!work) return -1; + dfsrsa_genprime(p, work, len); + dfsrsa_genprime(q, work, len); + dfsrsa_mul(n, p, q, len); + dfsrsa_debug(GEN, "pq", n, len << 1); + --*p, --*q; + dfsrsa_mul(phin0, p, q, len); + len <<= 1; + dfsrsa_copy(phin, phin0, len); + dfsrsa_debug(GEN, "(p-1)(q-1)", phin, len); + dfsrsa_geninv(privkey, pubkey, phin, work, len); + dfsrsa_copy(phin, n, len); + dfsrsa_free(work); + return 0; +#undef kwork +} + + + +/*********** + * testing * + ***********/ + +#if !defined(DFSTOOLS) && !defined(__DuS__) && !defined(QDNET) +#define DFSRSA_TEST +#endif + +#ifdef DFSRSA_TEST + +#include +#include +#include +#include "../dfslib/dfslib_random.h" + +static void dfsrsa_fillrand(dfsrsa_t *arr, int len) +{ + dfslib_random_fill(arr, len * (DFSRSA_T_BITS >> 3), 0, 0); +} + +#define MINLEN 4 +#define MAXLEN (TEST_MAX_BITS >> 4) +#define MAXDATALEN (TEST_MAX_BITS >> 3) +#define STARTLEN 4 +#define ENDLEN 4 + +int work(int keylen, int datalen) +{ + dfsrsa_t pubkey[MAXLEN], privkey[MAXLEN], data[MAXDATALEN], data0[MAXDATALEN]; + int i; + if(keylen > MAXLEN) return -1; + if(datalen > MAXDATALEN) return -2; + + /* генерация ключей */ + dfsrsa_fillrand(pubkey, keylen); + dfsrsa_debug(TOP, "pubkey random", pubkey, keylen); + dfsrsa_set(privkey, keylen, 0); + if(dfsrsa_keygen(privkey, pubkey, keylen)) return -3; + dfsrsa_debug(TOP, "pubkey", pubkey, keylen); + dfsrsa_debug(TOP, "privkey", privkey, keylen); + + /* генерация данных, старший бит в каждой порции данных должен быть 0 */ + dfsrsa_fillrand(data0, datalen); + for(i = 1; i <= datalen / (keylen / 2); ++i) + data0[i * keylen / 2 - 1] &= ((dfsrsa_t)1 << (DFSRSA_T_BITS - 1)) - 1; + dfsrsa_copy(data, data0, datalen); + dfsrsa_debug(TOP, "data", data, datalen); + + /* кодирование открытым ключом, декодирование закрытым */ + if(dfsrsa_crypt(data, datalen, pubkey, keylen)) return -4; + dfsrsa_debug(TOP, "data+pub", data, datalen); + if(!dfsrsa_cmp(data, data0, datalen)) return -5; + if(dfsrsa_crypt(data, datalen, privkey, keylen)) return -6; + dfsrsa_debug(TOP, "data+pub+priv", data, datalen); + if(dfsrsa_cmp(data, data0, datalen)) return -7; + + /* кодирование закрытым ключом, декодирование открытым */ + if(dfsrsa_crypt(data, datalen, privkey, keylen)) return -8; + dfsrsa_debug(TOP, "data+priv", data, datalen); + if(!dfsrsa_cmp(data, data0, datalen)) return -9; + if(dfsrsa_crypt(data, datalen, pubkey, keylen)) return -10; + dfsrsa_debug(TOP, "data+priv+pub", data, datalen); + if(dfsrsa_cmp(data, data0, datalen)) return -11; + + return 0; +} + +static void miller_test(void) +{ + dfsrsa_t n = 0xCB0DB667, work[16]; int i, res = 0, res1; + for(i = 0; i <= 100 || !res; ++i, n += 4) { + res = dfsrsa_isprime(&n, work, 1); + res1 = dfsrsa_isprime0(n); + if(res != res1) { + printf("Error: %u is %sprime, Miller wrong!\n", n, (res1 ? "" : "not ")); + exit(0); + } + } +} + +int main(int argc, char **argv) +{ + int len, keylen, datalen, res; struct tms t0, t; + printf("%s %s %s\n", DFSRSA_TITLE, DFSRSA_VERSION, DFSRSA_COPYRIGHT); + miller_test(); + for(keylen = MINLEN; keylen <= MAXLEN; keylen <<= 1) { + len = keylen / 2; + for(datalen = STARTLEN * len; datalen <= ENDLEN * len; datalen += len) { + printf("%s test: keylen = %4d bits, datalen = %5d bits, result: ", + argv[0], len * DFSRSA_T_BITS, datalen * DFSRSA_T_BITS); + fflush(stdout); + times(&t0); + res = work(keylen, datalen); + times(&t); + if(res) printf("error %d\n", res); + else printf("OK, time = %8.4lf + %8.4lf s\n", + (double)(t.tms_utime - t0.tms_utime) / sysconf(_SC_CLK_TCK), + (double)(t.tms_stime - t0.tms_stime) / sysconf(_SC_CLK_TCK) + ); + fflush(stdout); + } + } + return 0; +} + +#endif diff --git a/ldus/source/include/ldus/atomic.h b/ldus/source/include/ldus/atomic.h index 5264029f..604b5cd9 100644 --- a/ldus/source/include/ldus/atomic.h +++ b/ldus/source/include/ldus/atomic.h @@ -1,125 +1,125 @@ -/* атомарные операции, T11.596-T13.155; $DVS:time$ */ - -#ifndef LDUS_ATOMIC_H_INCLUDED -#define LDUS_ATOMIC_H_INCLUDED - -#include - -#define LDUS_USE_ATOMIC - -#ifndef _GCC_VERSION -#define _GCC_VERSION (__GNUC__ * 10000 | __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) -#endif - -#if _GCC_VERSION <= 40603 -#define __atomic_load_n(ptr, mode) (*(ptr)) -#define __atomic_store_n(ptr, value, mode) (*(ptr) = (value)) -#define __atomic_add_fetch(ptr, value, mode) __sync_add_and_fetch(ptr, value) -#define __atomic_sub_fetch(ptr, value, mode) __sync_sub_and_fetch(ptr, value) -#define __atomic_compare_exchange_n(ptr, old_, new_, param, mode1, mode2) (*(old_) = __sync_val_compare_and_swap(ptr, *(old_), new_)) -#endif - -typedef uint32_t ldus_atomic; -typedef uint64_t ldus_atomic64; - -static inline uint32_t ldus_atomic_read(volatile ldus_atomic *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); -#else - return *ptr; -#endif -} - -static inline uint32_t ldus_atomic_inc_return(volatile ldus_atomic *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST); -#else - return ++*ptr; -#endif -} - -static inline uint32_t ldus_atomic_add_return(volatile ldus_atomic *ptr, uint32_t value) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); -#else - return *ptr += value; -#endif -} - -static inline uint32_t ldus_atomic_dec_return(volatile ldus_atomic *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST); -#else - return --*ptr; -#endif -} - -static inline void ldus_atomic_set(volatile ldus_atomic *ptr, uint32_t value) { -#if defined(LDUS_USE_ATOMIC) - __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); -#else - *ptr = value; -#endif -} - -static inline uint32_t ldus_atomic_cmpxchg(volatile ldus_atomic *ptr, uint32_t old_, uint32_t new_) { -#if defined(LDUS_USE_ATOMIC) - __atomic_compare_exchange_n(ptr, &old_, new_, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return old_; -#else - if (*ptr == old_) { *ptr = new_; return old_; } - else return *ptr; -#endif -} - -static inline uint64_t ldus_atomic64_read(volatile ldus_atomic64 *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); -#else - return *ptr; -#endif -} - -static inline uint64_t ldus_atomic64_inc_return(volatile ldus_atomic64 *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST); -#else - return ++*ptr; -#endif -} - -static inline uint64_t ldus_atomic64_add_return(volatile ldus_atomic64 *ptr, uint64_t value) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); -#else - return *ptr += value; -#endif -} - -static inline uint64_t ldus_atomic64_dec_return(volatile ldus_atomic64 *ptr) { -#if defined(LDUS_USE_ATOMIC) - return __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST); -#else - return --*ptr; -#endif -} - -static inline void ldus_atomic64_set(volatile ldus_atomic64 *ptr, uint64_t value) { -#if defined(LDUS_USE_ATOMIC) - __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); -#else - *ptr = value; -#endif -} - -static inline uint64_t ldus_atomic64_cmpxchg(volatile ldus_atomic64 *ptr, uint64_t old_, uint64_t new_) { -#if defined(LDUS_USE_ATOMIC) - __atomic_compare_exchange_n(ptr, &old_, new_, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return old_; -#else - if (*ptr == old_) { *ptr = new_; return old_; } - else return *ptr; -#endif -} - -#endif +/* атомарные операции, T11.596-T13.155; $DVS:time$ */ + +#ifndef LDUS_ATOMIC_H_INCLUDED +#define LDUS_ATOMIC_H_INCLUDED + +#include + +#define LDUS_USE_ATOMIC + +#ifndef _GCC_VERSION +#define _GCC_VERSION (__GNUC__ * 10000 | __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if _GCC_VERSION <= 40603 +#define __atomic_load_n(ptr, mode) (*(ptr)) +#define __atomic_store_n(ptr, value, mode) (*(ptr) = (value)) +#define __atomic_add_fetch(ptr, value, mode) __sync_add_and_fetch(ptr, value) +#define __atomic_sub_fetch(ptr, value, mode) __sync_sub_and_fetch(ptr, value) +#define __atomic_compare_exchange_n(ptr, old_, new_, param, mode1, mode2) (*(old_) = __sync_val_compare_and_swap(ptr, *(old_), new_)) +#endif + +typedef uint32_t ldus_atomic; +typedef uint64_t ldus_atomic64; + +static inline uint32_t ldus_atomic_read(volatile ldus_atomic *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); +#else + return *ptr; +#endif +} + +static inline uint32_t ldus_atomic_inc_return(volatile ldus_atomic *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST); +#else + return ++*ptr; +#endif +} + +static inline uint32_t ldus_atomic_add_return(volatile ldus_atomic *ptr, uint32_t value) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); +#else + return *ptr += value; +#endif +} + +static inline uint32_t ldus_atomic_dec_return(volatile ldus_atomic *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST); +#else + return --*ptr; +#endif +} + +static inline void ldus_atomic_set(volatile ldus_atomic *ptr, uint32_t value) { +#if defined(LDUS_USE_ATOMIC) + __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); +#else + *ptr = value; +#endif +} + +static inline uint32_t ldus_atomic_cmpxchg(volatile ldus_atomic *ptr, uint32_t old_, uint32_t new_) { +#if defined(LDUS_USE_ATOMIC) + __atomic_compare_exchange_n(ptr, &old_, new_, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return old_; +#else + if (*ptr == old_) { *ptr = new_; return old_; } + else return *ptr; +#endif +} + +static inline uint64_t ldus_atomic64_read(volatile ldus_atomic64 *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_load_n(ptr, __ATOMIC_SEQ_CST); +#else + return *ptr; +#endif +} + +static inline uint64_t ldus_atomic64_inc_return(volatile ldus_atomic64 *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST); +#else + return ++*ptr; +#endif +} + +static inline uint64_t ldus_atomic64_add_return(volatile ldus_atomic64 *ptr, uint64_t value) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_add_fetch(ptr, value, __ATOMIC_SEQ_CST); +#else + return *ptr += value; +#endif +} + +static inline uint64_t ldus_atomic64_dec_return(volatile ldus_atomic64 *ptr) { +#if defined(LDUS_USE_ATOMIC) + return __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST); +#else + return --*ptr; +#endif +} + +static inline void ldus_atomic64_set(volatile ldus_atomic64 *ptr, uint64_t value) { +#if defined(LDUS_USE_ATOMIC) + __atomic_store_n(ptr, value, __ATOMIC_SEQ_CST); +#else + *ptr = value; +#endif +} + +static inline uint64_t ldus_atomic64_cmpxchg(volatile ldus_atomic64 *ptr, uint64_t old_, uint64_t new_) { +#if defined(LDUS_USE_ATOMIC) + __atomic_compare_exchange_n(ptr, &old_, new_, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + return old_; +#else + if (*ptr == old_) { *ptr = new_; return old_; } + else return *ptr; +#endif +} + +#endif diff --git a/ldus/source/include/ldus/list.h b/ldus/source/include/ldus/list.h index 71287bd4..977cb304 100644 --- a/ldus/source/include/ldus/list.h +++ b/ldus/source/include/ldus/list.h @@ -1,46 +1,46 @@ -/* работа с циклическим списком, T10.544-T11.692; $DVS:time$ */ - -#ifndef LDUS_LIST_H_INCLUDED -#define LDUS_LIST_H_INCLUDED - -#include - -// get rid of access memory 0x0000000000000000 runtime error which will cause dnet restart. -#define container_of(ptr, type, member) ((type *)((char *)(ptr) - (size_t)offsetof(type, member))) -//#define container_of(ptr, type, member) ((type *)((char *)(ptr) - (size_t)&((type *)0)->member)) - -/* doubly linked list */ -struct list { - struct list *prev; - struct list *next; -}; - -/* initialize an empty list */ -static inline void list_init(struct list *head) { - head->prev = head->next = head; -} - -/* adds a node to the end of the list */ -static inline void list_insert(struct list *head, struct list *node) { - node->prev = head; - node->next = head->next; - node->next->prev = head->next = node; -} - -/* adds the node to the beginning of the list */ -static inline void list_insert_before(struct list *head, struct list *node) { - node->next = head; - node->prev = head->prev; - node->prev->next = head->prev = node; -} - -/* remove the node from the list */ -static inline void list_remove(struct list *node) { - struct list *prev = node->prev; - struct list *next = node->next; - prev->next = next; - next->prev = prev; - node->prev = node->next = node; -} - -#endif +/* работа с циклическим списком, T10.544-T11.692; $DVS:time$ */ + +#ifndef LDUS_LIST_H_INCLUDED +#define LDUS_LIST_H_INCLUDED + +#include + +// get rid of access memory 0x0000000000000000 runtime error which will cause dnet restart. +#define container_of(ptr, type, member) ((type *)((char *)(ptr) - (size_t)offsetof(type, member))) +//#define container_of(ptr, type, member) ((type *)((char *)(ptr) - (size_t)&((type *)0)->member)) + +/* doubly linked list */ +struct list { + struct list *prev; + struct list *next; +}; + +/* initialize an empty list */ +static inline void list_init(struct list *head) { + head->prev = head->next = head; +} + +/* adds a node to the end of the list */ +static inline void list_insert(struct list *head, struct list *node) { + node->prev = head; + node->next = head->next; + node->next->prev = head->next = node; +} + +/* adds the node to the beginning of the list */ +static inline void list_insert_before(struct list *head, struct list *node) { + node->next = head; + node->prev = head->prev; + node->prev->next = head->prev = node; +} + +/* remove the node from the list */ +static inline void list_remove(struct list *node) { + struct list *prev = node->prev; + struct list *next = node->next; + prev->next = next; + next->prev = prev; + node->prev = node->next = node; +} + +#endif diff --git a/ldus/source/include/ldus/rbtree.h b/ldus/source/include/ldus/rbtree.h index 954ed943..bd06e22c 100644 --- a/ldus/source/include/ldus/rbtree.h +++ b/ldus/source/include/ldus/rbtree.h @@ -1,216 +1,216 @@ -/* red-black tree, T11.684-T13.285; $DVS:time$ */ - -#ifndef LDUS_RBTREE_H_INCLUDED -#define LDUS_RBTREE_H_INCLUDED - -#include - -struct ldus_rbtree { - struct ldus_rbtree *left; - struct ldus_rbtree *right; -}; - -static inline struct ldus_rbtree *_rbtree_ptr(struct ldus_rbtree *ptr) { return (struct ldus_rbtree *)((uintptr_t)ptr & ~(uintptr_t)1); } - -static inline int _rbtree_color(struct ldus_rbtree *ptr) { return (uintptr_t)ptr & 1; } - -static inline struct ldus_rbtree *_rbtree_set_color(struct ldus_rbtree *ptr, int color) { return (struct ldus_rbtree *)(((uintptr_t)ptr & ~(uintptr_t)1) | color); } - -static inline void ldus_rbtree_init(struct ldus_rbtree **proot) { *proot = 0; } - -static inline void ldus_rbtree_walk_up(struct ldus_rbtree *root, void (*callback)(struct ldus_rbtree *node)) { - if (root) { - root = _rbtree_ptr(root); - if (root->left) ldus_rbtree_walk_up(root->left, callback); - if (root->right) ldus_rbtree_walk_up(root->right, callback); - callback(root); - } -} - -static inline void ldus_rbtree_walk_right(struct ldus_rbtree *root, void (*callback)(struct ldus_rbtree *node)) { - while (root) { - root = _rbtree_ptr(root); - if (root->left) ldus_rbtree_walk_right(root->left, callback); - callback(root); - root = root->right; - } -} - -static inline void _rbtree_rotate_left(struct ldus_rbtree **proot) { - struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(root->right); - int color = _rbtree_color(root->right); - *proot = _rbtree_set_color(node, _rbtree_color(*proot)); - root->right = node->left; - node->left = _rbtree_set_color(root, color); -} - -static inline void _rbtree_rotate_right(struct ldus_rbtree **proot) { - struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(root->left); - int color = _rbtree_color(root->left); - *proot = _rbtree_set_color(node, _rbtree_color(*proot)); - root->left = node->right; - node->right = _rbtree_set_color(root, color); -} - -static inline int _rbtree_insert_balance_left(struct ldus_rbtree **proot, int res) { - struct ldus_rbtree *root; - if (res <= 0) return res; - root = _rbtree_ptr(*proot); - if (res == 1) { - root->left = _rbtree_set_color(root->left, 1); - if (!_rbtree_color(*proot)) return 0; - return 2; - } else { - if (_rbtree_color(root->right)) { - root->left = _rbtree_set_color(root->left, 0); - root->right = _rbtree_set_color(root->right, 0); - return 1; - } - if (res == 3) _rbtree_rotate_left(&root->left); - _rbtree_rotate_right(proot); - return 0; - } -} - -static inline int _rbtree_insert_balance_right(struct ldus_rbtree **proot, int res) { - struct ldus_rbtree *root; - if (res <= 0) return res; - root = _rbtree_ptr(*proot); - if (res == 1) { - root->right = _rbtree_set_color(root->right, 1); - if (!_rbtree_color(*proot)) return 0; - return 3; - } else { - if (_rbtree_color(root->left)) { - root->left = _rbtree_set_color(root->left, 0); - root->right = _rbtree_set_color(root->right, 0); - return 1; - } - if (res == 2) _rbtree_rotate_right(&root->right); - _rbtree_rotate_left(proot); - return 0; - } -} - -static inline int _rbtree_remove_balance_left(struct ldus_rbtree **proot, int res) { - struct ldus_rbtree *root, *s; - if (res <= 0) return res; - root = _rbtree_ptr(*proot); - if (_rbtree_color(root->right)) { - _rbtree_rotate_left(proot); - proot = &_rbtree_ptr(*proot)->left; - } - s = _rbtree_ptr(root->right); - if (!_rbtree_color(s->right)) { - if (!_rbtree_color(s->left)) { - root->right = _rbtree_set_color(s, 1); - if (!_rbtree_color(*proot)) return 1; - *proot = _rbtree_set_color(root, 0); - return 0; - } - _rbtree_rotate_right(&root->right); - s = _rbtree_ptr(root->right); - } - _rbtree_rotate_left(proot); - s->right = _rbtree_set_color(s->right, 0); - return 0; -} - -static inline int _rbtree_remove_balance_right(struct ldus_rbtree **proot, int res) { - struct ldus_rbtree *root, *s; - if (res <= 0) return res; - root = _rbtree_ptr(*proot); - if (_rbtree_color(root->left)) { - _rbtree_rotate_right(proot); - proot = &_rbtree_ptr(*proot)->right; - } - s = _rbtree_ptr(root->left); - if (!_rbtree_color(s->left)) { - if (!_rbtree_color(s->right)) { - root->left = _rbtree_set_color(s, 1); - if (!_rbtree_color(*proot)) return 1; - *proot = _rbtree_set_color(root, 0); - return 0; - } - _rbtree_rotate_left(&root->left); - s = _rbtree_ptr(root->left); - } - _rbtree_rotate_right(proot); - s->left = _rbtree_set_color(s->left, 0); - return 0; -} - -static inline int _rbtree_remove_left(struct ldus_rbtree **proot, struct ldus_rbtree **pnode) { - struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(*pnode); - if (root->right) { - int res = _rbtree_remove_left(&root->right, pnode); - if (proot == &node->left) proot = &_rbtree_ptr(*pnode)->left; - return _rbtree_remove_balance_right(proot, res); - } else { - int color = _rbtree_color(*proot); - *proot = root->left; - root->left = node->left; - root->right = node->right; - *pnode = _rbtree_set_color(root, _rbtree_color(*pnode)); - if (color) return 0; - if (_rbtree_color(*proot)) { - if (*proot == root->left) proot = &root->left; - *proot = _rbtree_set_color(*proot, 0); - return 0; - } - return 1; - } -} - -static inline int _rbtree_remove_right(struct ldus_rbtree **proot, struct ldus_rbtree **pnode) { - struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(*pnode); - if (root->left) { - int res = _rbtree_remove_right(&root->left, pnode); - if (proot == &node->right) proot = &_rbtree_ptr(*pnode)->right; - return _rbtree_remove_balance_left(proot, res); - } else { - int color = _rbtree_color(*proot); - *proot = root->right; - root->left = node->left; - root->right = node->right; - *pnode = _rbtree_set_color(root, _rbtree_color(*pnode)); - if (color) return 0; - if (_rbtree_color(*proot)) { - if (*proot == root->right) proot = &root->right; - *proot = _rbtree_set_color(*proot, 0); - return 0; - } - return 1; - } -} - -#define ldus_rbtree_define_prefix(lessthan, prefix, postfix) \ - \ -prefix int ldus_rbtree_insert(struct ldus_rbtree **proot, struct ldus_rbtree *node) { \ - struct ldus_rbtree *root = _rbtree_ptr(*proot); \ - if (!root) { *proot = node, node->left = node->right = 0; return 1; } \ - if (lessthan(node, root)) return _rbtree_insert_balance_left (proot, ldus_rbtree_insert(&root->left, node)); \ - if (lessthan(root, node)) return _rbtree_insert_balance_right(proot, ldus_rbtree_insert(&root->right, node)); \ - return -1; \ -} \ - \ -prefix struct ldus_rbtree *ldus_rbtree_find(struct ldus_rbtree *root, struct ldus_rbtree *node) postfix { \ - root = _rbtree_ptr(root); \ - if (!root) return 0; \ - if (lessthan(node, root)) return ldus_rbtree_find(root->left, node); \ - if (lessthan(root, node)) return ldus_rbtree_find(root->right, node); \ - return root; \ -} \ - \ -prefix int ldus_rbtree_remove(struct ldus_rbtree **proot, struct ldus_rbtree *node) { \ - struct ldus_rbtree *root = _rbtree_ptr(*proot); \ - if (!root) return -1; \ - if (lessthan(node, root)) return _rbtree_remove_balance_left (proot, ldus_rbtree_remove (&root->left, node )); \ - if (lessthan(root, node)) return _rbtree_remove_balance_right(proot, ldus_rbtree_remove (&root->right, node )); \ - if (root->left ) return _rbtree_remove_balance_left (proot, _rbtree_remove_left (&root->left, proot)); \ - if (root->right) return _rbtree_remove_balance_right(proot, _rbtree_remove_right(&root->right, proot)); \ - if (_rbtree_color(*proot)) { *proot = 0; return 0; } \ - *proot = 0; return 1; \ -} - -#endif +/* red-black tree, T11.684-T13.285; $DVS:time$ */ + +#ifndef LDUS_RBTREE_H_INCLUDED +#define LDUS_RBTREE_H_INCLUDED + +#include + +struct ldus_rbtree { + struct ldus_rbtree *left; + struct ldus_rbtree *right; +}; + +static inline struct ldus_rbtree *_rbtree_ptr(struct ldus_rbtree *ptr) { return (struct ldus_rbtree *)((uintptr_t)ptr & ~(uintptr_t)1); } + +static inline int _rbtree_color(struct ldus_rbtree *ptr) { return (uintptr_t)ptr & 1; } + +static inline struct ldus_rbtree *_rbtree_set_color(struct ldus_rbtree *ptr, int color) { return (struct ldus_rbtree *)(((uintptr_t)ptr & ~(uintptr_t)1) | color); } + +static inline void ldus_rbtree_init(struct ldus_rbtree **proot) { *proot = 0; } + +static inline void ldus_rbtree_walk_up(struct ldus_rbtree *root, void (*callback)(struct ldus_rbtree *node)) { + if (root) { + root = _rbtree_ptr(root); + if (root->left) ldus_rbtree_walk_up(root->left, callback); + if (root->right) ldus_rbtree_walk_up(root->right, callback); + callback(root); + } +} + +static inline void ldus_rbtree_walk_right(struct ldus_rbtree *root, void (*callback)(struct ldus_rbtree *node)) { + while (root) { + root = _rbtree_ptr(root); + if (root->left) ldus_rbtree_walk_right(root->left, callback); + callback(root); + root = root->right; + } +} + +static inline void _rbtree_rotate_left(struct ldus_rbtree **proot) { + struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(root->right); + int color = _rbtree_color(root->right); + *proot = _rbtree_set_color(node, _rbtree_color(*proot)); + root->right = node->left; + node->left = _rbtree_set_color(root, color); +} + +static inline void _rbtree_rotate_right(struct ldus_rbtree **proot) { + struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(root->left); + int color = _rbtree_color(root->left); + *proot = _rbtree_set_color(node, _rbtree_color(*proot)); + root->left = node->right; + node->right = _rbtree_set_color(root, color); +} + +static inline int _rbtree_insert_balance_left(struct ldus_rbtree **proot, int res) { + struct ldus_rbtree *root; + if (res <= 0) return res; + root = _rbtree_ptr(*proot); + if (res == 1) { + root->left = _rbtree_set_color(root->left, 1); + if (!_rbtree_color(*proot)) return 0; + return 2; + } else { + if (_rbtree_color(root->right)) { + root->left = _rbtree_set_color(root->left, 0); + root->right = _rbtree_set_color(root->right, 0); + return 1; + } + if (res == 3) _rbtree_rotate_left(&root->left); + _rbtree_rotate_right(proot); + return 0; + } +} + +static inline int _rbtree_insert_balance_right(struct ldus_rbtree **proot, int res) { + struct ldus_rbtree *root; + if (res <= 0) return res; + root = _rbtree_ptr(*proot); + if (res == 1) { + root->right = _rbtree_set_color(root->right, 1); + if (!_rbtree_color(*proot)) return 0; + return 3; + } else { + if (_rbtree_color(root->left)) { + root->left = _rbtree_set_color(root->left, 0); + root->right = _rbtree_set_color(root->right, 0); + return 1; + } + if (res == 2) _rbtree_rotate_right(&root->right); + _rbtree_rotate_left(proot); + return 0; + } +} + +static inline int _rbtree_remove_balance_left(struct ldus_rbtree **proot, int res) { + struct ldus_rbtree *root, *s; + if (res <= 0) return res; + root = _rbtree_ptr(*proot); + if (_rbtree_color(root->right)) { + _rbtree_rotate_left(proot); + proot = &_rbtree_ptr(*proot)->left; + } + s = _rbtree_ptr(root->right); + if (!_rbtree_color(s->right)) { + if (!_rbtree_color(s->left)) { + root->right = _rbtree_set_color(s, 1); + if (!_rbtree_color(*proot)) return 1; + *proot = _rbtree_set_color(root, 0); + return 0; + } + _rbtree_rotate_right(&root->right); + s = _rbtree_ptr(root->right); + } + _rbtree_rotate_left(proot); + s->right = _rbtree_set_color(s->right, 0); + return 0; +} + +static inline int _rbtree_remove_balance_right(struct ldus_rbtree **proot, int res) { + struct ldus_rbtree *root, *s; + if (res <= 0) return res; + root = _rbtree_ptr(*proot); + if (_rbtree_color(root->left)) { + _rbtree_rotate_right(proot); + proot = &_rbtree_ptr(*proot)->right; + } + s = _rbtree_ptr(root->left); + if (!_rbtree_color(s->left)) { + if (!_rbtree_color(s->right)) { + root->left = _rbtree_set_color(s, 1); + if (!_rbtree_color(*proot)) return 1; + *proot = _rbtree_set_color(root, 0); + return 0; + } + _rbtree_rotate_left(&root->left); + s = _rbtree_ptr(root->left); + } + _rbtree_rotate_right(proot); + s->left = _rbtree_set_color(s->left, 0); + return 0; +} + +static inline int _rbtree_remove_left(struct ldus_rbtree **proot, struct ldus_rbtree **pnode) { + struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(*pnode); + if (root->right) { + int res = _rbtree_remove_left(&root->right, pnode); + if (proot == &node->left) proot = &_rbtree_ptr(*pnode)->left; + return _rbtree_remove_balance_right(proot, res); + } else { + int color = _rbtree_color(*proot); + *proot = root->left; + root->left = node->left; + root->right = node->right; + *pnode = _rbtree_set_color(root, _rbtree_color(*pnode)); + if (color) return 0; + if (_rbtree_color(*proot)) { + if (*proot == root->left) proot = &root->left; + *proot = _rbtree_set_color(*proot, 0); + return 0; + } + return 1; + } +} + +static inline int _rbtree_remove_right(struct ldus_rbtree **proot, struct ldus_rbtree **pnode) { + struct ldus_rbtree *root = _rbtree_ptr(*proot), *node = _rbtree_ptr(*pnode); + if (root->left) { + int res = _rbtree_remove_right(&root->left, pnode); + if (proot == &node->right) proot = &_rbtree_ptr(*pnode)->right; + return _rbtree_remove_balance_left(proot, res); + } else { + int color = _rbtree_color(*proot); + *proot = root->right; + root->left = node->left; + root->right = node->right; + *pnode = _rbtree_set_color(root, _rbtree_color(*pnode)); + if (color) return 0; + if (_rbtree_color(*proot)) { + if (*proot == root->right) proot = &root->right; + *proot = _rbtree_set_color(*proot, 0); + return 0; + } + return 1; + } +} + +#define ldus_rbtree_define_prefix(lessthan, prefix, postfix) \ + \ +prefix int ldus_rbtree_insert(struct ldus_rbtree **proot, struct ldus_rbtree *node) { \ + struct ldus_rbtree *root = _rbtree_ptr(*proot); \ + if (!root) { *proot = node, node->left = node->right = 0; return 1; } \ + if (lessthan(node, root)) return _rbtree_insert_balance_left (proot, ldus_rbtree_insert(&root->left, node)); \ + if (lessthan(root, node)) return _rbtree_insert_balance_right(proot, ldus_rbtree_insert(&root->right, node)); \ + return -1; \ +} \ + \ +prefix struct ldus_rbtree *ldus_rbtree_find(struct ldus_rbtree *root, struct ldus_rbtree *node) postfix { \ + root = _rbtree_ptr(root); \ + if (!root) return 0; \ + if (lessthan(node, root)) return ldus_rbtree_find(root->left, node); \ + if (lessthan(root, node)) return ldus_rbtree_find(root->right, node); \ + return root; \ +} \ + \ +prefix int ldus_rbtree_remove(struct ldus_rbtree **proot, struct ldus_rbtree *node) { \ + struct ldus_rbtree *root = _rbtree_ptr(*proot); \ + if (!root) return -1; \ + if (lessthan(node, root)) return _rbtree_remove_balance_left (proot, ldus_rbtree_remove (&root->left, node )); \ + if (lessthan(root, node)) return _rbtree_remove_balance_right(proot, ldus_rbtree_remove (&root->right, node )); \ + if (root->left ) return _rbtree_remove_balance_left (proot, _rbtree_remove_left (&root->left, proot)); \ + if (root->right) return _rbtree_remove_balance_right(proot, _rbtree_remove_right(&root->right, proot)); \ + if (_rbtree_color(*proot)) { *proot = 0; return 0; } \ + *proot = 0; return 1; \ +} + +#endif