summaryrefslogtreecommitdiffstats
path: root/pica-client/skynet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pica-client/skynet.cpp')
-rw-r--r--pica-client/skynet.cpp446
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)
+{
+
+}