summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xPICA_client.c166
-rwxr-xr-xPICA_client.h32
-rwxr-xr-xPICA_proto.h8
-rwxr-xr-xdoc/proto.txt14
-rw-r--r--pica-client/skynet.cpp2
-rw-r--r--pica-client/skynet.h2
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);
//создание канала с собеседником