├── .gitignore ├── src ├── totp.h ├── socks.c ├── socks.h ├── box.h ├── packet.h ├── spinlock.h ├── box.c ├── handshake.h ├── totp.c ├── common.h ├── queue.h ├── typroto.h ├── packet.c ├── rqutils.h ├── typroto.c ├── handshake.c └── queue.c ├── cmake ├── uninstall.cmake ├── FindSodium.cmake └── FindGlib.cmake ├── SPEC.md ├── tools ├── gen_key.c ├── tperf_client.c └── tperf_server.c ├── tests ├── test_pkt.c ├── test_hs.c ├── test_network.c └── test_stress.c ├── .gitlab-ci.yml └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | .idea/ 3 | -------------------------------------------------------------------------------- /src/totp.h: -------------------------------------------------------------------------------- 1 | // 2 | // totp.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #ifndef totp_h 10 | #define totp_h 11 | 12 | #include "common.h" 13 | 14 | 15 | void hotp(const unsigned char *key, size_t keylen, uint64_t counter, int ndigits, char *buf10, char *buf16, size_t buflen); 16 | 17 | void totp(const unsigned char *key, size_t keylen, int timeStep, int ndigits, char *buf10, char *buf16, size_t buflen); 18 | 19 | #endif /* totp_h */ 20 | -------------------------------------------------------------------------------- /cmake/uninstall.cmake: -------------------------------------------------------------------------------- 1 | set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") 2 | 3 | if(NOT EXISTS ${MANIFEST}) 4 | message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") 5 | endif() 6 | 7 | file(STRINGS ${MANIFEST} files) 8 | foreach(file ${files}) 9 | if(EXISTS ${file}) 10 | message(STATUS "Removing file: '${file}'") 11 | 12 | exec_program( 13 | ${CMAKE_COMMAND} ARGS "-E remove ${file}" 14 | OUTPUT_VARIABLE stdout 15 | RETURN_VALUE result 16 | ) 17 | 18 | if(NOT "${result}" STREQUAL 0) 19 | message(FATAL_ERROR "Failed to remove file: '${file}'.") 20 | endif() 21 | else() 22 | MESSAGE(STATUS "File '${file}' does not exist.") 23 | endif() 24 | endforeach(file) -------------------------------------------------------------------------------- /src/socks.c: -------------------------------------------------------------------------------- 1 | // 2 | // socks.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #include "socks.h" 10 | #include 11 | #include 12 | 13 | // TODO: Add O(1) sock map type 14 | // Current only support very simple fd id based map 15 | 16 | struct Socket *_temp_skt_map[1024]; 17 | 18 | const struct Socket *tp_get_sock_by_id(int fd){ 19 | return _temp_skt_map[fd]; 20 | } 21 | 22 | void tp_add_sock(int fd, struct Socket * skt){ 23 | _temp_skt_map[fd] = skt; 24 | } 25 | 26 | void tp_remove_sock(int fd){ 27 | struct Socket *skt = _temp_skt_map[fd]; 28 | if(skt){ 29 | tp_send_queue_destroy(skt->sendqueue); 30 | tp_recv_queue_destroy(skt->recvqueue); 31 | free(skt->addr); 32 | sodium_free(skt->transfer_key); 33 | free(skt); 34 | } 35 | } -------------------------------------------------------------------------------- /src/socks.h: -------------------------------------------------------------------------------- 1 | // 2 | // socks.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #ifndef socks_h 10 | #define socks_h 11 | 12 | 13 | #ifdef _WIN32 14 | #include 15 | #else 16 | #include 17 | #endif 18 | #include "queue.h" 19 | #include "typroto.h" 20 | 21 | struct Socket { 22 | int fd; 23 | 24 | struct sockaddr *addr; 25 | socklen_t sockaddr_len; 26 | 27 | uint8_t *transfer_key; 28 | uint32_t packet_size; 29 | 30 | struct SendQueue *sendqueue; 31 | struct RecvQueue *recvqueue; 32 | 33 | event_cb_t evt; 34 | void *evt_userdata; 35 | }; 36 | 37 | #ifdef __cplusplus 38 | extern "C" { 39 | #endif 40 | 41 | const struct Socket *tp_get_sock_by_id(int fd); 42 | void tp_add_sock(int fd, struct Socket * skt); 43 | void tp_remove_sock(int fd); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif /* socks_h */ 50 | -------------------------------------------------------------------------------- /src/box.h: -------------------------------------------------------------------------------- 1 | // 2 | // box.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #ifndef box_h 10 | #define box_h 11 | #include "common.h" 12 | 13 | #define PT_CLIENT_HELLO 1 14 | #define PT_SERVER_HELLO 2 15 | #define PT_DATA 3 16 | #define PT_DATA_NEED_ACK 4 17 | #define PT_ACK 11 18 | #define PT_SACK 12 19 | 20 | #define TP_SEC_HEADER_SIZE 15 21 | 22 | struct Box { 23 | uint8_t type; 24 | uint32_t timestamp; 25 | uint64_t packet_id; 26 | uint16_t payload_length; 27 | uint8_t *payload; 28 | // Padding will removed 29 | }; 30 | 31 | enum _BOX_ERROR 32 | { 33 | B_SUCCESS = 0, 34 | B_INVALID_INPUT = -1, 35 | B_BUFFER_TOO_SMALL = -2, 36 | }; 37 | 38 | typedef enum _BOX_ERROR BOX_ERROR; 39 | 40 | BOX_ERROR tp_box_data_build(struct Box *inbox, uint8_t *buf, uint32_t buflen); 41 | BOX_ERROR tp_box_data_open(struct Box *outbox, uint8_t *buf, uint32_t buflen); 42 | 43 | 44 | #endif /* box_h */ 45 | -------------------------------------------------------------------------------- /src/packet.h: -------------------------------------------------------------------------------- 1 | // 2 | // packet.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #ifndef packet_h 10 | #define packet_h 11 | 12 | 13 | 14 | #include "box.h" 15 | 16 | #define PKT_TAG_SIZE crypto_aead_chacha20poly1305_ABYTES 17 | #define PKT_NONCE_SIZE crypto_aead_chacha20poly1305_NPUBBYTES 18 | 19 | struct Packet { 20 | uint8_t *nonce; 21 | uint8_t *secret_box; 22 | uint8_t *tag; 23 | 24 | // Box may not always exists ( eg: encrypt & send ), you must alloc it before call decrypt function 25 | struct Box *box; 26 | uint32_t secret_box_len; 27 | }; 28 | 29 | enum _PKT_ERROR 30 | { 31 | P_TIMESTAMP_MISMATCH = 1, 32 | P_SUCCESS = 0, 33 | P_ENCRYPT_FAILED = -1, 34 | P_BUFFER_TOO_SMALL = -2, 35 | P_BOX_BUILD_FAILED = -3, 36 | P_BOX_OPEN_FAILED = -4, 37 | P_DECRYPT_FAILED = -5, 38 | P_INCORRECT_TAG = -6, 39 | }; 40 | 41 | typedef enum _PKT_ERROR PKT_ERROR; 42 | 43 | PKT_ERROR tp_packet_encrypt(struct Box *inbox, uint8_t *buf, uint32_t buflen, const uint8_t *key); 44 | PKT_ERROR tp_packet_decrypt(struct Packet *outpkt, uint8_t *buf, uint32_t buflen, const uint8_t *key); 45 | 46 | #endif /* packet_h */ 47 | -------------------------------------------------------------------------------- /cmake/FindSodium.cmake: -------------------------------------------------------------------------------- 1 | 2 | # - Find Sodium 3 | # Find the native libsodium includes and library. 4 | # Once done this will define 5 | # 6 | # SODIUM_INCLUDE_DIR - where to find libsodium header files, etc. 7 | # SODIUM_LIBRARY - List of libraries when using libsodium. 8 | # SODIUM_FOUND - True if libsodium found. 9 | # 10 | 11 | find_package(PkgConfig) 12 | pkg_check_modules(PC_SODIUM QUIET sodium) 13 | pkg_check_modules(PC_LSODIUM QUIET libsodium) 14 | 15 | FIND_LIBRARY(SODIUM_LIBRARY 16 | NAMES sodium libsodium 17 | HINTS ${SODIUM_ROOT_DIR}/lib 18 | ${PC_SODIUM_LIBDIR} 19 | ${PC_LSODIUM_LIBDIR} 20 | ) 21 | 22 | find_path(SODIUM_INCLUDE_DIR 23 | NAMES sodium.h 24 | HINTS ${SODIUM_ROOT_DIR}/include 25 | ${PC_SODIUM_INCLUDEDIR} 26 | ${PC_SODIUM_INCLUDE_DIRS} 27 | ${PC_LSODIUM_INCLUDEDIR} 28 | ${PC_LSODIUM_INCLUDE_DIRS} 29 | ) 30 | 31 | # handle the QUIETLY and REQUIRED arguments and set SODIUM_FOUND to TRUE if 32 | # all listed variables are TRUE 33 | INCLUDE(FindPackageHandleStandardArgs) 34 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(Sodium REQUIRED_VARS SODIUM_LIBRARY SODIUM_INCLUDE_DIR) 35 | 36 | MARK_AS_ADVANCED(SODIUM_LIBRARY SODIUM_INCLUDE_DIR) 37 | -------------------------------------------------------------------------------- /src/spinlock.h: -------------------------------------------------------------------------------- 1 | #ifdef __APPLE__ 2 | #include 3 | #ifndef PTHREAD_SPIN_LOCK_SHIM 4 | #define PTHREAD_SPIN_LOCK_SHIM 5 | 6 | typedef int pthread_spinlock_t; 7 | 8 | #ifndef PTHREAD_PROCESS_SHARED 9 | # define PTHREAD_PROCESS_SHARED 1 10 | #endif 11 | #ifndef PTHREAD_PROCESS_PRIVATE 12 | # define PTHREAD_PROCESS_PRIVATE 2 13 | #endif 14 | 15 | static inline int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { 16 | __asm__ __volatile__ ("" ::: "memory"); 17 | *lock = 0; 18 | return 0; 19 | } 20 | 21 | static inline int pthread_spin_destroy(pthread_spinlock_t *lock) { 22 | return 0; 23 | } 24 | 25 | static inline int pthread_spin_lock(pthread_spinlock_t *lock) { 26 | while (1) { 27 | int i; 28 | for (i=0; i < 10000; i++) { 29 | if (__sync_bool_compare_and_swap(lock, 0, 1)) { 30 | return 0; 31 | } 32 | } 33 | sched_yield(); 34 | } 35 | } 36 | 37 | static inline int pthread_spin_trylock(pthread_spinlock_t *lock) { 38 | if (__sync_bool_compare_and_swap(lock, 0, 1)) { 39 | return 0; 40 | } 41 | return EBUSY; 42 | } 43 | 44 | static inline int pthread_spin_unlock(pthread_spinlock_t *lock) { 45 | __asm__ __volatile__ ("" ::: "memory"); 46 | *lock = 0; 47 | return 0; 48 | } 49 | 50 | #endif 51 | 52 | #endif -------------------------------------------------------------------------------- /SPEC.md: -------------------------------------------------------------------------------- 1 | # TYProto SPEC v0.1 2 | 3 | ## Packet 4 | | NONCE | Secret Box | Tag | 5 | |:-----:|:------------:|:-----:| 6 | | * | * | * | 7 | ## Secret Box 8 | | Type | Timestamp | Packet ID | Payload Length | Payload | Padding | 9 | |:------:|:-------------:|:------------:|:--------------:|:-------:|:-------:| 10 | | 1 byte | 4 bytes int32 | 8 byte int64 | 2 bytes int16 | * | * | 11 | 12 | Secret box is encrypted using CHACHA20-POLY1305 13 | 14 | ## Packet Types 15 | 16 | 1. Client Hello 17 | 2. Server Hello 18 | 3. Data 19 | 11. ACK 20 | 12. SACK 21 | 22 | # Connection 23 | 24 | ## Client Hello 25 | ##### TYPE:1 , PAYLOAD: Public Key 26 | 27 | Handshake is encrypted using 256 bit pre-shared key: 28 | 29 | HMAC_SHA256(PSK, TOTP_HEX(PSK)) 30 | 31 | Client generate a RSA key pair. and put the public key in secret box. 32 | 33 | ## Server Hello 34 | ##### TYPE:2 , PAYLOAD: Encrypted transfer key 35 | Server generate a random key for data transfer , encrypt it with public key , and send it to client. 36 | 37 | ## Data 38 | ##### TYPE:3-10 , PAYLOAD: Data 39 | User custom data 40 | 41 | ``` 42 | 3: Normal Data 43 | 44 | 4: Data must reply ACK 45 | 46 | 5-10: Reversed 47 | ``` 48 | 49 | ## ACK 50 | ##### TYPE:11 , PAYLOAD: 8 Byte Last Confirmed Packet ID 51 | Confirm packet is received 52 | 53 | ## SACK 54 | ##### TYPE:12 , PAYLOAD: 8 Byte First Missing Packet ID + 4 Bit Int Array Size + Packet Status Bit Array 55 | If server received out-of-order packet , request missing packet immediately. -------------------------------------------------------------------------------- /src/box.c: -------------------------------------------------------------------------------- 1 | // 2 | // box.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #include "box.h" 10 | #include "common.h" 11 | #include 12 | 13 | BOX_ERROR tp_box_data_build(struct Box *inbox, uint8_t *buf, uint32_t buflen){ 14 | if(buflen - TP_SEC_HEADER_SIZE < inbox->payload_length){ 15 | printd("Buffer length %d too short, at least need %d\n",buflen, inbox->payload_length + TP_SEC_HEADER_SIZE); 16 | return B_BUFFER_TOO_SMALL; 17 | } 18 | buf[0] = inbox->type; 19 | memcpy(buf+1, &inbox->timestamp, 4); 20 | memcpy(buf+5, &inbox->packet_id, 8); 21 | memcpy(buf+13, &inbox->payload_length, 2); 22 | 23 | if(inbox->payload_length > 0){ 24 | memcpy(buf + TP_SEC_HEADER_SIZE, inbox->payload, inbox->payload_length); 25 | } 26 | 27 | uint64_t offset = TP_SEC_HEADER_SIZE + inbox->payload_length; 28 | 29 | memset(buf + offset, 0, buflen - offset); 30 | 31 | return B_SUCCESS; 32 | } 33 | 34 | BOX_ERROR tp_box_data_open(struct Box *outbox, uint8_t *buf, uint32_t buflen){ 35 | if(buflen < 15){ 36 | printd("Invalid buffer length %d\n",buflen); 37 | return B_BUFFER_TOO_SMALL; 38 | } 39 | outbox->type = buf[0]; 40 | memcpy(&outbox->timestamp, buf+1, 4); 41 | memcpy(&outbox->packet_id, buf+5, 8); 42 | memcpy(&outbox->payload_length, buf+13, 2); 43 | 44 | if(outbox->payload_length > 0){ 45 | outbox->payload = malloc(outbox->payload_length); 46 | memcpy(outbox->payload, buf + TP_SEC_HEADER_SIZE, outbox->payload_length); 47 | } 48 | 49 | return B_SUCCESS; 50 | } -------------------------------------------------------------------------------- /tools/gen_key.c: -------------------------------------------------------------------------------- 1 | // 2 | // gen_key.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/8. 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int write_file(const char* name, const uint8_t *buf, uint32_t size){ 17 | int rv = -1; 18 | FILE *file; 19 | file = fopen(name, "w"); 20 | if (file) { 21 | fwrite(&size, 4, 1, file); 22 | fwrite(buf, size, 1, file); 23 | rv = 0; 24 | fclose(file); 25 | } 26 | return rv; 27 | } 28 | 29 | 30 | int main(int argc, char *argv[]){ 31 | if(argc < 2){ 32 | printf("Usage: ./gen_key LENGTH_BITS\n"); 33 | return -1; 34 | } 35 | int kb = atoi(argv[1]); 36 | if(kb < 1024){ 37 | printf("At least 1024 bits\n"); 38 | return -1; 39 | }else if(kb < 4096){ 40 | printf("We suggest you use > 4096 bits key\n"); 41 | } 42 | 43 | printf("Generating %d bits RSA keypair\n",kb); 44 | 45 | RSA *rsa_o = RSA_new(); 46 | BIGNUM *big_number = BN_new(); 47 | BN_set_word(big_number , RSA_F4); 48 | int ret = RSA_generate_key_ex(rsa_o, kb, big_number, NULL); 49 | if(ret != 1){ 50 | printf("RSA keypair generate failed with ret %d\n",ret); 51 | return -1; 52 | } 53 | 54 | uint8_t *private_key = NULL; 55 | int private_key_length = i2d_RSAPrivateKey(rsa_o, &private_key); 56 | write_file("rsa_priv", private_key, private_key_length); 57 | 58 | uint8_t *public_key = NULL; 59 | int public_key_length = i2d_RSAPublicKey(rsa_o, &public_key); 60 | write_file("rsa_pub", public_key, public_key_length); 61 | } -------------------------------------------------------------------------------- /tests/test_pkt.c: -------------------------------------------------------------------------------- 1 | // 2 | // test_pkt.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | 10 | #include "../src/typroto.h" 11 | #include "../src/packet.h" 12 | #include "../src/box.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | void test(){ 20 | unsigned char key[crypto_aead_chacha20poly1305_KEYBYTES]; 21 | randombytes_buf(key, sizeof key); 22 | 23 | unsigned char *c = (unsigned char *)"Hello world"; 24 | 25 | struct Box inbox; 26 | inbox.packet_id = 1; 27 | inbox.timestamp = time(NULL); 28 | inbox.type = 1; 29 | inbox.payload = c; 30 | inbox.payload_length = 11; 31 | 32 | uint8_t *inbuf = malloc(1400); 33 | 34 | printf("Start encrypt packet\n"); 35 | 36 | int rv = tp_packet_encrypt(&inbox, inbuf, 1400, key); 37 | assert(rv == 0); 38 | 39 | printf("Packet encrypted\n"); 40 | 41 | struct Box outbox; 42 | 43 | struct Packet outpkt; 44 | outpkt.box = &outbox; 45 | 46 | rv = tp_packet_decrypt(&outpkt, inbuf, 1400, key); 47 | assert(rv == 0); 48 | 49 | printf("Decrypted packet: %s\n",outpkt.box->payload); 50 | assert(memcmp(outpkt.box->payload, c, 11) == 0); 51 | free(outpkt.box->payload); 52 | free(inbuf); 53 | } 54 | 55 | int main(){ 56 | int rv = tp_init(); 57 | if(rv != 0){ 58 | printf("Failed to init typroto\n"); 59 | return -1; 60 | } 61 | struct rusage* memory = malloc(sizeof(struct rusage)); 62 | getrusage(RUSAGE_SELF, memory); 63 | long init_memory = memory->ru_maxrss; 64 | for (int i = 0; i < 10000; i++) { 65 | test(); 66 | } 67 | getrusage(RUSAGE_SELF, memory); 68 | if(memory->ru_maxrss - init_memory > 120000){ 69 | printf("Possible memory leak detected: init usage: %ld after: %ld\n",init_memory,memory->ru_maxrss); 70 | return -1; 71 | } 72 | return 0; 73 | } -------------------------------------------------------------------------------- /tests/test_hs.c: -------------------------------------------------------------------------------- 1 | // 2 | // test_hs.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | 10 | #include "../src/typroto.h" 11 | #include "../src/packet.h" 12 | #include "../src/box.h" 13 | #include "../src/handshake.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | void test(){ 23 | const char *psk = "123456"; 24 | 25 | void *kb = sodium_malloc(8192); 26 | void *hsp = malloc(1400); 27 | int klen = tp_build_handshake_packet(kb, hsp, 1400, psk); 28 | assert(klen > 0); 29 | 30 | 31 | void *skb = malloc(32); 32 | void *rsp = malloc(1400); 33 | int rv = tp_build_handshake_packet_response(skb, rsp, 1400, hsp, 1400, psk); 34 | assert(rv == 0); 35 | 36 | void *outskb = malloc(32); 37 | rv = tp_handshake_response_decrypt(outskb, kb, klen, rsp, 1400, psk); 38 | assert(rv == 0); 39 | 40 | assert(sodium_memcmp(skb, outskb, 32) == 0); 41 | 42 | sodium_mprotect_readwrite(kb); 43 | sodium_free(kb); 44 | free(hsp); 45 | free(rsp); 46 | free(skb); 47 | free(outskb); 48 | } 49 | 50 | int main(){ 51 | int rv = tp_init(); 52 | if(rv != 0){ 53 | printf("Failed to init typroto\n"); 54 | return -1; 55 | } 56 | struct rusage* memory = malloc(sizeof(struct rusage)); 57 | getrusage(RUSAGE_SELF, memory); 58 | long init_memory = memory->ru_maxrss; 59 | for (int i = 0; i < 10; i++) { 60 | test(); 61 | } 62 | CRYPTO_cleanup_all_ex_data(); 63 | ERR_free_strings(); 64 | ERR_remove_state(0); 65 | EVP_cleanup(); 66 | getrusage(RUSAGE_SELF, memory); 67 | if(memory->ru_maxrss - init_memory > 600000){ // There are some leaks by openssl 68 | printf("Possible memory leak detected: init usage: %ld after: %ld\n",init_memory,memory->ru_maxrss); 69 | return -1; 70 | } 71 | return 0; 72 | } -------------------------------------------------------------------------------- /src/handshake.h: -------------------------------------------------------------------------------- 1 | // 2 | // handshake.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #ifndef handshake_h 10 | #define handshake_h 11 | 12 | #include "common.h" 13 | 14 | #define TP_RSA_KEY_BITS 4096 15 | 16 | /** @brief Calc encryption key for handshake packet 17 | * 18 | * @param psk The pre-shared key 19 | * @param buf Key buffer ( 32 bytes ) 20 | */ 21 | void tp_calc_encrypt_key(const char *psk, uint8_t *buf); 22 | 23 | /** @brief Build a handshake request 24 | * 25 | * This function should never fail, if -1 is returned , please build with debug mode and watch logs 26 | * 27 | * @param keybuf Output private key buffer, the buffer must be allocated with sodium_malloc 28 | * @param databuf Output packet data buffer 29 | * @param buflen Length of output packet buffer 30 | * @return size of private key , -1 for fail 31 | */ 32 | int tp_build_handshake_packet(uint8_t *keybuf, uint8_t *databuf, uint32_t buflen, const char *psk); 33 | 34 | /** @brief Decode handshake request and build a reply 35 | * 36 | * If return value is not 0 , free your all buf , and do not reply anything to client 37 | * Error codes may in enum PKT_ERROR 38 | * 39 | * @param outkeybuf New symmetry key output buffer ( 32 bytes ) 40 | * @param respbuf Output response packet buffer 41 | * @param rbuflen Length of response buffer 42 | * @param databuf Input packet data buffer 43 | * @param buflen Length of input packet buffer 44 | * @return 0 for success , other for fail 45 | */ 46 | int tp_build_handshake_packet_response(uint8_t *outkeybuf, uint8_t *respbuf, uint32_t rbuflen, uint8_t *databuf, uint32_t buflen, const char *psk); 47 | 48 | /** @brief Decrypt a handshake response 49 | * 50 | * @param outkeybuf New symmetry key output buffer ( 32 byte ) 51 | * @param inkeybuf Keybuf of build_handshake_packet 52 | * @param inkeylen Return value of build_handshake_packet 53 | * @param inbuf Input data 54 | * @param inlen Input data length 55 | * @return 0 for success , other for fail 56 | */ 57 | int tp_handshake_response_decrypt(uint8_t *outkeybuf, uint8_t *inkeybuf, uint32_t inkeylen,uint8_t *inbuf, uint32_t inlen, const char *psk); 58 | 59 | #endif /* handshake_h */ 60 | -------------------------------------------------------------------------------- /src/totp.c: -------------------------------------------------------------------------------- 1 | // 2 | // totp.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #include "totp.h" 10 | #include 11 | #include 12 | 13 | /* Powers of ten */ 14 | static const int powers10[] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 1000000000 }; 15 | 16 | /* 17 | * Generate an OTP using the algorithm specified in RFC 4226, 18 | */ 19 | void hotp(const unsigned char *key, size_t keylen, uint64_t counter, int ndigits, char *buf10, char *buf16, size_t buflen) 20 | { 21 | const int max10 = sizeof(powers10) / sizeof(*powers10); 22 | const int max16 = 8; 23 | const EVP_MD *sha1_md = EVP_sha1(); 24 | unsigned char hash[EVP_MAX_MD_SIZE]; 25 | unsigned int hash_len; 26 | unsigned char tosign[8]; 27 | int offset; 28 | int value; 29 | int i; 30 | 31 | /* Encode counter */ 32 | for (i = sizeof(tosign) - 1; i >= 0; i--) { 33 | tosign[i] = counter & 0xff; 34 | counter >>= 8; 35 | } 36 | 37 | /* Compute HMAC */ 38 | HMAC(sha1_md, key, keylen, tosign, sizeof(tosign), hash, &hash_len); 39 | 40 | /* Extract selected bytes to get 32 bit integer value */ 41 | offset = hash[hash_len - 1] & 0x0f; 42 | value = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16) 43 | | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff); 44 | 45 | /* Sanity check max # digits */ 46 | if (ndigits < 1) 47 | ndigits = 1; 48 | 49 | /* Generate decimal digits */ 50 | if (buf10 != NULL) { 51 | snprintf(buf10, buflen, "%0*d", ndigits < max10 ? ndigits : max10, 52 | ndigits < max10 ? value % powers10[ndigits - 1] : value); 53 | } 54 | 55 | /* Generate hexadecimal digits */ 56 | if (buf16 != NULL) { 57 | snprintf(buf16, buflen, "%0*x", ndigits < max16 ? ndigits : max16, 58 | ndigits < max16 ? (value & ((1 << (4 * ndigits)) - 1)) : value); 59 | } 60 | } 61 | 62 | void totp(const unsigned char *key, size_t keylen, int timeStep, int ndigits, char *buf10, char *buf16, size_t buflen){ 63 | int timeCounter = floor(time(NULL) / timeStep); 64 | hotp(key, keylen, timeCounter, ndigits, buf10, buf16, buflen); 65 | } 66 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | // 2 | // common.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #ifndef common_h 10 | #define common_h 11 | #define TYPROTO 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) 21 | 22 | 23 | // The buffer size is in "packet", not in bytes 24 | // To control the packet size , look at the pktSize param of connect() and accept() 25 | #define TP_SEND_BUFFER_SIZE 2048 26 | #define TP_RECV_BUFFER_SIZE 2048 // Set a larger value if you have enough memory 27 | 28 | // Receive timeout ( seconds ) 29 | #define TP_RECV_TIMEOUT 2 30 | 31 | // ACK Delay in ms , Be careful: ACK Packet is also padded to full size ( = pktSize ) 32 | // Send timeout will be set to ACK_DELAY + f(NETWORK_DELAY) 33 | // Set a lager value for downloading / mobile device 34 | #define TP_ACK_SEND_DELAY 100 35 | // Repeat send x times ACK packet 36 | #define TP_ACK_REPEAT_COUNT 2 37 | 38 | // If last received id - last free id > sack threshold , an SACK packet will be sent 39 | #define TP_SACK_THRESHOLD 10 40 | // Min delay between two SACK packets 41 | #define TP_SACK_SEND_DELAY 100 42 | // Repeat send x times SACK packet 43 | #define TP_SACK_REPEAT_COUNT 1 44 | // never > mtu 1500, 2048 is safe 45 | #define TP_SACK_BUFFER_SIZE 2048 46 | 47 | #define TP_INIT_WINDOW_SIZE 500 48 | 49 | #define TP_INIT_RESEND_DELAY 250 50 | 51 | // Enable it will log every packet send , recv , ack , free 52 | #define ENABLE_VERBOSE_LOGGING 0 53 | // Enable random packet loss , Percent 54 | #define ENABLE_RANDOM_PACKET_LOSS 0 55 | 56 | #ifdef DEBUG 57 | #define printd(fmt, ...) printf("[TYProto][%s-%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) 58 | #else 59 | #define printd(fmt, ...) 60 | #endif 61 | 62 | #if ENABLE_VERBOSE_LOGGING == 1 63 | #define printv(fmt, ...) printf("[TYProto][%s-%d] " fmt, __FILENAME__, __LINE__, __VA_ARGS__) 64 | #else 65 | #define printv(fmt, ...) 66 | #endif 67 | 68 | // Add some random packet drop, percent , 1-100. comment to disable 69 | // #define ENABLE_PACKET_DROP 10 70 | 71 | // Enable it to allow read RSA KEY from file , will decrease security, only for very low performance devices 72 | // #define TP_RSA_LOAD_FROM_FILE 1 73 | 74 | #ifndef CHAR_BIT 75 | #define CHAR_BIT 8 76 | #endif 77 | 78 | #endif /* common_h */ 79 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | GIT_SSL_NO_VERIFY: "true" 3 | 4 | stages: 5 | - build 6 | 7 | build: 8 | stage: build 9 | tags: 10 | - typcn 11 | script: 12 | - mkdir build 13 | - cd build 14 | - cmake .. 15 | - make 16 | - make test 17 | 18 | build_sec: 19 | stage: build 20 | tags: 21 | - typcn 22 | script: 23 | - mkdir build 24 | - cd build 25 | - cmake .. -DENABLE_SEC=1 26 | - make 27 | - make test 28 | 29 | build_for_tysocks_linux32: 30 | stage: build 31 | tags: 32 | - kirito 33 | - archlinux 34 | - i686 35 | script: 36 | - mkdir build-linux32 37 | - cd build-linux32 38 | - cmake .. -DENABLE_SEC=1 39 | - make 40 | - sudo make install 41 | 42 | build_for_tysocks_linux64: 43 | stage: build 44 | tags: 45 | - kirito 46 | - archlinux 47 | - x86_64 48 | script: 49 | - mkdir build-linux64 50 | - cd build-linux64 51 | - cmake .. -DENABLE_SEC=1 52 | - make 53 | - sudo make install 54 | 55 | build_for_tysocks_win32: 56 | stage: build 57 | tags: 58 | - mingw 59 | - i686 60 | variables: 61 | TARGET: "i686-w64-mingw32" 62 | script: 63 | - mkdir build-win32 64 | - cd build-win32 65 | - ${TARGET}-cmake .. -DENABLE_SEC=1 66 | - make 67 | - sudo make install 68 | 69 | build_for_tysocks_win64: 70 | stage: build 71 | tags: 72 | - mingw 73 | - x86_64 74 | variables: 75 | TARGET: "x86_64-w64-mingw32" 76 | script: 77 | - mkdir build-win64 78 | - cd build-win64 79 | - ${TARGET}-cmake .. -DENABLE_SEC=1 80 | - make 81 | - sudo make install 82 | 83 | build_for_tysocks_armv5tel: 84 | stage: build 85 | tags: 86 | - armv5tel 87 | variables: 88 | TARGET: "armv5tel-unknown-linux-gnueabi" 89 | script: 90 | - mkdir build-armv5tel 91 | - cd build-armv5tel 92 | - ${TARGET}-cmake .. -DENABLE_SEC=1 93 | - make 94 | - sudo make install 95 | 96 | build_for_tysocks_armv6h: 97 | stage: build 98 | tags: 99 | - armv6h 100 | variables: 101 | TARGET: "armv6l-unknown-linux-gnueabihf" 102 | script: 103 | - mkdir build-armv6h 104 | - cd build-armv6h 105 | - ${TARGET}-cmake .. -DENABLE_SEC=1 106 | - make 107 | - sudo make install 108 | 109 | build_for_tysocks_armv7h: 110 | stage: build 111 | tags: 112 | - armv7h 113 | variables: 114 | TARGET: "armv7l-unknown-linux-gnueabihf" 115 | script: 116 | - mkdir build-armv7h 117 | - cd build-armv7h 118 | - ${TARGET}-cmake .. -DENABLE_SEC=1 119 | - make 120 | - sudo make install 121 | 122 | build_for_tysocks_aarch64: 123 | stage: build 124 | tags: 125 | - aarch64 126 | variables: 127 | TARGET: "aarch64-unknown-linux-gnueabi" 128 | script: 129 | - mkdir build-aarch64 130 | - cd build-aarch64 131 | - ${TARGET}-cmake .. -DENABLE_SEC=1 132 | - make 133 | - sudo make install 134 | 135 | build_for_tysocks_darwin64: 136 | stage: build 137 | tags: 138 | - darwin64 139 | variables: 140 | TARGET: "x86_64-apple-darwin15" 141 | script: 142 | - mkdir build-darwin64 143 | - cd build-darwin64 144 | - ${TARGET}-cmake .. -DENABLE_SEC=1 145 | - make 146 | - sudo make install 147 | -------------------------------------------------------------------------------- /src/queue.h: -------------------------------------------------------------------------------- 1 | // 2 | // queue.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #ifndef queue_h 10 | #define queue_h 11 | 12 | #include 13 | #include 14 | #include "box.h" 15 | #include "packet.h" 16 | #include "socks.h" 17 | #include "common.h" 18 | #include "spinlock.h" 19 | #include "typroto.h" 20 | 21 | struct SendQueue { 22 | const struct Socket* skt; 23 | 24 | // Some firewall may drop packet with same content, and may identify this is an rudp protocol 25 | // So just save the raw box, if packet got dropped , encrypt it with different nonce then resend 26 | struct Box *boxes[TP_SEND_BUFFER_SIZE]; // Same position should never writed before sent 27 | uint64_t sent_ts[TP_SEND_BUFFER_SIZE]; 28 | 29 | pthread_t thread; 30 | pthread_mutex_t lock; 31 | pthread_spinlock_t ack_lock; 32 | 33 | pthread_cond_t idle_cond; 34 | pthread_cond_t nobufs_cond; 35 | 36 | bool idle_wait; 37 | bool nobufs_wait; 38 | 39 | // These 2 numbers need lock for r/w 40 | uint64_t sent_offset; // Incr on every packet sent, reset to 0 on reach int64 max (TODO) 41 | uint64_t write_offset; 42 | 43 | // These 5 values need ack_lock for r/w 44 | uint64_t last_ack_id; 45 | uint64_t last_sack_id; 46 | int last_sack_length; 47 | uint8_t sack_bitmap[TP_SACK_BUFFER_SIZE]; 48 | bool ack_reset_perform; 49 | bool sack_reset_perform; 50 | 51 | // These 1 number should only read/write on same thread 52 | uint64_t last_packet_id; 53 | 54 | bool stopping; 55 | 56 | // Options - You can change it via user interface ot others 57 | int window_size; 58 | int resend_delay; 59 | int speed_limit; // Packet per second 60 | int max_resend_timeout; // How many resends without ACK cause timeout 61 | 62 | // Stats - Read it may cause race cond and got invalid value, and do not write it 63 | uint64_t packet_num; // Packets transmitted include resends 64 | uint64_t packet_resend; // Resend packets 65 | }; 66 | 67 | struct RecvQueue { 68 | const struct Socket* skt; 69 | recv_cb_t callback; 70 | void *callback_userdata; 71 | 72 | struct Box *boxes[TP_RECV_BUFFER_SIZE]; 73 | 74 | pthread_t thread; 75 | 76 | // These numbers should only read/write on receiving thread 77 | uint64_t last_received_id; 78 | uint64_t last_completed_id; 79 | uint64_t last_ack_time; 80 | uint64_t last_sack_time; 81 | uint64_t last_sack_sent; 82 | 83 | // Options - You can change it via user interface ot others 84 | int sack_send_delay; 85 | int sack_threshold; 86 | int ack_send_delay; 87 | 88 | 89 | // Stats - Read it may cause race cond , and do not write it 90 | uint64_t user_bytes; // Bytes of payload received and not dropped 91 | uint64_t real_bytes; // Bytes include header / tag / invalid packets 92 | uint64_t packet_num; // Packets received 93 | uint64_t packet_dup; // Duplicate packets 94 | uint64_t packet_dropped; // Dropped packets due buffer full, if > 0 you need adjust recv buffer size 95 | }; 96 | 97 | 98 | // These functions should never fail, except memory alloc failed / thread create failed, just let it crash... 99 | struct SendQueue *tp_send_queue_create(const struct Socket *skt); 100 | struct RecvQueue *tp_recv_queue_create(const struct Socket *skt); 101 | 102 | 103 | int tp_send_queue_destroy(struct SendQueue *q); 104 | int tp_recv_queue_destroy(struct RecvQueue *q); 105 | 106 | 107 | #endif /* queue_h */ 108 | -------------------------------------------------------------------------------- /src/typroto.h: -------------------------------------------------------------------------------- 1 | // 2 | // typroto.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #ifndef typroto_h 10 | #define typroto_h 11 | #ifdef _WIN32 12 | #include 13 | #include 14 | #else 15 | #include 16 | #endif 17 | #include 18 | 19 | // 1 type + 4 timestamp + 8 packetid + 2 payload length + 8 nonce + 16 tag 20 | #define PROTOCOL_ABYTE 39 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /** @brief Init typroto 27 | * 28 | * @return 0 for success 29 | */ 30 | int tp_init(); 31 | 32 | /** @brief Create fd 33 | * 34 | * @return fd 35 | */ 36 | int tp_socket(int af); 37 | 38 | /** @brief Connect to server 39 | * 40 | * @param sockfd fd 41 | * @param pktSize size per packet ( all packets will be padding to this size to avoid detection ) 42 | * @param key Pre-shared key 43 | * @param addr Server addr 44 | * @param addrlen Server addr len 45 | * @return 0 for success 46 | */ 47 | int tp_connect(int sockfd, int pktSize, const char *key, const struct sockaddr *addr, socklen_t addrlen); 48 | 49 | /** @brief Listen to address 50 | * 51 | * @param sockfd fd 52 | * @param addr Server addr 53 | * @param addrlen Server addr len 54 | * @return same as bind() 55 | */ 56 | int tp_listen(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 57 | 58 | /** @brief Waiting for a incoming connection 59 | * 60 | * Return value can be PKT_ERROR and : 61 | * -1001 (Incorrect type ) 62 | * -1002 (Fail to decode public key) 63 | * -1003 (Fail to encrypt key) 64 | * -1004 (Fail to build packet) 65 | * 66 | * @param sockfd fd 67 | * @param pktSize Paket Size , need to same as client 68 | * @param key Pre-shared key 69 | * @param addr Incoming client addr ( writeable ) 70 | * @param addrlen Addr len ( writeable ) 71 | * @return 0 for success 72 | */ 73 | int tp_accept(int sockfd, int pktSize, const char *key, struct sockaddr *addr, socklen_t *addrlen); 74 | 75 | /** @brief Send some data 76 | * 77 | * Push the packet to queue , and waiting for send. 78 | * If return value is 0 , the buf will be freed after ACK 79 | * 80 | * Will block on buffer full 81 | * 82 | * @param sockfd fd 83 | * @param buf Buffer to send 84 | * @param len Buffer length ( must < pktSize - PROTOCOL_ABYTE ) 85 | * @return 0 for success, -1 Invalid fd 86 | */ 87 | int tp_send(int sockfd, uint8_t *buf, size_t len); 88 | 89 | 90 | // Not need to say 91 | typedef void (*recv_cb_t)(int fd, const uint8_t *buf, uint32_t len, const struct sockaddr* addr, socklen_t addrlen, void *userdata); 92 | 93 | int tp_set_recv_callback(int sockfd, recv_cb_t cb, void *userdata); 94 | 95 | 96 | /** @brief Event callback function 97 | * 98 | * Code can be PKT_ERROR, errno and: 99 | * -2001 Invalid packet size 100 | * -2002 Long time no ACK 101 | * 102 | * @param fd FD 103 | * @param code Error code 104 | * @param addr Incoming client addr 105 | * @param addrlen Addr len 106 | */ 107 | typedef void (*event_cb_t)(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata); 108 | 109 | int tp_set_event_callback(int sockfd, event_cb_t cb, void *userdata); 110 | 111 | int tp_shutdown(int sockfd); 112 | #ifdef __cplusplus 113 | } 114 | #endif 115 | 116 | #endif /* typroto_h */ 117 | -------------------------------------------------------------------------------- /src/packet.c: -------------------------------------------------------------------------------- 1 | // 2 | // packet.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/3. 6 | // 7 | // 8 | 9 | #include "packet.h" 10 | #include "common.h" 11 | #include 12 | #include 13 | 14 | PKT_ERROR tp_packet_encrypt(struct Box *inbox, uint8_t *buf, uint32_t buflen, const uint8_t *key){ 15 | uint32_t inbox_min_size = TP_SEC_HEADER_SIZE + inbox->payload_length; 16 | uint32_t pkt_min_size = inbox_min_size + PKT_NONCE_SIZE + PKT_TAG_SIZE; 17 | if(buflen < pkt_min_size){ 18 | printd("Buffer length %d not enough, at least %d needed\n", buflen, pkt_min_size); 19 | return P_BUFFER_TOO_SMALL; 20 | } 21 | uint32_t inbox_max_size = buflen - PKT_NONCE_SIZE - PKT_TAG_SIZE; 22 | uint8_t box_buf[inbox_max_size]; 23 | BOX_ERROR box_rv = tp_box_data_build(inbox, box_buf, inbox_max_size); 24 | if(box_rv != B_SUCCESS){ 25 | printd("Box build failed with error %d\n",box_rv); 26 | return P_BOX_BUILD_FAILED; 27 | } 28 | 29 | uint8_t cipher[inbox_max_size]; 30 | uint8_t tag[PKT_TAG_SIZE]; 31 | uint8_t nonce[PKT_NONCE_SIZE]; 32 | 33 | randombytes_buf(nonce, PKT_NONCE_SIZE); 34 | 35 | uint64_t taglen = PKT_TAG_SIZE; 36 | int crypt_rv = crypto_aead_chacha20poly1305_encrypt_detached(cipher, tag, (unsigned long long *)&taglen, box_buf, inbox_max_size, NULL, 0, NULL, nonce, key); 37 | if(crypt_rv != 0){ 38 | printd("Crypt function failed with error %d\n",crypt_rv); 39 | return P_ENCRYPT_FAILED; 40 | } 41 | 42 | memcpy(buf, nonce, PKT_NONCE_SIZE); 43 | memcpy(buf + PKT_NONCE_SIZE, cipher, inbox_max_size); 44 | memcpy(buf + PKT_NONCE_SIZE + inbox_max_size, tag, PKT_TAG_SIZE); 45 | return P_SUCCESS; 46 | } 47 | 48 | PKT_ERROR tp_packet_decrypt(struct Packet *outpkt, uint8_t *buf, uint32_t buflen, const uint8_t *key){ 49 | uint32_t pos_tag_start = buflen - PKT_TAG_SIZE; 50 | if(buflen < PKT_NONCE_SIZE + PKT_TAG_SIZE + 2){ 51 | printd("Invalid inbound packet: Buffer length %d too small\n",buflen); 52 | return P_BUFFER_TOO_SMALL; 53 | } 54 | outpkt->tag = (uint8_t *)(buf + pos_tag_start); 55 | outpkt->nonce = (uint8_t *)buf; 56 | outpkt->secret_box = (uint8_t *)(buf + PKT_NONCE_SIZE); 57 | outpkt->secret_box_len = buflen - PKT_NONCE_SIZE - PKT_TAG_SIZE; 58 | 59 | // An UDP packet generally not more than 20000 60 | if(outpkt->secret_box_len > 20000){ 61 | printd("Invalid inbound packet: Buffer length %d invalid\n",buflen); 62 | return P_BUFFER_TOO_SMALL; 63 | } 64 | 65 | uint8_t box_data[outpkt->secret_box_len]; 66 | int decrypt_rv = crypto_aead_chacha20poly1305_decrypt_detached(box_data, NULL, outpkt->secret_box, outpkt->secret_box_len, outpkt->tag, NULL, 0, outpkt->nonce, key); 67 | 68 | if(decrypt_rv == -1){ 69 | printd("Tag not valid for packet %p , len %d\n",buf, buflen); 70 | return P_INCORRECT_TAG; 71 | }else if(decrypt_rv != 0){ 72 | printd("Decrypt function failed with error %d\n",decrypt_rv); 73 | return P_DECRYPT_FAILED; 74 | }else if(!outpkt->box){ 75 | printd("API MISUSE: Box of %p is not allocated\n",outpkt); 76 | } 77 | 78 | BOX_ERROR openbox_rv = tp_box_data_open(outpkt->box, box_data, outpkt->secret_box_len); 79 | if(openbox_rv != B_SUCCESS){ 80 | printd("Box open failed with error %d\n",openbox_rv); 81 | return P_BOX_OPEN_FAILED; 82 | } 83 | 84 | if(abs((int)(time(NULL) - outpkt->box->timestamp)) > 30){ 85 | printd("Possible replay attack! PktTime: %d, CurrentTime: %ld\n",outpkt->box->timestamp,time(NULL)); 86 | free(outpkt->box->payload); 87 | return P_TIMESTAMP_MISMATCH; 88 | } 89 | 90 | return P_SUCCESS; 91 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | project(typroto) 3 | 4 | LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 5 | 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1z") 7 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11") 8 | 9 | if (NOT CMAKE_BUILD_TYPE) 10 | message(STATUS "No build type selected, default to Release") 11 | set(CMAKE_BUILD_TYPE "Release") 12 | endif() 13 | 14 | if(CMAKE_BUILD_TYPE STREQUAL "Release") 15 | if (NOT ENABLE_SEC) 16 | message(STATUS "CANARY , PIE , RELRO , FORTIFY not enabled, if you have enough performance (laptop/pc/server) / memory (>2MB) , and want to protect against pwning , please enable it by -DENABLE_SEC=1") 17 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") 18 | else() 19 | if (WIN32) 20 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions --param=ssp-buffer-size=4") 21 | else() 22 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all -D_FORTIFY_SOURCE=2 -O2") 23 | if (APPLE) 24 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE -Wl,-pie") 25 | else() 26 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-z,relro,-z,now -fPIE -pie") 27 | endif() 28 | endif() 29 | endif() 30 | endif() 31 | 32 | 33 | set(CMAKE_C_FLAGS_DEBUG "-DDEBUG -g") 34 | 35 | file(GLOB SOURCE_FILES 36 | "src/*.h" 37 | "src/*.c" 38 | "src/*.hpp" 39 | "src/*.cpp" 40 | ) 41 | 42 | if (NOT CMAKE_CROSSCOMPILING) 43 | include_directories(/usr/local/include) 44 | link_directories(/usr/local/lib) 45 | endif() 46 | 47 | if (CMAKE_CROSSCOMPILING AND APPLE) 48 | find_package(ZLIB REQUIRED) 49 | endif() 50 | find_package(Threads REQUIRED) 51 | find_package(OpenSSL REQUIRED) 52 | find_package(Sodium REQUIRED) 53 | 54 | include_directories(${OPENSSL_INCLUDE_DIR} ${SODIUM_INCLUDE_DIR}) 55 | 56 | enable_testing() 57 | 58 | add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES}) 59 | target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${SODIUM_LIBRARY} m) 60 | if (WIN32) 61 | target_link_libraries(${PROJECT_NAME} wsock32 ws2_32) 62 | endif() 63 | if (CMAKE_CROSSCOMPILING AND APPLE) 64 | target_link_libraries(${PROJECT_NAME} ${ZLIB_LIBRARIES}) 65 | endif() 66 | 67 | add_library(${PROJECT_NAME}_static STATIC ${SOURCE_FILES}) 68 | target_link_libraries(${PROJECT_NAME}_static ${CMAKE_THREAD_LIBS_INIT} ${OPENSSL_LIBRARIES} ${SODIUM_LIBRARY} m) 69 | set_target_properties(${PROJECT_NAME}_static PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) 70 | 71 | 72 | install(DIRECTORY src/ DESTINATION include/typroto 73 | FILES_MATCHING PATTERN "*.h") 74 | 75 | install(TARGETS ${PROJECT_NAME} ${PROJECT_NAME}_static DESTINATION lib) 76 | 77 | add_custom_target(uninstall 78 | "${CMAKE_COMMAND}" -P "${CMAKE_MODULE_PATH}/uninstall.cmake" 79 | ) 80 | if (NOT CMAKE_CROSSCOMPILING) 81 | add_executable(tperf_client tools/tperf_client.c) 82 | target_link_libraries(tperf_client ${PROJECT_NAME}) 83 | 84 | add_executable(tperf_server tools/tperf_server.c) 85 | target_link_libraries(tperf_server ${PROJECT_NAME}) 86 | 87 | add_executable(gen_key tools/gen_key.c) 88 | target_link_libraries(gen_key ${OPENSSL_LIBRARIES}) 89 | 90 | 91 | 92 | add_executable(test_box_packet tests/test_pkt.c) 93 | target_link_libraries(test_box_packet ${PROJECT_NAME}) 94 | 95 | add_executable(test_handshake tests/test_hs.c) 96 | target_link_libraries(test_handshake ${PROJECT_NAME}) 97 | 98 | add_executable(test_network tests/test_network.c) 99 | target_link_libraries(test_network ${PROJECT_NAME}) 100 | 101 | add_executable(test_stress tests/test_stress.c) 102 | target_link_libraries(test_stress ${PROJECT_NAME}) 103 | 104 | add_test(NAME test_box_packet COMMAND ./test_box_packet) 105 | add_test(NAME test_handshake COMMAND ./test_handshake) 106 | add_test(NAME test_network COMMAND ./test_network) 107 | add_test(NAME test_stress COMMAND ./test_stress) 108 | endif() -------------------------------------------------------------------------------- /src/rqutils.h: -------------------------------------------------------------------------------- 1 | // 2 | // rqutils.h 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/7. 6 | // 7 | // 8 | 9 | #ifndef rqutils_h 10 | #define rqutils_h 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "queue.h" 18 | 19 | #define BITMASK(b) (1 << ((b) % CHAR_BIT)) 20 | #define BITSLOT(b) ((b) / CHAR_BIT) 21 | #define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b)) 22 | #define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b)) 23 | #define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b)) 24 | #define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT) 25 | 26 | #ifdef _WIN32 27 | /* Macros for min/max. */ 28 | #define MIN(a,b) (((a)<(b))?(a):(b)) 29 | #define MAX(a,b) (((a)>(b))?(a):(b)) 30 | #endif 31 | 32 | inline static uint64_t get_clock_ms(){ 33 | struct timeval now; 34 | gettimeofday(&now, NULL); 35 | return (now.tv_sec * 1000LL) + now.tv_usec / 1000; 36 | } 37 | 38 | inline static void tr_send_control_packet(const struct Socket *skt, struct Box *box, int repeat){ 39 | for (int i = 0; i < repeat; i++) { 40 | uint8_t buf[skt->packet_size]; 41 | int rv = tp_packet_encrypt(box, buf, skt->packet_size, skt->transfer_key); 42 | if(rv != 0){ 43 | printd("Packet encrypt failed with rv %d",rv); 44 | return; 45 | } 46 | sendto(skt->fd, buf, skt->packet_size, 0, skt->addr, skt->sockaddr_len); 47 | } 48 | } 49 | 50 | inline static void tr_sendACK(struct RecvQueue *q, bool force){ 51 | uint64_t current = get_clock_ms(); 52 | // printv("Current time %llu , last ack %llu\n",current, q->last_ack_time); 53 | if(current - q->last_ack_time > q->ack_send_delay || force){ 54 | struct Box box; 55 | box.packet_id = 0; 56 | box.timestamp = time(NULL); 57 | box.type = PT_ACK; 58 | box.payload = (uint8_t *)&q->last_completed_id; 59 | box.payload_length = 8; 60 | tr_send_control_packet(q->skt, &box, TP_ACK_REPEAT_COUNT); 61 | printv("Sending ACK with ID %llu\n",*(uint64_t *)box.payload); 62 | q->last_ack_time = current; 63 | } 64 | } 65 | 66 | inline static void tr_sendSACK(struct RecvQueue *q, uint64_t missing_pkt_id, uint64_t end_pkt_id){ 67 | uint64_t current = get_clock_ms(); 68 | // printv("Current time %llu , last sack %llu\n",current, q->last_sack_time); 69 | if(current - q->last_sack_time > q->sack_send_delay){ 70 | q->last_sack_sent = missing_pkt_id; 71 | 72 | int max_body = q->skt->packet_size - PROTOCOL_ABYTE; 73 | 74 | int start_bit = 12 * CHAR_BIT; 75 | int max_slot = (max_body - 12) * CHAR_BIT; 76 | int ack_length = MIN(end_pkt_id - missing_pkt_id, max_slot); 77 | 78 | uint8_t arr[max_body]; 79 | memset(arr, 0, max_body); 80 | memcpy(arr, &missing_pkt_id, 8); 81 | memcpy(arr + 8, &ack_length, 4); 82 | 83 | int b; 84 | for (int i = 0; i < ack_length; i++) { 85 | int idx = (missing_pkt_id + i) % TP_SEND_BUFFER_SIZE; 86 | if(q->boxes[idx]){ 87 | b = i + start_bit; 88 | BITSET(arr, b); 89 | } 90 | } 91 | 92 | struct Box box; 93 | box.packet_id = 0; 94 | box.timestamp = time(NULL); 95 | box.type = PT_SACK; 96 | box.payload = arr; 97 | box.payload_length = max_body; 98 | tr_send_control_packet(q->skt, &box, TP_SACK_REPEAT_COUNT); 99 | q->last_sack_time = current; 100 | } 101 | } 102 | 103 | inline static uint64_t tr_procACK(struct SendQueue *q, uint64_t sent_offset, uint64_t last_ack, bool isBufFull){ 104 | if(last_ack > sent_offset){ 105 | for (uint64_t i = sent_offset; i < last_ack; i++) { 106 | int idx = i % TP_SEND_BUFFER_SIZE; 107 | struct Box *b = q->boxes[idx]; 108 | if(!b){ 109 | continue; 110 | } 111 | if(b->payload_length && b->payload){ 112 | free(b->payload); 113 | } 114 | free(b); 115 | q->boxes[idx] = NULL; 116 | q->sent_ts[idx] = 0; 117 | } 118 | if(isBufFull){ 119 | pthread_cond_signal(&q->nobufs_cond); 120 | } 121 | } 122 | return last_ack; 123 | } 124 | 125 | #endif /* rqutils_h */ 126 | -------------------------------------------------------------------------------- /tests/test_network.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #ifdef _WIN32 6 | #include 7 | #include 8 | #else 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #endif 15 | 16 | #include 17 | #include "../src/typroto.h" 18 | #include "../src/socks.h" 19 | 20 | #define TEST_BIND_TO "127.0.0.1" 21 | #define TEST_PORT 29910 22 | 23 | void printHex(int x, uint8_t *buf){ 24 | int i; 25 | for (i = 0; i < x; i++) 26 | { 27 | if (i > 0) printf(":"); 28 | printf("%02X", buf[i]); 29 | } 30 | printf("\n"); 31 | } 32 | 33 | void recvcb(int fd, const uint8_t *buf, uint32_t len, const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 34 | const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 35 | printf("[Fd %d] Got a packet from %s:%d : %s\n",fd, inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), buf); 36 | } 37 | 38 | void evtcb(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 39 | const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 40 | printf("[Fd %d] Event %d from %s:%d : %s\n",fd, code , inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), msg); 41 | } 42 | 43 | 44 | void *client(){ 45 | struct sockaddr_in addr; 46 | socklen_t slen = sizeof(addr); 47 | memset((void *) &addr, 0, slen); 48 | addr.sin_family = AF_INET; 49 | addr.sin_port = htons(TEST_PORT); 50 | inet_aton(TEST_BIND_TO, &addr.sin_addr); 51 | 52 | int fd = tp_socket(AF_INET); 53 | printf("[Client] Got fd %d, Ready to connect %s:%d\n",fd, TEST_BIND_TO,TEST_PORT); 54 | int rv = tp_connect(fd, 1400, "123456", (const struct sockaddr*)&addr, slen); 55 | printf("[Client] connect() returned %d\n",rv); 56 | tp_set_recv_callback(fd, recvcb, NULL); 57 | tp_set_event_callback(fd, evtcb, NULL); 58 | 59 | const struct Socket *skt = tp_get_sock_by_id(fd); 60 | printf("[Client] Size per packet: %d Transfer Key: ",skt->packet_size); 61 | printHex(32,skt->transfer_key); 62 | 63 | char *c = "Hello world packet from client"; 64 | uint8_t *data_to_send = malloc(strlen(c)); 65 | memcpy(data_to_send, c, strlen(c)); 66 | tp_send(fd, data_to_send, strlen(c)); 67 | sleep(5); 68 | tp_shutdown(fd); 69 | return NULL; 70 | } 71 | 72 | void *server(){ 73 | int fd = tp_socket(AF_INET); 74 | printf("[Server] Got fd %d, Ready to listen %s:%d\n",fd, TEST_BIND_TO,TEST_PORT); 75 | struct sockaddr_in addr; 76 | socklen_t slen = sizeof(addr); 77 | memset((void *) &addr, 0, slen); 78 | addr.sin_family = AF_INET; 79 | addr.sin_port = htons(TEST_PORT); 80 | inet_aton(TEST_BIND_TO, &addr.sin_addr); 81 | 82 | tp_listen(fd, (const struct sockaddr*)&addr, slen); 83 | for (int i = 0;i < 100;i++) { 84 | struct sockaddr_in incoming_addr; 85 | socklen_t slen = sizeof(incoming_addr); 86 | int rv = tp_accept(fd, 1400, "123456", (struct sockaddr *)&incoming_addr,&slen); 87 | if(rv != 0){ 88 | printf("[Server] Invalid packet from %s:%d, Code %d\n", 89 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port), rv); 90 | continue; 91 | } 92 | tp_set_recv_callback(fd, recvcb, NULL); 93 | tp_set_event_callback(fd, evtcb, NULL); 94 | printf("[Server] Accepted a connection from %s:%d\n", 95 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port)); 96 | const struct Socket *skt = tp_get_sock_by_id(fd); 97 | printf("[Server] Size per packet: %d Transfer Key: ",skt->packet_size); 98 | printHex(32,skt->transfer_key); 99 | 100 | char *c = "Hello world packet from server"; 101 | uint8_t *data_to_send = malloc(strlen(c)); 102 | memcpy(data_to_send, c, strlen(c)); 103 | tp_send(fd, data_to_send, strlen(c)); 104 | sleep(5); 105 | tp_shutdown(fd); 106 | return NULL; 107 | } 108 | printf("[Server] Unable to get connection"); 109 | exit(-1); 110 | return NULL; 111 | } 112 | 113 | int main(int argc, char *argv[]){ 114 | printf("Starting TYProto test\n"); 115 | int rv = tp_init(); 116 | if(rv != 0){ 117 | printf("Failed to init typroto\n"); 118 | return -1; 119 | } 120 | pthread_t server_t; 121 | pthread_create(&server_t, NULL, server, NULL); 122 | sleep(1); 123 | pthread_t client_t; 124 | pthread_create(&client_t, NULL, client, NULL); 125 | pthread_join(server_t, NULL); 126 | } -------------------------------------------------------------------------------- /tests/test_stress.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "../src/typroto.h" 12 | #include "../src/socks.h" 13 | 14 | #define TEST_BIND_TO "127.0.0.1" 15 | #define TEST_PORT 29910 16 | 17 | void printHex(int x, uint8_t *buf){ 18 | int i; 19 | for (i = 0; i < x; i++) 20 | { 21 | if (i > 0) printf(":"); 22 | printf("%02X", buf[i]); 23 | } 24 | printf("\n"); 25 | } 26 | 27 | void recvcb(int fd, const uint8_t *buf, uint32_t len, const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 28 | // const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 29 | //printf("[Fd %d] Got a packet from %s:%d : %s\n",fd, inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), buf); 30 | } 31 | 32 | void evtcb(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 33 | const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 34 | printf("[Fd %d] Event %d from %s:%d : %s\n",fd, code , inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), msg); 35 | } 36 | 37 | 38 | void *client(){ 39 | struct sockaddr_in addr; 40 | socklen_t slen = sizeof(addr); 41 | memset((void *) &addr, 0, slen); 42 | addr.sin_family = AF_INET; 43 | addr.sin_port = htons(TEST_PORT); 44 | inet_aton(TEST_BIND_TO, &addr.sin_addr); 45 | 46 | int fd = tp_socket(AF_INET); 47 | printf("[Client] Got fd %d, Ready to connect %s:%d\n",fd, TEST_BIND_TO,TEST_PORT); 48 | int rv = tp_connect(fd, 1400, "123456", (const struct sockaddr*)&addr, slen); 49 | printf("[Client] connect() returned %d\n",rv); 50 | tp_set_recv_callback(fd, recvcb, NULL); 51 | tp_set_event_callback(fd, evtcb, NULL); 52 | 53 | const struct Socket *skt = tp_get_sock_by_id(fd); 54 | printf("[Client] Size per packet: %d Transfer Key: ",skt->packet_size); 55 | printHex(32,skt->transfer_key); 56 | 57 | for (int x = 0; x < 10000 ; x++) { 58 | uint8_t *data_to_send = malloc(25); 59 | int rv = tp_send(fd, (uint8_t *)data_to_send, 25); 60 | if(rv != 0){ 61 | free(data_to_send); 62 | } 63 | } 64 | 65 | sleep(5); 66 | uint64_t rs = skt->sendqueue->packet_resend; 67 | uint64_t sp = skt->sendqueue->packet_num; 68 | printf("Stats: Sent %llu, Resend: %llu\n", sp - rs, rs); 69 | tp_shutdown(fd); 70 | return NULL; 71 | } 72 | 73 | void *server(){ 74 | int fd = tp_socket(AF_INET); 75 | printf("[Server] Got fd %d, Ready to listen %s:%d\n",fd, TEST_BIND_TO,TEST_PORT); 76 | struct sockaddr_in addr; 77 | socklen_t slen = sizeof(addr); 78 | memset((void *) &addr, 0, slen); 79 | addr.sin_family = AF_INET; 80 | addr.sin_port = htons(TEST_PORT); 81 | inet_aton(TEST_BIND_TO, &addr.sin_addr); 82 | 83 | tp_listen(fd, (const struct sockaddr*)&addr, slen); 84 | for (int i = 0;i < 100;i++) { 85 | struct sockaddr_in incoming_addr; 86 | socklen_t slen = sizeof(incoming_addr); 87 | int rv = tp_accept(fd, 1400, "123456", (struct sockaddr *)&incoming_addr,&slen); 88 | if(rv != 0){ 89 | printf("[Server] Invalid packet from %s:%d, Code %d\n", 90 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port), rv); 91 | continue; 92 | } 93 | tp_set_recv_callback(fd, recvcb, NULL); 94 | tp_set_event_callback(fd, evtcb, NULL); 95 | printf("[Server] Accepted a connection from %s:%d\n", 96 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port)); 97 | const struct Socket *skt = tp_get_sock_by_id(fd); 98 | printf("[Server] Size per packet: %d Transfer Key: ",skt->packet_size); 99 | printHex(32,skt->transfer_key); 100 | 101 | char *c = "Hello world packet from server"; 102 | uint8_t *data_to_send = malloc(strlen(c)); 103 | memcpy(data_to_send, c, strlen(c)); 104 | tp_send(fd, data_to_send, strlen(c)); 105 | sleep(50); 106 | tp_shutdown(fd); 107 | return NULL; 108 | } 109 | printf("[Server] Unable to get connection"); 110 | exit(-1); 111 | return NULL; 112 | } 113 | 114 | int main(int argc, char *argv[]){ 115 | printf("Starting TYProto test\n"); 116 | int rv = tp_init(); 117 | if(rv != 0){ 118 | printf("Failed to init typroto\n"); 119 | return -1; 120 | } 121 | pthread_t server_t; 122 | pthread_create(&server_t, NULL, server, NULL); 123 | sleep(1); 124 | pthread_t client_t; 125 | pthread_create(&client_t, NULL, client, NULL); 126 | pthread_join(client_t, NULL); 127 | } -------------------------------------------------------------------------------- /cmake/FindGlib.cmake: -------------------------------------------------------------------------------- 1 | 2 | # - Try to find Glib and its components (gio, gobject etc) 3 | # Once done, this will define 4 | # 5 | # GLIB_FOUND - system has Glib 6 | # GLIB_INCLUDE_DIRS - the Glib include directories 7 | # GLIB_LIBRARIES - link these to use Glib 8 | # 9 | # Optionally, the COMPONENTS keyword can be passed to find_package() 10 | # and Glib components can be looked for. Currently, the following 11 | # components can be used, and they define the following variables if 12 | # found: 13 | # 14 | # gio: GLIB_GIO_LIBRARIES 15 | # gobject: GLIB_GOBJECT_LIBRARIES 16 | # gmodule: GLIB_GMODULE_LIBRARIES 17 | # gthread: GLIB_GTHREAD_LIBRARIES 18 | # 19 | # Note that the respective _INCLUDE_DIR variables are not set, since 20 | # all headers are in the same directory as GLIB_INCLUDE_DIRS. 21 | # 22 | # Copyright (C) 2012 Raphael Kubo da Costa 23 | # 24 | # Redistribution and use in source and binary forms, with or without 25 | # modification, are permitted provided that the following conditions 26 | # are met: 27 | # 1. Redistributions of source code must retain the above copyright 28 | # notice, this list of conditions and the following disclaimer. 29 | # 2. Redistributions in binary form must reproduce the above copyright 30 | # notice, this list of conditions and the following disclaimer in the 31 | # documentation and/or other materials provided with the distribution. 32 | # 33 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS 34 | # IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 35 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS 37 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 38 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 39 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 40 | # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 41 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 42 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 43 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 44 | 45 | find_package(PkgConfig) 46 | pkg_check_modules(PC_GLIB QUIET glib-2.0) 47 | 48 | find_library(GLIB_LIBRARIES 49 | NAMES glib-2.0 50 | HINTS ${PC_GLIB_LIBDIR} 51 | ${PC_GLIB_LIBRARY_DIRS} 52 | ) 53 | 54 | # Files in glib's main include path may include glibconfig.h, which, 55 | # for some odd reason, is normally in $LIBDIR/glib-2.0/include. 56 | get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH) 57 | find_path(GLIBCONFIG_INCLUDE_DIR 58 | NAMES glibconfig.h 59 | HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR} 60 | ${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS} 61 | PATH_SUFFIXES glib-2.0/include 62 | ) 63 | 64 | find_path(GLIB_INCLUDE_DIR 65 | NAMES glib.h 66 | HINTS ${PC_GLIB_INCLUDEDIR} 67 | ${PC_GLIB_INCLUDE_DIRS} 68 | PATH_SUFFIXES glib-2.0 69 | ) 70 | 71 | set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR}) 72 | 73 | # Version detection 74 | if (EXISTS "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h") 75 | file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS) 76 | string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") 77 | set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}") 78 | string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") 79 | set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}") 80 | string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}") 81 | set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}") 82 | set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}") 83 | endif () 84 | 85 | # Additional Glib components. We only look for libraries, as not all of them 86 | # have corresponding headers and all headers are installed alongside the main 87 | # glib ones. 88 | foreach (_component ${GLIB_FIND_COMPONENTS}) 89 | if (${_component} STREQUAL "gio") 90 | find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR}) 91 | set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES) 92 | elseif (${_component} STREQUAL "gobject") 93 | find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR}) 94 | set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES) 95 | elseif (${_component} STREQUAL "gmodule") 96 | find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR}) 97 | set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES) 98 | elseif (${_component} STREQUAL "gthread") 99 | find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR}) 100 | set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES) 101 | elseif (${_component} STREQUAL "gio-unix") 102 | # gio-unix is compiled as part of the gio library, but the include paths 103 | # are separate from the shared glib ones. Since this is currently only used 104 | # by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config. 105 | pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0) 106 | endif () 107 | endforeach () 108 | 109 | include(FindPackageHandleStandardArgs) 110 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS} 111 | VERSION_VAR GLIB_VERSION) 112 | 113 | mark_as_advanced( 114 | GLIBCONFIG_INCLUDE_DIR 115 | GLIB_GIO_LIBRARIES 116 | GLIB_GIO_UNIX_LIBRARIES 117 | GLIB_GMODULE_LIBRARIES 118 | GLIB_GOBJECT_LIBRARIES 119 | GLIB_GTHREAD_LIBRARIES 120 | GLIB_INCLUDE_DIR 121 | GLIB_INCLUDE_DIRS 122 | GLIB_LIBRARIES 123 | ) -------------------------------------------------------------------------------- /src/typroto.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #ifdef _WIN32 4 | #include 5 | #include 6 | #else 7 | #include 8 | #include 9 | #endif 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "typroto.h" 16 | #include "common.h" 17 | #include "packet.h" 18 | #include "socks.h" 19 | #include "handshake.h" 20 | 21 | int tp_init(){ 22 | int rv = sodium_init(); 23 | printd("libsodium init returned with %d\n",rv); 24 | if(rv == -1){ 25 | return -1; 26 | } 27 | printd("chacha20-poly1305 tag size %d\n",PKT_TAG_SIZE); 28 | printd("chacha20-poly1305 nonce size %d\n",PKT_NONCE_SIZE); 29 | printd("chacha20-poly1305 key size %d\n",crypto_aead_chacha20poly1305_KEYBYTES); 30 | return 0; 31 | } 32 | 33 | int tp_socket(int af){ 34 | int fd = socket(af, SOCK_DGRAM, IPPROTO_UDP); 35 | return fd; 36 | } 37 | 38 | static void tp_default_event_callback(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 39 | return; 40 | } 41 | 42 | int tp_connect(int sockfd, int pktSize, const char *key, const struct sockaddr *addr, socklen_t addrlen){ 43 | uint8_t *rsa_privkey_buf = sodium_malloc(8192); 44 | uint8_t *data_buf = malloc(pktSize); 45 | int rsa_privkey_len = tp_build_handshake_packet(rsa_privkey_buf, data_buf, pktSize, key); 46 | sendto(sockfd, data_buf, pktSize, 0, addr, addrlen); 47 | 48 | ssize_t recvlen = recvfrom(sockfd, data_buf, pktSize, 0, NULL, NULL); 49 | if(recvlen < 1){ 50 | return -1; 51 | } 52 | 53 | uint8_t *transKey = sodium_malloc(crypto_aead_chacha20poly1305_KEYBYTES); 54 | 55 | int rv = tp_handshake_response_decrypt(transKey, rsa_privkey_buf, rsa_privkey_len, data_buf, recvlen, key); 56 | if(rv != 0){ 57 | return rv; 58 | } 59 | 60 | sodium_mprotect_readwrite(rsa_privkey_buf); 61 | sodium_free(rsa_privkey_buf); 62 | free(data_buf); 63 | 64 | struct sockaddr *paddr = malloc(addrlen); 65 | memcpy(paddr, addr, addrlen); 66 | 67 | int sktSize = sizeof(struct Socket); 68 | struct Socket *skt = malloc(sktSize); 69 | memset(skt, 0, sizeof(sktSize)); 70 | skt->fd = sockfd; 71 | skt->addr = paddr; 72 | skt->sockaddr_len = addrlen; 73 | skt->transfer_key = transKey; 74 | skt->packet_size = pktSize; 75 | skt->sendqueue = tp_send_queue_create(skt); 76 | skt->recvqueue = tp_recv_queue_create(skt); 77 | skt->evt = tp_default_event_callback; 78 | tp_add_sock(sockfd, skt); 79 | return 0; 80 | } 81 | 82 | int tp_listen(int sockfd, const struct sockaddr *addr, socklen_t addrlen){ 83 | int rv = bind(sockfd, addr, addrlen); 84 | printd("bind() returned %d\n",rv); 85 | return rv; 86 | } 87 | 88 | int tp_accept(int sockfd, int pktSize, const char *key, struct sockaddr *addr, socklen_t *addrlen){ 89 | uint8_t data_buf[pktSize]; 90 | ssize_t recvlen = recvfrom(sockfd, data_buf, pktSize, 0, addr, addrlen); 91 | if(recvlen < 1){ 92 | return -1; 93 | } 94 | uint8_t resp_buf[pktSize]; 95 | uint8_t *transKey = sodium_malloc(crypto_aead_chacha20poly1305_KEYBYTES); 96 | int rv = tp_build_handshake_packet_response(transKey, resp_buf, pktSize, data_buf, recvlen, key); 97 | if(rv != 0){ 98 | return rv; 99 | } 100 | rv = sendto(sockfd, resp_buf, pktSize, 0, addr, *addrlen); 101 | printd("Sent server hello with rv %d, errno %d\n",rv,errno); 102 | 103 | struct sockaddr *paddr = malloc(*addrlen); 104 | memcpy(paddr, addr, *addrlen); 105 | 106 | int sktSize = sizeof(struct Socket); 107 | struct Socket *skt = malloc(sktSize); 108 | memset(skt, 0, sizeof(sktSize)); 109 | skt->fd = sockfd; 110 | skt->addr = paddr; 111 | skt->sockaddr_len = *addrlen; 112 | skt->transfer_key = transKey; 113 | skt->packet_size = pktSize; 114 | skt->sendqueue = tp_send_queue_create(skt); 115 | skt->recvqueue = tp_recv_queue_create(skt); 116 | skt->evt = tp_default_event_callback; 117 | tp_add_sock(sockfd, skt); 118 | return 0; 119 | } 120 | 121 | int tp_send(int sockfd, uint8_t *buf, size_t len){ 122 | const struct Socket* skt = tp_get_sock_by_id(sockfd); 123 | if(!skt){ 124 | return -1; 125 | } 126 | struct SendQueue *q = skt->sendqueue; 127 | pthread_mutex_lock(&q->lock); 128 | start_send:; 129 | 130 | bool is_full = (q->write_offset - q->sent_offset >= TP_SEND_BUFFER_SIZE); 131 | uint64_t write_offset = q->write_offset; 132 | if(!is_full){ 133 | q->write_offset++; 134 | }else{ 135 | printv("Blocking at %ld\n",time(NULL)); 136 | q->nobufs_wait = true; 137 | } 138 | 139 | if(q->idle_wait){ 140 | pthread_cond_signal(&q->idle_cond); 141 | } 142 | 143 | if(is_full){ 144 | pthread_cond_wait(&q->nobufs_cond, &q->lock); 145 | q->nobufs_wait = false; 146 | goto start_send; 147 | } 148 | 149 | 150 | int boxSize = sizeof(struct Box); 151 | struct Box *box = malloc(boxSize); 152 | box->packet_id = q->last_packet_id++; 153 | box->payload = buf; 154 | box->payload_length = len; 155 | 156 | int idx = write_offset % TP_SEND_BUFFER_SIZE; 157 | q->boxes[idx] = box; 158 | 159 | pthread_mutex_unlock(&q->lock); 160 | return 0; 161 | } 162 | 163 | int tp_set_recv_callback(int sockfd, recv_cb_t cb, void *userdata){ 164 | const struct Socket* skt = tp_get_sock_by_id(sockfd); 165 | if(!skt){ 166 | return -1; 167 | } 168 | skt->recvqueue->callback = cb; 169 | skt->recvqueue->callback_userdata = userdata; 170 | return 0; 171 | } 172 | 173 | int tp_set_event_callback(int sockfd, event_cb_t cb, void *userdata){ 174 | struct Socket* skt = (struct Socket*)tp_get_sock_by_id(sockfd); 175 | if(!skt){ 176 | return -1; 177 | } 178 | skt->evt = cb; 179 | skt->evt_userdata = userdata; 180 | return 0; 181 | } 182 | 183 | int tp_shutdown(int sockfd){ 184 | close(sockfd); 185 | tp_remove_sock(sockfd); 186 | return 0; 187 | } -------------------------------------------------------------------------------- /tools/tperf_client.c: -------------------------------------------------------------------------------- 1 | // 2 | // tperf_client.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/8. 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "../src/typroto.h" 22 | #include "../src/socks.h" 23 | 24 | int msgtime = 0; 25 | 26 | void recvcb(int fd, const uint8_t *buf, uint32_t len, const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 27 | msgtime = time(NULL); 28 | } 29 | 30 | void evtcb(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 31 | const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 32 | printf("[Fd %d] Event %d from %s:%d : %s\n",fd, code , inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), msg); 33 | } 34 | 35 | void printHex(int x, uint8_t *buf){ 36 | int i; 37 | for (i = 0; i < x; i++) 38 | { 39 | if (i > 0) printf(":"); 40 | printf("%02X", buf[i]); 41 | } 42 | printf("\n"); 43 | } 44 | 45 | char *paddings = " "; 46 | 47 | void print_padding(int width, char *fmt, ...){ 48 | char *txt = NULL; 49 | va_list arglist; 50 | va_start(arglist, fmt); 51 | vasprintf(&txt, fmt, arglist); 52 | va_end(arglist); 53 | int len = strlen(txt); 54 | int padding = width - len; 55 | if(padding < 0 ){ 56 | padding = 0; 57 | } 58 | char padstr[100]; 59 | memset(padstr, 0, 100); 60 | memcpy(padstr, paddings, padding); 61 | fprintf(stderr,"%s%s",txt,padstr); 62 | } 63 | 64 | void *print_stats(void *skt_p){ 65 | const struct Socket *skt = (const struct Socket *)skt_p; 66 | struct SendQueue *sq = skt->sendqueue; 67 | struct RecvQueue *rq = skt->recvqueue; 68 | int psize = skt->packet_size; 69 | uint64_t send_last_user_byte = 0; 70 | uint64_t send_last_real_byte = 0; 71 | uint64_t recv_last_user_byte = 0; 72 | uint64_t recv_last_real_byte = 0; 73 | while (1) { 74 | sleep(1); 75 | // Print send bytes 76 | fprintf(stderr, "Send --- "); 77 | uint64_t spus = (sq->packet_num - sq->packet_resend) * psize; 78 | uint64_t sprs = sq->packet_num * psize; 79 | print_padding(20, "User: %lluKB", spus / 1024); 80 | print_padding(20, "Real: %lluKB", sprs / 1024); 81 | print_padding(20, "Rsnd: %lluKB", (sq->packet_resend * psize) / 1024); 82 | // Print send packets 83 | fprintf(stderr,"| PKTS --- "); 84 | print_padding(20, "User: %llu", sq->packet_num - sq->packet_resend); 85 | print_padding(20, "Real: %llu", sq->packet_num); 86 | print_padding(20, "Rsnd: %llu", sq->packet_resend); 87 | 88 | // Print send speed 89 | fprintf(stderr,"| "); 90 | print_padding(20, "U: %lluKB/s", (spus - send_last_user_byte) / 1024); 91 | print_padding(20, "R: %lluKB/s", (sprs - send_last_real_byte) / 1024); 92 | 93 | // Print recv bytes 94 | fprintf(stderr,"\nRecv --- "); 95 | print_padding(20, "User: %lluKB", rq->user_bytes / 1024); 96 | print_padding(20, "Real: %lluKB", rq->real_bytes / 1024); 97 | print_padding(20, "Ovhd: %lluKB", (rq->real_bytes - rq->user_bytes) / 1024); 98 | 99 | // Print recv packets 100 | fprintf(stderr,"| PKTS --- "); 101 | print_padding(20, "All : %llu", rq->packet_num); 102 | print_padding(20, "Dups: %llu", rq->packet_dup); 103 | print_padding(20, "Drop: %llu", rq->packet_dropped); 104 | 105 | // Print recv speed 106 | fprintf(stderr,"| "); 107 | print_padding(20, "U: %lluKB/s", (rq->user_bytes - recv_last_user_byte) / 1024); 108 | print_padding(20, "R: %lluKB/s", (rq->real_bytes - recv_last_real_byte) / 1024); 109 | 110 | fprintf(stderr,"\n"); 111 | 112 | send_last_user_byte = spus; 113 | send_last_real_byte = sprs; 114 | recv_last_user_byte = rq->user_bytes; 115 | recv_last_real_byte = rq->real_bytes; 116 | } 117 | return NULL; 118 | } 119 | 120 | int main(int argc, char *argv[]){ 121 | int rv = tp_init(); 122 | if(rv != 0){ 123 | printf("Failed to init typroto\n"); 124 | return -1; 125 | } 126 | if(argc < 7){ 127 | printf("Usage: ./tperf_client remote_ip remote_port packet_size password speed_kb_s\n"); 128 | return -1; 129 | } 130 | struct sockaddr_in addr; 131 | socklen_t slen = sizeof(addr); 132 | memset((void *) &addr, 0, slen); 133 | addr.sin_family = AF_INET; 134 | addr.sin_port = htons(atoi(argv[2])); 135 | inet_aton(argv[1], &addr.sin_addr); 136 | 137 | int psize = atoi(argv[3]); 138 | char *password = argv[4]; 139 | 140 | int fd = tp_socket(AF_INET); 141 | printf("[Client] Got fd %d, Ready to connect %s:%s\n",fd, argv[1], argv[2]); 142 | rv = tp_connect(fd, psize, password, (const struct sockaddr*)&addr, slen); 143 | printf("[Client] connect() returned %d\n",rv); 144 | if(rv){ 145 | exit(rv); 146 | } 147 | 148 | tp_set_recv_callback(fd, recvcb, NULL); 149 | tp_set_event_callback(fd, evtcb, NULL); 150 | 151 | const struct Socket *skt = tp_get_sock_by_id(fd); 152 | printf("[Client] Size per packet: %d Transfer Key: ",skt->packet_size); 153 | printHex(32,skt->transfer_key); 154 | 155 | int type = 1; 156 | if(strcmp(argv[5], "upload") == 0){ 157 | type = 2; 158 | } 159 | 160 | int speed = atoi(argv[6]); 161 | 162 | int packets_per_second_esta = (int)((double)speed*1000) / (double)psize; 163 | printf("Packet per second: %d\n",packets_per_second_esta); 164 | 165 | skt->sendqueue->speed_limit = packets_per_second_esta; 166 | 167 | pthread_t stats_t; 168 | pthread_create(&stats_t, NULL, print_stats, (void *)skt); 169 | 170 | if(type == 2){ 171 | while (1) { 172 | uint8_t *buf = malloc(psize - PROTOCOL_ABYTE); 173 | int r = tp_send(fd, buf, psize - PROTOCOL_ABYTE); 174 | if(r){ 175 | free(buf); 176 | } 177 | } 178 | }else{ 179 | msgtime = time(NULL); 180 | uint8_t *buf = malloc(4); 181 | memcpy(buf, &packets_per_second_esta, 4); 182 | tp_send(fd, buf, 4); 183 | while (1) { 184 | if(time(NULL) - msgtime > 5){ 185 | printf("[Client] Server timeout\n"); 186 | pthread_cancel(stats_t); 187 | tp_shutdown(fd); 188 | return 0; 189 | } 190 | sleep(1); 191 | 192 | uint8_t *buf = malloc(1); // Keep alive 193 | int r = tp_send(fd, buf, 1); 194 | if(r){ 195 | free(buf); 196 | } 197 | } 198 | } 199 | 200 | return 0; 201 | } -------------------------------------------------------------------------------- /tools/tperf_server.c: -------------------------------------------------------------------------------- 1 | // 2 | // tperf_server.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/8. 6 | // 7 | // 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "../src/typroto.h" 21 | #include "../src/socks.h" 22 | 23 | int msgtime = 0; 24 | int reverse_started = 0; 25 | int speed_limit = 0; 26 | 27 | void recvcb(int fd, const uint8_t *buf, uint32_t len, const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 28 | // const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 29 | //printf("[Fd %d] Got a packet from %s:%d : %s\n",fd, inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), buf); 30 | msgtime = time(NULL); 31 | if(len == 4){ 32 | speed_limit = *(int *)buf; 33 | } 34 | } 35 | 36 | void evtcb(int fd, int code, const char* msg,const struct sockaddr* addr, socklen_t addrlen, void *userdata){ 37 | const struct sockaddr_in *iaddr = (const struct sockaddr_in *)addr; 38 | printf("[Fd %d] Event %d from %s:%d : %s\n",fd, code , inet_ntoa(iaddr->sin_addr), ntohs(iaddr->sin_port), msg); 39 | } 40 | 41 | void printHex(int x, uint8_t *buf){ 42 | int i; 43 | for (i = 0; i < x; i++) 44 | { 45 | if (i > 0) printf(":"); 46 | printf("%02X", buf[i]); 47 | } 48 | printf("\n"); 49 | } 50 | 51 | char *paddings = " "; 52 | 53 | void print_padding(int width, char *fmt, ...){ 54 | char *txt = NULL; 55 | va_list arglist; 56 | va_start(arglist, fmt); 57 | vasprintf(&txt, fmt, arglist); 58 | va_end(arglist); 59 | int len = strlen(txt); 60 | int padding = width - len; 61 | char padstr[100]; 62 | memset(padstr, 0, 100); 63 | memcpy(padstr, paddings, padding); 64 | fprintf(stderr,"%s%s",txt,padstr); 65 | } 66 | 67 | void *print_stats(void *skt_p){ 68 | const struct Socket *skt = (const struct Socket *)skt_p; 69 | struct SendQueue *sq = skt->sendqueue; 70 | struct RecvQueue *rq = skt->recvqueue; 71 | int psize = skt->packet_size; 72 | uint64_t send_last_user_byte = 0; 73 | uint64_t send_last_real_byte = 0; 74 | uint64_t recv_last_user_byte = 0; 75 | uint64_t recv_last_real_byte = 0; 76 | while (1) { 77 | sleep(1); 78 | // Print send bytes 79 | fprintf(stderr, "Send --- "); 80 | uint64_t spus = (sq->packet_num - sq->packet_resend) * psize; 81 | uint64_t sprs = sq->packet_num * psize; 82 | print_padding(20, "User: %lluKB", spus / 1024); 83 | print_padding(20, "Real: %lluKB", sprs / 1024); 84 | print_padding(20, "Rsnd: %lluKB", (sq->packet_resend * psize) / 1024); 85 | // Print send packets 86 | fprintf(stderr,"| PKTS --- "); 87 | print_padding(20, "User: %llu", sq->packet_num - sq->packet_resend); 88 | print_padding(20, "Real: %llu", sq->packet_num); 89 | print_padding(20, "Rsnd: %llu", sq->packet_resend); 90 | 91 | // Print send speed 92 | fprintf(stderr,"| "); 93 | print_padding(20, "U: %lluKB/s", (spus - send_last_user_byte) / 1024); 94 | print_padding(20, "R: %lluKB/s", (sprs - send_last_real_byte) / 1024); 95 | 96 | // Print recv bytes 97 | fprintf(stderr,"\nRecv --- "); 98 | print_padding(20, "User: %lluKB", rq->user_bytes / 1024); 99 | print_padding(20, "Real: %lluKB", rq->real_bytes / 1024); 100 | print_padding(20, "Ovhd: %lluKB", (rq->real_bytes - rq->user_bytes) / 1024); 101 | 102 | // Print recv packets 103 | fprintf(stderr,"| PKTS --- "); 104 | print_padding(20, "All : %llu", rq->packet_num); 105 | print_padding(20, "Dups: %llu", rq->packet_dup); 106 | print_padding(20, "Drop: %llu", rq->packet_dropped); 107 | 108 | // Print recv speed 109 | fprintf(stderr,"| "); 110 | print_padding(20, "U: %lluKB/s", (rq->user_bytes - recv_last_user_byte) / 1024); 111 | print_padding(20, "R: %lluKB/s", (rq->real_bytes - recv_last_real_byte) / 1024); 112 | 113 | fprintf(stderr,"\n"); 114 | 115 | send_last_user_byte = spus; 116 | send_last_real_byte = sprs; 117 | recv_last_user_byte = rq->user_bytes; 118 | recv_last_real_byte = rq->real_bytes; 119 | } 120 | return NULL; 121 | } 122 | 123 | 124 | void *reverse_sending(void *skt_p){ 125 | const struct Socket *skt = (const struct Socket *)skt_p; 126 | int fd = skt->fd; 127 | int psize = skt->packet_size; 128 | while (1) { 129 | uint8_t *buf = malloc(psize - PROTOCOL_ABYTE); 130 | int r = tp_send(fd, buf, psize - PROTOCOL_ABYTE); 131 | if(r){ 132 | free(buf); 133 | } 134 | } 135 | return NULL; 136 | } 137 | 138 | int main(int argc, char *argv[]){ 139 | int rv = tp_init(); 140 | if(rv != 0){ 141 | printf("Failed to init typroto\n"); 142 | return -1; 143 | } 144 | if(argc < 5){ 145 | printf("Usage: ./tperf_server bind_ip bind_port packet_size password\n"); 146 | return -1; 147 | } 148 | 149 | slisten: sleep(1); 150 | 151 | 152 | int fd = tp_socket(AF_INET); 153 | printf("[Server] Got fd %d, Ready to listen %s:%s\n",fd, argv[1], argv[2]); 154 | 155 | struct sockaddr_in addr; 156 | socklen_t slen = sizeof(addr); 157 | memset((void *) &addr, 0, slen); 158 | addr.sin_family = AF_INET; 159 | addr.sin_port = htons(atoi(argv[2])); 160 | inet_aton(argv[1], &addr.sin_addr); 161 | tp_listen(fd, (const struct sockaddr*)&addr, slen); 162 | 163 | int psize = atoi(argv[3]); 164 | char *password = argv[4]; 165 | 166 | struct sockaddr_in incoming_addr; 167 | socklen_t alen = sizeof(incoming_addr); 168 | acceptc: 169 | 170 | rv = tp_accept(fd, psize, password, (struct sockaddr *)&incoming_addr,&alen); 171 | if(rv != 0){ 172 | if(errno == EAGAIN){ 173 | goto acceptc; 174 | } 175 | printf("[Server] Invalid packet from %s:%d, Code %d\n", 176 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port), rv); 177 | goto acceptc; 178 | } 179 | msgtime = time(NULL); 180 | tp_set_recv_callback(fd, recvcb, NULL); 181 | tp_set_event_callback(fd, evtcb, NULL); 182 | printf("[Server] Accepted a connection from %s:%d\n", 183 | inet_ntoa(incoming_addr.sin_addr), ntohs(incoming_addr.sin_port)); 184 | const struct Socket *skt = tp_get_sock_by_id(fd); 185 | printf("[Server] Size per packet: %d Transfer Key: ",skt->packet_size); 186 | printHex(32,skt->transfer_key); 187 | 188 | pthread_t stats_t; 189 | pthread_create(&stats_t, NULL, print_stats, (void *)skt); 190 | 191 | pthread_t rsend_t; 192 | 193 | while (1) { 194 | if(time(NULL) - msgtime > 5){ 195 | printf("[Server] Client timeout\n"); 196 | if(reverse_started){ 197 | pthread_cancel(rsend_t); 198 | } 199 | reverse_started = 0; 200 | speed_limit = 0; 201 | pthread_cancel(stats_t); 202 | tp_shutdown(fd); 203 | goto slisten; 204 | }else if(!reverse_started && speed_limit > 0){ 205 | skt->sendqueue->speed_limit = speed_limit; 206 | pthread_create(&rsend_t, NULL, reverse_sending, (void *)skt); 207 | reverse_started = 1; 208 | } 209 | sleep(1); 210 | } 211 | return 0; 212 | } -------------------------------------------------------------------------------- /src/handshake.c: -------------------------------------------------------------------------------- 1 | // 2 | // handshake.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #include "handshake.h" 10 | #include "totp.h" 11 | #include "packet.h" 12 | #include "common.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | void tp_calc_encrypt_key(const char *psk, uint8_t *buf){ 21 | char totpkey[9]; 22 | totp((uint8_t *)psk, strlen(psk), 30, 8, NULL, totpkey, 9); 23 | totpkey[8] = '\0'; 24 | 25 | uint32_t hs_key_len; 26 | HMAC(EVP_sha256(), totpkey, 8, (uint8_t *)psk, strlen(psk), buf, &hs_key_len); 27 | if(hs_key_len != 32){ 28 | printd("Key size %d may not suitable for encrypt\n",hs_key_len); 29 | } 30 | } 31 | 32 | int read_file(const char* name, uint8_t *buf, int *size){ 33 | int rv = -1; 34 | FILE *file; 35 | file = fopen(name, "r"); 36 | if (file) { 37 | uint32_t datasize; 38 | int len = fread(&datasize, 1, 4, file); 39 | if(len == 4){ 40 | int len = fread(buf, 1, datasize, file); 41 | if(len == datasize){ 42 | *size = len; 43 | rv = 0; 44 | } 45 | } 46 | fclose(file); 47 | } 48 | return rv; 49 | } 50 | 51 | int tp_build_handshake_packet(uint8_t *keybuf, uint8_t *databuf, uint32_t buflen, const char *psk){ 52 | 53 | int status = -1; 54 | 55 | #ifdef TP_RSA_LOAD_FROM_FILE 56 | printf("WARNING: RSA KEY WILL BE LOADED FROM FILE, PLEASE KEEP IT SAFE, AND CHANGE IT DAILY\n"); 57 | uint8_t *private_key = malloc(8192); 58 | int private_key_length = 0; 59 | int rfrv = read_file("rsa_priv", private_key, &private_key_length); 60 | if(rfrv == -1){ 61 | printf("You don't have rsa_priv, generate it with gen_key .\n"); 62 | exit(-1); 63 | } 64 | sodium_mprotect_readwrite(keybuf); 65 | memcpy(keybuf, private_key, private_key_length); 66 | sodium_mprotect_noaccess(keybuf); 67 | free(private_key); 68 | 69 | uint8_t *public_key = malloc(8192); 70 | int public_key_length = 0; 71 | rfrv = read_file("rsa_pub", public_key, &public_key_length); 72 | if(rfrv == -1){ 73 | printf("You don't have rsa_pub, generate it with gen_key .\n"); 74 | exit(-1); 75 | } 76 | 77 | #else 78 | // Generate RSA Keypair 79 | printd("Generating %d bit RSA keypair, this may take a while\n", TP_RSA_KEY_BITS); 80 | 81 | if(RAND_status() != 1){ 82 | printd("OpenSSL rand status: %d , do you have /dev/urandom ?\n", RAND_status()); 83 | } 84 | 85 | RSA *rsa_o = RSA_new(); 86 | BIGNUM *big_number = BN_new(); 87 | BN_set_word(big_number , RSA_F4); 88 | int ret = RSA_generate_key_ex(rsa_o, TP_RSA_KEY_BITS, big_number, NULL); 89 | if(ret != 1){ 90 | printd("RSA keypair generate failed with ret %d\n",ret); 91 | goto cleanup; 92 | } 93 | 94 | // Save private key 95 | 96 | uint8_t *private_key = NULL; 97 | int private_key_length = i2d_RSAPrivateKey(rsa_o, &private_key); 98 | sodium_mprotect_readwrite(keybuf); 99 | memcpy(keybuf, private_key, private_key_length); 100 | sodium_mprotect_noaccess(keybuf); 101 | sodium_memzero(private_key, private_key_length); 102 | free(private_key); 103 | 104 | // Save public key 105 | 106 | uint8_t *public_key = NULL; 107 | int public_key_length = i2d_RSAPublicKey(rsa_o, &public_key); 108 | #endif 109 | 110 | // Generate secret box 111 | 112 | struct Box inbox; 113 | inbox.packet_id = 0; 114 | inbox.type = PT_CLIENT_HELLO; 115 | inbox.timestamp = time(NULL); 116 | inbox.payload = public_key; 117 | inbox.payload_length = public_key_length; 118 | 119 | // Generate handshake encrypt key 120 | 121 | uint8_t hs_encrypt_key[EVP_MAX_MD_SIZE]; 122 | tp_calc_encrypt_key(psk, hs_encrypt_key); 123 | 124 | // Encrypt packet 125 | 126 | int rv = tp_packet_encrypt(&inbox, databuf, buflen, hs_encrypt_key); 127 | sodium_memzero(public_key, public_key_length); 128 | free(public_key); 129 | 130 | if(rv != P_SUCCESS){ 131 | printd("Packet encrypt failed, buflen: %d\n",buflen); 132 | goto cleanup; 133 | } 134 | status = private_key_length; 135 | 136 | cleanup: 137 | #ifndef TP_RSA_LOAD_FROM_FILE 138 | RSA_free(rsa_o); 139 | BN_free(big_number); 140 | #endif 141 | return status; 142 | } 143 | 144 | int tp_build_handshake_packet_response(uint8_t *outkeybuf,uint8_t *respbuf, uint32_t rbuflen, uint8_t *databuf, uint32_t buflen, const char *psk){ 145 | 146 | // Decrypt handshake request 147 | 148 | struct Box box; 149 | struct Packet pkt; 150 | pkt.box = &box; 151 | 152 | uint8_t hs_encrypt_key[EVP_MAX_MD_SIZE]; 153 | tp_calc_encrypt_key(psk, hs_encrypt_key); 154 | 155 | int rv = tp_packet_decrypt(&pkt, databuf, buflen, hs_encrypt_key); 156 | if(rv != P_SUCCESS){ 157 | printd("Packet decrypt failed, rv: %d\n",rv); 158 | return rv; 159 | } 160 | 161 | if(box.type != PT_CLIENT_HELLO || box.packet_id != 0){ 162 | printd("Incorrect packet id %lld type %d for handshake\n",box.packet_id, box.type); 163 | return -1001; 164 | } 165 | 166 | int status = -1; 167 | 168 | // Decode RSA public key 169 | 170 | const unsigned char *pkptr = box.payload; 171 | 172 | RSA *r = d2i_RSAPublicKey(NULL, &pkptr, box.payload_length); 173 | free(box.payload); 174 | if(!r){ 175 | printd("Failed to decode rsa public key %d\n",box.payload_length); 176 | return -1002; 177 | } 178 | 179 | randombytes_buf(outkeybuf, 32); 180 | 181 | int to_size = RSA_size(r); 182 | uint8_t target[to_size]; 183 | 184 | int ret = RSA_public_encrypt(32, outkeybuf, target, r, RSA_PKCS1_PADDING); 185 | if(ret < 0){ 186 | printd("RSA encrypt failed with ret %d\n",ret); 187 | status = -1003; 188 | goto cleanup; 189 | } 190 | 191 | printd("size: %d to_size:%d\n",ret,to_size); 192 | 193 | // Generate secret box 194 | 195 | struct Box inbox; 196 | inbox.packet_id = 0; 197 | inbox.type = PT_SERVER_HELLO; 198 | inbox.timestamp = time(NULL); 199 | inbox.payload = target; 200 | inbox.payload_length = ret; 201 | 202 | // Encrypt packet 203 | 204 | rv = tp_packet_encrypt(&inbox, respbuf, rbuflen, hs_encrypt_key); 205 | if(rv != P_SUCCESS){ 206 | printd("Packet encrypt failed, buflen: %d\n",buflen); 207 | status = -1004; 208 | goto cleanup; 209 | } 210 | status = 0; 211 | 212 | cleanup: 213 | RSA_free(r); 214 | return status; 215 | } 216 | 217 | int tp_handshake_response_decrypt(uint8_t *outkeybuf, uint8_t *inkeybuf, uint32_t inkeylen, uint8_t *inbuf, uint32_t inlen, const char *psk){ 218 | // Decrypt handshake response 219 | 220 | struct Box box; 221 | struct Packet pkt; 222 | pkt.box = &box; 223 | 224 | uint8_t hs_encrypt_key[EVP_MAX_MD_SIZE]; 225 | tp_calc_encrypt_key(psk, hs_encrypt_key); 226 | 227 | int rv = tp_packet_decrypt(&pkt, inbuf, inlen, hs_encrypt_key); 228 | if(rv != P_SUCCESS){ 229 | printd("Packet decrypt failed, rv: %d\n",rv); 230 | return rv; 231 | } 232 | 233 | if(box.type != PT_SERVER_HELLO || box.packet_id != 0){ 234 | printd("Incorrect packet id %lld type %d for handshake\n",box.packet_id, box.type); 235 | return -1101; 236 | } 237 | 238 | // Decode RSA private key 239 | sodium_mprotect_readonly(inkeybuf); 240 | const unsigned char *ibptr = inkeybuf; 241 | RSA *r = d2i_RSAPrivateKey(NULL, &ibptr, inkeylen); 242 | if(!r){ 243 | printd("Failed to decode rsa private key %d",inkeylen); 244 | return -1102; 245 | } 246 | 247 | int status = -1; 248 | 249 | int ret = RSA_private_decrypt(box.payload_length, box.payload, outkeybuf, r, RSA_PKCS1_PADDING); 250 | free(box.payload); 251 | if(ret < 0){ 252 | printd("RSA decrypt failed with ret %d\n",ret); 253 | status = -1103; 254 | goto cleanup; 255 | }else if(ret != 32){ 256 | printd("Key size %d may not suitable for encrypt\n",ret); 257 | } 258 | 259 | status = 0; 260 | cleanup: 261 | RSA_free(r); 262 | sodium_mprotect_noaccess(inkeybuf); 263 | return status; 264 | } -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | // 2 | // queue.c 3 | // typroto 4 | // 5 | // Created by TYPCN on 2016/6/4. 6 | // 7 | // 8 | 9 | #include "queue.h" 10 | #include "packet.h" 11 | #include 12 | #include 13 | #include 14 | #ifdef _WIN32 15 | #include 16 | #include 17 | #else 18 | #include 19 | #include 20 | #endif 21 | #include "rqutils.h" 22 | 23 | void *tp_send_loop(); 24 | void *tp_recv_loop(); 25 | 26 | #define send_event(code,msg) q->skt->evt(sockfd,code,msg,addr,alen,q->skt->evt_userdata) 27 | 28 | struct SendQueue *tp_send_queue_create(const struct Socket *skt){ 29 | int size = sizeof(struct SendQueue); 30 | struct SendQueue *q = malloc(size); 31 | memset(q, 0, size); 32 | q->skt = skt; 33 | q->write_offset = 1; 34 | q->last_packet_id = 1; 35 | q->packet_num = 1; 36 | q->window_size = TP_INIT_WINDOW_SIZE; 37 | q->resend_delay = TP_INIT_RESEND_DELAY; 38 | q->speed_limit = 50000; 39 | q->max_resend_timeout = 1000; 40 | pthread_mutex_init(&q->lock,NULL); 41 | pthread_spin_init(&q->ack_lock, PTHREAD_PROCESS_PRIVATE); 42 | pthread_cond_init(&q->idle_cond, NULL); 43 | pthread_cond_init(&q->nobufs_cond, NULL); 44 | pthread_create(&q->thread, NULL, tp_send_loop, (void *)q); 45 | return q; 46 | } 47 | struct RecvQueue *tp_recv_queue_create(const struct Socket *skt){ 48 | int size = sizeof(struct RecvQueue); 49 | struct RecvQueue *q = malloc(size); 50 | memset(q, 0, size); 51 | q->skt = skt; 52 | q->real_bytes = skt->packet_size; // 1 Handshake packet 53 | q->packet_num = 1; 54 | q->sack_send_delay = TP_SACK_SEND_DELAY; 55 | q->sack_threshold = TP_SACK_THRESHOLD; 56 | q->ack_send_delay = TP_ACK_SEND_DELAY; 57 | //pthread_spin_init(&q->lock, PTHREAD_PROCESS_PRIVATE); 58 | pthread_create(&q->thread, NULL, tp_recv_loop, (void *)q); 59 | return q; 60 | } 61 | 62 | void *tp_send_loop(void *queue){ 63 | struct SendQueue *q = (struct SendQueue *)queue; 64 | int psize = q->skt->packet_size; 65 | int sockfd = q->skt->fd; 66 | const struct sockaddr *addr = q->skt->addr; 67 | socklen_t alen = q->skt->sockaddr_len; 68 | int rv = 0; 69 | pthread_mutex_t *lock = &q->lock; 70 | pthread_spinlock_t *ack_lock = &q->ack_lock; 71 | 72 | pthread_cond_t *idle_cond = &q->idle_cond; 73 | 74 | uint64_t ts_ignore_until = 0; 75 | int resends_since_last_ack = 0; 76 | 77 | int us_factor = 1000*1000; 78 | 79 | while (!q->stopping) { 80 | pthread_spin_lock(ack_lock); 81 | uint64_t last_ack = q->last_ack_id; 82 | bool ack_reset_perform = q->ack_reset_perform; 83 | if(ack_reset_perform){ 84 | q->ack_reset_perform = false; 85 | } 86 | pthread_spin_unlock(ack_lock); 87 | 88 | pthread_mutex_lock(lock); 89 | uint64_t last_write = q->write_offset; 90 | uint64_t last_sent = q->sent_offset; 91 | bool is_buf_full = q->nobufs_wait; 92 | last_sent = tr_procACK(q, last_sent, last_ack, is_buf_full); 93 | q->sent_offset = last_sent; 94 | pthread_mutex_unlock(lock); 95 | 96 | int pkt_end = MIN(last_write, last_sent + q->window_size); 97 | int pkt_sent_this_cycle = 0; 98 | 99 | last_sent++; 100 | 101 | printv("Sending %llu to %d\n", last_sent, pkt_end); 102 | 103 | for (uint64_t i = last_sent; i < pkt_end; i++) { 104 | int idx = i % TP_SEND_BUFFER_SIZE; 105 | uint64_t current = get_clock_ms(); 106 | 107 | if(current - q->sent_ts[idx] < (q->resend_delay + TP_ACK_SEND_DELAY) && i > ts_ignore_until){ 108 | printv("resend delay %d preventing packet %llu sending.\n",q->resend_delay, i); 109 | continue; 110 | } 111 | 112 | pthread_spin_lock(ack_lock); 113 | bool sack_reset = q->sack_reset_perform; 114 | bool ack_pres = q->last_ack_id > i+1; 115 | int sack_id = i - q->last_sack_id; 116 | bool sack_prevent = false; 117 | if(sack_id < TP_SACK_BUFFER_SIZE){ 118 | sack_prevent = BITTEST(q->sack_bitmap, sack_id); 119 | } 120 | if(sack_reset){ 121 | q->sack_reset_perform = false; 122 | } 123 | pthread_spin_unlock(ack_lock); 124 | 125 | if(sack_prevent){ 126 | printv("SACK ID %d preventing packet %llu sending\n",sack_id,i); 127 | continue; 128 | }else if(q->sent_ts[idx] > 0){ 129 | resends_since_last_ack++; 130 | q->packet_resend++; 131 | printv("Resending %llu\n", i); 132 | } 133 | 134 | if(!q->boxes[idx]){ 135 | printv("Box of %llu is empty\n", i); 136 | continue; 137 | } 138 | 139 | q->packet_num++; 140 | q->boxes[idx]->timestamp = time(NULL); 141 | 142 | if(i+1 == pkt_end){ 143 | q->boxes[idx]->type = PT_DATA_NEED_ACK; 144 | }else{ 145 | q->boxes[idx]->type = PT_DATA; 146 | } 147 | 148 | uint8_t buf[psize]; 149 | rv = tp_packet_encrypt(q->boxes[idx], buf, psize, q->skt->transfer_key); 150 | if(rv != 0){ 151 | send_event(rv, "packet encrypt failed"); 152 | goto breakout; 153 | } 154 | rv = sendto(sockfd, buf, psize, 0, addr, alen); 155 | if(rv < 0){ 156 | send_event(errno, "sendto() failed"); 157 | goto breakout; 158 | } 159 | 160 | pkt_sent_this_cycle++; 161 | 162 | printv("send() %llu returned %d with errno %d\n", i ,rv,errno); 163 | q->sent_ts[idx] = current; 164 | 165 | if(ack_pres){ 166 | goto breakout; 167 | }else if(sack_reset){ 168 | pthread_spin_lock(ack_lock); 169 | q->sack_reset_perform = false; 170 | ts_ignore_until = q->last_sack_id + q->last_sack_length; 171 | pthread_spin_unlock(ack_lock); 172 | printv("Ignore timeout until packet %llu , last_sent %llu\n",ts_ignore_until,i); 173 | goto breakout; 174 | } 175 | } 176 | 177 | if(ts_ignore_until > 0){ 178 | ts_ignore_until = 0; 179 | } 180 | 181 | if(ack_reset_perform){ 182 | resends_since_last_ack = 0; 183 | } 184 | 185 | if(resends_since_last_ack > q->max_resend_timeout){ 186 | send_event(-2002, "no ack"); 187 | printf("WARNING: NO ACKS AFTER %d Resends, is remote down? \n",resends_since_last_ack); 188 | sleep(1); 189 | } 190 | 191 | if(last_write - last_sent > 1){ 192 | usleep((us_factor / q->speed_limit) * (pkt_end - last_sent)); 193 | continue; 194 | } 195 | 196 | pthread_mutex_lock(lock); 197 | q->idle_wait = true; 198 | pthread_cond_wait(idle_cond, lock); 199 | q->idle_wait = false; 200 | pthread_mutex_unlock(lock); 201 | breakout:; 202 | } 203 | printd("Sending fd %d thread exiting\n",sockfd); 204 | return NULL; 205 | } 206 | 207 | void *tp_recv_loop(void *queue){ 208 | struct RecvQueue *q = (struct RecvQueue *)queue; 209 | const struct Socket *skt = q->skt; 210 | struct SendQueue *sq = skt->sendqueue; 211 | 212 | int psize = skt->packet_size; 213 | int sockfd = skt->fd; 214 | 215 | struct sockaddr *addr; 216 | 217 | if(skt->addr->sa_family == AF_INET){ 218 | struct sockaddr_in incoming_addr; 219 | addr = (struct sockaddr*)&incoming_addr; 220 | }else{ 221 | struct sockaddr_in6 incoming_addr; 222 | addr = (struct sockaddr*)&incoming_addr; 223 | } 224 | 225 | socklen_t alen = skt->sockaddr_len; 226 | uint8_t buf[psize]; 227 | struct Packet outpkt; 228 | 229 | uint32_t boxSize = sizeof(struct Box); 230 | 231 | while (1) { 232 | if(!q->callback){ 233 | sleep(1); 234 | continue; 235 | } 236 | int rsize = recvfrom(sockfd, buf, psize, 0, addr, &alen); 237 | if(errno == EBADF){ 238 | printd("Fd %d was closed , thread exiting\n",sockfd); 239 | break; 240 | } 241 | if(errno == ETIMEDOUT || errno == EAGAIN){ 242 | continue; 243 | }else if(rsize < psize){ 244 | if(rsize < 0){ 245 | send_event(errno, "recvfrom() failed"); 246 | }else{ 247 | send_event(-2001, "invalid packet size"); 248 | } 249 | continue; 250 | } 251 | 252 | #if ENABLE_RANDOM_PACKET_LOSS > 0 253 | if(((float)rand() / (float)RAND_MAX) * 100 < ENABLE_RANDOM_PACKET_LOSS){ 254 | continue; 255 | } 256 | #endif 257 | q->real_bytes += rsize; 258 | 259 | struct Box *outbox = malloc(boxSize); 260 | outpkt.box = outbox; 261 | // TODO: Anti nonce reuse , request missing packet, verify overflow 262 | 263 | int e = tp_packet_decrypt(&outpkt, buf, rsize, skt->transfer_key); 264 | if(e != 0){ 265 | send_event(e, "packet decrypt failed"); 266 | free(outbox); 267 | continue; 268 | } 269 | 270 | q->packet_num++; 271 | 272 | if(outbox->type == PT_ACK){ 273 | uint64_t ackid = *(uint64_t *)outbox->payload; 274 | pthread_spin_lock(&sq->ack_lock); 275 | if(ackid > sq->last_ack_id){ 276 | sq->last_ack_id = ackid; 277 | sq->ack_reset_perform = true; 278 | } 279 | pthread_spin_unlock(&sq->ack_lock); 280 | printv("Got ACK from %llu to %llu\n",ackid, *(uint64_t *)outbox->payload); 281 | free(outbox->payload); 282 | free(outbox); 283 | continue; 284 | }else if(outbox->type == PT_SACK){ 285 | uint64_t sackid = *(uint64_t *)outbox->payload; 286 | int sack_len = *(int *)(outbox->payload + 8); 287 | pthread_spin_lock(&sq->ack_lock); 288 | // Prevent SACK packet delay 289 | if(sackid > sq->last_ack_id){ 290 | sq->sack_reset_perform = true; 291 | sq->last_ack_id = sackid - 1; 292 | sq->last_sack_id = sackid; 293 | sq->last_sack_length = sack_len; 294 | memcpy(sq->sack_bitmap, outbox->payload + 12, outbox->payload_length - 12); 295 | printv("Got SACK packet with ID %llu\n",sackid); 296 | } 297 | pthread_spin_unlock(&sq->ack_lock); 298 | free(outbox->payload); 299 | free(outbox); 300 | continue; 301 | } 302 | 303 | printv("LastRecv: %llu, LastComplete: %llu\n",q->last_received_id, q->last_completed_id); 304 | 305 | if(q->last_received_id - q->last_completed_id >= TP_RECV_BUFFER_SIZE // Check is write to a in use slot 306 | && outbox->packet_id > q->last_received_id){ // Check is bigger than last recv ( need write to end ) 307 | q->packet_dropped++; 308 | free(outbox->payload); 309 | free(outbox); 310 | printd("WARNING: Packet dropped because buffer full %llu\n",q->packet_dropped); 311 | continue; 312 | }else if(outbox->packet_id <= q->last_completed_id){ 313 | q->packet_dup++; 314 | printd("WARNING: Received a ACKed packet %llu\n",outbox->packet_id); 315 | free(outbox->payload); 316 | free(outbox); 317 | tr_sendACK(q, false); 318 | continue; 319 | } 320 | 321 | int insert_position = outbox->packet_id % TP_RECV_BUFFER_SIZE; 322 | 323 | if(q->boxes[insert_position]){ 324 | printv("Received DUP packet %llu %p, box pos %d\n", outbox->packet_id, q->boxes[insert_position], insert_position); 325 | q->packet_dup++; 326 | free(outbox->payload); 327 | free(outbox); 328 | tr_sendSACK(q, q->last_completed_id + 1, q->last_received_id - 1); 329 | continue; 330 | } 331 | 332 | q->user_bytes += outbox->payload_length; 333 | 334 | printv("Insert pos %d %p , packet id %llu\n",insert_position, outbox, outbox->packet_id); 335 | q->boxes[insert_position] = outbox; 336 | 337 | if(outbox->packet_id > q->last_received_id){ 338 | q->last_received_id = outbox->packet_id; 339 | } 340 | 341 | uint64_t target_id = q->last_completed_id + 1; 342 | uint64_t end_id = q->last_received_id + 1; 343 | for (int i = target_id; i < end_id; i++) { 344 | int key = i % TP_RECV_BUFFER_SIZE; 345 | struct Box *box = q->boxes[key]; 346 | if(!box){ 347 | break; 348 | } 349 | q->callback(sockfd, box->payload, box->payload_length, addr, alen, q->callback_userdata); 350 | if(box->payload_length > 0 && box->payload){ 351 | free(box->payload); 352 | } 353 | free(box); 354 | printv("Box: %d %p was freed, pos %d\n",i,box, key); 355 | q->boxes[key] = NULL; 356 | printv("Box: %d %p was freed, pos %d\n",i,box, key); 357 | q->last_completed_id = i; 358 | } 359 | 360 | target_id = q->last_completed_id; 361 | 362 | if(end_id - target_id > q->sack_threshold){ 363 | tr_sendSACK(q, target_id + 1, end_id - 1); 364 | } 365 | 366 | if(outbox->type == PT_DATA_NEED_ACK || outbox->packet_id == q->last_sack_sent){ 367 | tr_sendACK(q, true); 368 | }else{ 369 | tr_sendACK(q, false); 370 | } 371 | } 372 | return NULL; 373 | } 374 | 375 | int tp_send_queue_destroy(struct SendQueue *q){ 376 | q->stopping = true; 377 | pthread_cond_signal(&q->idle_cond); 378 | pthread_cond_signal(&q->nobufs_cond); 379 | pthread_join(q->thread, NULL); 380 | pthread_mutex_destroy(&q->lock); 381 | pthread_spin_destroy(&q->ack_lock); 382 | pthread_cond_destroy(&q->idle_cond); 383 | pthread_cond_destroy(&q->nobufs_cond); 384 | for (int i = 0; i < TP_SEND_BUFFER_SIZE; i++) { 385 | struct Box *box = q->boxes[i]; 386 | if(!box){ 387 | continue; 388 | } 389 | if(box->payload_length > 0 && box->payload){ 390 | free(box->payload); 391 | } 392 | free(box); 393 | q->boxes[i] = NULL; 394 | } 395 | free(q); 396 | return 0; 397 | } 398 | int tp_recv_queue_destroy(struct RecvQueue *q){ 399 | pthread_cancel(q->thread); 400 | for (int i = 0; i < TP_RECV_BUFFER_SIZE; i++) { 401 | struct Box *box = q->boxes[i]; 402 | if(!box){ 403 | continue; 404 | } 405 | if(box->payload_length > 0 && box->payload){ 406 | free(box->payload); 407 | } 408 | free(box); 409 | q->boxes[i] = NULL; 410 | } 411 | free(q); 412 | return 0; 413 | } --------------------------------------------------------------------------------