diff options
Diffstat (limited to 'pica-client/skynet.cpp')
| -rw-r--r-- | pica-client/skynet.cpp | 446 |
1 files changed, 321 insertions, 125 deletions
diff --git a/pica-client/skynet.cpp b/pica-client/skynet.cpp index 63da308..a016b48 100644 --- a/pica-client/skynet.cpp +++ b/pica-client/skynet.cpp @@ -8,21 +8,23 @@ //#include "dialogs/forgedcertdialog.h" #include <QDebug> #include "history.h" +#include "dhparam.h" +#include "askpassword.h" +#include "settings.h" SkyNet::SkyNet() : nodes(config_dbname), QObject(0) { self_aware = false; - reconnect_enabled = false; PICA_client_callbacks cbs = { newmsg_cb, msgok_cb, - channel_established_cb, - channel_failed, + c2c_established_cb, + c2c_failed, accept_cb, notfound_cb, - channel_closed_cb, + c2c_closed_cb, nodelist_cb, peer_cert_verify_cb, accept_file_cb, @@ -30,81 +32,144 @@ PICA_client_callbacks cbs = { denied_file_cb, file_progress, file_control, - file_finished + file_finished, + c2n_established_cb, + c2n_failed_cb, + c2n_closed_cb, + listener_error_cb }; PICA_client_init(&cbs); -nodelink = NULL; +this->active_nodelink = NULL; +this->acc = NULL; +this->listener = NULL; connect(this, SIGNAL(PeerCertificateReceived(QByteArray,QString,bool*)), this, SLOT(verify_peer_cert(QByteArray,QString,bool*)),Qt::DirectConnection); -timer_id = startTimer(10000); +event_loop_timer_id = startTimer(0); + } -void SkyNet::nodethread_finished() +void SkyNet::nodelink_activated(PICA_c2n *c2n) { -//удалить здесь завершившийся поток - for (int i=0;i<threads.count();i++) - { - if (threads[i]->isFinished()) - { - delete threads.takeAt(i); - break; - } - } + for (int i = 0; i < connecting_nodes.size(); i++) + { + if (connecting_nodes[i].first == c2n) + { + node_status_changed(connecting_nodes[i].second, true); + connecting_nodes.removeAt(i); + break; + } + } - if (threads.count() == 0) - { - self_aware = false; - emit LostSelfAwareness(); - } -} + if (self_aware) + { + PICA_close_c2n(c2n); + } + else + { + self_aware = true; + active_nodelink = c2n; -void SkyNet::nodethread_connected(QString addr, quint16 port, NodeThread *thread) -{ - if (self_aware) - { - emit BecameSelfAware(); + emit BecameSelfAware(); + // + //restore old peer connections, if any + QList<QByteArray> c2c_peer_ids; - //restore old peer connections, if any - QList<QByteArray> c2c_peer_ids; + //load undelivered messages from history + if (msgqueues.isEmpty()) + { + History h(config_dbname, Accounts::GetCurrentAccount().id); - //load undelivered messages from history - if (msgqueues.isEmpty()) - { - History h(config_dbname, Accounts::GetCurrentAccount().id); + msgqueues = h.GetUndeliveredMessages(); + } - msgqueues = h.GetUndeliveredMessages(); - } + //load file transfers to be completed + // sndfilequeues = ... - //load file transfers to be completed - // sndfilequeues = ... + QMap<QByteArray, QList<QString> > queues = msgqueues; - QMap<QByteArray, QList<QString> > queues = msgqueues; + queues.unite(sndfilequeues); - queues.unite(sndfilequeues); + c2c_peer_ids = queues.uniqueKeys(); - c2c_peer_ids = queues.uniqueKeys(); + for (int i = 0; i < c2c_peer_ids.size(); i++) + { + int ret; + struct PICA_c2c *chan = NULL; - for (int i = 0; i < c2c_peer_ids.size(); i++) - { - int ret; - write_mutex.lock(); - struct PICA_chaninfo *chan = NULL; + ret = PICA_new_c2c(active_nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), NULL, &chan); - ret = PICA_create_channel(nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), &chan); + qDebug()<<"restoring c2c to "<<c2c_peer_ids[i]<<" ret ="<<ret<<"\n"; + } - qDebug()<<"restoring channel to "<<c2c_peer_ids[i]<<" ret ="<<ret<<"\n"; - write_mutex.unlock(); - } + //start timer + retry_timer_id = startTimer(10000); + // + } - } + +} + +void SkyNet::nodelink_closed(PICA_c2n *c2n, int error) +{ + if (self_aware && c2n == active_nodelink) + { + active_nodelink = NULL; + emit LostSelfAwareness(); + } + else + { + for (int i = 0; i < connecting_nodes.size(); i++) + { + if (connecting_nodes[i].first == c2n) + { + connecting_nodes.removeAt(i); + break; + } + } + } +} + +void SkyNet::nodelink_failed(PICA_c2n *c2n, int error) +{ + for (int i = 0; i < connecting_nodes.size(); i++) + { + if (connecting_nodes[i].first == c2n) + { + switch(error) + { + case PICA_ERRPROTONEW: + + emit StatusMsg(QString("Node %1:%2 has newer protocol version. Please check if update for pica-client is available") + .arg(connecting_nodes[i].second.address) + .arg(connecting_nodes[i].second.port), + true); + break; + + case PICA_ERRPROTOOLD: + + emit StatusMsg(QString("Node %1:%2 has older protocol. Disconnected.") + .arg(connecting_nodes[i].second.address) + .arg(connecting_nodes[i].second.port), + false); + break; + } + + node_status_changed(connecting_nodes[i].second, false); + connecting_nodes.removeAt(i); + break; + } + } + if (connecting_nodes.empty()) + emit LostSelfAwareness(); } -void SkyNet::node_status_changed(QString addr, quint16 port, bool alive) + + +void SkyNet::node_status_changed(Nodes::NodeRecord nr, bool alive) { - Nodes::NodeRecord nr = {addr, port}; nodes.UpdateStatus(nr, alive); } @@ -166,70 +231,184 @@ void SkyNet::verify_peer_cert(QByteArray peer_id, QString cert_pem, bool *verifi void SkyNet::timerEvent(QTimerEvent *e) { + if (e->timerId() == event_loop_timer_id) + { + if (connecting_nodes.size() > 0 || self_aware) + { + int ret; + QVector<struct PICA_c2n *> nodelinks; + + nodelinks.reserve(connecting_nodes.size() + 1); + + for (int i = 0; i < connecting_nodes.size(); i++) + nodelinks.append(connecting_nodes[i].first); + + if (self_aware) + nodelinks.append(active_nodelink); + + nodelinks.append(NULL); + + ret = PICA_event_loop(nodelinks.data(), 1); + + if (ret != PICA_OK) + emit StatusMsg("event loop error!", true);//show some error message + } + + return; + } + + if (self_aware) { - if (write_mutex.tryLock(10)) - { - QMap<QByteArray, QList<QString> > queues = msgqueues; - queues.unite(sndfilequeues); + QMap<QByteArray, QList<QString> > queues = msgqueues; + queues.unite(sndfilequeues); - QList<QByteArray> c2c_peer_ids = queues.uniqueKeys(); + QList<QByteArray> c2c_peer_ids = queues.uniqueKeys(); - c2c_peer_ids = filter_existing_chans(c2c_peer_ids); + c2c_peer_ids = filter_existing_chans(c2c_peer_ids); - for (int i = 0; i < c2c_peer_ids.size(); i++) - { - int ret; + for (int i = 0; i < c2c_peer_ids.size(); i++) + { + int ret; - struct PICA_chaninfo *chan = NULL; + struct PICA_c2c *chan = NULL; - ret = PICA_create_channel(nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), &chan); + ret = PICA_new_c2c(active_nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), NULL, &chan); - qDebug()<<"restoring channel to "<<c2c_peer_ids[i]<<" ret ="<<ret<<" in timer event\n"; + qDebug()<<"restoring c2c to "<<c2c_peer_ids[i]<<" ret ="<<ret<<" in timer event\n"; + + } - } - write_mutex.unlock(); - } } -else if (threads.count() == 0 && reconnect_enabled) +else { + killTimer(e->timerId()); Accounts::AccountRecord acc = this->CurrentAccount(); Join(acc); } } +bool SkyNet::open_account() +{ + int ret; + + AskPassword::clear(); + do + { + ret = PICA_open_acc(skynet_account.cert_file.toUtf8().constData(), + skynet_account.pkey_file.toUtf8().constData(), + DHParam::GetDHParamFilename().toUtf8().constData(), + AskPassword::ask_password_cb, + &acc); + + if (ret == PICA_ERRINVPKEYPASSPHRASE) + AskPassword::setInvalidPassword(); + } while (ret == PICA_ERRINVPKEYPASSPHRASE); + + qDebug() << "PICA_open_acc() returned " << ret; + + if (ret != PICA_OK) + return false; + + return true; +} + void SkyNet::Join(Accounts::AccountRecord &accrec) { - QList<Nodes::NodeRecord> nodelist; + PICA_directc2c_config directc2c_cfg = PICA_DIRECTC2C_CFG_DISABLED; + Settings st(config_dbname); + skynet_account = accrec; - nodelist = nodes.GetNodes(); - reconnect_enabled = true; - if (nodelist.count()==0) + QList<Nodes::NodeRecord> noderecords = nodes.GetNodes(); + + if (!acc) + { + if (!open_account()) + return; + } + + if (noderecords.count()==0) { - status = QObject::tr("No known Pica Pica nodes"); + emit StatusMsg(QString(tr("No known Pica Pica nodes")), true); return; } + directc2c_cfg = (PICA_directc2c_config)st.loadValue("direct_c2c.state", 1).toInt(); + + if (!listener && directc2c_cfg == PICA_DIRECTC2C_CFG_ALLOWINCOMING) + { + int pub_port = st.loadValue("direct_c2c.public_port", 2298).toInt(); + int loc_port = st.loadValue("direct_c2c.local_port", 2298).toInt(); + + int ret = PICA_new_listener(acc, + st.loadValue("direct_c2c.public_addr", "0.0.0.0").toString().toAscii().constData(), + pub_port, + loc_port, &listener); + if (ret != PICA_OK) + { + emit StatusMsg(QString(tr("Failed to open port %1 for incoming direct connections")).arg(loc_port), true); + directc2c_cfg = PICA_DIRECTC2C_CFG_CONNECTONLY; + } + } + + if (!connecting_nodes.empty()) + { + for (int i = 0; i < connecting_nodes.size(); i++) + PICA_close_c2n(connecting_nodes[i].first); + + connecting_nodes.clear(); + } + + for (int i = 0; i < noderecords.size();i++) + { + int ret; + struct PICA_c2n *c2n = NULL; + + ret = PICA_new_c2n(acc, noderecords[i].address.toUtf8().constData(), noderecords[i].port, + directc2c_cfg, listener, &c2n); + + if (ret == PICA_OK) + { + connecting_nodes.append(QPair<struct PICA_c2n *, Nodes::NodeRecord>(c2n, noderecords[i])); + } + else + { + node_status_changed(noderecords[i], false); + } + } +/* for (int i=0;i<nodelist.count() && !self_aware;i++) {//TODO FIXME сделать запуск потоков порциями, а не все сразу - threads.append(new NodeThread(nodelist[i],&self_aware,skynet_account,&nodelink, &write_mutex)); + threads.append(new NodeThread(nodelist[i],&self_aware, acc,&nodelink, &write_mutex)); connect(threads.last(), SIGNAL(finished()),this,SLOT(nodethread_finished())); connect(threads.last(), SIGNAL(NodeStatusChanged(QString,quint16,bool)), this, SLOT(node_status_changed(QString,quint16,bool))); connect(threads.last(), SIGNAL(ConnectedToNode(QString,quint16,NodeThread*)), this, SLOT(nodethread_connected(QString,quint16,NodeThread*))); connect(threads.last(), SIGNAL(ErrorMsg(QString)), this, SIGNAL(ErrMsgFromNode(QString))); - } + }*/ } void SkyNet::Exit() { - for (int i = 0; i< threads.count(); i++) - threads[i]->CloseThread(); + if (self_aware && active_nodelink) + { + PICA_close_c2n(active_nodelink); + active_nodelink = NULL; + } self_aware = false; - reconnect_enabled = false; - emit LostSelfAwareness(); + + killTimer(retry_timer_id); + + msgqueues.clear(); + + for (int i = 0; i < connecting_nodes.size(); i++) + PICA_close_c2n(connecting_nodes[i].first); + + connecting_nodes.clear(); + + emit LostSelfAwareness(); } bool SkyNet::isSelfAware() @@ -240,9 +419,9 @@ bool SkyNet::isSelfAware() void SkyNet::SendFile(QByteArray to, QString filepath) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(to)) ) { @@ -253,7 +432,7 @@ if ( (iptr = find_active_chan(to)) ) //show error somewhere somehow } - write_mutex.unlock();//>> + return; } @@ -263,16 +442,16 @@ if ( (iptr = find_active_chan(to)) ) } else { - struct PICA_chaninfo *chan = NULL; + struct PICA_c2c *chan = NULL; - ret = PICA_create_channel(nodelink, (const unsigned char*)to.constData(), &chan); + ret = PICA_new_c2c(active_nodelink, (const unsigned char*)to.constData(), NULL, &chan); QList<QString> l; l.append(filepath); sndfilequeues[to] = l; } -write_mutex.unlock();//>> + if (ret!= PICA_OK) { @@ -283,9 +462,9 @@ write_mutex.unlock();//>> void SkyNet::AcceptFile(QByteArray from, QString filepath) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(from)) ) { ret = PICA_accept_file(iptr, filepath.toUtf8().data(), filepath.toUtf8().size()); @@ -296,15 +475,15 @@ if ( (iptr = find_active_chan(from)) ) //show error somewhere somehow } } -write_mutex.unlock();//>> + } void SkyNet::DenyFile(QByteArray from) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(from)) ) { ret = PICA_deny_file(iptr); @@ -315,15 +494,15 @@ if ( (iptr = find_active_chan(from)) ) //show error somewhere somehow } } -write_mutex.unlock();//>> + } void SkyNet::PauseFile(QByteArray peer_id, bool pause_sending) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(peer_id)) ) { qDebug() << "calling PICA_pause_file(" << iptr << "," << pause_sending << ")\n"; @@ -334,15 +513,15 @@ if ( (iptr = find_active_chan(peer_id)) ) qDebug() << "PICA_pause_file() returned " << ret << "\n"; } } -write_mutex.unlock();//>> + } void SkyNet::ResumeFile(QByteArray peer_id, bool resume_sending) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(peer_id)) ) { ret = PICA_resume_file(iptr, (int)resume_sending ); @@ -352,15 +531,15 @@ if ( (iptr = find_active_chan(peer_id)) ) //show error somewhere somehow } } -write_mutex.unlock();//>> + } void SkyNet::CancelFile(QByteArray peer_id, bool cancel_sending) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(peer_id)) ) { ret = PICA_cancel_file(iptr, (int)cancel_sending ); @@ -370,15 +549,15 @@ if ( (iptr = find_active_chan(peer_id)) ) //show error somewhere somehow } } -write_mutex.unlock();//>> + } void SkyNet::SendMessage(QByteArray to, QString msg) { int ret = PICA_OK; -struct PICA_chaninfo *iptr; +struct PICA_c2c *iptr; + -write_mutex.lock();//<< if ( (iptr = find_active_chan(to)) ) { @@ -389,7 +568,7 @@ if ( (iptr = find_active_chan(to)) ) if (ret != PICA_OK) emit UnableToDeliver(to, msg); - write_mutex.unlock();//>> + return; } @@ -399,9 +578,9 @@ if ( (iptr = find_active_chan(to)) ) } else { - struct PICA_chaninfo *chan = NULL; + struct PICA_c2c *chan = NULL; - ret = PICA_create_channel(nodelink, (const unsigned char*)to.constData(), &chan); + ret = PICA_new_c2c(active_nodelink, (const unsigned char*)to.constData(), NULL, &chan); QList<QString> l; l.append(msg); @@ -409,7 +588,7 @@ if ( (iptr = find_active_chan(to)) ) } -write_mutex.unlock();//>> + if (ret != PICA_OK) emit UnableToDeliver(to, msg); @@ -418,7 +597,7 @@ write_mutex.unlock();//>> void SkyNet::flush_queues(QByteArray to) { - struct PICA_chaninfo *chan; + struct PICA_c2c *chan; int ret; if (self_aware && (msgqueues.contains(to) || sndfilequeues.contains(to))) @@ -466,16 +645,16 @@ void SkyNet::flush_queues(QByteArray to) } } -struct PICA_chaninfo * SkyNet::find_active_chan(QByteArray peer_id) +struct PICA_c2c * SkyNet::find_active_chan(QByteArray peer_id) { -if (!nodelink) +if (!active_nodelink) return NULL; -struct PICA_chaninfo *iptr = nodelink->chan_list_head; +struct PICA_c2c *iptr = active_nodelink->chan_list_head; while(iptr) { - if (iptr->state == PICA_CHANSTATE_ACTIVE && QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE) == peer_id) + if (iptr->state == PICA_C2C_STATE_ACTIVE && QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE) == peer_id) break; iptr = iptr->next; @@ -488,10 +667,10 @@ QList<QByteArray> SkyNet::filter_existing_chans(QList<QByteArray> peer_ids) { QList<QByteArray> ret = peer_ids; - if (!nodelink) + if (!active_nodelink) return ret; - struct PICA_chaninfo *iptr = nodelink->chan_list_head; + struct PICA_c2c *iptr = active_nodelink->chan_list_head; while(iptr) { @@ -594,17 +773,14 @@ void SkyNet::emit_IncomingFileFinished(QByteArray peer_id) emit IncomingFileFinished(peer_id); } -void SkyNet::emit_ChannelClosed(QByteArray peer_id) +void SkyNet::emit_c2cClosed(QByteArray peer_id) { - emit ChannelClosed(peer_id); + emit c2cClosed(peer_id); } //callbacks -//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, const char *msgbuf, unsigned int nb, int type) { QString msg = QString::fromUtf8(msgbuf, nb); @@ -617,14 +793,14 @@ void SkyNet::msgok_cb(const unsigned char *peer_id) skynet->emit_Delivered(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } -void SkyNet::channel_established_cb(const unsigned char *peer_id) +void SkyNet::c2c_established_cb(const unsigned char *peer_id) { skynet->flush_queues(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } -void SkyNet::channel_failed(const unsigned char *peer_id) +void SkyNet::c2c_failed(const unsigned char *peer_id) { - qDebug()<<"channel failed ("<<QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64()<<")\n"; + qDebug()<<"c2c failed ("<<QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64()<<")\n"; } int SkyNet::accept_cb(const unsigned char *caller_id) @@ -649,12 +825,12 @@ void SkyNet::notfound_cb(const unsigned char *callee_id) */ } -void SkyNet::channel_closed_cb(const unsigned char *peer_id, int reason) +void SkyNet::c2c_closed_cb(const unsigned char *peer_id, int reason) { - qDebug()<<"channel closed ("<<QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64() + qDebug()<<"c2c closed ("<<QByteArray((const char*)peer_id, PICA_ID_SIZE).toBase64() <<", error_code =" << reason << ")\n"; - skynet->emit_ChannelClosed(QByteArray((const char*)peer_id, PICA_ID_SIZE)); + skynet->emit_c2cClosed(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } void SkyNet::nodelist_cb(int type, void *addr_bin, const char *addr_str, unsigned int port) @@ -759,3 +935,23 @@ void SkyNet::file_finished(const unsigned char *peer_id, int sending) else skynet->emit_IncomingFileFinished(QByteArray((const char *)peer_id, PICA_ID_SIZE)); } + +void SkyNet::c2n_established_cb(struct PICA_c2n *c2n) +{ + skynet->nodelink_activated(c2n); +} + +void SkyNet::c2n_failed_cb(struct PICA_c2n *c2n, int error) +{ + skynet->nodelink_failed(c2n, error); +} + +void SkyNet::c2n_closed_cb(struct PICA_c2n *c2n, int error) +{ + skynet->nodelink_closed(c2n, error); +} + +void SkyNet::listener_error_cb(struct PICA_listener *lst, int errorcode) +{ + +} |
