Advanced networking code. Attempted (not working) implementation of sockets with...
authorMatthew Mitchell <matthewmitchell@godofgod.co.uk>
Tue, 21 Aug 2012 17:21:02 +0000 (18:21 +0100)
committerMatthew Mitchell <matthewmitchell@godofgod.co.uk>
Tue, 21 Aug 2012 17:21:02 +0000 (18:21 +0100)
14 files changed:
dependencies/sockets/CBLibEventSockets.c
dependencies/sockets/CBLibEventSockets.h
dependencies/sockets/CBLibevSockets.c [new file with mode: 0644]
dependencies/sockets/CBLibevSockets.h [new file with mode: 0644]
src/CBDependencies.h
src/structures/CBObject/CBMessage/CBAddressManager/CBAddressManager.c
src/structures/CBObject/CBMessage/CBAddressManager/CBAddressManager.h
src/structures/CBObject/CBMessage/CBNetworkAddress/CBNetworkAddress.c
src/structures/CBObject/CBMessage/CBNetworkAddress/CBNode/CBNode.c
src/structures/CBObject/CBMessage/CBNetworkAddress/CBNode/CBNode.h
src/structures/CBObject/CBMessage/CBVersion/CBVersion.c
src/structures/CBObject/CBNetworkCommunicator/CBNetworkCommunicator.c
src/structures/CBObject/CBNetworkCommunicator/CBNetworkCommunicator.h
test/testCBNetworkCommunicator.c

index 29f35cb..7d6bc72 100644 (file)
@@ -35,7 +35,7 @@ CBSocketReturn CBNewSocket(uint64_t * socketID,bool IPv6){
        // Stop SIGPIPE annoying us.
        if (CB_NOSIGPIPE) {
                int i = 1;
-               setsockopt(*socketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
+               setsockopt((evutil_socket_t)*socketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
        }
        // Make socket non-blocking
        evutil_make_socket_nonblocking((evutil_socket_t)*socketID);
@@ -103,34 +103,18 @@ bool CBSocketListen(uint64_t socketID,uint16_t maxConnections){
        }
        return true;
 }
-bool CBSocketAcceptIPv4(uint64_t socketID,uint64_t * connectionSocketID,uint8_t * IP,uint16_t * port){
-       struct sockaddr_in address;
-       socklen_t size = sizeof(address);
-       *connectionSocketID = accept((evutil_socket_t)socketID, (struct sockaddr *)&address, &size);
+bool CBSocketAccept(uint64_t socketID,uint64_t * connectionSocketID){
+       *connectionSocketID = accept((evutil_socket_t)socketID, NULL, NULL);
        if (*connectionSocketID == -1) {
                return false;
        }
-       // Fill out IPv4 address
-       memcpy(IP, &address.sin_addr, 4);
-       // Set port which will be some random connection port.
-       *port = address.sin_port;
        // Make socket non-blocking
        evutil_make_socket_nonblocking((evutil_socket_t)*connectionSocketID);
-       return true;
-}
-bool CBSocketAcceptIPv6(uint64_t socketID,uint64_t * connectionSocketID,uint8_t * IP,uint16_t * port){
-       struct sockaddr_in6 address;
-       socklen_t size = sizeof(address);
-       *connectionSocketID = accept((evutil_socket_t)socketID, (struct sockaddr *)&address, &size);
-       if (*connectionSocketID == -1) {
-               return false;
+       // Stop SIGPIPE
+       if (CB_NOSIGPIPE) {
+               int i = 1;
+               setsockopt((evutil_socket_t)*connectionSocketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
        }
-       // Fill out IPv6 address
-       memcpy(IP, &address.sin6_addr, 16);
-       // Set port
-       *port = address.sin6_port;
-       // Make socket non-blocking
-       evutil_make_socket_nonblocking((evutil_socket_t)*connectionSocketID);
        return true;
 }
 bool CBNewEventLoop(uint64_t * loopID,void (*onError)(void *),void (*onDidTimeout)(void *,void *,CBTimeOutType),void * communicator){
@@ -280,11 +264,6 @@ void CBSocketFreeEvent(uint64_t eventID){
 }
 int32_t CBSocketSend(uint64_t socketID,uint8_t * data,uint32_t len){
        ssize_t res = send((evutil_socket_t)socketID, data, len, CB_SEND_FLAGS);
-       printf("SENT (%li): ",res);
-       for (uint32_t x = 0; x < res; x++) {
-               printf("%c",data[x]);
-       }
-       printf("\n");
        if (res >= 0)
                return (int32_t)res;
        if (errno == EAGAIN)
@@ -293,11 +272,6 @@ int32_t CBSocketSend(uint64_t socketID,uint8_t * data,uint32_t len){
 }
 int32_t CBSocketReceive(uint64_t socketID,uint8_t * data,uint32_t len){
        ssize_t res = read((evutil_socket_t)socketID, data, len);
-       printf("RECEIVED: ");
-       for (uint32_t x = 0; x < res; x++) {
-               printf("%c",data[x]);
-       }
-       printf("\n");
        if (res > 0)
                return (int32_t)res; // OK, read data.
        if (NOT res)
index 4ea594d..01d3dd0 100644 (file)
  @brief This is an implementation of the networking dependencies for cbitcoin. It can be included as as a source file in any projects using cbitcoin which require networking capabilities. This file uses libevent for effecient event-based sockets and POSIX threads. The sockets are POSIX sockets with compatibility functions taken from libevent to try and be compatible with windows.
  */
 
+#include "CBDependencies.h" // cbitcoin dependencies to implement
+#include <pthread.h> // POSIX threads
+#include <event2/event.h> // libevent events
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
 #ifndef CBLIBEVENTSOCKETSH
 #define CBLIBEVENTSOCKETSH
 
 // Define if we have SO_NOSIGPIPE
 
 #ifdef SO_NOSIGPIPE
-       #define CB_NOSIGPIPE true
+#define CB_NOSIGPIPE true
 #else
-       #define CB_NOSIGPIPE false
+#define CB_NOSIGPIPE false
+#define SO_NOSIGPIPE 0
 #endif
 
 // Define send flags
 
 #ifdef MSG_NOSIGNAL
-       #define CB_SEND_FLAGS MSG_NOSIGNAL
+#define CB_SEND_FLAGS MSG_NOSIGNAL
 #else
-       #define CB_SEND_FLAGS 0
+#define CB_SEND_FLAGS 0
 #endif
 
-#include "CBDependencies.h" // cbitcoin dependencies to implement
-#include <pthread.h> // POSIX threads
-#include <event2/event.h> // libevent events
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdlib.h>
-
 void event_base_add_virtual(struct event_base *); // Add virtual event.
 void * CBStartEventLoop(void *);
 void CBCanAccept(evutil_socket_t socketID,short eventNum,void * arg);
diff --git a/dependencies/sockets/CBLibevSockets.c b/dependencies/sockets/CBLibevSockets.c
new file mode 100644 (file)
index 0000000..b37d926
--- /dev/null
@@ -0,0 +1,320 @@
+//
+//  CBLibEventSockets.c
+//  cbitcoin
+//
+//  Created by Matthew Mitchell on 30/05/2012.
+//  Copyright (c) 2012 Matthew Mitchell
+//  
+//  This file is part of cbitcoin.
+//
+//  cbitcoin is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//  
+//  cbitcoin is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with cbitcoin.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "CBLibevSockets.h"
+
+// Implementation
+
+CBSocketReturn CBNewSocket(uint64_t * socketID,bool IPv6){
+       *socketID = socket(IPv6 ? PF_INET6 : PF_INET, SOCK_STREAM, 0);
+       if (*socketID == -1) {
+               if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
+                       return CB_SOCKET_NO_SUPPORT;
+               }
+               return CB_SOCKET_BAD;
+       }
+       // Stop SIGPIPE annoying us.
+       if (CB_NOSIGPIPE) {
+               int i = 1;
+               setsockopt((int)*socketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
+       }
+       // Make socket non-blocking
+       fcntl((int)*socketID, F_SETFL, fcntl((int)*socketID, F_GETFL, 0) | O_NONBLOCK);
+       return CB_SOCKET_OK;
+}
+bool CBSocketBind(uint64_t * socketID,bool IPv6,uint16_t port){
+       struct addrinfo hints,*res,*ptr;
+       // Set hints for the computer's addresses.
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_flags = AI_PASSIVE;
+       hints.ai_family = IPv6 ? AF_INET6 : AF_INET;
+       hints.ai_socktype = SOCK_STREAM;
+       // Get host for listening
+       char portStr[6];
+       sprintf(portStr, "%u",port);
+       if (getaddrinfo(NULL, portStr, &hints, &res))
+               return false;
+       // Attempt to bind to one of the addresses.
+       for(ptr = res; ptr != NULL; ptr = ptr->ai_next) {
+               if ((*socketID = socket(ptr->ai_family, ptr->ai_socktype,ptr->ai_protocol)) == -1)
+                       continue;
+               if (bind((int)*socketID, ptr->ai_addr, ptr->ai_addrlen) == -1) {
+                       close((int)*socketID);
+                       continue;
+               }
+               break; // Success.
+       }
+       freeaddrinfo(res);
+       if (ptr == NULL) // Failure
+               return false;
+       // Prevent SIGPIPE
+       if (CB_NOSIGPIPE) {
+               int i = 1;
+               setsockopt((int)*socketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
+       }
+       // Make socket non-blocking
+       fcntl((int)*socketID, F_SETFL, fcntl((int)*socketID, F_GETFL, 0) | O_NONBLOCK);
+       return true;
+}
+bool CBSocketConnect(uint64_t socketID,uint8_t * IP,bool IPv6,uint16_t port){
+       // Create sockaddr_in6 information for a IPv6 address
+       int res;
+       if (IPv6) {
+               struct sockaddr_in6 address;
+               memset(&address, 0, sizeof(address)); // Clear structure.
+               address.sin6_family = AF_INET6;
+               memcpy(&address.sin6_addr, IP, 16); // Move IP address into place.
+               address.sin6_port = htons(port); // Port number to network order
+               res = connect((int)socketID, (struct sockaddr *)&address, sizeof(address));
+       }else{
+               struct sockaddr_in address;
+               memset(&address, 0, sizeof(address)); // Clear structure.
+               address.sin_family = AF_INET;
+               memcpy(&address.sin_addr, IP + 12, 4); // Move IP address into place. Last 4 bytes for IPv4.
+               address.sin_port = htons(port); // Port number to network order
+               res = connect((int)socketID, (struct sockaddr *)&address, sizeof(address));
+       }
+       if (NOT res || errno == EINPROGRESS)
+               return true;
+       return false;
+}
+bool CBSocketListen(uint64_t socketID,uint16_t maxConnections){
+       if(listen((int)socketID, maxConnections) == -1){
+               return false;
+       }
+       return true;
+}
+bool CBSocketAccept(uint64_t socketID,uint64_t * connectionSocketID){
+       *connectionSocketID = accept((int)socketID, NULL, NULL);
+       if (*connectionSocketID == -1) {
+               return false;
+       }
+       // Stop SIGPIPE
+       if (CB_NOSIGPIPE) {
+               int i = 1;
+               setsockopt((int)*connectionSocketID, SOL_SOCKET, SO_NOSIGPIPE, &i, sizeof(i));
+       }
+       // Make socket non-blocking
+       fcntl((int)*connectionSocketID, F_SETFL, fcntl((int)*connectionSocketID, F_GETFL, 0) | O_NONBLOCK);
+       return true;
+}
+bool CBNewEventLoop(uint64_t * loopID,void (*onError)(void *),void (*onDidTimeout)(void *,void *,CBTimeOutType),void * communicator){
+       struct ev_loop * base = ev_loop_new(0);
+       // Create arguments for the loop
+       CBEventLoop * loop = malloc(sizeof(*loop));
+       loop->base = base;
+       loop->onError = onError;
+       loop->onTimeOut = onDidTimeout;
+       loop->communicator = communicator;
+       loop->userEvent = malloc(sizeof(*loop->userEvent));
+       ev_async_init((struct ev_async *)loop->userEvent, CBDoRun);
+       ev_async_start(base, (struct ev_async *)loop->userEvent);
+       // Create thread attributes explicitly for portability reasons.
+       pthread_attr_t attr;
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // May need to be joinable.
+       // Create joinable thread
+       if(pthread_create(&loop->loopThread, &attr, CBStartEventLoop, loop)){
+               // Thread creation failed.
+               pthread_attr_destroy(&attr);
+               ev_loop_destroy(base);
+               free(loop->userEvent);
+               return 0;
+       }
+       pthread_attr_destroy(&attr);
+       *loopID = (uint64_t)loop;
+       return loop;
+}
+void * CBStartEventLoop(void * vloop){
+       CBEventLoop * loop = vloop;
+       // Start event loop
+       ev_run(loop->base, 0);
+       // Break from loop. Free everything.
+       ev_loop_destroy(loop->base);
+       free(loop->userEvent);
+       free(loop);
+       return NULL;
+}
+bool CBSocketCanAcceptEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onCanAccept)(void *,uint64_t)){
+       CBIOEvent * event = malloc(sizeof(*event));
+       event->loop = (CBEventLoop *) loopID;
+       event->onEvent.i = onCanAccept;
+       event->socket = (int)socketID;
+       ev_io_init((struct ev_io *)event, CBCanAccept, (int)socketID, EV_READ);
+       *eventID = (uint64_t)event;
+       return true;
+}
+void CBCanAccept(struct ev_loop * loop,struct ev_io * watcher,int eventID){
+       CBIOEvent * event = (CBIOEvent *)watcher;
+       event->onEvent.i(event->loop->communicator,event->socket);
+}
+bool CBSocketDidConnectEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onDidConnect)(void *,void *),void * node){
+       CBIOEvent * event = malloc(sizeof(*event));
+       event->loop = (CBEventLoop *)loopID;
+       event->onEvent.ptr = onDidConnect;
+       event->node = node;
+       event->timerCallback = CBDidConnectTimeout;
+       ev_io_init((struct ev_io *)event, CBDidConnect, (int)socketID, EV_WRITE);
+       *eventID = (uint64_t)event;
+       return true;
+}
+void CBDidConnect(struct ev_loop * loop,struct ev_io * watcher,int eventID){
+       CBIOEvent * event = (CBIOEvent *)watcher;
+       // Reset timeout
+       if (event->timeout)
+               ev_timer_again(loop, (struct ev_timer *)event->timeout);
+       // This is a one-shot event.
+       ev_io_stop(loop, watcher);
+       // Connection successful
+       event->onEvent.ptr(event->loop->communicator,event->node);
+}
+void CBDidConnectTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID){
+       CBTimer * event = (CBTimer *) watcher;
+       event->loop->onTimeOut(event->loop->communicator,event->node,CB_TIMEOUT_CONNECT);
+}
+bool CBSocketCanSendEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onCanSend)(void *,void *),void * node){
+       CBIOEvent * event = malloc(sizeof(*event));
+       event->loop = (CBEventLoop *)loopID;
+       event->onEvent.ptr = onCanSend;
+       event->node = node;
+       event->timerCallback = CBCanSendTimeout;
+       ev_io_init((struct ev_io *)event, CBCanSend, (int)socketID, EV_WRITE);
+       *eventID = (uint64_t)event;
+       return true;
+}
+void CBCanSend(struct ev_loop * loop,struct ev_io * watcher,int eventID){
+       CBIOEvent * event = (CBIOEvent *)watcher;
+       // Reset timeout
+       if (event->timeout)
+               ev_timer_again(loop, (struct ev_timer *)event->timeout);
+       // Can send
+       event->onEvent.ptr(event->loop->communicator,event->node);
+}
+void CBCanSendTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID){
+       CBTimer * event = (CBTimer *) watcher;
+       event->loop->onTimeOut(event->loop->communicator,event->node,CB_TIMEOUT_SEND);
+}
+bool CBSocketCanReceiveEvent(uint64_t * eventID,uint64_t loopID,uint64_t socketID,void (*onCanReceive)(void *,void *),void * node){
+       CBIOEvent * event = malloc(sizeof(*event));
+       event->loop = (CBEventLoop *)loopID;
+       event->onEvent.ptr = onCanReceive;
+       event->node = node;
+       event->timerCallback = CBCanReceiveTimeout;
+       ev_io_init((struct ev_io *)event, CBCanReceive, (int)socketID, EV_READ);
+       *eventID = (uint64_t)event;
+       return true;
+}
+void CBCanReceive(struct ev_loop * loop,struct ev_io * watcher,int eventID){
+       CBIOEvent * event = (CBIOEvent *)watcher;
+       // Reset timeout
+       if (event->timeout)
+               ev_timer_again(loop, (struct ev_timer *)event->timeout);
+       // Can receive
+       event->onEvent.ptr(event->loop->communicator,event->node);
+}
+void CBCanReceiveTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID){
+       CBTimer * event = (CBTimer *) watcher;
+       event->loop->onTimeOut(event->loop->communicator,event->node,CB_TIMEOUT_RECEIVE);
+}
+bool CBSocketAddEvent(uint64_t eventID,uint16_t timeout){
+       CBIOEvent * event = (CBIOEvent *)eventID;
+       ev_io_start(event->loop->base, (struct ev_io *)event);
+       if (timeout) {
+               // Add timer
+               event->timeout = malloc(sizeof(*event->timeout));
+               event->timeout->loop = event->loop;
+               event->timeout->node = event->node;
+               ev_timer_init((struct ev_timer *)event->timeout, event->timerCallback, 0, timeout);
+               ev_timer_start(event->loop->base, (struct ev_timer *)event->timeout);
+       }else
+               event->timeout = NULL;
+       return true;
+}
+bool CBSocketRemoveEvent(uint64_t eventID){
+       CBIOEvent * event = (CBIOEvent *)eventID;
+       if (event->timeout){
+               ev_timer_stop(event->loop->base, (struct ev_timer *)event->timeout);
+               free(event->timeout);
+               event->timeout = NULL;
+       }
+       ev_io_stop(event->loop->base, (struct ev_io *)event);
+}
+void CBSocketFreeEvent(uint64_t eventID){
+       CBSocketRemoveEvent(eventID);
+       free((CBIOEvent *)eventID);
+}
+int32_t CBSocketSend(uint64_t socketID,uint8_t * data,uint32_t len){
+       ssize_t res = send((int)socketID, data, len, CB_SEND_FLAGS);
+       if (res >= 0)
+               return (int32_t)res;
+       if (errno == EAGAIN)
+               return 0; // False event. Wait again.
+       return CB_SOCKET_FAILURE; // Failure
+}
+int32_t CBSocketReceive(uint64_t socketID,uint8_t * data,uint32_t len){
+       ssize_t res = read((int)socketID, data, len);
+       if (res > 0)
+               return (int32_t)res; // OK, read data.
+       if (NOT res)
+               return CB_SOCKET_CONNECTION_CLOSE; // If read() gives zero it means the connection was closed.
+       if (errno == EAGAIN)
+               return 0; // False event. Wait again. No bytes read.
+       return CB_SOCKET_FAILURE; // Failure
+}
+bool CBStartTimer(uint64_t loopID,uint64_t * timer,uint16_t time,void (*callback)(void *),void * arg){
+       CBTimer * theTimer = malloc(sizeof(*theTimer));
+       theTimer->callback = callback;
+       theTimer->arg = arg;
+       theTimer->loop = (CBEventLoop *)loopID;
+       ev_timer_init((struct ev_timer *)theTimer, CBFireTimer, 0, time);
+       ev_timer_start(((CBEventLoop *)loopID)->base, (struct ev_timer *)theTimer);
+       *timer = (uint64_t)theTimer;
+       return true;
+}
+void CBFireTimer(struct ev_loop * loop,struct ev_timer * watcher,int eventID){
+       CBTimer * theTimer = (CBTimer *)watcher;
+       theTimer->callback(theTimer->arg);
+}
+void CBEndTimer(uint64_t timer){
+       CBTimer * theTimer = (CBTimer *)timer;
+       ev_timer_stop(theTimer->loop->base, (struct ev_timer *)theTimer);
+       free(theTimer);
+}
+void CBDoRun(struct ev_loop * loop,struct ev_async * watcher,int event){
+       CBEventLoop * evloop = (CBEventLoop *)((CBAsyncEvent *)watcher)->loop;
+       evloop->userCallback(evloop->userArg);
+}
+bool CBRunOnNetworkThread(uint64_t loopID,void (*callback)(void *),void * arg){
+       CBEventLoop * loop = (CBEventLoop *) loopID;
+       loop->userCallback = callback;
+       loop->userArg = arg;
+       ev_async_send(loop->base, (struct ev_async *)loop->userEvent);
+}
+void CBCloseSocket(uint64_t socketID){
+       close((int)socketID);
+}
+void CBExitEventLoop(uint64_t loopID){
+       if (NOT loopID)
+               return;
+       CBEventLoop * loop = (CBEventLoop *) loopID;
+       ev_unloop(loop->base, EVUNLOOP_ONE);
+}
diff --git a/dependencies/sockets/CBLibevSockets.h b/dependencies/sockets/CBLibevSockets.h
new file mode 100644 (file)
index 0000000..99f219a
--- /dev/null
@@ -0,0 +1,117 @@
+//
+//  CBLibEventSockets.h
+//  cbitcoin
+//
+//  Created by Matthew Mitchell on 10/08/2012.
+//  Copyright (c) 2012 Matthew Mitchell
+//  
+//  This file is part of cbitcoin.
+//
+//  cbitcoin is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//  
+//  cbitcoin is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with cbitcoin.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ @file
+ @brief This is an implementation of the networking dependencies for cbitcoin. It can be included as as a source file in any projects using cbitcoin which require networking capabilities. This file uses libevent for effecient event-based sockets and POSIX threads. The sockets are POSIX sockets with compatibility functions taken from libevent to try and be compatible with windows.
+ */
+
+#include "CBDependencies.h" // cbitcoin dependencies to implement
+#include <pthread.h> // POSIX threads
+#include <ev.h> // libev events
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#ifndef CBLIBEVENTSOCKETSH
+#define CBLIBEVENTSOCKETSH
+
+// Define if we have SO_NOSIGPIPE
+
+#ifdef SO_NOSIGPIPE
+#define CB_NOSIGPIPE true
+#else
+#define CB_NOSIGPIPE false
+#define SO_NOSIGPIPE 0
+#endif
+
+// Define send flags
+
+#ifdef MSG_NOSIGNAL
+#define CB_SEND_FLAGS MSG_NOSIGNAL
+#else
+#define CB_SEND_FLAGS 0
+#endif
+
+void * CBStartEventLoop(void *);
+void CBCanAccept(struct ev_loop * loop,struct ev_io * watcher,int eventID);
+void CBDidConnect(struct ev_loop * loop,struct ev_io * watcher,int eventID);
+void CBDidConnectTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID);
+void CBCanSend(struct ev_loop * loop,struct ev_io * watcher,int eventID);
+void CBCanSendTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID);
+void CBCanReceive(struct ev_loop * loop,struct ev_io * watcher,int eventID);
+void CBCanReceiveTimeout(struct ev_loop * loop,struct ev_timer * watcher,int eventID);
+void CBFireTimer(struct ev_loop * loop,struct ev_timer * watcher,int eventID);
+void CBDoRun(struct ev_loop * loop,struct ev_async * watcher,int event);
+/**
+ @brief Runs a callback on the network thread.
+ @param loopID The loop ID
+ @returns true if sucessful, false otherwise.
+ */
+bool CBRunOnNetworkThread(uint64_t loopID,void (*callback)(void *),void * arg);
+
+typedef struct{
+       struct ev_async base;
+       void * loop;
+}CBAsyncEvent;
+
+typedef struct{
+       struct ev_loop * base;
+       void (*onError)(void *);
+       void (*onTimeOut)(void *,void *,CBTimeOutType); /**< Callback for timeouts */
+       void * communicator;
+       pthread_t loopThread; /**< The thread ID for the event loop. */
+       void  (*userCallback)(void *);
+       void * userArg;
+       CBAsyncEvent * userEvent;
+}CBEventLoop;
+
+union CBOnEvent{
+       void (*i)(void *,uint64_t);
+       void (*ptr)(void *,void *);
+};
+
+typedef struct{
+       struct ev_timer base;
+       CBEventLoop * loop;
+       void (*callback)(void *);
+       void * arg;
+       void * node;
+}CBTimer;
+
+typedef struct{
+       struct ev_io base; /**< libev event. */
+       CBEventLoop * loop; /**< For getting timeout events */
+       union CBOnEvent onEvent;
+       int socket;
+       void * node;
+       void (*timerCallback)(struct ev_loop *,struct ev_timer *,int);
+       CBTimer * timeout;
+}CBIOEvent;
+
+#endif
index 290028c..1e5c02f 100644 (file)
@@ -47,8 +47,7 @@
 #pragma weak CBSocketBind
 #pragma weak CBSocketConnect
 #pragma weak CBSocketListen
