online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#include <stdio.h> #include <string.h> #include <time.h> #include <stdint.h> #include <pthread.h> #include <limits.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #ifndef TLS #define TLS __thread #endif TLS char STORAGE_PATH[PATH_MAX] = "/var/lib/ripple/data.bin"; TLS char USERNAME[33] = "Default"; TLS char SERVER_ADDRESS[33] = "127.0.0.1"; TLS unsigned short PORT = 2012; #define SECRET_KEY { \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, \ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 \ } TLS unsigned char secret_block[32+4] = SECRET_KEY; /* * FIPS 180-2 SHA-224/256/384/512 implementation * Last update: 02/02/2007 * Issue date: 04/30/2005 * * Copyright (C) 2013, Con Kolivas <[email protected]> * Copyright (C) 2005, 2007 Olivier Gay <[email protected]> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define SHA256_DIGEST_SIZE ( 256 / 8) #define SHA256_BLOCK_SIZE ( 512 / 8) #define SHFR(x, n) (x >> n) #define ROTR(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) #define CH(x, y, z) ((x & y) ^ (~x & z)) #define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) #define SHA256_F1(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) #define SHA256_F2(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) #define SHA256_F3(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHFR(x, 3)) #define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10)) typedef struct { unsigned int tot_len; unsigned int len; unsigned char block[2 * SHA256_BLOCK_SIZE]; uint32_t h[8]; } sha256_ctx; #define UNPACK32(x, str) \ { \ *((str) + 3) = (uint8_t) ((x) ); \ *((str) + 2) = (uint8_t) ((x) >> 8); \ *((str) + 1) = (uint8_t) ((x) >> 16); \ *((str) + 0) = (uint8_t) ((x) >> 24); \ } #define PACK32(str, x) \ { \ *(x) = ((uint32_t) *((str) + 3) ) \ | ((uint32_t) *((str) + 2) << 8) \ | ((uint32_t) *((str) + 1) << 16) \ | ((uint32_t) *((str) + 0) << 24); \ } #define SHA256_SCR(i) \ { \ w[i] = SHA256_F4(w[i - 2]) + w[i - 7] \ + SHA256_F3(w[i - 15]) + w[i - 16]; \ } uint32_t sha256_h0[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; uint32_t sha256_k[64] = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; /* SHA-256 functions */ void sha256_transf(sha256_ctx *ctx, const unsigned char *message, unsigned int block_nb) { uint32_t w[64]; uint32_t wv[8]; uint32_t t1, t2; const unsigned char *sub_block; int i; int j; for (i = 0; i < (int) block_nb; i++) { sub_block = message + (i << 6); for (j = 0; j < 16; j++) { PACK32(&sub_block[j << 2], &w[j]); } for (j = 16; j < 64; j++) { SHA256_SCR(j); } for (j = 0; j < 8; j++) { wv[j] = ctx->h[j]; } for (j = 0; j < 64; j++) { t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6]) + sha256_k[j] + w[j]; t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]); wv[7] = wv[6]; wv[6] = wv[5]; wv[5] = wv[4]; wv[4] = wv[3] + t1; wv[3] = wv[2]; wv[2] = wv[1]; wv[1] = wv[0]; wv[0] = t1 + t2; } for (j = 0; j < 8; j++) { ctx->h[j] += wv[j]; } } } void sha256_init(sha256_ctx *ctx) { int i; for (i = 0; i < 8; i++) { ctx->h[i] = sha256_h0[i]; } ctx->len = 0; ctx->tot_len = 0; } void sha256_update(sha256_ctx *ctx, const unsigned char *message, unsigned int len) { unsigned int block_nb; unsigned int new_len, rem_len, tmp_len; const unsigned char *shifted_message; tmp_len = SHA256_BLOCK_SIZE - ctx->len; rem_len = len < tmp_len ? len : tmp_len; memcpy(&ctx->block[ctx->len], message, rem_len); if (ctx->len + len < SHA256_BLOCK_SIZE) { ctx->len += len; return; } new_len = len - rem_len; block_nb = new_len / SHA256_BLOCK_SIZE; shifted_message = message + rem_len; sha256_transf(ctx, ctx->block, 1); sha256_transf(ctx, shifted_message, block_nb); rem_len = new_len % SHA256_BLOCK_SIZE; memcpy(ctx->block, &shifted_message[block_nb << 6], rem_len); ctx->len = rem_len; ctx->tot_len += (block_nb + 1) << 6; } void sha256_final(sha256_ctx *ctx, unsigned char *digest) { unsigned int block_nb; unsigned int pm_len; unsigned int len_b; int i; block_nb = (1 + ((SHA256_BLOCK_SIZE - 9) < (ctx->len % SHA256_BLOCK_SIZE))); len_b = (ctx->tot_len + ctx->len) << 3; pm_len = block_nb << 6; memset(ctx->block + ctx->len, 0, pm_len - ctx->len); ctx->block[ctx->len] = 0x80; UNPACK32(len_b, ctx->block + pm_len - 4); sha256_transf(ctx, ctx->block, block_nb); for (i = 0 ; i < 8; i++) { UNPACK32(ctx->h[i], &digest[i << 2]); } } void sha256(const unsigned char *message, unsigned int len, unsigned char *digest) { sha256_ctx ctx; sha256_init(&ctx); sha256_update(&ctx, message, len); sha256_final(&ctx, digest); } TLS unsigned char one_time_key_buf[SHA256_DIGEST_SIZE]; #define MAX_DG 508 TLS unsigned char send_buf[MAX_DG]; void compute_one_time_key() { memcpy(secret_block + 32, send_buf + 1, 4); sha256(secret_block, 36, one_time_key_buf); } #define SCHEDULER_PERIOD 60 #define BUFFER_SIZE 16 #define TIMEOUT 300 #define MAX_DEPTH 7 #define PENALTY_RATE_SEC 300 #define FEE_RATE 0.02 #define COMMIT 0 #define SEAL 1 #define FINALIZE 2 #define CANCEL 3 #define CLEANUP 4 #define SYNCING_MASK 0x06 struct account { unsigned char username[32]; unsigned char server_address[32]; unsigned short port; unsigned char secret_key[32]; unsigned int counter_in; unsigned int counter_out; long long balance; unsigned long long creditlimit; unsigned long long creditlimit_in; unsigned char ack_pending : 1; float width; unsigned long long tax_syncing; unsigned long long sync_in; unsigned long long sync_out; }; struct payment { unsigned char identifier[32]; unsigned long long amount; signed char incoming; signed char outgoing; unsigned int penalty_rate; unsigned long long fee_in; unsigned long long fee_out; unsigned long long commit_penalty; unsigned long long finalize_out; unsigned char preimage[32]; unsigned char status : 3; unsigned char counterpart : 1; unsigned char commit_out : 1; unsigned char ack_preimage : 1; unsigned char ack_sync : 1; unsigned char synced : 1; long long created_at; unsigned long long tax; }; struct receipt { unsigned char identifier[32]; unsigned char username[32]; unsigned char server_address[32]; long long amount; long long timestamp; }; struct storage { unsigned int counter; struct account accounts[BUFFER_SIZE]; unsigned short acc_bitmap; struct payment payments[BUFFER_SIZE]; unsigned char num_payments; struct receipt receipts[BUFFER_SIZE]; unsigned char receipts_head; float trust_index; }; TLS struct storage storage; void save_storage(void) { FILE *fp = fopen(STORAGE_PATH, "wb"); if (!fp) return; fwrite(&storage, sizeof(struct storage), 1, fp); fclose(fp); } void load_storage() { FILE *fp = fopen(STORAGE_PATH, "rb"); if (!fp) return; fread(&storage, sizeof(struct storage), 1, fp); fclose(fp); } signed char lookup_account_idx(unsigned char *identifier) { unsigned short temp_bitmap = storage.acc_bitmap; signed char i = 0; while (temp_bitmap) { struct account *a = &storage.accounts[i]; if ((temp_bitmap & 1) && strncmp(a->username, identifier, 32) == 0 && strncmp(a->server_address, identifier + 32, 32) == 0) { return i; } i++; temp_bitmap >>= 1; }; return -1; } TLS struct { unsigned char username[32]; unsigned char server_address[32]; unsigned short port; unsigned char secret_key[32]; unsigned int counter_in; unsigned int counter_out; } counterpart; struct pathfinding { unsigned char identifier[32]; unsigned long long amount; signed char incoming; signed char outgoing; unsigned int penalty_rate; unsigned long long fee; unsigned char hops; unsigned char depth; unsigned char counterpart : 1; unsigned char in_or_out : 1; unsigned char commit : 1; long long timeout; unsigned long long tax; }; TLS struct pathfinding paths[BUFFER_SIZE+1]; TLS unsigned char num_paths; TLS unsigned char preimage[32]; TLS unsigned long long tax_buffer[BUFFER_SIZE]; signed char get_pathfinding(unsigned char *payment_id) { signed char idx = 0; while (idx < num_paths) { if (memcmp(paths[idx].identifier, payment_id, 32) == 0) { break; } idx++; } if (idx == num_paths) { return -1; } if (paths[idx].timeout < time(NULL)) { paths[idx] = paths[--num_paths]; return -1; } return idx; } void set_commit(struct pathfinding *pf) { pf->timeout = time(NULL) + TIMEOUT; pf->commit = 1; } unsigned long long fee_in(struct pathfinding *pf) { return ((unsigned long long)pf->hops + 1) * pf->fee; } unsigned long long fee_out(struct pathfinding *pf) { return (unsigned long long)pf->hops * pf->fee; } unsigned long long preview_bandwidth_in(signed char account_idx) { struct account *acc = &storage.accounts[account_idx]; long long bandwidth = (long long)acc->creditlimit - acc->balance; for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->incoming == account_idx) { bandwidth -= (long long)(p->amount + p->fee_in + p->tax); } } for (unsigned char i = 0; i < num_paths; i++) { struct pathfinding *pf = &paths[i]; if (paths[i].timeout < time(NULL)) { paths[i] = paths[--num_paths]; i--; continue; } if (pf->incoming == account_idx && pf->commit) { bandwidth -= (long long)(pf->amount + fee_in(pf) + pf->tax); } } return (unsigned long long)(bandwidth > 0 ? bandwidth : 0); } unsigned long long preview_bandwidth_out(signed char account_idx) { struct account *acc = &storage.accounts[account_idx]; long long bandwidth = (long long)acc->creditlimit_in + acc->balance; for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->outgoing == account_idx) { bandwidth -= (long long)(p->amount + p->fee_out + p->tax); } } for (unsigned char i = 0; i < num_paths; i++) { struct pathfinding *pf = &paths[i]; if (paths[i].timeout < time(NULL)) { paths[i] = paths[--num_paths]; i--; continue; } if (pf->outgoing == account_idx && pf->commit) { bandwidth -= (long long)(pf->amount + fee_out(pf) + pf->tax); } } return (unsigned long long)(bandwidth > 0 ? bandwidth : 0); } #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/time.h> #define DATA_TYPE 0 #define ACK_TYPE 1 #define HEADER_SIZE 5 #define MAX_RETRIES 8 #define BASE_DELAY 1 #define MAX_DELAY 16 #define ACCOUNT_SESSION 0 #define USER_SESSION 2 #define COUNTERPART_SESSION 4 #define USER_SENDER BUFFER_SIZE #define CPT_SENDER BUFFER_SIZE+1 #define TX_ENVELOPE (1+32+64+4+32) #define REQ_ENVELOPE (1+4+32) short endianess; TLS int sockfd; TLS time_t next_timer; struct datagram { unsigned char payload[MAX_DG]; unsigned short len; struct sockaddr_in addr; }; struct send_rtx { signed char sender_idx; struct datagram send_queue[BUFFER_SIZE]; unsigned char head; unsigned char tail; unsigned char size; time_t deadline; unsigned char retries; }; TLS struct send_rtx send_tasks[BUFFER_SIZE+2]; TLS unsigned char num_active_sends = 0; void remove_send_task(unsigned char idx) { struct send_rtx* t = &send_tasks[idx]; t->head = (t->head + 1) % BUFFER_SIZE; t->size--; if (t->size == 0) { send_tasks[idx] = send_tasks[num_active_sends - 1]; num_active_sends--; return; } struct datagram *dg = &t->send_queue[t->head]; sendto(sockfd, dg->payload, dg->len, 0, (struct sockaddr *)&dg->addr, sizeof(struct sockaddr_in)); t->retries = 0; time_t deadline = time(NULL) + BASE_DELAY; t->deadline = deadline; if (deadline < next_timer) { next_timer = deadline; } } void retransmit(time_t current_time) { for (unsigned char i = 0; i < num_active_sends; i++) { struct send_rtx *t = &send_tasks[i]; if (t->deadline <= current_time) { struct datagram *dg = &t->send_queue[t->head]; sendto(sockfd, dg->payload, dg->len, 0, (struct sockaddr *)&dg->addr, sizeof(struct sockaddr_in)); t->retries++; if (t->retries >= MAX_RETRIES) { remove_send_task(i); i--; continue; } unsigned char delay = BASE_DELAY << t->retries; if (delay > MAX_DELAY) delay = MAX_DELAY; t->deadline = current_time + delay; } if (t->deadline < next_timer) { next_timer = t->deadline; } } } void enqueue_send(signed char sender_idx, unsigned short len, struct sockaddr_in *addr) { unsigned char idx = 0; while (idx < num_active_sends) { if (send_tasks[idx].sender_idx == sender_idx) { break; } idx++; } struct send_rtx* t = &send_tasks[idx]; if (idx == num_active_sends) { memset(&t->head, 0, sizeof(struct send_rtx) - ((char*)&t->head-(char*)t)); t->sender_idx = sender_idx; num_active_sends++; } else if (t->size >= BUFFER_SIZE) { return; } struct datagram *slot = &t->send_queue[t->tail]; memcpy(slot->payload, send_buf, len); slot->len = len; slot->addr = *addr; t->tail = (t->tail + 1) % BUFFER_SIZE; t->size++; if (t->size == 1) { time_t deadline = time(NULL) + BASE_DELAY; t->deadline = deadline; if (deadline < next_timer) { next_timer = deadline; } sendto(sockfd, slot->payload, slot->len, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); } } #include <netdb.h> int create_sockaddr_in(const char *addr_str, unsigned short port, struct sockaddr_in *addr) { memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; addr->sin_port = htons(port); if (inet_pton(AF_INET, addr_str, &addr->sin_addr) == 1) { return 0; } else { struct hostent *host = gethostbyname(addr_str); if (host == NULL) { return -1; } memcpy(&addr->sin_addr, host->h_addr, host->h_length); return 0; } } int verify_signature(unsigned char *data, unsigned short len, unsigned char *secret_key) { unsigned char hash[SHA256_DIGEST_SIZE]; unsigned char signature[32]; memcpy(signature, data + len - 32, 32); memcpy(data + len - 32, secret_key, 32); sha256(data, len, hash); return memcmp(hash, signature, 32) == 0; } void sign_data(unsigned short len, unsigned char *secret_key) { unsigned char signature[SHA256_DIGEST_SIZE]; memcpy(send_buf + len, secret_key, 32); sha256(send_buf, len+32, signature); memcpy(send_buf + len, signature, 32); } void bswapn(unsigned char* dst, unsigned char* src, unsigned char n) { unsigned char fwd = 0; unsigned char rev = n - 1; unsigned char half = n/2; while (fwd < half) { dst[fwd] = src[rev]; dst[rev] = src[fwd]; fwd++; rev--; } } void ntohn(void* dst, unsigned char* src, unsigned char n, unsigned char size) { unsigned char *dst_c = (unsigned char*)dst; unsigned char padding = size-n; if (endianess) { bswapn(dst_c, src, n); dst_c = dst_c+n; } else { memcpy(dst_c+padding, src, n); } if (padding) { memset(dst_c, 0, padding); } } void htonn(void* src, unsigned char* dst, unsigned char n, unsigned char size) { unsigned char *src_c = (unsigned char*)src; if (endianess) { bswapn(dst, src_c, n); } else { memcpy(dst, src_c+size-n, n); } } unsigned short error_message(unsigned char *msg, unsigned short len) { send_buf[5] = 1; memcpy(send_buf + 6, msg, len); return len + 1; } unsigned short success_message(unsigned char *msg, unsigned short len) { send_buf[5] = 0; memcpy(send_buf + 6, msg, len); return len + 1; } unsigned short add_account(unsigned char *data) { unsigned char *id = data; unsigned char *portBytes = data+64; unsigned char *acc_secret_key = data + 66; if (lookup_account_idx(id) != -1) { return error_message("Peer already exists", 20); } signed char account_idx = 0; unsigned short temp_bitmap = storage.acc_bitmap; while (temp_bitmap) { if ((temp_bitmap & 1) == 0) { break; } account_idx++; temp_bitmap >>= 1; } if (account_idx == BUFFER_SIZE) { return error_message("Peer slots full", 16); } compute_one_time_key(); for (unsigned char i = 0; i < 32; i++) { acc_secret_key[i] ^= one_time_key_buf[i]; } struct account *acc = &storage.accounts[account_idx]; strncpy(acc->username, id, 32); strncpy(acc->server_address, id + 32, 31); acc->server_address[31] = '\0'; ntohn(&acc->port, portBytes, 2, sizeof(short)); memcpy(acc->secret_key, acc_secret_key, 32); memset(&acc->counter_in, 0, sizeof(struct account) - ((char*)&acc->counter_in - (char*)acc)); storage.acc_bitmap |= (1 << account_idx); save_storage(); return success_message("Add account", 12); } unsigned short remove_account(unsigned char *data) { unsigned char *id = data; signed char account_idx = lookup_account_idx(id); if (account_idx == -1) { return error_message("Peer does not exist", 20); } for (unsigned char i = 0; i < num_paths; ) { struct pathfinding *pf = &paths[i]; if (pf->incoming == account_idx || pf->outgoing == account_idx) { paths[i] = paths[--num_paths]; } else { i++; } } for (unsigned char i = 0; i < storage.num_payments; ) { struct payment *p = &storage.payments[i]; if (p->incoming == account_idx) { p->incoming = -1; } if (p->outgoing == account_idx) { p->outgoing = -1; } if (p->incoming == -1 && p->outgoing == -1) { storage.payments[i] = storage.payments[--storage.num_payments]; } else { i++; } } storage.acc_bitmap &= ~(1 << account_idx); save_storage(); return success_message("Remove account", 15); } void tx_header(unsigned char session_type, unsigned char * username) { send_buf[0] = session_type; strncpy(send_buf+1, username, 32); strcpy(send_buf+33, USERNAME); strcpy(send_buf+65, SERVER_ADDRESS); } void account_sign_and_send(signed char account_idx, unsigned short len) { struct account *acc = &storage.accounts[account_idx]; tx_header(ACCOUNT_SESSION, acc->username); acc->counter_out++; save_storage(); htonn(&acc->counter_out, send_buf+97, 4, sizeof(int)); sign_data(TX_ENVELOPE + len - 32, acc->secret_key); struct sockaddr_in addr; create_sockaddr_in(acc->server_address, acc->port, &addr); enqueue_send(account_idx, TX_ENVELOPE + len, &addr); } void cpt_sign_and_send(unsigned char cmd) { tx_header(COUNTERPART_SESSION, counterpart.username); counterpart.counter_out++; htonn(&counterpart.counter_out, send_buf + 97, 4, sizeof(int)); send_buf[101] = cmd; sign_data(TX_ENVELOPE + 1 - 32, counterpart.secret_key); struct sockaddr_in addr; create_sockaddr_in(counterpart.server_address, counterpart.port, &addr); enqueue_send(CPT_SENDER, TX_ENVELOPE + 1, &addr); } void account_send_32_bytes(signed char account_idx, unsigned char cmd, unsigned char* bytes) { send_buf[101] = cmd; memcpy(send_buf + 102, bytes, 32); account_sign_and_send(account_idx, 1 + 32); } void account_send_32_1(signed char account_idx, unsigned char cmd, unsigned char* bytes, unsigned char byte) { send_buf[101] = cmd; memcpy(send_buf + 102, bytes, 32); send_buf[134] = byte; account_sign_and_send(account_idx, 1 + 32 + 1); } void account_send_sync_payment(signed char account_idx, unsigned char* bytes, unsigned long long amount) { send_buf[101] = 10; memcpy(send_buf + 102, bytes, 32); htonn(&amount, send_buf + 134, 8, sizeof(long long)); account_sign_and_send(account_idx, 1 + 40); } void account_send_8(signed char account_idx, unsigned char cmd, unsigned long long val) { send_buf[101] = cmd; htonn(&val, send_buf + 102, 8, sizeof(long long)); account_sign_and_send(account_idx, 1 + 8); } void account_send_16(signed char account_idx, unsigned char cmd, unsigned long long val1, unsigned long long val2) { send_buf[101] = cmd; htonn(&val1, send_buf + 102, 8, sizeof(long long)); htonn(&val2, send_buf + 110, 8, sizeof(long long)); account_sign_and_send(account_idx, 1 + 16); } unsigned short set_trustline(unsigned char *data) { unsigned char *id = data; unsigned long long value; ntohn(&value, data + 64, 8, sizeof(long long)); signed char account_idx = lookup_account_idx(id); if (account_idx == -1) { return error_message("Peer does not exist", 20); } struct account *acc = &storage.accounts[account_idx]; acc->creditlimit = value; acc->ack_pending = 1; save_storage(); account_send_8(account_idx, 14, value); return success_message("Set trustline", 14); } unsigned short new_payment(unsigned char *data) { unsigned char *id = data; unsigned char *portBytes = data+64; unsigned char *cpt_secret_key = data + 66; unsigned long long amount; ntohn(&amount, data+98, 8, sizeof(long long)); unsigned char in_or_out = data[106]; unsigned int penalty_rate; ntohn(&penalty_rate, data+107, 4, sizeof(int)); unsigned long long fee; ntohn(&fee, data+111, 8, sizeof(long long)); unsigned long long tax; ntohn(&tax, data+119, 8, sizeof(long long)); strncpy(counterpart.username, id, 32); strncpy(counterpart.server_address, id + 32, 31); counterpart.server_address[31] = '\0'; ntohn(&counterpart.port, portBytes, 2, sizeof(short)); compute_one_time_key(); for (unsigned char i = 0; i < 32; i++) { cpt_secret_key[i] ^= one_time_key_buf[i]; } memcpy(counterpart.secret_key, cpt_secret_key, 32); counterpart.counter_in = 0; counterpart.counter_out = 0; unsigned char pay_id_buf[SHA256_DIGEST_SIZE]; sha256(preimage, 32, pay_id_buf); unsigned char idx = 0; while (idx < num_paths) { if (memcmp(paths[idx].identifier, pay_id_buf, 32) == 0) { break; } idx++; } memcpy(preimage, cpt_secret_key, 32); sha256(cpt_secret_key, 32, pay_id_buf); struct pathfinding *path = &paths[idx]; if (idx == num_paths) { num_paths++; } memcpy(path->identifier, pay_id_buf, 32); path->amount = amount; path->incoming = -1, path->outgoing = -1, path->counterpart = 1; path->in_or_out = in_or_out; path->penalty_rate = penalty_rate; path->fee = fee; path->hops = 0, path->depth = 0, path->commit = 0, path->timeout = time(NULL) + TIMEOUT; path->tax = tax; return success_message("New payment", 12); } void forward_find_path(unsigned char path_idx) { struct pathfinding *path = &paths[path_idx]; signed char from; unsigned long long (*bandwidth_fn)(signed char); if (path->in_or_out) { bandwidth_fn = preview_bandwidth_in; from = path->outgoing; } else { bandwidth_fn = preview_bandwidth_out; from = path->incoming; } unsigned short temp_bitmap = storage.acc_bitmap; signed char i = 0; while (temp_bitmap) { if (temp_bitmap & 1 && i != from && bandwidth_fn(i) >= path->amount + fee_in(path) + path->tax) { struct account *a = &storage.accounts[i]; send_buf[101] = 0; unsigned char *data = send_buf+102; memcpy(data, path->identifier, 32); htonn(&path->amount, data+32, 8, sizeof(long long)); data[40] = path->in_or_out; htonn(&path->penalty_rate, data+41, 4, sizeof(int)); htonn(&path->fee, data+45, 8, sizeof(long long)); data[53] = path->hops; htonn(&path->tax, data+54, 8, sizeof(long long)); account_sign_and_send(i, 1 + 62); } i++; temp_bitmap >>= 1; }; } unsigned short start_payment(unsigned char *data) { unsigned char pay_id_buf[SHA256_DIGEST_SIZE]; sha256(preimage, 32, pay_id_buf); signed char idx = get_pathfinding(pay_id_buf); if (idx == -1) { return error_message("No active payment", 18); } forward_find_path(idx); return success_message("Start payment", 14); } unsigned short get_num_accounts(unsigned char *data) { unsigned short temp_bitmap = storage.acc_bitmap; unsigned char count = 0; while (temp_bitmap) { if (temp_bitmap & 1) { count++; } temp_bitmap >>= 1; }; send_buf[5] = 0; send_buf[6] = count; return 2; } unsigned short get_account(unsigned char *data) { unsigned char idx = data[0]; unsigned short temp_bitmap = storage.acc_bitmap; unsigned char count = 0; unsigned char account_idx = 0; while (temp_bitmap) { if (temp_bitmap & 1) { if (count == idx) break; count++; } temp_bitmap >>= 1; account_idx++; } if (!temp_bitmap) { return error_message("Account not found", 18); } struct account *a = &storage.accounts[account_idx]; send_buf[5] = 0; unsigned char *resp_data = send_buf+6; memcpy(resp_data, a->username, 32); memcpy(resp_data+32, a->server_address, 32); htonn(&a->balance, resp_data+64, 8, sizeof(long long)); htonn(&a->creditlimit, resp_data+72, 8, sizeof(long long)); htonn(&a->creditlimit_in, resp_data+80, 8, sizeof(long long)); return 89; } unsigned short get_payment(unsigned char *data) { unsigned char pay_id_buf[SHA256_DIGEST_SIZE]; sha256(preimage, 32, pay_id_buf); unsigned char idx = 0; while (idx < num_paths) { if (memcmp(paths[idx].identifier, pay_id_buf, 32) == 0) { break; } idx++; } if (idx == num_paths || paths[idx].timeout < time(NULL)) { return error_message("No active payment", 18); } send_buf[5] = 0; unsigned char *resp_data = send_buf + 6; char hex[] = "0123456789abcdef"; for (unsigned char i = 0; i < 32; i++) { unsigned char byte = pay_id_buf[i]; resp_data[i * 2] = hex[(byte >> 4) & 0xf]; resp_data[i * 2 + 1] = hex[byte & 0xf]; } return 65; } unsigned short set_trust_index(unsigned char *data) { uint32_t bits; ntohn(&bits, data, 4, sizeof(uint32_t)); float val = *((float*)&bits); storage.trust_index = val; save_storage(); return success_message("Set trust index", 15); } unsigned char is_path_found(struct pathfinding *pf) { return pf->incoming != -1 && (pf->outgoing != -1 || pf->counterpart); } void find_path(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; unsigned long long amount; ntohn(&amount, args + 32, 8, sizeof(long long)); unsigned char in_or_out = args[40]; unsigned int penalty_rate; ntohn(&penalty_rate, args + 41, 4, sizeof(int)); unsigned long long fee; ntohn(&fee, args + 45, 8, sizeof(long long)); unsigned char hops = args[53]; unsigned long long tax; ntohn(&tax, args + 54, 8, sizeof(long long)); if (!in_or_out && preview_bandwidth_in(account_idx) < amount) { return; } signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) { if (amount == 0 || penalty_rate < PENALTY_RATE_SEC / 2 || (float)fee / (float)amount < FEE_RATE / 2) { printf("11111111111111"); return; } float tax_rate = (float)tax / (float)amount; if(tax_rate < storage.trust_index / 2 || tax_rate > storage.trust_index * 1.5) { return; } if (num_paths >= BUFFER_SIZE - storage.num_payments) { return; } pf_idx = num_paths++; struct pathfinding *pf = &paths[pf_idx]; memcpy(pf->identifier, payment_id, 32); pf->amount = amount; pf->counterpart = 0; pf->in_or_out = in_or_out; pf->penalty_rate = penalty_rate; pf->fee = fee; pf->depth = 0; pf->commit = 0; pf->timeout = time(NULL) + TIMEOUT; pf->tax = tax; if (!in_or_out) { pf->incoming = account_idx; pf->outgoing = -1; pf->hops = 0; } else { pf->incoming = -1; pf->outgoing = account_idx; pf->hops = hops+1; } account_send_32_1(account_idx, 1, payment_id, 0); return; } struct pathfinding *pf = &paths[pf_idx]; if (pf->commit || is_path_found(pf) || pf->depth >= MAX_DEPTH) { return; } if (in_or_out != pf->in_or_out) { if (amount != pf->amount || penalty_rate != pf->penalty_rate || fee != pf->fee || tax != pf->tax) { return; } if (!in_or_out) { pf->incoming = account_idx; } else { pf->outgoing = account_idx; pf->hops = hops + 1; } if (pf->counterpart) { if (!pf->in_or_out) { set_commit(pf); account_send_32_bytes(account_idx, 3, payment_id); return; } } account_send_32_1(pf->incoming, 2, payment_id, pf->hops); return; } if (!in_or_out && pf->incoming == account_idx || in_or_out && pf->outgoing == account_idx) { forward_find_path(pf_idx); } } void path_recurse(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; unsigned char depth = args[32]; signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) { return; } struct pathfinding *pf = &paths[pf_idx]; if (pf->commit || is_path_found(pf) || depth < pf->depth || depth >= MAX_DEPTH) { return; } pf->depth = depth + 1; if (pf->counterpart) { cpt_sign_and_send(0); return; } signed char prev_idx; if (!pf->in_or_out) { prev_idx = pf->incoming; } else { prev_idx = pf->outgoing; } account_send_32_1(prev_idx, 1, payment_id, pf->depth); } void path_found(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; unsigned char hops = args[32]; signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) { return; } struct pathfinding *pf = &paths[pf_idx]; if (is_path_found(pf) || pf->commit) { return; } if (pf->counterpart) { if (pf->in_or_out) { return; } pf->outgoing = account_idx; pf->hops = hops + 1; set_commit(pf); account_send_32_bytes(account_idx, 3, payment_id); return; } if (pf->incoming == -1) { return; } pf->outgoing = account_idx; pf->hops = hops + 1; account_send_32_1(pf->incoming, 2, payment_id, pf->hops); } void prepare_path(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) { return; } struct pathfinding *pf = &paths[pf_idx]; if (pf->commit || preview_bandwidth_in(account_idx) < pf->amount + fee_in(pf) + pf->tax) { return; } pf->incoming = account_idx; set_commit(pf); if (pf->counterpart) { if (!pf->in_or_out) { return; } cpt_sign_and_send(1); return; } if (pf->outgoing == -1) { return; } account_send_32_bytes(pf->outgoing, 3, payment_id); } void commit_payment(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) { return; } struct pathfinding *pf = &paths[pf_idx]; if (!pf->commit || account_idx != pf->incoming) { return; } struct payment *payment = &storage.payments[storage.num_payments]; storage.num_payments++; memcpy(payment->identifier, payment_id, 32); payment->amount = pf->amount; payment->incoming = account_idx; payment->penalty_rate = pf->penalty_rate; payment->fee_in = fee_in(pf); payment->created_at = time(NULL); payment->tax = pf->tax; if (pf->counterpart) { payment->counterpart = 1; payment->outgoing = -1; memcpy(payment->preimage, preimage, 32); save_storage(); paths[pf_idx] = paths[--num_paths]; cpt_sign_and_send(2); return; } paths[pf_idx] = paths[--num_paths]; payment->outgoing = pf->outgoing; payment->fee_out = fee_out(pf); payment->status = COMMIT; save_storage(); account_send_32_bytes(pf->outgoing, 4, payment_id); } unsigned long long penalty_ticker(struct payment *payment) { long long now = time(NULL); if (now > payment->created_at && payment->penalty_rate > 0) { unsigned long long ticker = (unsigned long long)(now - payment->created_at) / (unsigned long long)payment->penalty_rate; return ticker > payment->amount ? payment->amount : ticker; } return 0; } signed char get_payment_idx(unsigned char *payment_id) { for (signed char i = 0; i < storage.num_payments; i++) { if (memcmp(storage.payments[i].identifier, payment_id, 32) == 0) { return i; } } return -1; } void seal_payment(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { return; } struct payment *payment = &storage.payments[pay_idx]; if (payment->status != COMMIT || payment->incoming != account_idx) { return; } unsigned long long ticker = penalty_ticker(payment); payment->commit_penalty = ticker; if (ticker >= payment->amount) { payment->status = CLEANUP; save_storage(); account_send_32_bytes(account_idx, 8, payment_id); if (payment->outgoing != -1) { payment->finalize_out = payment->amount + payment->fee_out + payment->tax; save_storage(); account_send_32_bytes(payment->outgoing, 8, payment_id); } return; } if (payment->counterpart) { payment->status = FINALIZE; save_storage(); account_send_32_bytes(account_idx, 6, payment->preimage); return; } payment->status = SEAL; save_storage(); if (payment->outgoing != -1) { account_send_32_bytes(payment->outgoing, 5, payment_id); } } unsigned long long seal_penalty(struct payment *payment, unsigned long long ticker) { return ticker > payment->commit_penalty ? ticker - payment->commit_penalty : 0; } unsigned long long finalize_out(struct payment *payment) { unsigned long long ticker = penalty_ticker(payment); unsigned long long amount = payment->amount - seal_penalty(payment, ticker); unsigned long long tax = payment->tax * amount / payment->amount; unsigned long long fee = payment->fee_out * ticker / payment->amount; return amount + tax + fee; } static void send_ack_preimage(signed char sender_idx, unsigned char *payment_id) { account_send_32_bytes(sender_idx, 9, payment_id); } void finalize_payment(signed char account_idx, unsigned char *args) { unsigned char *preimage_arg = args; unsigned char payment_id[32]; sha256(preimage_arg, 32, payment_id); signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { send_ack_preimage(account_idx, payment_id); return; } struct payment *payment = &storage.payments[pay_idx]; if (payment->status == FINALIZE || payment->status == CLEANUP) { send_ack_preimage(account_idx, payment_id); return; } if (payment->status != SEAL || payment->outgoing != account_idx) { return; } payment->finalize_out = finalize_out(payment); payment->status = FINALIZE; memcpy(payment->preimage, preimage_arg, 32); save_storage(); account_send_sync_payment(account_idx, payment_id, payment->finalize_out); send_ack_preimage(account_idx, payment_id); if (payment->incoming != -1) { account_send_32_bytes(payment->incoming, 6, preimage_arg); } } unsigned long long cancel_out(struct payment *payment) { unsigned long long ticker = penalty_ticker(payment); unsigned long long total = payment->amount + payment->fee_out; if (ticker >= payment->amount) { return total; } else { return total * ticker / payment->amount; } } void cancel_payment(signed char account_idx, unsigned char *args) { unsigned char *preimage_arg = args; unsigned char payment_id[32]; sha256(preimage_arg, 32, payment_id); signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { send_ack_preimage(account_idx, payment_id); return; } struct payment *payment = &storage.payments[pay_idx]; unsigned char status = payment->status; if (status == CANCEL || status == CLEANUP) { send_ack_preimage(account_idx, payment_id); return; } if (status != COMMIT || payment->incoming != account_idx) { return; } memcpy(payment->preimage, preimage_arg, 32); payment->status = CANCEL; if (payment->outgoing != -1) { payment->finalize_out = cancel_out(payment); } save_storage(); if (payment->outgoing != -1) { account_send_32_bytes(payment->outgoing, 7, payment->preimage); } send_ack_preimage(account_idx, payment_id); } unsigned long long cleanup_out(struct payment *payment) { return payment->amount - seal_penalty(payment, payment->amount) + payment->fee_out; } void cleanup_payment(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { return; } struct payment *payment = &storage.payments[pay_idx]; if ((payment->status & SYNCING_MASK) || penalty_ticker(payment) < payment->amount) { return; } if (payment->status == COMMIT) { payment->commit_penalty = payment->amount; } payment->status = CLEANUP; if (payment->outgoing != -1) { payment->finalize_out = cleanup_out(payment); save_storage(); if (payment->outgoing != account_idx) { account_send_32_bytes(payment->outgoing, 8, payment_id); } } save_storage(); if (payment->incoming != -1 && payment->incoming != account_idx) { account_send_32_bytes(payment->incoming, 8, payment_id); } } unsigned char counterpart_in(struct payment *payment) { return payment->counterpart && payment->incoming == -1; } unsigned char synchronized_in(struct payment *payment) { unsigned char ack_preimage = payment->status != FINALIZE || payment->ack_preimage; return payment->synced && ack_preimage || counterpart_in(payment); } unsigned char synchronized_out(struct payment *payment) { unsigned char ack_preimage = payment->status != CANCEL || payment->ack_preimage; unsigned char commit_out = payment->status == FINALIZE || payment->commit_out; return payment->ack_sync && ack_preimage && commit_out || payment->counterpart && payment->outgoing == -1; } void ack_preimage(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { return; } struct payment *payment = &storage.payments[pay_idx]; unsigned char status = payment->status; if (payment->ack_preimage || !((status == FINALIZE && payment->incoming == account_idx) || (status == CANCEL && payment->outgoing == account_idx))) { return; } payment->ack_preimage = 1; if (synchronized_in(payment)) { payment->incoming = -1; } if (synchronized_out(payment)) { payment->outgoing = -1; } if (payment->incoming == -1 && payment->outgoing == -1) { storage.payments[pay_idx] = storage.payments[--storage.num_payments]; } save_storage(); } void write_receipt(unsigned char* payment_id, long long amount) { struct receipt *r = &storage.receipts[storage.receipts_head]; storage.receipts_head = (storage.receipts_head + 1) % BUFFER_SIZE; save_storage(); memcpy(r->identifier, payment_id, 32); r->amount = amount; r->timestamp = time(NULL); unsigned char pay_id_buf[32]; sha256(counterpart.secret_key, 32, pay_id_buf); if (memcmp(pay_id_buf, payment_id, 32) == 0) { memcpy(r->username, counterpart.username, 32); memcpy(r->server_address, counterpart.server_address, 32); } else { memset(r->username, 0, 64); } } long long preview_balance(signed char account_idx) { struct account *acc = &storage.accounts[account_idx]; long long bal = acc->balance; for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->incoming == account_idx) { bal -= (long long)(p->amount + p->fee_in + p->tax); } } for (unsigned char i = 0; i < num_paths; i++) { struct pathfinding *pf = &paths[i]; if (pf->timeout < time(NULL)) { paths[i] = paths[--num_paths]; i--; continue; } if (pf->incoming == account_idx && pf->commit) { bal -= (long long)(pf->amount + fee_in(pf) + pf->tax); } } return bal; } unsigned long long calculate_tax(struct payment *payment) { return payment->tax * (payment->amount - seal_penalty(payment, penalty_ticker(payment)))/payment->amount; } void redistribute(signed char from_idx, unsigned long long tax, float tax_rate) { if (tax == 0) return; struct { signed char idx; unsigned long long val; } positive_balances[BUFFER_SIZE]; unsigned char num_positive = 0; float total_width = 0.0; unsigned short temp_bitmap = storage.acc_bitmap; signed char i = 0; while (temp_bitmap) { if (temp_bitmap & 1 && i != from_idx) { long long preview = preview_balance(i); if (preview > 0) { positive_balances[num_positive].idx = i; positive_balances[num_positive].val = (unsigned long long)preview; total_width += storage.accounts[i].width; num_positive++; } } i++; temp_bitmap >>= 1; } if (total_width == 0.0) return; if (total_width < tax_rate) { tax = (unsigned long long)((float)tax * (total_width / tax_rate)); } for (unsigned char j = 0; j < num_positive; j++) { signed char idx = positive_balances[j].idx; struct account *acc = &storage.accounts[idx]; float proportion = acc->width / total_width; unsigned long long dist = (unsigned long long)((float)tax * proportion); if (dist == 0) continue; if (dist > positive_balances[j].val) dist = positive_balances[j].val; tax_buffer[idx] += dist; if (acc->tax_syncing == 0) { acc->sync_out++; acc->tax_syncing = tax_buffer[idx]; save_storage(); account_send_16(idx, 16, acc->tax_syncing, acc->sync_out); tax_buffer[idx] = 0; } } } float get_tax_rate(struct payment *p) { if (p->tax == 0) { return 0; } return (float)p->tax / (float)(p->amount + p->tax); } void increase_balance(signed char account_idx, unsigned long long amount, float tax_rate) { struct account *acc = &storage.accounts[account_idx]; long long old_balance = acc->balance; acc->balance += (long long)amount; long long new_balance = acc->balance; if (new_balance > 0) { float weight; if (old_balance > 0) { weight = (float)old_balance / (float)new_balance; acc->width = weight * acc->width + (1 - weight) * tax_rate; } else { acc->width = tax_rate; tax_buffer[account_idx] = 0; } } } void decrease_balance(signed char account_idx, unsigned long long amount, float tax_rate) { struct account *acc = &storage.accounts[account_idx]; long long old_balance = acc->balance; acc->balance -= (long long)amount; long long new_balance = acc->balance; if (new_balance < 0) { float weight; if (old_balance < 0) { weight = (float)(-old_balance) / (float)(-new_balance); acc->width = weight * acc->width + (1 - weight) * tax_rate; } else { acc->width = tax_rate; } } } void sync_payment(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; unsigned long long amount; ntohn(&amount, args + 32, 8, sizeof(long long)); signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { account_send_32_bytes(account_idx, 11, payment_id); return; } struct payment *payment = &storage.payments[pay_idx]; if (!(payment->status & SYNCING_MASK) || (payment->incoming != -1 && payment->incoming != account_idx) || amount > payment->amount + payment->fee_in + payment->tax) { return; } if (payment->incoming == account_idx && !payment->synced) { float tax_rate = get_tax_rate(payment); increase_balance(payment->incoming, amount, tax_rate); payment->synced = 1; if (synchronized_in(payment)) { payment->incoming = -1; } if (payment->status == FINALIZE && payment->counterpart) { write_receipt(payment_id, (long long)payment->amount); } save_storage(); redistribute(account_idx, calculate_tax(payment), tax_rate); } if (payment->incoming == -1 && payment->outgoing == -1) { storage.payments[pay_idx] = storage.payments[--storage.num_payments]; save_storage(); } account_send_32_bytes(account_idx, 11, payment_id); } void ack_sync(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { return; } struct payment *payment = &storage.payments[pay_idx]; if (!(payment->status & SYNCING_MASK) || payment->ack_sync || payment->outgoing != account_idx) { return; } payment->ack_sync = 1; decrease_balance(payment->outgoing, payment->finalize_out, get_tax_rate(payment)); if (payment->status == FINALIZE && payment->counterpart) { write_receipt(payment_id, -(long long)payment->amount); } if (synchronized_out(payment)) { payment->outgoing = -1; } if (payment->incoming == -1 && payment->outgoing == -1) { storage.payments[pay_idx] = storage.payments[--storage.num_payments]; } save_storage(); } void verify_commit(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { account_send_32_1(account_idx, 13, payment_id, 1); return; } struct payment *payment = &storage.payments[pay_idx]; if (payment->incoming != -1 && payment->incoming != account_idx) { return; } account_send_32_1(account_idx, 13, payment_id, 0); } void ack_commit(signed char account_idx, unsigned char *args) { unsigned char *payment_id = args; unsigned char status = args[32]; signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) { return; } struct payment *payment = &storage.payments[pay_idx]; if (payment->commit_out || payment->outgoing != account_idx) { return; } if (status == 0) { payment->commit_out = 1; } else { payment->outgoing = -1; if (payment->incoming == -1) { storage.payments[pay_idx] = storage.payments[--storage.num_payments]; } } save_storage(); } void sync_trustline(signed char account_idx, unsigned char *args) { unsigned long long limit; ntohn(&limit, args, 8, sizeof(long long)); struct account *acc = &storage.accounts[account_idx]; acc->creditlimit_in = limit; save_storage(); account_send_8(account_idx, 15, limit); } void ack_trustline(signed char account_idx, unsigned char *args) { unsigned long long limit; ntohn(&limit, args, 8, sizeof(long long)); struct account *acc = &storage.accounts[account_idx]; if (!acc->ack_pending || acc->creditlimit != limit) { return; } acc->ack_pending = 0; save_storage(); } void swarm_redistribution(signed char account_idx, unsigned char *args) { unsigned long long amount; ntohn(&amount, args, 8, sizeof(long long)); unsigned long long counter; ntohn(&counter, args + 8, 8, sizeof(long long)); struct account *acc = &storage.accounts[account_idx]; if (counter > acc->sync_in) { if (acc->balance + (long long)amount > 0) return; acc->balance += (long long)amount; acc->sync_in = counter; save_storage(); redistribute(account_idx, amount, acc->width); } account_send_8(account_idx, 17, counter); } void redistribution_ack(signed char account_idx, unsigned char *args) { unsigned long long counter; ntohn(&counter, args, 8, sizeof(long long)); struct account *acc = &storage.accounts[account_idx]; if (acc->tax_syncing > 0 && counter == acc->sync_out) { acc->balance -= (long long)acc->tax_syncing; acc->tax_syncing = 0; save_storage(); } } void cpt_find_path(void) { unsigned char payment_id[32]; sha256(counterpart.secret_key, 32, payment_id); signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) return; forward_find_path(pf_idx); } void cpt_commit_payment(void) { unsigned char payment_id[32]; sha256(counterpart.secret_key, 32, payment_id); signed char pf_idx = get_pathfinding(payment_id); if (pf_idx == -1) return; struct pathfinding *pf = &paths[pf_idx]; if (!pf->counterpart || pf->in_or_out || !pf->commit) return; struct payment *payment = &storage.payments[storage.num_payments]; storage.num_payments++; memcpy(payment->identifier, payment_id, 32); payment->amount = pf->amount; payment->incoming = -1; payment->outgoing = pf->outgoing; payment->penalty_rate = pf->penalty_rate; payment->fee_in = 0; payment->fee_out = fee_out(pf); memcpy(payment->preimage, preimage, 32); payment->status = COMMIT; payment->counterpart = 1; payment->created_at = time(NULL); payment->tax = pf->tax; save_storage(); paths[pf_idx] = paths[--num_paths]; account_send_32_bytes(pf->outgoing, 4, payment_id); } void cpt_seal_payment(void) { unsigned char payment_id[32]; sha256(counterpart.secret_key, 32, payment_id); signed char pay_idx = get_payment_idx(payment_id); if (pay_idx == -1) return; struct payment *payment = &storage.payments[pay_idx]; if (payment->status != COMMIT || payment->incoming != -1) return; unsigned long long ticker = penalty_ticker(payment); payment->commit_penalty = ticker; if (ticker >= payment->amount) { payment->status = CLEANUP; save_storage(); account_send_32_bytes(payment->outgoing, 8, payment_id); return; } payment->status = SEAL; save_storage(); account_send_32_bytes(payment->outgoing, 5, payment_id); } unsigned short (*user_handlers[])(unsigned char*) = { add_account, remove_account, set_trustline, new_payment, start_payment, get_num_accounts, get_account, get_payment, set_trust_index }; void (*acc_handlers[])(signed char, unsigned char*) = { find_path, path_recurse, path_found, prepare_path, commit_payment, seal_payment, finalize_payment, cancel_payment, cleanup_payment, ack_preimage, sync_payment, ack_sync, verify_commit, ack_commit, sync_trustline, ack_trustline, swarm_redistribution, redistribution_ack }; void (*cpt_handlers[])(void) = { cpt_find_path, cpt_commit_payment, cpt_seal_payment }; unsigned short acc_args_len[] = {62, 33, 33, 32, 32, 32, 32, 32, 32, 32, 40, 32, 32, 33, 8, 8, 16, 8}; unsigned short user_args_len[] = {98, 64, 72, 127, 0, 0, 1, 0, 4}; void push_finalize_routine(void) { for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->status == FINALIZE && !p->ack_preimage && p->incoming != -1) { account_send_32_bytes(p->incoming, 6, p->preimage); } } } void push_cancel_routine(void) { for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->status == CANCEL && !p->ack_preimage && p->outgoing != -1) { account_send_32_bytes(p->outgoing, 7, p->preimage); } } } void push_sync_payment(void) { for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (!(p->status & SYNCING_MASK) || p->outgoing == -1 || p->ack_sync) continue; if ((p->status == CANCEL || p->status == CLEANUP) && !p->commit_out) { account_send_32_bytes(p->outgoing, 12, p->identifier); continue; } account_send_sync_payment(p->outgoing, p->identifier, p->finalize_out); } } void push_sync_trustline(void) { unsigned short temp_bitmap = storage.acc_bitmap; signed char idx = 0; while (temp_bitmap) { if ((temp_bitmap & 1) && storage.accounts[idx].ack_pending) { account_send_8(idx, 14, storage.accounts[idx].creditlimit); } idx++; temp_bitmap >>= 1; } } void push_redistribution_routine(void) { unsigned short temp_bitmap = storage.acc_bitmap; signed char idx = 0; while (temp_bitmap) { if ((temp_bitmap & 1) && storage.accounts[idx].tax_syncing > 0) { account_send_16(idx, 16, storage.accounts[idx].tax_syncing, storage.accounts[idx].sync_out); } idx++; temp_bitmap >>= 1; } } void auto_cancel_routine(void) { long long now = time(NULL); for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if (p->status != COMMIT || !counterpart_in(p) || now - p->created_at <= TIMEOUT) continue; p->status = CANCEL; save_storage(); account_send_32_bytes(p->outgoing, 7, p->preimage); } } void cleanup_payment_routine(void) { for (unsigned char i = 0; i < storage.num_payments; i++) { struct payment *p = &storage.payments[i]; if ((p->status & SYNCING_MASK) || penalty_ticker(p) < p->amount) continue; if (p->status == COMMIT) p->commit_penalty = p->amount; if (p->incoming != -1) { account_send_32_bytes(p->incoming, 8, p->identifier); } if (p->outgoing != -1) { p->finalize_out = cleanup_out(p); account_send_32_bytes(p->outgoing, 8, p->identifier); } p->status = CLEANUP; save_storage(); } } void ack_received(signed char sender_idx, unsigned char *data, unsigned char offset) { for (unsigned char i = 0; i < num_active_sends; i++) { struct send_rtx *t = &send_tasks[i]; if (t->sender_idx == sender_idx) { if (memcmp(t->send_queue[t->head].payload + offset, data+offset, 4) == 0) { remove_send_task(i); } break; } } } unsigned int receive_tx(unsigned char session_type, signed char sender_idx, struct sockaddr_in *addr, unsigned char *username, unsigned char *server_address, unsigned char *secret_key, unsigned int counter_in, unsigned char *data, unsigned short len) { if (!verify_signature(data, len, secret_key)) { return 0; } if (data[0]&1) { ack_received(sender_idx, data, 97); return 0; } unsigned int counter; ntohn(&counter, data+97, 4, sizeof(int)); if (counter < counter_in) { return 0; } tx_header(session_type | 1, username); memcpy(send_buf+97, data+97, 4); sign_data(TX_ENVELOPE-32, secret_key); sendto(sockfd, send_buf, TX_ENVELOPE, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); if (counter == counter_in) { return 0; } return counter; } #if 1 #define DEBUG_PRINT_MESSAGE(addr, type, cmd) print_message(addr, type, cmd) static const char* command_names[] = { "ACCOUNT_FIND_PATH", "ACCOUNT_PATH_RECURSE", "ACCOUNT_PATH_FOUND", "ACCOUNT_PREPARE_PATH", "ACCOUNT_COMMIT_PAYMENT", "ACCOUNT_SEAL_PAYMENT", "ACCOUNT_FINALIZE_PAYMENT", "ACCOUNT_CANCEL_PAYMENT", "ACCOUNT_CLEANUP_PAYMENT", "ACCOUNT_ACK_PREIMAGE", "ACCOUNT_SYNC_PAYMENT", "ACCOUNT_ACK_SYNC", "ACCOUNT_VERIFY_COMMIT", "ACCOUNT_ACK_COMMIT", "ACCOUNT_SYNC_TRUSTLINE", "ACCOUNT_ACK_TRUSTLINE", "ACCOUNT_SWARM_REDISTRIBUTION", "ACCOUNT_REDISTRIBUTION_ACK", "USER_ADD_ACCOUNT", "USER_REMOVE_ACCOUNT", "USER_SET_TRUSTLINE", "USER_NEW_PAYMENT", "USER_START_PAYMENT", "USER_GET_NUM_ACCOUNTS", "USER_GET_ACCOUNT", "USER_GET_PAYMENT", "USER_SET_TRUST_INDEX", "COUNTERPART_FIND_PATH", "COUNTERPART_COMMIT_PAYMENT", "COUNTERPART_SEAL_PAYMENT" }; void print_message(struct sockaddr_in *addr, unsigned char type, unsigned char cmd) { printf("%s:%d: %s (0x%02X)\n", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), command_names[cmd + ((type&2)>>1)*18 + (type>>2)*27], cmd); } #else #define DEBUG_PRINT_MESSAGE(addr, type, cmd) ((void)0) #endif void transport_datagram(unsigned char *data, unsigned short len, struct sockaddr_in *addr) { if (len<1) return; unsigned char session_type = data[0]&6; if (session_type%4==0) { if (len < TX_ENVELOPE) { return; } if (session_type==ACCOUNT_SESSION) { signed char account_idx = lookup_account_idx(data+33); if (account_idx == -1) { return; } struct account *acc = &storage.accounts[account_idx]; unsigned int counter = receive_tx(ACCOUNT_SESSION, account_idx, addr, acc->username, acc->server_address, acc->secret_key, acc->counter_in, data, len); if (!counter) { return; } acc->counter_in = counter; save_storage(); unsigned char cmd = data[101]; if (cmd <= 17 && len-TX_ENVELOPE >= 1 + acc_args_len[cmd]) { DEBUG_PRINT_MESSAGE(addr, session_type, cmd); acc_handlers[cmd](account_idx, data+102); } } else { if (strncmp(counterpart.username, data+33, 32) != 0 || strncmp(counterpart.server_address, data+65, 32) != 0) { return; } unsigned int counter = receive_tx(COUNTERPART_SESSION, CPT_SENDER, addr, counterpart.username, counterpart.server_address, counterpart.secret_key, counterpart.counter_in, data, len); if (!counter) { return; } counterpart.counter_in = counter; unsigned char cmd = data[101]; if (cmd <= 2) { DEBUG_PRINT_MESSAGE(addr, session_type, cmd); cpt_handlers[cmd](); } } } else if ((len >= REQ_ENVELOPE) && (verify_signature(data, len, secret_block))) { if (data[0]&1) { ack_received(USER_SENDER, data, 1); return; } unsigned int counter; ntohn(&counter, data+1, 4, sizeof(int)); if (counter < storage.counter) { return; } send_buf[0] = 1; memcpy(send_buf+1, data+1, 4); sign_data(REQ_ENVELOPE-32, secret_block); sendto(sockfd, send_buf, REQ_ENVELOPE, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_in)); if (counter == storage.counter) { return; } storage.counter = counter; save_storage(); unsigned short out_len; unsigned char cmd = data[5]; if (cmd <= 8 && len-REQ_ENVELOPE >= 1 + user_args_len[cmd]) { DEBUG_PRINT_MESSAGE(addr, session_type, cmd); out_len = user_handlers[cmd](data+6); } else { out_len = error_message("Invalid instruction", 20); } send_buf[0] = 0; memcpy(send_buf+1, data+1, 4); sign_data(5+out_len, secret_block); enqueue_send(USER_SENDER, REQ_ENVELOPE+out_len, addr); } } #include <signal.h> static volatile sig_atomic_t running = 1; static void on_shutdown_signal(int sig) { running = 0; } void run_loop() { unsigned int period = 0; struct timeval tv; tv.tv_usec = 0; unsigned char buf[MAX_DG]; struct sockaddr_in src_addr; socklen_t addrlen; while (running) { time_t now = time(NULL); unsigned int current_period = (unsigned int)now / SCHEDULER_PERIOD; if (current_period > period) { period = current_period; int tz = __builtin_ctzl(current_period); push_finalize_routine(); push_cancel_routine(); push_sync_payment(); push_sync_trustline(); push_redistribution_routine(); if (tz >= 1) auto_cancel_routine(); if (tz >= 2) cleanup_payment_routine(); } next_timer = (current_period + 1) * SCHEDULER_PERIOD; retransmit(now); tv.tv_sec = next_timer - now; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); addrlen = sizeof(struct sockaddr_in); ssize_t n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&src_addr, &addrlen); if (n >= REQ_ENVELOPE) { transport_datagram(buf, (unsigned short)n, &src_addr); } } } static int server_main(void) { load_storage(); struct sockaddr_in server_addr; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket"); return 1; } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(PORT); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind"); return 1; } struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = on_shutdown_signal; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); fprintf(stderr, "[%s:%u] server started (storage=%s)\n", USERNAME, (unsigned)PORT, STORAGE_PATH); run_loop(); close(sockfd); fprintf(stderr, "[%s:%u] server stopped\n", USERNAME, (unsigned)PORT); return 0; } typedef struct { const char *username; const char *storage_path; unsigned short port; unsigned char secret32[32]; } ServerConfig; static void *server_thread(void *arg) { ServerConfig *cfg = (ServerConfig*)arg; strncpy(USERNAME, cfg->username, 32); USERNAME[32] = 0; strncpy(SERVER_ADDRESS, "127.0.0.1", 32); strncpy(STORAGE_PATH, cfg->storage_path, PATH_MAX-1); STORAGE_PATH[PATH_MAX-1] = 0; PORT = cfg->port; memcpy(secret_block, cfg->secret32, 32); server_main(); return NULL; } static const unsigned char SECRET_A[32] = { [0 ... 31] = 0x00 }; static const unsigned char SECRET_B[32] = { [0 ... 31] = 0x11 }; static const unsigned char SECRET_C[32] = { [0 ... 31] = 0x22 }; static const unsigned char SECRET_33[32] = { [0 ... 31] = 0x33 }; static const unsigned char SECRET_44[32] = { [0 ... 31] = 0x44 }; static const unsigned char SECRET_AC[32] = { [0 ... 31] = 0x55 }; static int ctl_sock = -1; static void sign_user_packet(unsigned char *buf, unsigned short len_wo_sig, const unsigned char *secret32) { unsigned char sig[SHA256_DIGEST_SIZE]; memcpy(buf + len_wo_sig, secret32, 32); sha256(buf, len_wo_sig + 32, sig); memcpy(buf + len_wo_sig, sig, 32); } static void derive_one_time_key(const unsigned char *secret32, uint32_t counter, unsigned char out32[32]) { unsigned char tmp[36]; memcpy(tmp, secret32, 32); htonn(&counter, tmp+32, 4, sizeof(uint32_t)); sha256(tmp, 36, out32); } static unsigned short build_user_request(unsigned char *out, uint32_t counter, unsigned char cmd, const unsigned char *args, unsigned short args_len, const unsigned char *secret32) { out[0] = USER_SESSION | DATA_TYPE; htonn(&counter, out+1, 4, sizeof(uint32_t)); out[5] = cmd; if (args_len) memcpy(out + 6, args, args_len); unsigned short len_wo_sig = (unsigned short)(1 + 4 + 1 + args_len); sign_user_packet(out, len_wo_sig, secret32); return (unsigned short)(len_wo_sig + 32); } typedef struct { const char *ip; unsigned short port; unsigned char secret32[32]; uint32_t user_counter; const char *name; } ClientTarget; static int send_user_cmd(const char *ip, unsigned short port, const unsigned char *secret32, uint32_t *ctr_io, unsigned char cmd, const unsigned char *args, unsigned short alen, unsigned char *resp_buf, unsigned short *resp_len) { struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (inet_pton(AF_INET, ip, &addr.sin_addr) != 1) return -1; if (ctl_sock < 0) { ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); if (ctl_sock < 0) { perror("client socket"); return -1; } struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; setsockopt(ctl_sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); } uint32_t ctr = ++(*ctr_io); unsigned char packet[REQ_ENVELOPE + 256]; unsigned short len = build_user_request(packet, ctr, cmd, args, alen, secret32); if (sendto(ctl_sock, packet, len, 0, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("sendto"); return -1; } for (;;) { struct sockaddr_in from; socklen_t flen = sizeof(from); ssize_t n = recvfrom(ctl_sock, resp_buf, 1024, 0, (struct sockaddr*)&from, &flen); if (n < 0) { return -2; } if (n >= REQ_ENVELOPE) { if ((resp_buf[0] & 1) == 0) { unsigned char ack[REQ_ENVELOPE]; ack[0] = USER_SESSION | ACK_TYPE; memcpy(ack + 1, resp_buf + 1, 4); sign_user_packet(ack, REQ_ENVELOPE - 32, secret32); sendto(ctl_sock, ack, REQ_ENVELOPE, 0, (struct sockaddr*)&addr, sizeof(addr)); *resp_len = (unsigned short)n; return 0; } } } } static int cmd_add_account(ClientTarget *T, const char *peer_user, unsigned short peer_port, const unsigned char peer_secret32[32]) { unsigned char args[64 + 2 + 32]; memset(args, 0, sizeof(args)); strncpy((char*)args, peer_user, 32); strncpy((char*)args + 32, "127.0.0.1", 32); htonn(&peer_port, args + 64, 2, sizeof(short)); unsigned char otk[32]; derive_one_time_key(T->secret32, T->user_counter + 1, otk); for (int i = 0; i < 32; i++) args[66 + i] = (unsigned char)(peer_secret32[i] ^ otk[i]); unsigned char resp[1024]; unsigned short rn = 0; int rc = send_user_cmd(T->ip, T->port, T->secret32, &T->user_counter, 0, args, sizeof(args), resp, &rn); if (rc == 0) { if (rn >= REQ_ENVELOPE + 1 && resp[5] == 0) { printf("[auto] %s: add_account('%s',%u) → OK\n", T->name, peer_user, (unsigned)peer_port); } else { printf("[auto] %s: add_account('%s',%u) → ERROR\n", T->name, peer_user, (unsigned)peer_port); } } else { printf("[auto] %s: add_account('%s',%u) → rc=%d\n", T->name, peer_user, (unsigned)peer_port, rc); } return rc; } static int cmd_set_trustline(ClientTarget *T, const char *peer_user, unsigned long long limit) { unsigned char args[64 + 8]; memset(args, 0, sizeof(args)); strncpy((char*)args, peer_user, 32); strncpy((char*)args + 32, "127.0.0.1", 32); htonn(&limit, args + 64, 8, sizeof(long long)); unsigned char resp[1024]; unsigned short rn = 0; int rc = send_user_cmd(T->ip, T->port, T->secret32, &T->user_counter, 2 /* USER_SET_TRUSTLINE */, args, sizeof(args), resp, &rn); if (rc == 0) { if (rn >= REQ_ENVELOPE + 1 && resp[5] == 0) { printf("[auto] %s: set_trustline('%s', %llu) → OK\n", T->name, peer_user, (unsigned long long)limit); } else { printf("[auto] %s: set_trustline('%s', %llu) → ERROR\n", T->name, peer_user, (unsigned long long)limit); } } else { printf("[auto] %s: set_trustline('%s', %llu) → rc=%d\n", T->name, peer_user, (unsigned long long)limit, rc); } return rc; } static int cmd_new_payment(ClientTarget *T, const char *cp_user, unsigned short cp_port, const unsigned char cp_secret32[32], unsigned long long amount, unsigned char in_or_out, unsigned int penalty_rate, unsigned long long fee, unsigned long long tax) { unsigned char args[127]; memset(args, 0, sizeof(args)); strncpy((char*)args, cp_user, 32); strncpy((char*)args + 32, "127.0.0.1", 32); htonn(&cp_port, args + 64, 2, sizeof(unsigned short)); unsigned char otk[32]; derive_one_time_key(T->secret32, T->user_counter + 1, otk); for (int i = 0; i < 32; i++) args[66 + i] = (unsigned char)(cp_secret32[i] ^ otk[i]); htonn(&amount, args + 98, 8, sizeof(unsigned long long)); args[106] = in_or_out; htonn(&penalty_rate, args + 107, 4, sizeof(unsigned int)); htonn(&fee, args + 111, 8, sizeof(unsigned long long)); htonn(&tax, args + 119, 8, sizeof(unsigned long long)); unsigned char resp[1024]; unsigned short rn = 0; int rc = send_user_cmd(T->ip, T->port, T->secret32, &T->user_counter, 3, args, sizeof(args), resp, &rn); if (rc == 0) { printf("[auto] %s: new_payment(cp=%s:%u, amount=%llu, in_or_out=%u, fee=%llu, tax=%llu) → %s\n", T->name, cp_user, (unsigned)cp_port, (unsigned long long)amount, (unsigned)in_or_out, (unsigned long long)fee, (unsigned long long)tax, (rn >= REQ_ENVELOPE + 1 && resp[5] == 0) ? "OK" : "ERROR"); } return rc; } static int cmd_start_payment(ClientTarget *T) { unsigned char resp[1024]; unsigned short rn = 0; int rc = send_user_cmd(T->ip, T->port, T->secret32, &T->user_counter, 4, NULL, 0, resp, &rn); if (rc == 0) { printf("[auto] %s: start_payment → %s\n", T->name, (rn >= REQ_ENVELOPE + 1 && resp[5] == 0) ? "OK" : "ERROR"); } return rc; } int main(void) { if ((unsigned char)~0 != 0xFF) return 1; short tmp = 0x0001; endianess = *(char*)&tmp; ServerConfig cfg[3] = { { "Alice", "/tmp/ripple_A.bin", 2012, {0} }, { "Bob", "/tmp/ripple_B.bin", 2013, {0} }, { "Carol", "/tmp/ripple_C.bin", 2014, {0} } }; memcpy(cfg[0].secret32, SECRET_A, 32); memcpy(cfg[1].secret32, SECRET_B, 32); memcpy(cfg[2].secret32, SECRET_C, 32); pthread_t th[3]; for (int i = 0; i < 3; i++) { if (pthread_create(&th[i], NULL, server_thread, &cfg[i]) != 0) { perror("pthread_create"); running = 0; for (int j = 0; j < i; j++) pthread_kill(th[j], SIGTERM); for (int j = 0; j < i; j++) pthread_join(th[j], NULL); return 1; } } usleep(200 * 1000); ClientTarget T[3] = { { "127.0.0.1", cfg[0].port, {0}, 0, cfg[0].username }, { "127.0.0.1", cfg[1].port, {0}, 0, cfg[1].username }, { "127.0.0.1", cfg[2].port, {0}, 0, cfg[2].username } }; memcpy(T[0].secret32, cfg[0].secret32, 32); memcpy(T[1].secret32, cfg[1].secret32, 32); memcpy(T[2].secret32, cfg[2].secret32, 32); cmd_add_account(&T[0], "Bob", cfg[1].port, SECRET_33); cmd_add_account(&T[1], "Alice", cfg[0].port, SECRET_33); cmd_add_account(&T[1], "Carol", cfg[2].port, SECRET_44); cmd_add_account(&T[2], "Bob", cfg[1].port, SECRET_44); printf("[auto] added accounts (Alice<->Bob key=33.., Bob<->Carol key=44..)\n"); cmd_set_trustline(&T[1], "Alice", 10000ULL); cmd_set_trustline(&T[2], "Bob", 10000ULL); printf("[auto] trustlines set (Bob->Alice=10000, Carol->Bob=10000)\n"); const unsigned long long amount = 1000ULL; const unsigned long long fee = 20ULL; const unsigned long long tax = 0ULL; const unsigned int penalty= 300U; cmd_new_payment(&T[0], "Carol", cfg[2].port, SECRET_AC, amount, 0 , penalty, fee, tax); cmd_new_payment(&T[2], "Alice", cfg[0].port, SECRET_AC, amount, 1, penalty, fee, tax); cmd_start_payment(&T[2]); printf("[auto] registered new_payment (A:out, C:in), start_payment from C.\n"); for (int i = 0; i < 3; i++) pthread_join(th[i], NULL); if (ctl_sock >= 0) close(ctl_sock); return 0; }

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue