diff options
| -rwxr-xr-x | PICA_client.c | 166 | ||||
| -rwxr-xr-x | PICA_client.h | 32 | ||||
| -rwxr-xr-x | PICA_proto.h | 8 | ||||
| -rwxr-xr-x | doc/proto.txt | 14 | ||||
| -rw-r--r-- | pica-client/skynet.cpp | 2 | ||||
| -rw-r--r-- | pica-client/skynet.h | 2 |
6 files changed, 218 insertions, 6 deletions
diff --git a/PICA_client.c b/PICA_client.c index 7bf9eb1..33442c0 100755 --- a/PICA_client.c +++ b/PICA_client.c @@ -41,6 +41,10 @@ static unsigned int procmsg_CLNODELIST(unsigned char*,unsigned int,void*); static unsigned int procmsg_MSGUTF8(unsigned char*,unsigned int,void*); static unsigned int procmsg_MSGOK(unsigned char*,unsigned int,void*); static unsigned int procmsg_PINGREQ(unsigned char*,unsigned int,void*); +static unsigned int procmsg_SENDFILEREQUEST(unsigned char*,unsigned int,void*); +static unsigned int procmsg_ACCEPTEDFILE(unsigned char*,unsigned int,void*); +static unsigned int procmsg_DENIEDFILE(unsigned char*,unsigned int,void*); +static unsigned int procmsg_FILEFRAGMENT(unsigned char*,unsigned int,void*); static struct PICA_proto_msg* c2n_writebuf_push(struct PICA_conninfo *ci, unsigned int msgid, unsigned int size); static struct PICA_proto_msg* c2c_writebuf_push(struct PICA_chaninfo *chn, unsigned int msgid, unsigned int size); @@ -50,13 +54,17 @@ const struct PICA_msginfo c2n_messages[] = { {PICA_PROTO_CONNREQINC, PICA_MSG_FIXED_SIZE, PICA_PROTO_CONNREQINC_SIZE, procmsg_CONNREQINC}, {PICA_PROTO_NOTFOUND, PICA_MSG_FIXED_SIZE, PICA_PROTO_NOTFOUND_SIZE, procmsg_NOTFOUND}, {PICA_PROTO_FOUND, PICA_MSG_FIXED_SIZE, PICA_PROTO_FOUND_SIZE, procmsg_FOUND}, - {PICA_PROTO_CLNODELIST, PICA_MSG_VAR_SIZE, PICA_MSG_VARSIZE_INT16, procmsg_CLNODELIST}, - {PICA_PROTO_PINGREQ, PICA_MSG_FIXED_SIZE, PICA_PROTO_PINGREQ_SIZE, procmsg_PINGREQ} + {PICA_PROTO_CLNODELIST, PICA_MSG_VAR_SIZE, PICA_MSG_VARSIZE_INT16, procmsg_CLNODELIST}, + {PICA_PROTO_PINGREQ, PICA_MSG_FIXED_SIZE, PICA_PROTO_PINGREQ_SIZE, procmsg_PINGREQ} };//---!!! PING!!! const struct PICA_msginfo c2c_messages[] = { {PICA_PROTO_MSGUTF8, PICA_MSG_VAR_SIZE, PICA_MSG_VARSIZE_INT16, procmsg_MSGUTF8}, - {PICA_PROTO_MSGOK, PICA_MSG_FIXED_SIZE, PICA_PROTO_MSGOK_SIZE, procmsg_MSGOK} + {PICA_PROTO_MSGOK, PICA_MSG_FIXED_SIZE, PICA_PROTO_MSGOK_SIZE, procmsg_MSGOK}, + {PICA_PROTO_SENDFILEREQUEST, PICA_MSG_VAR_SIZE, PICA_MSG_VARSIZE_INT16, procmsg_SENDFILEREQUEST}, + {PICA_PROTO_ACCEPTEDFILE, PICA_MSG_FIXED_SIZE, PICA_PROTO_ACCEPTEDFILE_SIZE, procmsg_ACCEPTEDFILE}, + {PICA_PROTO_DENIEDFILE, PICA_MSG_FIXED_SIZE, PICA_PROTO_DENIEDFILE_SIZE, procmsg_DENIEDFILE}, + {PICA_PROTO_FILEFRAGMENT, PICA_MSG_VAR_SIZE, PICA_MSG_VARSIZE_INT16, procmsg_FILEFRAGMENT} }; struct PICA_msginfo c2n_init_messages[] = { @@ -636,6 +644,95 @@ else return 1; } +static unsigned int procmsg_SENDFILEREQUEST(unsigned char* buf, unsigned int nb, void* p) +{ +struct PICA_chaninfo *chan = (struct PICA_chaninfo *)p; +struct PICA_proto_msg *mp; +unsigned int reply; +unsigned int replysize; + +if (chan->recvfilestate != PICA_CHANRECVFILESTATE_IDLE) + return 0; + +if (callbacks.accept_file_cb(chan->peer_id, *(uint64_t*)(buf + 4), buf + 12, *(uint16_t*)(buf + 2) - 8)) + { + reply = PICA_PROTO_ACCEPTEDFILE; + replysize = PICA_PROTO_ACCEPTEDFILE_SIZE; + + chan->recvfilestate = PICA_CHANRECVFILESTATE_RECEIVING; + chan->recvfile_size = *(uint64_t*)(buf + 4); + chan->recvfile_pos = 0; + } +else + { + reply = PICA_PROTO_DENIEDFILE; + reply = PICA_PROTO_DENIEDFILE_SIZE; + } + +mp = c2c_writebuf_push( chan, reply, replysize); + +if (mp) + { + RAND_bytes(mp->tail, 2); + } +else + return 0; + +return 1; +} + +static unsigned int procmsg_ACCEPTEDFILE(unsigned char* buf, unsigned int nb, void* p) +{ +struct PICA_chaninfo *chan = (struct PICA_chaninfo *)p; + +if (chan->sendfilestate != PICA_CHANSENDFILESTATE_SENTREQ) + return 0; + +callbacks.accepted_file_cb(chan->peer_id); + +chan->sendfilestate = PICA_CHANSENDFILESTATE_SENDING; + +return 1; +} + +static unsigned int procmsg_DENIEDFILE(unsigned char* buf, unsigned int nb, void* p) +{ +struct PICA_chaninfo *chan = (struct PICA_chaninfo *)p; + +if (chan->sendfilestate != PICA_CHANSENDFILESTATE_SENTREQ) + return 0; + +callbacks.denied_file_cb(chan->peer_id); + +chan->sendfilestate = PICA_CHANSENDFILESTATE_IDLE; + +return 1; +} + +static unsigned int procmsg_FILEFRAGMENT(unsigned char* buf, unsigned int nb, void* p) +{ +struct PICA_chaninfo *chan = (struct PICA_chaninfo *)p; + + +if (chan->recvfilestate != PICA_CHANRECVFILESTATE_RECEIVING) + return 0; + +if (nb - 4 != *(uint16_t*)(buf + 2)) + return 0; + +chan->recvfile_pos += (nb - 4); + +if (chan->recvfile_pos == chan->recvfile_size) + chan->recvfilestate = PICA_CHANRECVFILESTATE_IDLE; + +if (chan->recvfile_pos > chan->recvfile_size) //received more than file_size + return 0; + +callbacks.file_fragment(chan->peer_id, buf + 4, nb - 4); + +return 1; +} + #ifdef PICA_MULTITHREADED #ifdef WIN32 @@ -1434,6 +1531,69 @@ else return PICA_OK; } +int PICA_send_file_request(struct PICA_chaninfo *chn, const char *filename, uint64_t file_size) +{ +struct PICA_proto_msg *mp; +size_t namelen; + +if (chn->sendfilestate != PICA_CHANSENDFILESTATE_IDLE) + return PICA_ERRFILETRANSFERINPROGRESS; + +if (filename == NULL) + return PICA_ERRINVFILENAME; + +namelen = strlen(filename); + +if (namelen == 0 || namelen > PICA_PROTO_C2CMSG_MAXFILENAMESIZE) + return PICA_ERRINVFILENAME; + +if ((mp = c2c_writebuf_push(chn, PICA_PROTO_SENDFILEREQUEST, namelen + 12))) + { + *((uint16_t*)mp->tail) = namelen + 8; + *((uint64_t*)(mp->tail + 2)) = file_size; + + memcpy(mp->tail + 10, filename, namelen); + } +else + return PICA_ERRNOMEM; + +chn->sendfilestate = PICA_CHANSENDFILESTATE_SENTREQ; +chn->sendfile_size = file_size; +chn->sendfile_pos = 0; + +return PICA_OK; +} + +int PICA_send_file_fragment(struct PICA_chaninfo *chn, const char *buf, size_t fragment_size) +{ +struct PICA_proto_msg *mp; + +if (buf == NULL || fragment_size > PICA_PROTO_C2CMSG_MAXDATASIZE) + return PICA_ERRINVARG; + +if (chn->sendfilestate != PICA_CHANSENDFILESTATE_SENDING) + return PICA_ERRFILETRANSFERNOTINPROGRESS; + +if ((mp = c2c_writebuf_push(chn, PICA_PROTO_FILEFRAGMENT, fragment_size + 4))) + { + *((uint16_t*)mp->tail) = fragment_size; + + memcpy(mp->tail + 2, buf, fragment_size); + } +else + return PICA_ERRNOMEM; + +chn->sendfile_pos += fragment_size; + +if (chn->sendfile_pos == chn->sendfile_size) + chn->sendfilestate = PICA_CHANSENDFILESTATE_IDLE; + +if (chn->sendfile_pos > chn->sendfile_size) + return PICA_ERRFILEFRAGMENTCROSSEDSIZE; + +return PICA_OK; +} + void PICA_close_channel(struct PICA_chaninfo *chn) { struct PICA_chaninfo *ipt; diff --git a/PICA_client.h b/PICA_client.h index fc12aa1..4f637a9 100755 --- a/PICA_client.h +++ b/PICA_client.h @@ -11,6 +11,7 @@ #include <windows.h> typedef unsigned __int16 uint16_t; +typedef unsigned __int64 uint64_t; #else @@ -20,6 +21,7 @@ typedef unsigned __int16 uint16_t; #include <arpa/inet.h> #include <netdb.h> #include <signal.h> +#include <stdint.h> #ifdef PICA_MULTITHREADED #include <pthread.h> @@ -71,6 +73,10 @@ typedef unsigned __int16 uint16_t; #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_CHNMSGBUFLEN 104 @@ -83,6 +89,13 @@ typedef unsigned __int16 uint16_t; #define PICA_CONNSTATE_CONNECTING 17 #define PICA_CONNSTATE_CONNECTED 19 +#define PICA_CHANSENDFILESTATE_IDLE 0 +#define PICA_CHANSENDFILESTATE_SENTREQ 20 +#define PICA_CHANSENDFILESTATE_SENDING 22 + +#define PICA_CHANRECVFILESTATE_IDLE 0 +#define PICA_CHANRECVFILESTATE_RECEIVING 23 + #define PICA_CHAN_ACTIVATE_TIMEOUT 30 @@ -137,12 +150,18 @@ struct PICA_chaninfo *next; struct PICA_chaninfo *prev; int state; time_t timestamp; +int sendfilestate; +uint64_t sendfile_size; +uint64_t sendfile_pos; +int recvfilestate; +uint64_t recvfile_size; +uint64_t recvfile_pos; }; struct PICA_client_callbacks { //получение сообщения. -void (*newmsg_cb)(const unsigned char *peer_id,char* msgbuf,unsigned int nb,int type); +void (*newmsg_cb)(const unsigned char *peer_id,const char* msgbuf,unsigned int nb,int type); //получение подтверждения о доставке сообщения void (*msgok_cb)(const unsigned char *peer_id); //создание канала с собеседником @@ -160,6 +179,14 @@ void (*channel_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); + +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_fragment)(const unsigned char *peer_id, const char* buf,unsigned int nb); }; @@ -193,6 +220,9 @@ int PICA_write(struct PICA_conninfo *ci); int PICA_send_msg(struct PICA_chaninfo *chn, char *buf,unsigned int len); int PICA_read_msg(struct PICA_chaninfo *chn,char *buf,unsigned int *n); +int PICA_send_file_request(struct PICA_chaninfo *chn, const char *filename, uint64_t file_size); +int PICA_send_file_fragment(struct PICA_chaninfo *chn, const char *buf, size_t fragment_size); + void PICA_close_channel(struct PICA_chaninfo *chn); void PICA_close_connection(struct PICA_conninfo *cid); diff --git a/PICA_proto.h b/PICA_proto.h index d6b26bf..cfa0c05 100755 --- a/PICA_proto.h +++ b/PICA_proto.h @@ -28,6 +28,10 @@ #define PICA_PROTO_MSGUTF8 0x30 #define PICA_PROTO_MSGOK 0x40 +#define PICA_PROTO_SENDFILEREQUEST 0x50 +#define PICA_PROTO_ACCEPTEDFILE 0x51 +#define PICA_PROTO_DENIEDFILE 0x52 +#define PICA_PROTO_FILEFRAGMENT 0x53 #define PICA_PROTO_PINGREQ 0x68 #define PICA_PROTO_PINGREP 0x69 @@ -67,6 +71,9 @@ #define PICA_PROTO_MSGOK_SIZE 4 +#define PICA_PROTO_ACCEPTEDFILE_SIZE 4 +#define PICA_PROTO_DENIEDFILE_SIZE 4 + #define PICA_PROTO_PINGREQ_SIZE 4 #define PICA_PROTO_PINGREP_SIZE 4 @@ -89,6 +96,7 @@ #define PICA_PROTO_N2NMSG_MAXDATASIZE 65476 #define PICA_PROTO_C2CMSG_MAXDATASIZE 65532 +#define PICA_PROTO_C2CMSG_MAXFILENAMESIZE 255 struct PICA_proto_msg diff --git a/doc/proto.txt b/doc/proto.txt index cc4fa71..a6b681b 100755 --- a/doc/proto.txt +++ b/doc/proto.txt @@ -69,6 +69,20 @@ UH - user hash - SHA224 хэш от сертификата пользоватеÐ +++[отчет о доставке предыдущего сообщения] 0x40 0x40 (2 случайных байта) ++++ [запрос на отправку файла] +0x50 0x50 (длина сообщения - 2 байта, 9..263) (размер файла - 8 байт) имя файла в UTF-8, 1 - 255 байт + ++++ [подтверждение принятия файла] +0x51 0x51 (2 случайных байта) + +после получения этого сообщения отправитель начинает отправку файла + ++++ [отказ от приёма файла] +0x52 0x52 (2 случайных байта) + ++++ [фрагмент файла] +0x53 0x53 (длина фрагмента - 2 байта, 0 - 65532) фрагмент файла + Пинг diff --git a/pica-client/skynet.cpp b/pica-client/skynet.cpp index 2d2336f..7770388 100644 --- a/pica-client/skynet.cpp +++ b/pica-client/skynet.cpp @@ -358,7 +358,7 @@ void SkyNet::emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, //all callbacks are executed in separate thread, created in Nodethread instance, REMEMBER THAT !!! // write_mutex is locked -void SkyNet::newmsg_cb(const unsigned char *peer_id, char *msgbuf, unsigned int nb, int type) +void SkyNet::newmsg_cb(const unsigned char *peer_id, const char *msgbuf, unsigned int nb, int type) { QString msg = QString::fromUtf8(msgbuf, nb); diff --git a/pica-client/skynet.h b/pica-client/skynet.h index b6cdfb8..6c43d6a 100644 --- a/pica-client/skynet.h +++ b/pica-client/skynet.h @@ -56,7 +56,7 @@ private: void emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, bool *verified); //получение сообщения. - static void newmsg_cb(const unsigned char *peer_id,char* msgbuf,unsigned int nb,int type); + static void newmsg_cb(const unsigned char *peer_id,const char* msgbuf,unsigned int nb,int type); //получение подтверждения о доставке сообщения static void msgok_cb(const unsigned char *peer_id); //создание канала с собеседником |