-#pragma weak CBSocketAcceptIPv4
-#pragma weak CBSocketAcceptIPv6
+#pragma weak CBSocketAccept
 #pragma weak CBNewEventLoop
 #pragma weak CBSocketCanAcceptEvent
 #pragma weak CBSocketDidConnectEvent
@@ -143,20 +142,9 @@ bool CBSocketListen(uint64_t socketID,uint16_t maxConnections);
  @brief Accepts an incomming IPv4 connection on a bound socket. This should be non-blocking.
  @param socketID The socket id
  @param connectionSocketID A socket id for a new socket for the connection.
- @param IP 4 bytes to be set by the function for the IP of the incomming connection.
- @param port Set to the port of the connection.
  @returns true if function was sucessful and false otherwise.
  */
-bool CBSocketAcceptIPv4(uint64_t socketID,uint64_t * connectionSocketID,uint8_t * IP,uint16_t * port);
-/**
- @brief Accepts an incomming IPv6 connection on a bound socket. This should be non-blocking.
- @param socketID The socket id
- @param connectionSocketID A socket id for a new socket for the connection.
- @param IP 16 bytes to be set by the function for the IP of the incomming connection.
- @param port Set to the port of the connection.
- @returns true if function was sucessful and false otherwise.
- */
-bool CBSocketAcceptIPv6(uint64_t socketID,uint64_t * connectionSocketID,uint8_t * IP,uint16_t * port);
+bool CBSocketAccept(uint64_t socketID,uint64_t * connectionSocketID);
 /**
  @brief Starts a event loop for socket events on a seperate thread. Access to the loop id should be thread safe.
  @param loopID A uint64_t storing an integer or pointer representation of the new event loop.
index 550d544..34389c9 100644 (file)
@@ -242,14 +242,14 @@ CBNetworkAddress * CBAddressManagerGotNetworkAddress(CBAddressManager * self,CBN
        CBBucket * bucket = self->buckets + CBAddressManagerGetBucketIndex(self, addr);
        // Look in that bucket for the address...
        for (uint16_t x = 0; x < bucket->addrNum; x++)
-               if (CBByteArrayEquals(addr->ip, bucket->addresses[x]->ip))
-                       // Compares IPs
+               if (CBByteArrayEquals(addr->ip, bucket->addresses[x]->ip) && addr->port == bucket->addresses[x]->port)
+                       // Compares IPs and port
                        return bucket->addresses[x];
        return NULL;
 }
 CBNode * CBAddressManagerGotNode(CBAddressManager * self,CBNetworkAddress * addr){
        for (uint16_t x = 0; x < self->nodesNum; x++)
-               if (CBByteArrayEquals(CBGetNetworkAddress(self->nodes[x])->ip, addr->ip))
+               if (CBByteArrayEquals(CBGetNetworkAddress(self->nodes[x])->ip, addr->ip) && addr->port == CBGetNetworkAddress(self->nodes[x])->port)
                        return self->nodes[x];
        return NULL;
 }
@@ -310,8 +310,7 @@ void CBAddressManagerSetReachability(CBAddressManager * self, CBIPType type, boo
                self->reachablity &= ~type;
 }
 bool CBAddressManagerSetup(CBAddressManager * self){
-       // Allocate buckets
-       self->buckets = malloc(sizeof(*self->buckets) * CB_BUCKET_NUM);
+       // Clear buckets
        memset(self->buckets, 0, sizeof(*self->buckets) * CB_BUCKET_NUM);
        // Create random number generators.
        if (CBNewSecureRandomGenerator(&self->rndGen)) {
index a16db98..8761412 100644 (file)
@@ -58,7 +58,7 @@ typedef struct{
 */
 typedef struct{
        CBMessage base; /**< CBMessage base structure */
-       CBBucket * buckets; /**< Unconnected nodes stored in the buckets */
+       CBBucket buckets[CB_BUCKET_NUM]; /**< Unconnected nodes stored in the buckets */
        CBNode ** nodes; /**< Connected nodes sorted by the time offset. */
        uint32_t nodesNum; /**< Number of connected nodes */
        int16_t networkTimeOffset; /**< Offset to get from system time to network time. */
@@ -157,14 +157,14 @@ uint64_t CBAddressManagerGetGroup(CBAddressManager * self,CBNetworkAddress * add
  */
 uint64_t CBAddressManagerGetNumberOfAddresses(CBAddressManager * self);
 /**
- @brief Determines if a CBNetworkAddress already exists in the CBAddressManager. Compares the IP address.
+ @brief Determines if a CBNetworkAddress already exists in the CBAddressManager. Compares the IP address and port.
  @param self The CBAddressManager object.
  @param addr The address.
  @returns If the address already exists, returns the existing object. Else returns NULL.
  */
 CBNetworkAddress * CBAddressManagerGotNetworkAddress(CBAddressManager * self,CBNetworkAddress * addr);
 /**
- @brief Determines if a CBNetworkAddress is in the "nodes" list. Compares the IP address.
+ @brief Determines if a CBNetworkAddress is in the "nodes" list. Compares the IP address and port.
  @param self The CBAddressManager object.
  @param addr The address.
  @returns If the address already exists as a connected node, returns the existing object. Else returns NULL.
index 78b76ee..8f90ffe 100644 (file)
@@ -56,12 +56,13 @@ CBNetworkAddress * CBGetNetworkAddress(void * self){
 bool CBInitNetworkAddress(CBNetworkAddress * self,uint32_t score,CBByteArray * ip,uint16_t port,uint64_t services,CBEvents * events){
        self->score = score;
        self->ip = ip;
-       // Determine IP type
-       self->type = CBGetIPType(CBByteArrayGetData(ip));
        if (NOT ip) {
                ip = CBNewByteArrayOfSize(16, events);
                memset(CBByteArrayGetData(ip), 0, 16);
+               self->type = CB_IP_INVALID;
        }else{
+               // Determine IP type
+               self->type = CBGetIPType(CBByteArrayGetData(ip));
                CBRetainObject(ip);
        }
        self->port = port;
index 3d2fd87..6500396 100644 (file)
@@ -44,7 +44,6 @@ CBNode * CBGetNode(void * self){
 
 bool CBInitNodeByTakingNetworkAddress(CBNode * self){
        self->receive = NULL;
-       self->pingsSent = 0;
        self->versionSent = false;
        self->versionAck = false;
        self->versionMessage = NULL;
index efef0a4..39d99ba 100644 (file)
@@ -50,7 +50,6 @@ typedef struct{
        uint64_t receiveEvent; /**< Event for receving data from this node */
        uint64_t sendEvent; /**< Event for sending data from this node */
        uint64_t connectEvent; /**< Event for connecting to the node. */
-       uint16_t pingsSent; /**< Number of pings sent and thus how many responses expected */
        bool versionSent; /**< True if the version was sent to this node */
        CBVersion * versionMessage; /**< The version message from this node. */
        bool versionAck; /**< This node acknowledged the version message. */
index 4ad8ed7..69f6b1b 100644 (file)
@@ -109,7 +109,7 @@ uint32_t CBVersionDeserialise(CBVersion * self){
        // Readjust CBByteArray length for recieving address
        data->length = len;
        CBReleaseObject(data);
-       if (self->version >= 106) {
+       if (self->version >= 106) { // ??? Very old. No need for backwards compatibility? Might as well.
                if (bytes->length < 85) {
                        CBGetMessage(self)->events->onErrorReceived(CB_ERROR_MESSAGE_DESERIALISATION_BAD_BYTES,"Attempting to deserialise a CBVersion with less than 85 bytes required.");
                        return 0;
index 8709447..effe575 100644 (file)
@@ -80,37 +80,15 @@ void CBFreeNetworkCommunicator(void * vself){
 
 //  Functions
 
-void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket, bool IPv6){
+void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket){
        CBNetworkCommunicator * self = vself;
-       uint8_t * IP = malloc(IPv6 ? 16 : 4);
-       uint16_t port;
        uint64_t connectSocketID;
-       CBByteArray * ipByteArray;
-       if (IPv6) {
-               if (NOT CBSocketAcceptIPv6(socket, &connectSocketID, IP, &port)) {
-                       // No luck accepting the connection.
-                       free(IP);
-                       return;
-               }
-               ipByteArray = CBNewByteArrayWithData(IP, 16, self->events);
-       }else if (NOT CBSocketAcceptIPv4(socket, &connectSocketID, IP, &port)) {
-               // No luck accepting the connection.
-               free(IP);
+       printf("%s TRIED ACCEPT\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
+       if (NOT CBSocketAccept(socket, &connectSocketID))
                return;
-       }else{
-               // IPv4 Success
-               ipByteArray = CBNewByteArrayOfSize(16,self->events);
-               // Set first 10 bytes to zero.
-               memset(CBByteArrayGetData(ipByteArray),0,10);
-               // Next two bytes are 0xFF for an IPv4 mapped address
-               CBByteArraySetByte(ipByteArray, 10, 0xFF);
-               CBByteArraySetByte(ipByteArray, 11, 0xFF);
-               // Set IPv4
-               memcpy(CBByteArrayGetData(ipByteArray) + 12, IP, 4);
-       }
+       printf("%s MADE ACCEPT\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
        // Connected, add CBNetworkAddress
-       CBNode * node = CBNewNodeByTakingNetworkAddress(CBNewNetworkAddress(0, ipByteArray, port, 0, self->events));
-       CBReleaseObject(ipByteArray);
+       CBNode * node = CBNewNodeByTakingNetworkAddress(CBNewNetworkAddress(0, NULL, 0, 0, self->events));
        node->socketID = connectSocketID;
        node->acceptedTypes = CB_MESSAGE_TYPE_VERSION; // The node connected to us, we want the version from them.
        // Set up receive event
@@ -127,7 +105,7 @@ void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket, bool IP
                                node->connectionWorking = true;
                                self->attemptingOrWorkingConnections++;
                                self->numIncommingConnections++;
-                               printf("HAS ACCEPT WITH PORT %u\n",port);
+                               printf("%s HAS ACCEPTED OK\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
                                if (self->numIncommingConnections == self->maxIncommingConnections || self->attemptingOrWorkingConnections == self->maxConnections) {
                                        // Reached maximum connections, stop listening.
                                        CBNetworkCommunicatorStopListening(self);
@@ -141,12 +119,7 @@ void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket, bool IP
        // Failure, release node.
        CBCloseSocket(connectSocketID);
        CBReleaseObject(node);
-}
-void CBNetworkCommunicatorAcceptConnectionIPv4(void * vself,uint64_t socket){
-       CBNetworkCommunicatorAcceptConnection(vself, socket, false);
-}
-void CBNetworkCommunicatorAcceptConnectionIPv6(void * vself,uint64_t socket){
-       CBNetworkCommunicatorAcceptConnection(vself, socket, true);
+       printf("%s HAS ACCEPTED FAIL\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
 }
 CBConnectReturn CBNetworkCommunicatorConnect(CBNetworkCommunicator * self,CBNode * node){
        if (NOT CBAddressManagerIsReachable(self->addresses, CBGetNetworkAddress(node)->type))
@@ -167,31 +140,28 @@ CBConnectReturn CBNetworkCommunicatorConnect(CBNetworkCommunicator * self,CBNode
                }
                return CB_CONNECT_FAIL;
        }
-       // Add event for connection
-       if (CBSocketDidConnectEvent(&node->connectEvent,self->eventLoop, node->socketID, CBNetworkCommunicatorDidConnect, node)) {
-               if (CBSocketAddEvent(node->connectEvent, self->connectionTimeOut)) {
-                       printf("DID CONNECTION EVENT\n");
-                       // Connect
-                       if(CBSocketConnect(node->socketID, CBByteArrayGetData(CBGetNetworkAddress(node)->ip), isIPv6, CBGetNetworkAddress(node)->port)){
-                               printf("CONNECTION FINE\n");
+       // Connect
+       if(CBSocketConnect(node->socketID, CBByteArrayGetData(CBGetNetworkAddress(node)->ip), isIPv6, CBGetNetworkAddress(node)->port)){
+               // Add event for connection
+               if (CBSocketDidConnectEvent(&node->connectEvent,self->eventLoop, node->socketID, CBNetworkCommunicatorDidConnect, node)) {
+                       if (CBSocketAddEvent(node->connectEvent, self->connectionTimeOut)) {
+                               printf("%s CONNECTION WAIT\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
                                // Connection is fine. Retain for waiting for connect.
                                CBRetainObject(node);
                                self->attemptingOrWorkingConnections++;
                                return CB_CONNECT_OK;
-                       }else{
+                       }else
                                CBSocketFreeEvent(node->connectEvent);
-                               CBCloseSocket(node->socketID);
-                               return CB_CONNECT_BAD;
-                       }
                }
-               CBSocketFreeEvent(node->connectEvent);
+               CBCloseSocket(node->socketID);
+               return CB_CONNECT_FAIL;
        }
        CBCloseSocket(node->socketID);
-       return CB_CONNECT_FAIL;
+       return CB_CONNECT_BAD;
 }
 void CBNetworkCommunicatorDidConnect(void * vself,void * vnode){
-       printf("HAS CONNECT\n");
        CBNetworkCommunicator * self = vself;
+       printf("%s CONNECTED OK\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"));
        CBNode * node = vnode;
        CBSocketFreeEvent(node->connectEvent); // No longer need this event.
        // Make receive event
@@ -271,19 +241,23 @@ bool CBNetworkCommunicatorProcessMessageAutoDiscovery(CBNetworkCommunicator * se
                // Store addresses.
                uint64_t now = time(NULL) + self->addresses->networkTimeOffset;
                // Loop through addresses
+               bool didAdd = false; // True when we add an address.
                for (uint16_t x = 0; x < addrs->addrNum; x++) {
                        // Check if we have the address as a connected node
                        CBNode * nodeB = CBAddressManagerGotNode(self->addresses,addrs->addresses[x]);
                        if(NOT nodeB){
                                // Do not already have this address as a node
-                               if (addrs->addresses[x]->type & CB_IP_INVALID || addrs->addresses[x]->type & CB_IP_LOCAL)
-                                       // Address broadcasts should not contain invalid or local addresses.
+                               if (addrs->addresses[x]->type & CB_IP_INVALID)
+                                       // Address broadcasts should not contain invalid addresses.
+                                       return true;
+                               if (addrs->addresses[x]->type & CB_IP_LOCAL && NOT (CBGetNetworkAddress(node)->type & CB_IP_LOCAL))
+                                       // Do not allow nodes to send local addresses to non-local nodes.
                                        return true;
                                // Adjust time priority
                                if (addrs->addresses[x]->score > now + 600)
                                        // Address is advertised more than ten minutes from now. Give low priority at 5 days ago
                                        addrs->addresses[x]->score = (uint32_t)(now - 432000); // ??? Needs fixing for integer overflow in the year 2106.
-                               else if (addrs->addresses[x]->score > now - 900) // More than fifteen minutes ago. Give highest priority.
+                               else if (addrs->addresses[x]->score > now - 900) // Sooner than fifteen minutes ago. Give highest priority.
                                        addrs->addresses[x]->score = (uint32_t)now;
                                // Else leave the time
                                // Check if we have the address as a stored address
@@ -293,12 +267,10 @@ bool CBNetworkCommunicatorProcessMessageAutoDiscovery(CBNetworkCommunicator * se
                                        addr->score = addrs->addresses[x]->score;
                                        addr->services = addrs->addresses[x]->services;
                                        addr->version = addrs->addresses[x]->version;
-                               }else{
+                               }else if (CBAddressManagerIsReachable(self->addresses, addrs->addresses[x]->type)){
                                        // Do not have the address so add it if we believe we can reach it.
-                                       if (CBAddressManagerIsReachable(self->addresses, addrs->addresses[x]->type)) {
-                                               CBRetainObject(addrs->addresses[x]); // The CBMessage will be released with this CBNetworkAddress.
-                                               CBAddressManagerTakeAddress(self->addresses, addrs->addresses[x]);
-                                       }
+                                       CBAddressManagerAddAddress(self->addresses, addrs->addresses[x]);
+                                       didAdd = true;
                                }
                        }else
                                // We have an advertised node. This means it is public and should return to the address store.
@@ -312,36 +284,48 @@ bool CBNetworkCommunicatorProcessMessageAutoDiscovery(CBNetworkCommunicator * se
                                CBNetworkCommunicatorSendMessage(self, self->addresses->nodes[x], CBGetMessage(addrs));
                        }
                }
-               CBNetworkCommunicatorTryConnections(self); // We have new address information so try connecting to addresses.
-               if (node->getAddresses) node->getAddresses = false; // Got addresses.
+               if (didAdd)
+                       // We have new address information so try connecting to addresses.
+                       CBNetworkCommunicatorTryConnections(self);
+               // Got addresses.
+               node->getAddresses = false;
        }else if (node->receive->type == CB_MESSAGE_TYPE_GETADDR) {
-               // Give 33 nodes with the highest times with a some randomisation added. Try connected nodes first.
+               // Give 33 nodes with the highest times with a some randomisation added. Try connected nodes first. Do not send empty addr.
                CBAddressBroadcast * addrBroadcast = CBNewAddressBroadcast(self->version >= CB_ADDR_TIME_VERSION && node->versionMessage->version >= CB_ADDR_TIME_VERSION, self->events);
                CBGetMessage(addrBroadcast)->type = CB_MESSAGE_TYPE_ADDR;
                // Try connected nodes. Only send nodes that are selected to return to the addresses list and hence aren't private (private addresses are those which connect to us but haven't relayed their address).
                uint16_t nodesSent = 0;
                uint16_t y = 0;
-               while (nodesSent < 33 && y < self->addresses->nodesNum) {
-                       if (self->addresses->nodes[y]->returnToAddresses) {
-                               // Not private
+               while (nodesSent < 28 && y < self->addresses->nodesNum) { // 28 to have room for 5 addresses.
+                       if (self->addresses->nodes[y] != node // Not the node we are sending to
+                               && self->addresses->nodes[y]->returnToAddresses // Not private
+                               && (CBGetNetworkAddress(self->addresses->nodes[y])->type != CB_IP_LOCAL // OK if not local
+                                       || CBGetNetworkAddress(node)->type == CB_IP_LOCAL)) { //               Or if the node we are sending to is local
                                CBAddressBroadcastAddNetworkAddress(addrBroadcast, CBGetNetworkAddress(self->addresses->nodes[y]));
                                nodesSent++;
                        }
                        y++;
                }
-               // Now send stored addresses.
+               // Now add stored addresses
                CBNetworkAddressLocator * addrs = CBAddressManagerGetAddresses(self->addresses, 33 - nodesSent);
                for (u_int8_t x = 0; (addrs + x)->addr != NULL; x++){
-                       CBAddressBroadcastAddNetworkAddress(addrBroadcast, (addrs + x)->addr);
+                       if ((addrs + x)->addr->type != CB_IP_LOCAL
+                               || CBGetNetworkAddress(node)->type == CB_IP_LOCAL)
+                               // If the address is not local or if the node we are sending to is local, the address is acceptable.
+                               CBAddressBroadcastAddNetworkAddress(addrBroadcast, (addrs + x)->addr);
                        CBReleaseObject((addrs + x)->addr);
                }
                free(addrs);
-               // Send address broadcast
-               CBNetworkCommunicatorSendMessage(self, node, CBGetMessage(addrBroadcast));
+               // Send address broadcast, if we have at least one.
+               if (addrBroadcast->addrNum)
+                       CBNetworkCommunicatorSendMessage(self, node, CBGetMessage(addrBroadcast));
                CBReleaseObject(addrBroadcast);
        }
        // Use opportunity to discover if we should broadcast our own addresses for recieving incoming connections.
-       if (node->timeBroadcast < time(NULL) - 86400) {
+       if (self->numIncommingConnections // Only share address if we allow for incomming connections.
+               && (self->isListeningIPv4 || self->isListeningIPv6) // Share when we are listening for incoming connections.
+               && node->timeBroadcast < time(NULL) - 86400 // Every 24 hours
+               && node->acceptedTypes & CB_MESSAGE_TYPE_ADDR) { // Only share address if they are allowed.
                node->timeBroadcast = time(NULL);
                CBAddressBroadcast * addrBroadcast = CBNewAddressBroadcast(self->version >= CB_ADDR_TIME_VERSION && node->versionMessage->version >= CB_ADDR_TIME_VERSION, self->events);
                CBGetMessage(addrBroadcast)->type = CB_MESSAGE_TYPE_ADDR;
@@ -378,7 +362,11 @@ bool CBNetworkCommunicatorProcessMessageAutoHandshake(CBNetworkCommunicator * se
                        // Copy over reported version and services for the CBNetworkAddress.
                        CBGetNetworkAddress(node)->version = node->versionMessage->version;
                        CBGetNetworkAddress(node)->services = node->versionMessage->services;
-                       CBGetNetworkAddress(node)->score = (uint32_t)time(NULL); // ??? Loss of integer precision.
+                       CBGetNetworkAddress(node)->score = (uint32_t)time(NULL); // ??? Loss of integer precisibon.
+                       // Change port and IP number to the port and IP the node wants us to recognise them with.
+                       CBGetNetworkAddress(node)->port = node->versionMessage->addSource->port;
+                       CBGetNetworkAddress(node)->ip = node->versionMessage->addSource->ip;
+                       CBGetNetworkAddress(node)->type = CBGetIPType(CBByteArrayGetData(CBGetNetworkAddress(node)->ip));
                        // Adjust network time
                        node->timeOffset = node->versionMessage->time - time(NULL); // Set the time offset for this node.
                        // Disallow version from here.
@@ -426,7 +414,7 @@ bool CBNetworkCommunicatorProcessMessageAutoHandshake(CBNetworkCommunicator * se
                        // Request addresses
                        CBMessage * getaddr = CBNewMessageByObject(self->events);
                        getaddr->type = CB_MESSAGE_TYPE_GETADDR;
-                       getaddr->expectResponse = CB_MESSAGE_TYPE_ADDR; // Expect a response of addresses for this message.
+                       // Send the message without an expected response. We do not expect an "addr" message because the node may not send us anything if they do not have addresses to give.
                        CBNetworkCommunicatorSendMessage(self,node,getaddr);
                        CBReleaseObject(getaddr);
                        node->getAddresses = true;
@@ -547,6 +535,7 @@ void CBNetworkCommunicatorOnCanSend(void * vself,void * vnode){
                                memcpy(node->sendingHeader + 4, "alert\0\0\0\0\0\0\0", 12);
                        else if (toSend->type == CB_MESSAGE_TYPE_ALT)
                                memcpy(node->sendingHeader + 4, toSend->altText, 12);
+                       printf("%s SENT %s\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"),node->sendingHeader + 4);
                        // Length
                        if (toSend->bytes){
                                node->sendingHeader[16] = toSend->bytes->length;
@@ -781,6 +770,7 @@ void CBNetworkCommunicatorOnHeaderRecieved(CBNetworkCommunicator * self,CBNode *
                        }
                }
        }
+       printf("%s RECEIVED %s\n",(self->ourIPv4->port == 45562)? "L1" : ((self->ourIPv4->port == 45563)? "L2" : "CN"),CBByteArrayGetData(typeBytes));
        CBReleaseObject(typeBytes);
        if (error) {
                // Error with the message header type or length
@@ -861,6 +851,9 @@ void CBNetworkCommunicatorOnMessageReceived(CBNetworkCommunicator * self,CBNode
                        len = CBVersionDeserialise(CBGetVersion(node->receive));
                        break;
                case CB_MESSAGE_TYPE_ADDR:
+                       if (self->ourIPv4->port == 45563) {
+                               printf("ERR\n");
+                       }
                        node->receive = realloc(node->receive, sizeof(CBAddressBroadcast));
                        CBGetObject(node->receive)->free = CBFreeAddressBroadcast;
                        CBGetAddressBroadcast(node->receive)->timeStamps = node->versionMessage->version > 31401; // Timestamps start version 31402 and up.
@@ -933,13 +926,12 @@ void CBNetworkCommunicatorOnMessageReceived(CBNetworkCommunicator * self,CBNode
                if (self->flags & CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY)
                        // Auto discovery responses
                        disconnect = CBNetworkCommunicatorProcessMessageAutoDiscovery(self,node);
-               if (self->flags & CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE)
+               if (self->flags & CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE && NOT disconnect)
                        // Auto handshake responses
                        disconnect = CBNetworkCommunicatorProcessMessageAutoHandshake(self,node);
-               if (self->flags & CB_NETWORK_COMMUNICATOR_AUTO_PING) {
+               if (self->flags & CB_NETWORK_COMMUNICATOR_AUTO_PING && NOT disconnect)
                        // Auto ping response
                        disconnect = CBNetworkCommunicatorProcessMessageAutoPingPong(self, node);
-               }
        }
        // Release objects and get ready for next message
        if (disconnect)
@@ -963,7 +955,7 @@ void CBNetworkCommunicatorOnTimeOut(void * vself,void * vnode,CBTimeOutType type
                        // No response expected but node did not send any information for a long time.
                        type = CB_TIMEOUT_NO_DATA;
        }
-       if (node->returnToAddresses){
+       if (node->returnToAddresses && CBGetNetworkAddress(node)->ip){ // Cannot take node as address in the case where the IP is NULL
                CBRetainObject(node); // Retain node for returning to addresses list
                CBNetworkCommunicatorDisconnect(self,node, CB_24_HOURS); // Remove CBNetworkAddress. 1 day penalty.
                // Convert node to address and add it back to the addresses list.
@@ -1131,7 +1123,7 @@ void CBNetworkCommunicatorStartListening(CBNetworkCommunicator * self){
                // Create new bound IPv4 socket
                if (CBSocketBind(&self->listeningSocketIPv4, false, self->ourIPv4->port)){
                        // Add event for accepting connection for both sockets
-                       if (CBSocketCanAcceptEvent(&self->acceptEventIPv4,self->eventLoop, self->listeningSocketIPv4, CBNetworkCommunicatorAcceptConnectionIPv4)) {
+                       if (CBSocketCanAcceptEvent(&self->acceptEventIPv4,self->eventLoop, self->listeningSocketIPv4, CBNetworkCommunicatorAcceptConnection)) {
                                if(CBSocketAddEvent(self->acceptEventIPv4, 0)) // No timeout for listening for incomming connections.
                                        // Start listening on IPv4
                                        if(CBSocketListen(self->listeningSocketIPv4, self->maxIncommingConnections)){
@@ -1152,7 +1144,7 @@ void CBNetworkCommunicatorStartListening(CBNetworkCommunicator * self){
                // Create new bound IPv6 socket
                if (CBSocketBind(&self->listeningSocketIPv6, true, self->ourIPv6->port)){
                        // Add event for accepting connection for both sockets
-                       if (CBSocketCanAcceptEvent(&self->acceptEventIPv6,self->eventLoop, self->listeningSocketIPv6, CBNetworkCommunicatorAcceptConnectionIPv6)) {
+                       if (CBSocketCanAcceptEvent(&self->acceptEventIPv6,self->eventLoop, self->listeningSocketIPv6, CBNetworkCommunicatorAcceptConnection)) {
                                if(CBSocketAddEvent(self->acceptEventIPv6, 0)) // No timeout for listening for incomming connections.
                                        // Start listening on IPv6
                                        if(CBSocketListen(self->listeningSocketIPv6, self->maxIncommingConnections)){
index 603408d..ffe4c19 100644 (file)
@@ -113,21 +113,8 @@ void CBFreeNetworkCommunicator(void * self);
  @brief Accepts an incomming connection.
  @param vself The CBNetworkCommunicator object.
  @param socket The listening socket for accepting a connection.
- @param IPv6 True if an IPv6 connection, false if an IPv4 connection.
  */
-void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket,bool IPv6);
-/**
- @brief Accepts an incomming IPv4 connection.
- @param vself The CBNetworkCommunicator object.
- @param socket The listening socket for accepting a connection.
- */
-void CBNetworkCommunicatorAcceptConnectionIPv4(void * vself,uint64_t socket);
-/**
- @brief Accepts an incomming IPv6 connection.
- @param vself The CBNetworkCommunicator object.
- @param socket The listening socket for accepting a connection.
- */
-void CBNetworkCommunicatorAcceptConnectionIPv6(void * vself,uint64_t socket);
+void CBNetworkCommunicatorAcceptConnection(void * vself,uint64_t socket);
 /**
  @brief Returns true if it is beleived the network address can be connected to, otherwise false.
  @param self The CBNetworkCommunicator object.
index a466134..993a569 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <stdio.h>
 #include "CBNetworkCommunicator.h"
-#include "CBLibEventSockets.h"
+#include "CBLibevSockets.h"
 #include <event2/thread.h>
 #include <time.h>
 #include "stdarg.h"
@@ -39,198 +39,329 @@ void err(CBError a,char * format,...){
 typedef enum{
        GOTVERSION = 1,
        GOTACK = 2,
-       SUCCESS = 4
+       GOTPING = 4,
+       GOTPONG = 8,
+       GOTGETADDR = 16,
+}TesterProgress;
+
+typedef struct{
+       TesterProgress prog[6];
+       CBNode * nodeToProg[6];
+       uint8_t progNum;
+       int complete;
+       CBNetworkCommunicator * comms[3];
 }Tester;
+
 void onTimeOut(void * tester,void * comm,void * node,CBTimeOutType type);
 void onTimeOut(void * tester,void * comm,void * node,CBTimeOutType type){
-       if (NOT (*(Tester *)tester & SUCCESS)){
-               switch (type) {
-                       case CB_TIMEOUT_CONNECT:
-                               printf("TIMEOUT FAIL: CONNECT\n");
-                               break;
-                       case CB_TIMEOUT_NO_DATA:
-                               printf("TIMEOUT FAIL: NO DATA\n");
-                               break;
-                       case CB_TIMEOUT_RECEIVE:
-                               printf("TIMEOUT FAIL: RECEIVE\n");
-                               break;
-                       case CB_TIMEOUT_RESPONSE:
-                               printf("TIMEOUT FAIL: RESPONSE\n");
-                               break;
-                       case CB_TIMEOUT_SEND:
-                               printf("TIMEOUT FAIL: SEND\n");
-                               break;
-               }
+       switch (type) {
+               case CB_TIMEOUT_CONNECT:
+                       printf("TIMEOUT FAIL: CONNECT\n");
+                       break;
+               case CB_TIMEOUT_NO_DATA:
+                       printf("TIMEOUT FAIL: NO DATA\n");
+                       break;
+               case CB_TIMEOUT_RECEIVE:
+                       printf("TIMEOUT FAIL: RECEIVE\n");
+                       break;
+               case CB_TIMEOUT_RESPONSE:
+                       printf("TIMEOUT FAIL: RESPONSE\n");
+                       break;
+               case CB_TIMEOUT_SEND:
+                       printf("TIMEOUT FAIL: SEND\n");
+                       break;
        }
        CBNetworkCommunicatorStop((CBNetworkCommunicator *)comm);
 }
 bool onMessageReceived(void * vtester,void * vcomm,void * vnode);
 bool onMessageReceived(void * vtester,void * vcomm,void * vnode){
        Tester * tester = vtester;
-       CBNetworkCommunicator * comm = vcomm;
        CBNode * node = vnode;
        CBMessage * theMessage = node->receive;
+       // Assign node to tester progress.
+       uint8_t x = 0;
+       for (; x < tester->progNum; x++) {
+               if (tester->nodeToProg[x] == node) {
+                       break;
+               }
+       }
+       if (x == tester->progNum) {
+               tester->nodeToProg[x] = node;
+               tester->progNum++;
+       }
+       TesterProgress * prog = tester->prog + x;
        switch (theMessage->type) {
                case CB_MESSAGE_TYPE_VERSION:
-                       if (*tester && NOT (*tester == GOTACK && node->versionSent)) {
+                       if (NOT ((node->versionSent && *prog == GOTACK) || (*prog == 0))) {
                                printf("VERSION FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        if (CBGetVersion(theMessage)->services) {
                                printf("VERSION SERVICES FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        if (CBGetVersion(theMessage)->version != CB_PONG_VERSION) {
                                printf("VERSION VERSION FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        if (memcmp(CBByteArrayGetData(CBGetVersion(theMessage)->userAgent),CB_USER_AGENT_SEGMENT,CBGetVersion(theMessage)->userAgent->length)) {
                                printf("VERSION USER AGENT FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        if (memcmp(CBByteArrayGetData(CBGetVersion(theMessage)->addSource->ip),(uint8_t [16]){0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,127,0,0,1},CBGetVersion(theMessage)->addSource->ip->length)) {
                                printf("VERSION SOURCE IP FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        if (memcmp(CBByteArrayGetData(CBGetVersion(theMessage)->addRecv->ip),(uint8_t [16]){0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,127,0,0,1},CBGetVersion(theMessage)->addRecv->ip->length)) {
                                printf("VERSION RECEIVE IP FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
-                       }
-                       if (CBGetVersion(theMessage)->addSource->port != 45562 + (comm->ourIPv4->port == 45562)) {
-                               printf("VERSION SOURCE PORT FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
-                       *tester |= GOTVERSION;
+                       *prog |= GOTVERSION;
                        break;
                case CB_MESSAGE_TYPE_VERACK:
                        if ((NOT node->versionSent || node->versionAck)) {
                                printf("VERACK FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
-                       *tester |= GOTACK;
+                       *prog |= GOTACK;
                        break;
                case CB_MESSAGE_TYPE_PING:
-                       if (NOT (*tester & GOTVERSION && *tester & GOTACK)) {
+                       if (NOT (*prog & GOTVERSION && *prog & GOTACK)) {
                                printf("PING FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        CBGetPingPong(theMessage)->ID = CBGetPingPong(theMessage)->ID; // Test access to ID.
+                       *prog |= GOTPING;
                        break;
                case CB_MESSAGE_TYPE_PONG:
-                       if (NOT (*tester & GOTVERSION && *tester & GOTACK) || node->pingsSent != 1) {
+                       if (NOT (*prog & GOTVERSION && *prog & GOTACK)) {
                                printf("PONG FAIL\n");
-                               CBNetworkCommunicatorStop(comm);
+                               exit(EXIT_FAILURE);
                        }
                        CBGetPingPong(theMessage)->ID = CBGetPingPong(theMessage)->ID; // Test access to ID.
-                       // At least one of the pongs worked. Stop this communicator and thus allow the other communicator to timeout.
-                       *tester |= SUCCESS;
-                       CBNetworkCommunicatorStop(comm);
+                       // At least one of the pongs worked.
+                       *prog |= GOTPONG;
+                       break;
+               case CB_MESSAGE_TYPE_GETADDR:
+                       if (NOT (*prog & GOTVERSION && *prog & GOTACK)) {
+                               printf("GET ADDR FAIL\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       *prog |= GOTGETADDR;
+                       break;
+               case CB_MESSAGE_TYPE_ADDR:
+                       if (NOT (*prog & GOTVERSION && *prog & GOTACK && node->getAddresses)) {
+                               printf("GET ADDR FAIL\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       tester->complete++;
                        break;
                default:
                        printf("MESSAGE FAIL\n");
-                       CBNetworkCommunicatorStop(comm);
+                       exit(EXIT_FAILURE);
                        break;
        }
+       if ((*tester).complete == 10 && *prog == (GOTVERSION | GOTACK | GOTPING | GOTPONG |GOTGETADDR)) { // Connector sends self and other node twice (4). Listeners send self to connector (2). Listeners send self and connector to each other (4). 4 + 2 + 4 = 10
+               // Completed testing
+               CBNetworkCommunicatorStop((CBNetworkCommunicator *)vcomm);
+       }
        return false;
 }
 void onNetworkError(void * foo,void * comm);
 void onNetworkError(void * foo,void * comm){
-       printf("NETWORK ERROR FAIL\n");
-       CBNetworkCommunicatorStop((CBNetworkCommunicator *)comm);
+       printf("DID LOSE LAST NODE\n");
+       exit(EXIT_FAILURE);
 }
 void onBadTime(void * comm,void * addrMan);
 void onBadTime(void * comm,void * addrMan){
        printf("BAD TIME FAIL\n");
-       CBNetworkCommunicatorStop((CBNetworkCommunicator *)comm);
+       exit(EXIT_FAILURE);
 }
 
 int main(){
        CBEvents events;
-       Tester testerListen = 0, testerConnect = 0;
+       Tester tester;
+       memset(&tester, 0, sizeof(tester));
        events.onErrorReceived = err;
        events.onBadTime = onBadTime;
        events.onMessageReceived = onMessageReceived;
        events.onNetworkError = onNetworkError;
        events.onTimeOut = onTimeOut;
-       // Using multiple threads to access libevent
-       evthread_use_pthreads();
-       // Create two CBNetworkCommunicators and connect over the loopback address. One will listen, one will connect. Test auto handshake and auto ping between them.
+       // Create three CBNetworkCommunicators and connect over the loopback address. Two will listen, one will connect. Test auto handshake, auto ping and auto discovery.
        CBByteArray * altMessages = CBNewByteArrayOfSize(0, &events);
        CBByteArray * altMessages2 = CBNewByteArrayOfSize(0, &events);
+       CBByteArray * altMessages3 = CBNewByteArrayOfSize(0, &events);
        CBByteArray * loopBack = CBNewByteArrayWithDataCopy((uint8_t [16]){0,0,0,0,0,0,0,0,0,0,0xFF,0xFF,127,0,0,1}, 16, &events);
        CBByteArray * loopBack2 = CBByteArrayCopy(loopBack); // Do not use in more than one thread.
        CBNetworkAddress * addrListen = CBNewNetworkAddress(0, loopBack, 45562, 0, &events);
-       CBNetworkAddress * addrListen2 = CBNewNetworkAddress(0, loopBack, 45562, 0, &events); // Use in second thread.
-       CBNetworkAddress * addrConnect = CBNewNetworkAddress(0, loopBack2, 45563, 0, &events); // Different port over loopback to seperate the CBNetworkCommunicators.
+       CBNetworkAddress * addrListenB = CBNewNetworkAddress(0, loopBack2, 45562, 0, &events); // Use in second thread.
+       CBNetworkAddress * addrListen2 = CBNewNetworkAddress(0, loopBack, 45563, 0, &events);
+       CBNetworkAddress * addrListen2B = CBNewNetworkAddress(0, loopBack2, 45563, 0, &events); // Use in second thread.
+       CBNetworkAddress * addrConnect = CBNewNetworkAddress(0, loopBack, 45564, 0, &events); // Different port over loopback to seperate the CBNetworkCommunicators.
        CBReleaseObject(loopBack);
        CBReleaseObject(loopBack2);
        CBByteArray * userAgent = CBNewByteArrayFromString(CB_USER_AGENT_SEGMENT, &events);
-       // Listening CBNetworkCommunicator setup.
+       CBByteArray * userAgent2 = CBNewByteArrayFromString(CB_USER_AGENT_SEGMENT, &events);
+       CBByteArray * userAgent3 = CBNewByteArrayFromString(CB_USER_AGENT_SEGMENT, &events);
+       // First listening CBNetworkCommunicator setup.
        CBAddressManager * addrManListen = CBNewAddressManager(&events);
-       addrManListen->maxAddressesInBucket = 1;
+       addrManListen->maxAddressesInBucket = 2;
        CBAddressManagerSetReachability(addrManListen, CB_IP_IPv4 | CB_IP_LOCAL, true);
        CBNetworkCommunicator * commListen = CBNewNetworkCommunicator(&events);
        addrManListen->callbackHandler = commListen;
        commListen->networkID = CB_PRODUCTION_NETWORK_BYTES;
-       commListen->flags = CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING;
+       commListen->flags = CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING | CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY;
        commListen->version = CB_PONG_VERSION;
-       commListen->maxConnections = 1;
-       commListen->maxIncommingConnections = 1;
+       commListen->maxConnections = 2;
+       commListen->maxIncommingConnections = 2;
        commListen->heartBeat = 10;
-       commListen->timeOut = 20;
-       commListen->sendTimeOut = 1;
-       commListen->recvTimeOut = 10;
-       commListen->responseTimeOut = 10;
-       commListen->connectionTimeOut = 10;
+       commListen->timeOut = 0; //20;
+       commListen->sendTimeOut = 0; //1;
+       commListen->recvTimeOut = 0; //10;
+       commListen->responseTimeOut = 0; //10;
+       commListen->connectionTimeOut = 0; //10;
        CBNetworkCommunicatorSetAlternativeMessages(commListen, altMessages, NULL);
        CBNetworkCommunicatorSetAddressManager(commListen, addrManListen);
        CBNetworkCommunicatorSetUserAgent(commListen, userAgent);
        CBNetworkCommunicatorSetOurIPv4(commListen, addrListen);
-       commListen->callbackHandler = &testerListen;
+       commListen->callbackHandler = &tester;
+       // Second listenin CBNetworkCommunicator setup.
+       CBAddressManager * addrManListen2 = CBNewAddressManager(&events);
+       addrManListen2->maxAddressesInBucket = 2;
+       CBAddressManagerSetReachability(addrManListen2, CB_IP_IPv4 | CB_IP_LOCAL, true);
+       CBNetworkCommunicator * commListen2 = CBNewNetworkCommunicator(&events);
+       addrManListen2->callbackHandler = commListen2;
+       commListen2->networkID = CB_PRODUCTION_NETWORK_BYTES;
+       commListen2->flags = CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING | CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY;
+       commListen2->version = CB_PONG_VERSION;
+       commListen2->maxConnections = 2;
+       commListen2->maxIncommingConnections = 2;
+       commListen2->heartBeat = 10;
+       commListen2->timeOut = 0; //20;
+       commListen2->sendTimeOut = 0; //1;
+       commListen2->recvTimeOut = 0; //10;
+       commListen2->responseTimeOut = 0; //10;
+       commListen2->connectionTimeOut = 0; //10;
+       CBNetworkCommunicatorSetAlternativeMessages(commListen2, altMessages2, NULL);
+       CBNetworkCommunicatorSetAddressManager(commListen2, addrManListen2);
+       CBNetworkCommunicatorSetUserAgent(commListen2, userAgent2);
+       CBNetworkCommunicatorSetOurIPv4(commListen2, addrListen2);
+       commListen2->callbackHandler = &tester;
        // Connecting CBNetworkCommunicator setup.
        CBAddressManager * addrManConnect = CBNewAddressManager(&events);
-       addrManConnect->maxAddressesInBucket = 1;
+       addrManConnect->maxAddressesInBucket = 2;
        CBAddressManagerSetReachability(addrManConnect, CB_IP_IPv4 | CB_IP_LOCAL, true);
-       CBAddressManagerAddAddress(addrManConnect, addrListen2); // We are going to connect to the listing CBNetworkCommunicator.
+       // We are going to connect to both listing CBNetworkCommunicators.
+       CBAddressManagerAddAddress(addrManConnect, addrListenB);
+       CBAddressManagerAddAddress(addrManConnect, addrListen2B);
        CBNetworkCommunicator * commConnect = CBNewNetworkCommunicator(&events);
        addrManConnect->callbackHandler = commConnect;
        commConnect->networkID = CB_PRODUCTION_NETWORK_BYTES;
-       commConnect->flags = CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING;
+       commConnect->flags = CB_NETWORK_COMMUNICATOR_AUTO_HANDSHAKE | CB_NETWORK_COMMUNICATOR_AUTO_PING | CB_NETWORK_COMMUNICATOR_AUTO_DISCOVERY;
        commConnect->version = CB_PONG_VERSION;
-       commConnect->maxConnections = 1;
+       commConnect->maxConnections = 2;
        commConnect->maxIncommingConnections = 0;
        commConnect->heartBeat = 10;
-       commConnect->timeOut = 20;
-       commConnect->sendTimeOut = 1;
-       commConnect->recvTimeOut = 1;
-       commConnect->responseTimeOut = 10;
-       commConnect->connectionTimeOut = 10;
-       CBNetworkCommunicatorSetAlternativeMessages(commConnect, altMessages2, NULL);
+       commConnect->timeOut = 0; //20;
+       commConnect->sendTimeOut = 0; //1;
+       commConnect->recvTimeOut = 0; //1;
+       commConnect->responseTimeOut = 0; //10;
+       commConnect->connectionTimeOut = 0; //10;
+       CBNetworkCommunicatorSetAlternativeMessages(commConnect, altMessages3, NULL);
        CBNetworkCommunicatorSetAddressManager(commConnect, addrManConnect);
-       CBNetworkCommunicatorSetUserAgent(commConnect, userAgent);
+       CBNetworkCommunicatorSetUserAgent(commConnect, userAgent3);
        CBNetworkCommunicatorSetOurIPv4(commConnect, addrConnect);
-       commConnect->callbackHandler = &testerConnect;
+       commConnect->callbackHandler = &tester;
        // Release objects
        CBReleaseObject(altMessages);
-       CBReleaseObject(addrListen);
-       CBReleaseObject(addrListen2);
-       CBReleaseObject(addrConnect);
        CBReleaseObject(userAgent);
-       // Start listening. Can start listening on this thread since the event loop will not be doing anything.
+       // Give tester communicators
+       tester.comms[0] = commListen;
+       tester.comms[1] = commListen2;
+       tester.comms[2] = commConnect;
+       // Start listening on first listener. Can start listening on this thread since the event loop will not be doing anything.
        CBNetworkCommunicatorStart(commListen);
        pthread_t listenThread = ((CBEventLoop *) commListen->eventLoop)->loopThread;
        CBNetworkCommunicatorStartListening(commListen);
+       // Start listening on second listener.
+       CBNetworkCommunicatorStart(commListen2);
+       pthread_t listen2Thread = ((CBEventLoop *) commListen2->eventLoop)->loopThread;
+       CBNetworkCommunicatorStartListening(commListen2);
        // Start connection
        CBNetworkCommunicatorStart(commConnect);
        pthread_t connectThread = ((CBEventLoop *) commConnect->eventLoop)->loopThread;
        CBNetworkCommunicatorTryConnections(commConnect);
-       // Wait until the network loop ends for both CBNetworkCommunicators.
+       // Wait until the network loop ends for all CBNetworkCommunicators.
        pthread_join(listenThread, NULL);
+       pthread_join(listen2Thread, NULL);
        pthread_join(connectThread, NULL);
-       if (NOT (testerListen & SUCCESS) && NOT (testerConnect & SUCCESS))
+       if (NOT (tester.prog[0] == 127 && tester.prog[1] == 127 && tester.prog[2] == 127)){
                printf("NO SUCCESS\n");
-       // Release communicators
+               exit(EXIT_FAILURE);
+       }
+       // Check addresses in the first listening CBNetworkCommunicator
+       uint8_t i = CBAddressManagerGetBucketIndex(commListen->addresses, addrListen2);
+       CBBucket * bucket = commListen->addresses->buckets + i;
+       if (bucket->addrNum != 2) {
+               printf("ADDRESS DISCOVERY LISTEN ONE ADDR NUM FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if (i != CBAddressManagerGetBucketIndex(commListen->addresses, addrConnect)) {
+               printf("ADDRESS DISCOVERY LISTEN ONE SAME BUCKET FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commListen->addresses, addrListen2)){
+               printf("ADDRESS DISCOVERY LISTEN ONE LISTEN TWO FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commListen->addresses, addrConnect)){
+               printf("ADDRESS DISCOVERY LISTEN ONE CONNECT FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       // Check the addresses in the second.
+       i = CBAddressManagerGetBucketIndex(commListen2->addresses, addrListen);
+       bucket = commListen2->addresses->buckets + i;
+       if (bucket->addrNum != 2) {
+               printf("ADDRESS DISCOVERY LISTEN TWO ADDR NUM FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if (i != CBAddressManagerGetBucketIndex(commListen2->addresses, addrConnect)) {
+               printf("ADDRESS DISCOVERY LISTEN TWO SAME BUCKET FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commListen2->addresses, addrListen)){
+               printf("ADDRESS DISCOVERY LISTEN TWO LISTEN ONE FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commListen2->addresses, addrConnect)){
+               printf("ADDRESS DISCOVERY LISTEN TWO CONNECT FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       // And lastly the connecting CBNetworkCommunicator
+       i = CBAddressManagerGetBucketIndex(commConnect->addresses, addrListen);
+       bucket = commConnect->addresses->buckets + i;
+       if (bucket->addrNum != 2) {
+               printf("ADDRESS DISCOVERY CONNECT ADDR NUM FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if (i != CBAddressManagerGetBucketIndex(commConnect->addresses, addrListen2)) {
+               printf("ADDRESS DISCOVERY CONNECT SAME BUCKET FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commConnect->addresses, addrListen)){
+               printf("ADDRESS DISCOVERY CONNECT LISTEN ONE FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       if(!CBAddressManagerGotNetworkAddress(commConnect->addresses, addrListen2)){
+               printf("ADDRESS DISCOVERY CONNECT LISTEN TWO FAIL\n");
+               exit(EXIT_FAILURE);
+       }
+       // Release all final objects.
+       CBReleaseObject(addrListen);
+       CBReleaseObject(addrListen2);
+       CBReleaseObject(addrConnect);
        CBReleaseObject(commListen);
+       CBReleaseObject(commListen2);
        CBReleaseObject(commConnect);
-       return 0;
-}
\ No newline at end of file
+       return EXIT_SUCCESS;
+}