$ git clone http://socialnetwork.ion.nu/socialnetwork.git
commit eaa288a5a66924c33dc3e9086b004a7fc8d1a1a0
Author: Alicia <...>
Date: Sun Jan 8 15:02:21 2017 +0100
Added connectivity error handling to the peer-to-peer layer.
diff --git a/peer.c b/peer.c
index 05ae33b..851cc57 100644
--- a/peer.c
+++ b/peer.c
@@ -189,8 +189,8 @@ static int checkcert(gnutls_session_t tls)
size_t size=20;
gnutls_x509_crt_get_key_id(cert, 0, peer->id, &size);
gnutls_x509_crt_deinit(cert);
-// TODO: Make sure the ID is unique? and not ours?
- return 0;
+ // Make sure we're not connecting to ourselves. TODO: Make sure we're not connecting to someone else we're already connected to as well? (different addresses, same ID) may cause issues with reconnects and/or multiple sessions
+ return !memcmp(peer->id, peer_id, 20);
}
static void generatecert(gnutls_certificate_credentials_t cred)
@@ -234,6 +234,7 @@ struct peer* peer_new(struct udpstream* stream, char server)
peer->datalength=-1;
peer->addrlen=sizeof(peer->addr);
udpstream_getaddr(stream, &peer->addr, &peer->addrlen);
+ memset(peer->id, 0, 20);
gnutls_init(&peer->tls, (server?GNUTLS_SERVER:GNUTLS_CLIENT)|GNUTLS_NONBLOCK);
// Priority
gnutls_priority_set_direct(peer->tls, "NORMAL", 0);
@@ -303,6 +304,7 @@ void peer_bootstrap(int sock, const char* peerlist)
}
}
+#define readordie(x,y,z) {ssize_t r=gnutls_record_recv(x->tls,y,z); if(z && r<1){peer_disconnect(x, 0); continue;}}
void peer_handlesocket(int sock) // Incoming data
{
udpstream_readsocket(sock); // If it locks up here we're probably missing a bootstrap node
@@ -312,7 +314,9 @@ void peer_handlesocket(int sock) // Incoming data
if(!peer->handshake)
{
// TODO: GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET seems to indicate we're connecting to ourselves
- peer->handshake=!gnutls_handshake(peer->tls);
+ int res=gnutls_handshake(peer->tls);
+ if(gnutls_error_is_fatal(res)){peer_disconnect(peer, 0); continue;}
+ peer->handshake=!res;
// TODO: handle gnutls_error_is_fatal(x)?
if(peer->handshake)
{
@@ -323,25 +327,25 @@ void peer_handlesocket(int sock) // Incoming data
// Get command name, data, and then call the callbacks registered for the command
if(!peer->cmdlength)
{
- gnutls_record_recv(peer->tls, &peer->cmdlength, sizeof(peer->cmdlength));
+ readordie(peer, &peer->cmdlength, sizeof(peer->cmdlength));
continue;
}
else if(!peer->cmdname)
{
peer->cmdname=malloc(peer->cmdlength+1);
- gnutls_record_recv(peer->tls, peer->cmdname, peer->cmdlength);
+ readordie(peer, peer->cmdname, peer->cmdlength);
peer->cmdname[peer->cmdlength]=0;
continue;
}
else if(peer->datalength<0)
{
- gnutls_record_recv(peer->tls, &peer->datalength, sizeof(peer->datalength));
+ readordie(peer, &peer->datalength, sizeof(peer->datalength));
if(peer->datalength){continue;} // If it's a 0-length command just keep going
}
printf("Received command '%s' from peer "PEERFMT"\n", peer->cmdname, PEERARG(peer->id));
// Call the relevant callback, if any
char data[peer->datalength+1]; // TODO: malloc instead? or somehow conditionally
- gnutls_record_recv(peer->tls, data, peer->datalength);
+ readordie(peer, data, peer->datalength);
data[peer->datalength]=0;
unsigned int i;
for(i=0; i<commandcount; ++i)
@@ -378,3 +382,21 @@ void peer_sendcmd(struct peer* peer, const char* cmd, void* data, uint32_t len)
gnutls_record_send(peer->tls, data, len);
gnutls_record_uncork(peer->tls, GNUTLS_RECORD_WAIT);
}
+
+void peer_disconnect(struct peer* peer, char cleanly)
+{
+ if(cleanly){gnutls_bye(peer->tls, GNUTLS_SHUT_WR);}
+ gnutls_deinit(peer->tls);
+ udpstream_close(peer->stream);
+ free(peer->cmdname);
+ free(peer);
+ unsigned int i;
+ for(i=0; i<peercount; ++i)
+ {
+ if(peers[i]==peer)
+ {
+ --peercount;
+ memmove(&peers[i], &peers[i+1], sizeof(void*)*(peercount-i));
+ }
+ }
+}
diff --git a/peer.h b/peer.h
index 7f1b6c6..b4f619c 100644
--- a/peer.h
+++ b/peer.h
@@ -44,3 +44,4 @@ extern struct peer* peer_new_unique(int sock, struct sockaddr* addr, socklen_t a
extern void peer_bootstrap(int sock, const char* peerlist);
extern void peer_handlesocket(int sock); // Incoming data
extern void peer_sendcmd(struct peer* peer, const char* cmd, void* data, uint32_t len);
+extern void peer_disconnect(struct peer* peer, char cleanly);