#ifndef PICA_CLIENT_H #define PICA_CLIENT_H #include #include "PICA_id.h" #ifdef WIN32 #include #include #include typedef unsigned __int16 uint16_t; typedef unsigned __int64 uint64_t; #else #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #ifdef PICA_MULTITHREADED #include #endif #define SOCKET int #define SOCKET_ERROR -1 #endif #include #include #include #include #include #include #include #include #include #ifdef PICA_MULTITHREADED #define OPENSSL_THREAD_DEFINES #include #if defined(OPENSSL_THREADS) // thread support enabled #else #error "THREAD SUPPORT IS NOT ENABLED IN OPENSSL!" #endif #endif //#define PICA_MSGOK 3 //#define PICA_MSGUTF8 2 #define PICA_NEWCHAN 1 #define PICA_OK 0 #define PICA_ERRINVARG -1 #define PICA_ERRNOMEM -2 #define PICA_ERRSSL -3 #define PICA_ERRSOCK -4 #define PICA_ERRSERV -5 //#define PICA_ERRVERDIFFER -6 #define PICA_ERRNOTFOUND -7 #define PICA_ERRNOPEERCERT -8 #define PICA_ERRINVPEERCERT -9 #define PICA_ERRDISCONNECT -10 #define PICA_ERRINVCERT -11 #define PICA_ERRMSGSIZE -12 #define PICA_ERRDNSRESOLVE -13 #define PICA_ERRPROTOOLD -14 #define PICA_ERRPROTONEW -15 #define PICA_ERRINVFILENAME -16 #define PICA_ERRFILETRANSFERINPROGRESS -17 #define PICA_ERRFILETRANSFERNOTINPROGRESS -18 #define PICA_ERRFILEFRAGMENTCROSSEDSIZE -19 #define PICA_ERRFILEOPEN -20 #define PICA_ERRFILEIO -21 #define PICA_ERRINVPKEYPASSPHRASE -22 #define PICA_ERRINVPKEYFILE -23 #define PICA_ERRTIMEDOUT -24 //#define PICA_CHNMSGBUFLEN 104 #define PICA_CHANREADBUFSIZE 65536 #define PICA_CHANWRITEBUFSIZE 4096 #define PICA_CONNREADBUFSIZE 65536 #define PICA_CONNWRITEBUFSIZE 4096 #define PICA_FILEFRAGMENTSIZE 16384 //max size of TLS record #define PICA_CHANSENDFILESTATE_IDLE 0 #define PICA_CHANSENDFILESTATE_SENTREQ 20 #define PICA_CHANSENDFILESTATE_SENDING 22 #define PICA_CHANSENDFILESTATE_PAUSED 23 #define PICA_CHANRECVFILESTATE_IDLE 0 #define PICA_CHANRECVFILESTATE_RECEIVING 24 #define PICA_CHANRECVFILESTATE_PAUSED 25 #define PICA_CHANRECVFILESTATE_WAITACCEPT 26 #define PICA_C2C_ACTIVATE_TIMEOUT 30 #define PICA_C2C_INCOMING 0 #define PICA_C2C_OUTGOING 1 #define PICA_DIRECTC2C_INCOMING 0 #define PICA_DIRECTC2C_OUTGOING 1 struct PICA_c2n; struct PICA_c2c; struct PICA_acc { unsigned char id[PICA_ID_SIZE]; //SHA224 hash of user's certificate in DER format SSL_CTX* ctx; }; enum PICA_c2n_state { PICA_C2N_STATE_NEW = 0, PICA_C2N_STATE_CONNECTING, PICA_C2N_STATE_WAITINGREP, PICA_C2N_STATE_WAITINGTLS, PICA_C2N_STATE_CONNECTED }; enum PICA_directc2c_config { PICA_DIRECTC2C_CFG_DISABLED, PICA_DIRECTC2C_CFG_CONNECTONLY, PICA_DIRECTC2C_CFG_ALLOWINCOMING }; struct PICA_c2n { struct PICA_acc *acc; //#warning "sockaddr!" struct sockaddr_in srv_addr; // sockaddr !! //unsigned char id[PICA_ID_SIZE]; //SHA224 hash of user's certificate in DER format //SSL_CTX* ctx; SOCKET sck_comm; SSL* ssl_comm; enum PICA_c2n_state state; enum PICA_directc2c_config directc2c_config; struct PICA_listener *directc2c_listener; unsigned char *read_buf; unsigned char *write_buf; unsigned int read_pos; unsigned int write_pos; unsigned int write_buflen; unsigned int write_sslbytestowrite; struct PICA_c2c *chan_list_head; struct PICA_c2c *chan_list_end; int init_resp_ok; unsigned char node_ver_major, node_ver_minor; int disconnect_on_empty_write_buf; int want_write; }; enum PICA_c2c_state { PICA_C2C_STATE_NEW = 0, PICA_C2C_STATE_CONNECTING, PICA_C2C_STATE_CONNID, PICA_C2C_STATE_WAITINGTLS, PICA_C2C_STATE_WAITINGREP, PICA_C2C_STATE_WAITINGC2CPROTOVER, PICA_C2C_STATE_ACTIVE }; enum PICA_directc2c_state { PICA_DIRECTC2C_STATE_INACTIVE, PICA_DIRECTC2C_STATE_CONNECTING, PICA_DIRECTC2C_STATE_FAILEDTOCONNECT, PICA_DIRECTC2C_STATE_WAITINGINCOMING, PICA_DIRECTC2C_STATE_ACTIVE }; enum PICA_directc2c_connection_state { PICA_DIRECTC2C_CONNSTATE_NEW = 0, PICA_DIRECTC2C_CONNSTATE_CONNECTING, PICA_DIRECTC2C_CONNSTATE_WAITINGTLS, PICA_DIRECTC2C_CONNSTATE_ACTIVE, PICA_DIRECTC2C_CONNSTATE_FAILED }; struct PICA_directc2c { int is_outgoing; SOCKET sck; SSL *ssl; X509 *peer_cert; int want_write; uint8_t *addrlist; int addrpos; struct sockaddr_in addr; enum PICA_directc2c_connection_state state; struct PICA_directc2c *next; }; struct PICA_c2c { const struct PICA_acc *acc; struct PICA_c2n *conn;//соединение с сервером, через которое установлен данный логический канал связи unsigned char peer_id[PICA_ID_SIZE]; SOCKET sck_data; SSL *ssl; struct PICA_directc2c *direct; int outgoing;//1 если создание канала инициировано локальным клиентом, 0 - если собеседником X509 *peer_cert; //unsigned char msgbuf[PICA_CHNMSGBUFLEN]; unsigned char *read_buf; unsigned char *write_buf; unsigned int read_pos; unsigned int write_pos; unsigned int write_buflen; unsigned int write_sslbytestowrite; struct PICA_c2c *next; struct PICA_c2c *prev; enum PICA_c2c_state state; enum PICA_directc2c_state directc2c_state; time_t timestamp; int sendfilestate; uint64_t sendfile_size; uint64_t sendfile_pos; FILE *sendfile_stream; int recvfilestate; uint64_t recvfile_size; uint64_t recvfile_pos; FILE *recvfile_stream; //this flag should be set when connection must be closed after sending last pushed packet int disconnect_on_empty_write_buf; int switched_to_directc2c_write; int switched_to_directc2c_read; int want_write; unsigned int directc2c_write_barrier_pos; unsigned int directc2c_write_before_barrier_pos; }; struct PICA_listener { const struct PICA_acc *acc; SOCKET sck_listener; int public_port; int local_port; in_addr_t public_addr_ipv4; const char *public_addr_dns; struct PICA_directc2c *accepted_connections; }; struct PICA_client_callbacks { //получение сообщения. void (*newmsg_cb)(const unsigned char *peer_id, const char* msgbuf, unsigned int nb, int type); //получение подтверждения о доставке сообщения void (*msgok_cb)(const unsigned char *peer_id); //создание канала с собеседником void (*c2c_established_cb)(const unsigned char *peer_id); //создать канал не удалось void (*c2c_failed_cb)(const unsigned char *peer_id); //входящий запрос на создание канала от пользователя с номером caller_id //возвращаемое значение: 0 - отклонить запрос, ненулевое значение - принять запрос int (*accept_cb)(const unsigned char *caller_id); //запрошенный пользователь не найден, в оффлайне или отказался от общения void (*notfound_cb)(const unsigned char *callee_id); // void (*c2c_closed_cb)(const unsigned char *peer_id, int reason); void (*nodelist_cb)(int type, void *addr_bin, const char *addr_str, unsigned int port); //сертификат собеседника в формате PEM. Функция должна сравнить предъявленный сертификат с сохранённым (если есть) и вернуть 1 при успешной проверке, 0 - при неуспешной int (*peer_cert_verify_cb)(const unsigned char *peer_id, const char *cert_pem, unsigned int nb); // returns 0 if file is rejected, 1 if accepted, 2 if decision is postponed int (*accept_file_cb)(const unsigned char *peer_id, uint64_t file_size, const char *filename, unsigned int filename_size); void (*accepted_file_cb)(const unsigned char *peer_id); void (*denied_file_cb)(const unsigned char *peer_id); void (*file_progress_cb)(const unsigned char *peer_id, uint64_t sent, uint64_t received); void (*file_control_cb)(const unsigned char *peer_id, unsigned int sender_cmd, unsigned int receiver_cmd); void (*file_finished_cb)(const unsigned char *peer_id, int sending); void (*c2n_established_cb)(struct PICA_c2n *c2n); void (*c2n_failed_cb)(struct PICA_c2n *c2n, int error); void (*c2n_closed_cb)(struct PICA_c2n *c2n, int error); void (*listener_error_cb)(struct PICA_listener *lst, int errorcode); }; #ifdef __cplusplus extern "C" { #endif //read certificate from cert_file in PEM format, store id in buffer pointed by id int PICA_get_id_from_cert_file(const char *cert_file, unsigned char *id); //read certificate from C string in PEM format, store id in buffer pointed by id int PICA_get_id_from_cert_string(const char *cert_pem, unsigned char *id); int PICA_client_init(struct PICA_client_callbacks *clcbs); int PICA_new_c2n(const struct PICA_acc *acc, const char *nodeaddr, unsigned int port, enum PICA_directc2c_config direct_c2c_mode, struct PICA_listener *l, struct PICA_c2n **ci); int PICA_new_c2c(struct PICA_c2n *ci, const unsigned char *peer_id, struct PICA_listener *l, struct PICA_c2c **chn); int PICA_new_listener(const struct PICA_acc *acc, const char *public_addr, int public_port, int local_port, struct PICA_listener **l); // <<