#include "skynet.h" #include "globals.h" #include //#include "dialogs/viewcertdialog.h" #include "contacts.h" #include "openssltool.h" //#include //debug //#include "dialogs/forgedcertdialog.h" #include #include "history.h" #include "dhparam.h" #include "askpassword.h" #include "settings.h" SkyNet::SkyNet() : nodes(config_dbname), QObject(0) { self_aware = false; PICA_client_callbacks cbs = { newmsg_cb, msgok_cb, c2c_established_cb, c2c_failed, accept_cb, notfound_cb, c2c_closed_cb, nodelist_cb, peer_cert_verify_cb, accept_file_cb, accepted_file_cb, denied_file_cb, file_progress, file_control, file_finished, c2n_established_cb, c2n_failed_cb, c2n_closed_cb, listener_error_cb }; PICA_client_init(&cbs); 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); event_loop_timer_id = startTimer(0); } void SkyNet::nodelink_activated(PICA_c2n *c2n) { 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 (self_aware) { PICA_close_c2n(c2n); } else { self_aware = true; active_nodelink = c2n; emit BecameSelfAware(); // //restore old peer connections, if any QList c2c_peer_ids; //load undelivered messages from history if (msgqueues.isEmpty()) { History h(config_dbname, Accounts::GetCurrentAccount().id); msgqueues = h.GetUndeliveredMessages(); } //load file transfers to be completed // sndfilequeues = ... QMap > queues = msgqueues; queues.unite(sndfilequeues); c2c_peer_ids = queues.uniqueKeys(); for (int i = 0; i < c2c_peer_ids.size(); i++) { int ret; struct PICA_c2c *chan = NULL; ret = PICA_new_c2c(active_nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), NULL, &chan); qDebug()<<"restoring c2c to "<timerId() == event_loop_timer_id) { if (connecting_nodes.size() > 0 || self_aware) { int ret; QVector 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) { QMap > queues = msgqueues; queues.unite(sndfilequeues); QList c2c_peer_ids = queues.uniqueKeys(); c2c_peer_ids = filter_existing_chans(c2c_peer_ids); for (int i = 0; i < c2c_peer_ids.size(); i++) { int ret; struct PICA_c2c *chan = NULL; ret = PICA_new_c2c(active_nodelink, (const unsigned char*)c2c_peer_ids[i].constData(), NULL, &chan); qDebug()<<"restoring c2c to "<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) { PICA_directc2c_config directc2c_cfg = PICA_DIRECTC2C_CFG_DISABLED; Settings st(config_dbname); skynet_account = accrec; QList noderecords = nodes.GetNodes(); if (!acc) { if (!open_account()) return; } if (noderecords.count()==0) { 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(c2n, noderecords[i])); } else { node_status_changed(noderecords[i], false); } } /* for (int i=0;i l; l.append(filepath); sndfilequeues[to] = l; } if (ret!= PICA_OK) { //report error } } void SkyNet::AcceptFile(QByteArray from, QString filepath) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(from)) ) { ret = PICA_accept_file(iptr, filepath.toUtf8().data(), filepath.toUtf8().size()); qDebug() << "PICA_accept_file(" << filepath.toUtf8().data() << ", " << filepath.toUtf8().size() << ") returned " << ret << "\n"; if (ret != PICA_OK) { //show error somewhere somehow } } } void SkyNet::DenyFile(QByteArray from) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(from)) ) { ret = PICA_deny_file(iptr); qDebug() << "PICA_deny_file() returned " << ret << "\n"; if (ret != PICA_OK) { //show error somewhere somehow } } } void SkyNet::PauseFile(QByteArray peer_id, bool pause_sending) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(peer_id)) ) { qDebug() << "calling PICA_pause_file(" << iptr << "," << pause_sending << ")\n"; ret = PICA_pause_file(iptr, (int)pause_sending ); if (ret != PICA_OK) { qDebug() << "PICA_pause_file() returned " << ret << "\n"; } } } void SkyNet::ResumeFile(QByteArray peer_id, bool resume_sending) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(peer_id)) ) { ret = PICA_resume_file(iptr, (int)resume_sending ); if (ret != PICA_OK) { //show error somewhere somehow } } } void SkyNet::CancelFile(QByteArray peer_id, bool cancel_sending) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(peer_id)) ) { ret = PICA_cancel_file(iptr, (int)cancel_sending ); if (ret != PICA_OK) { //show error somewhere somehow } } } void SkyNet::SendMessage(QByteArray to, QString msg) { int ret = PICA_OK; struct PICA_c2c *iptr; if ( (iptr = find_active_chan(to)) ) { //write_mutex.lock();//<< ret = PICA_send_msg(iptr, msg.toUtf8().data(), msg.toUtf8().size()); //write_mutex.unlock();//>> if (ret != PICA_OK) emit UnableToDeliver(to, msg); return; } if (msgqueues.contains(to)) { msgqueues[to].append(msg); } else { struct PICA_c2c *chan = NULL; ret = PICA_new_c2c(active_nodelink, (const unsigned char*)to.constData(), NULL, &chan); QList l; l.append(msg); msgqueues[to] = l; } if (ret != PICA_OK) emit UnableToDeliver(to, msg); } void SkyNet::flush_queues(QByteArray to) { struct PICA_c2c *chan; int ret; if (self_aware && (msgqueues.contains(to) || sndfilequeues.contains(to))) { qDebug()<<"flushing "<chan_list_head; while(iptr) { if (iptr->state == PICA_C2C_STATE_ACTIVE && QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE) == peer_id) break; iptr = iptr->next; } return iptr; } QList SkyNet::filter_existing_chans(QList peer_ids) { QList ret = peer_ids; if (!active_nodelink) return ret; struct PICA_c2c *iptr = active_nodelink->chan_list_head; while(iptr) { if (peer_ids.contains(QByteArray((const char*)iptr->peer_id, PICA_ID_SIZE))) ret.removeOne((const char*)iptr->peer_id); iptr = iptr->next; } return ret; } void SkyNet::emit_Delivered(QByteArray to) { emit Delivered(to); } void SkyNet::emit_MessageReceived(QByteArray from, QString msg) { emit MessageReceived(from, msg); } void SkyNet::emit_UnableToDeliver(QByteArray to, QString msg) { emit UnableToDeliver(to, msg); } void SkyNet::emit_PeerCertificateReceived(QByteArray peer_id, QString cert_pem, bool *verified) { emit PeerCertificateReceived(peer_id, cert_pem, verified); } void SkyNet::emit_IncomingFileRequestReceived(QByteArray peer_id, quint64 file_size, QString filename) { emit IncomingFileRequestReceived(peer_id, file_size, filename); } void SkyNet::emit_OutgoingFileRequestAccepted(QByteArray peer_id) { emit OutgoingFileRequestAccepted(peer_id); } void SkyNet::emit_OutgoingFileRequestDenied(QByteArray peer_id) { emit OutgoingFileRequestDenied(peer_id); } void SkyNet::emit_FileProgress(QByteArray peer_id, quint64 bytes_sent, quint64 bytes_received) { emit FileProgress(peer_id, bytes_sent, bytes_received); } void SkyNet::emit_IncomingFilePaused(QByteArray peer_id) { emit IncomingFilePaused(peer_id); } void SkyNet::emit_IncomingFileCancelled(QByteArray peer_id) { emit IncomingFileCancelled(peer_id); } void SkyNet::emit_IncomingFileIoError(QByteArray peer_id) { emit IncomingFileIoError(peer_id); } void SkyNet::emit_IncomingFileResumed(QByteArray peer_id) { emit IncomingFileResumed(peer_id); } void SkyNet::emit_OutgoingFilePaused(QByteArray peer_id) { emit OutgoingFilePaused(peer_id); } void SkyNet::emit_OutgoingFileCancelled(QByteArray peer_id) { emit OutgoingFileCancelled(peer_id); } void SkyNet::emit_OutgoingFileIoError(QByteArray peer_id) { emit OutgoingFileIoError(peer_id); } void SkyNet::emit_OutgoingFileResumed(QByteArray peer_id) { emit OutgoingFileResumed(peer_id); } void SkyNet::emit_OutgoingFileFinished(QByteArray peer_id) { emit OutgoingFileFinished(peer_id); } void SkyNet::emit_IncomingFileFinished(QByteArray peer_id) { emit IncomingFileFinished(peer_id); } void SkyNet::emit_c2cClosed(QByteArray peer_id) { emit c2cClosed(peer_id); } //callbacks void SkyNet::newmsg_cb(const unsigned char *peer_id, const char *msgbuf, unsigned int nb, int type) { QString msg = QString::fromUtf8(msgbuf, nb); skynet->emit_MessageReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE), msg); } void SkyNet::msgok_cb(const unsigned char *peer_id) { skynet->emit_Delivered(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } void SkyNet::c2c_established_cb(const unsigned char *peer_id) { skynet->flush_queues(QByteArray((const char*)peer_id, PICA_ID_SIZE)); } void SkyNet::c2c_failed(const unsigned char *peer_id) { qDebug()<<"c2c failed ("<msgqueues.contains(callee_id)) { while ( ! skynet->msgqueues[callee_id].empty()) { skynet->emit_UnableToDeliver(callee_id, skynet->msgqueues[callee_id].last()); skynet->msgqueues[callee_id].removeLast(); } // msgqueues.remove(callee_id) was forgotten } */ } void SkyNet::c2c_closed_cb(const unsigned char *peer_id, int reason) { qDebug()<<"c2c closed ("<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) { Nodes::NodeRecord nr = {addr_str, port}; skynet->nodes.Add(nr); } int SkyNet::peer_cert_verify_cb(const unsigned char *peer_id, const char *cert_pem, unsigned int nb) { bool verified = true; skynet->emit_PeerCertificateReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE), QString::fromAscii(cert_pem, nb), &verified); if (!verified) return 0; return 1; } int SkyNet::accept_file_cb(const unsigned char *peer_id, uint64_t file_size, const char *filename, unsigned int filename_size) { skynet->emit_IncomingFileRequestReceived(QByteArray((const char*)peer_id, PICA_ID_SIZE), file_size, QString::fromUtf8(filename, filename_size)); return 2;//??? accept later code } void SkyNet::accepted_file_cb(const unsigned char *peer_id) { qDebug()<<"FILE: file was accepted by remote side\n"; skynet->emit_OutgoingFileRequestAccepted(QByteArray((const char *)peer_id, PICA_ID_SIZE)); } void SkyNet::denied_file_cb(const unsigned char *peer_id) { skynet->emit_OutgoingFileRequestDenied(QByteArray((const char *)peer_id, PICA_ID_SIZE)); } void SkyNet::file_progress(const unsigned char *peer_id, uint64_t sent, uint64_t received) { qDebug()<<"FILE: file progress" << sent << " sent " << received << "received\n"; skynet->emit_FileProgress(QByteArray((const char *)peer_id, PICA_ID_SIZE), sent, received); } void SkyNet::file_control(const unsigned char *peer_id, unsigned int sender_cmd, unsigned int receiver_cmd) { qDebug() << "file_control callback: sender_cmd=" << sender_cmd << ", receiver_cmd=" << receiver_cmd << "\n"; if (sender_cmd != PICA_PROTO_FILECONTROL_VOID && receiver_cmd == PICA_PROTO_FILECONTROL_VOID) { switch(sender_cmd) { case PICA_PROTO_FILECONTROL_PAUSE: skynet->emit_IncomingFilePaused(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_RESUME: skynet->emit_IncomingFileResumed(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_CANCEL: skynet->emit_IncomingFileCancelled(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_IOERROR: skynet->emit_IncomingFileIoError(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; } } else if (sender_cmd == PICA_PROTO_FILECONTROL_VOID && receiver_cmd != PICA_PROTO_FILECONTROL_VOID) { switch(receiver_cmd) { case PICA_PROTO_FILECONTROL_PAUSE: skynet->emit_OutgoingFilePaused(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_RESUME: skynet->emit_OutgoingFileResumed(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_CANCEL: skynet->emit_OutgoingFileCancelled(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; case PICA_PROTO_FILECONTROL_IOERROR: skynet->emit_OutgoingFileIoError(QByteArray((const char *)peer_id, PICA_ID_SIZE)); break; } } } void SkyNet::file_finished(const unsigned char *peer_id, int sending) { qDebug()<< "file_finished callback\n"; if (sending) skynet->emit_OutgoingFileFinished(QByteArray((const char *)peer_id, PICA_ID_SIZE)); 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) { }