]> git.seodisparate.com - UDPConnection/commitdiff
Fixes and improvements (add use of TSLQueue)
authorStephen Seo <seo.disparate@gmail.com>
Wed, 6 Nov 2019 05:35:16 +0000 (14:35 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 6 Nov 2019 05:39:09 +0000 (14:39 +0900)
Replace "unsigned long long" in TSLQueue with "unsigned long" to keep
compatibility with C.

Add top_and_pop_and_rsize() to TSLQueue.

Fix log levels in UDPC.

Replace TSQueue with TSLQueue in UDPC_Context.
Also fix NetworkTest with TSLQueue related changes.

cpp_impl/src/TSLQueue.hpp
cpp_impl/src/UDPC_Defines.hpp
cpp_impl/src/UDPConnection.cpp
cpp_impl/src/UDPConnection.h
cpp_impl/src/test/UDPC_NetworkTest.cpp

index d2e04c39f182b4ca677b3d3caa87a3e8cb6c2b10..d368f39f7bfaad8197d922398908f4b4e584346b 100644 (file)
@@ -30,10 +30,11 @@ class TSLQueue {
     bool pop();
     std::optional<T> top_and_pop();
     std::optional<T> top_and_pop_and_empty(bool *isEmpty);
+    std::optional<T> top_and_pop_and_rsize(unsigned long *rsize);
     void clear();
 
     bool empty();
-    unsigned long long size();
+    unsigned long size();
 
   private:
     struct TSLQNode {
@@ -63,7 +64,7 @@ class TSLQueue {
     public:
         TSLQIter(std::mutex &mutex,
                  std::weak_ptr<TSLQNode> currentNode,
-                 unsigned long long *msize);
+                 unsigned long *msize);
         ~TSLQIter();
 
         std::optional<T> current();
@@ -74,7 +75,7 @@ class TSLQueue {
     private:
         std::lock_guard<std::mutex> lock;
         std::weak_ptr<TSLQNode> currentNode;
-        unsigned long long *const msize;
+        unsigned long *const msize;
 
     };
 
@@ -85,7 +86,7 @@ class TSLQueue {
     std::mutex mutex;
     std::shared_ptr<TSLQNode> head;
     std::shared_ptr<TSLQNode> tail;
-    unsigned long long msize;
+    unsigned long msize;
 };
 
 template <typename T>
@@ -243,6 +244,31 @@ std::optional<T> TSLQueue<T>::top_and_pop_and_empty(bool *isEmpty) {
     return ret;
 }
 
+template <typename T>
+std::optional<T> TSLQueue<T>::top_and_pop_and_rsize(unsigned long *rsize) {
+    std::optional<T> ret = std::nullopt;
+    std::lock_guard lock(mutex);
+    if(head->next == tail) {
+        if(rsize) {
+            *rsize = 0;
+        }
+    } else {
+        assert(head->next->data);
+        ret = *head->next->data.get();
+
+        auto& newNext = head->next->next;
+        newNext->prev = head;
+        head->next = newNext;
+        assert(msize > 0);
+        --msize;
+
+        if(rsize) {
+            *rsize = msize;
+        }
+    }
+    return ret;
+}
+
 template <typename T>
 void TSLQueue<T>::clear() {
     std::lock_guard lock(mutex);
@@ -259,7 +285,7 @@ bool TSLQueue<T>::empty() {
 }
 
 template <typename T>
-unsigned long long TSLQueue<T>::size() {
+unsigned long TSLQueue<T>::size() {
     std::lock_guard lock(mutex);
     return msize;
 }
@@ -277,7 +303,7 @@ bool TSLQueue<T>::TSLQNode::isNormal() const {
 template <typename T>
 TSLQueue<T>::TSLQIter::TSLQIter(std::mutex &mutex,
                                 std::weak_ptr<TSLQNode> currentNode,
-                                unsigned long long *msize) :
+                                unsigned long *msize) :
 lock(mutex),
 currentNode(currentNode),
 msize(msize)
index 62bd37fce7dc367bf72729cc0c189b6e6a5a373a..a4d5d5e443a9a3074944ce6d8fec8422c3c11423 100644 (file)
@@ -33,6 +33,7 @@
 #include <iostream>
 
 #include "TSQueue.hpp"
+#include "TSLQueue.hpp"
 #include "UDPConnection.h"
 
 #include <sodium.h>
@@ -153,6 +154,9 @@ private:
         case UDPC_LoggingType::UDPC_INFO:
             std::cerr << "INFO: ";
             break;
+        case UDPC_LoggingType::UDPC_DEBUG:
+            std::cerr << "DEBUG: ";
+            break;
         default:
             return;
         }
@@ -197,8 +201,8 @@ public:
     std::unordered_map<struct in6_addr, std::unordered_set<UDPC_ConnectionId, ConnectionIdHasher>, IPV6_Hasher> addrConMap;
     // id to ipv6 address and port (as UDPC_ConnectionId)
     std::unordered_map<uint32_t, UDPC_ConnectionId> idMap;
-    TSQueue<UDPC_PacketInfo> receivedPkts;
-    TSQueue<UDPC_PacketInfo> cSendPkts;
+    TSLQueue<UDPC_PacketInfo> receivedPkts;
+    TSLQueue<UDPC_PacketInfo> cSendPkts;
 
     std::default_random_engine rng_engine;
 
index aba8b354206c2be59a104b3b67cd2007a5c3f339..481d8e93fe46509c20f2dbfd149c9d18242b7a6b 100644 (file)
@@ -165,13 +165,13 @@ flags(),
 isAcceptNewConnections(true),
 protocolID(UDPC_DEFAULT_PROTOCOL_ID),
 #ifndef NDEBUG
-loggingType(UDPC_INFO),
+loggingType(UDPC_DEBUG),
 #else
 loggingType(UDPC_WARNING),
 #endif
 atostrBufIndex(0),
-receivedPkts(UDPC_RECEIVED_PKTS_MAX_SIZE),
-cSendPkts(UDPC_QUEUED_PKTS_MAX_SIZE),
+receivedPkts(),
+cSendPkts(),
 rng_engine(),
 mutex()
 {
@@ -199,12 +199,21 @@ bool UDPC::Context::willLog(UDPC_LoggingType type) {
     case UDPC_LoggingType::UDPC_WARNING:
         return type == UDPC_LoggingType::UDPC_ERROR
             || type == UDPC_LoggingType::UDPC_WARNING;
+    case UDPC_LoggingType::UDPC_INFO:
+        return type == UDPC_LoggingType::UDPC_ERROR
+            || type == UDPC_LoggingType::UDPC_WARNING
+            || type == UDPC_LoggingType::UDPC_INFO;
     case UDPC_LoggingType::UDPC_VERBOSE:
         return type == UDPC_LoggingType::UDPC_ERROR
             || type == UDPC_LoggingType::UDPC_WARNING
+            || type == UDPC_LoggingType::UDPC_INFO
             || type == UDPC_LoggingType::UDPC_VERBOSE;
-    case UDPC_LoggingType::UDPC_INFO:
-        return type != UDPC_LoggingType::UDPC_SILENT;
+    case UDPC_LoggingType::UDPC_DEBUG:
+        return type == UDPC_LoggingType::UDPC_ERROR
+            || type == UDPC_LoggingType::UDPC_WARNING
+            || type == UDPC_LoggingType::UDPC_INFO
+            || type == UDPC_LoggingType::UDPC_VERBOSE
+            || type == UDPC_LoggingType::UDPC_DEBUG;
     default:
         return false;
     }
@@ -238,7 +247,7 @@ void UDPC::Context::update_impl() {
             if(iter->second.flags.test(1) && !iter->second.flags.test(2)) {
                 // good mode, bad rtt
                 UDPC_CHECK_LOG(this,
-                    UDPC_LoggingType::UDPC_INFO,
+                    UDPC_LoggingType::UDPC_VERBOSE,
                     "Switching to bad mode in connection with ",
                     UDPC_atostr((UDPC_HContext)this, iter->first.addr),
                     ", port = ",
@@ -264,7 +273,7 @@ void UDPC::Context::update_impl() {
                     iter->second.toggleTimer = std::chrono::steady_clock::duration::zero();
                     iter->second.toggledTimer = std::chrono::steady_clock::duration::zero();
                     UDPC_CHECK_LOG(this,
-                        UDPC_LoggingType::UDPC_INFO,
+                        UDPC_LoggingType::UDPC_VERBOSE,
                         "Switching to good mode in connection with ",
                         UDPC_atostr((UDPC_HContext)this, iter->first.addr),
                         ", port = ",
@@ -315,13 +324,33 @@ void UDPC::Context::update_impl() {
 
     // move queued in cSendPkts to existing connection's sendPkts
     {
-        unsigned int rsize = 0;
-        do {
-            auto next = cSendPkts.top_and_pop_and_rsize(&rsize);
+        auto sendIter = cSendPkts.begin();
+        while(true) {
+            auto next = sendIter.current();
             if(next) {
                 if(auto iter = conMap.find(next.value().receiver);
                         iter != conMap.end()) {
+                    if(iter->second.sendPkts.size() >= UDPC_QUEUED_PKTS_MAX_SIZE) {
+                        UDPC_CHECK_LOG(this,
+                            UDPC_LoggingType::UDPC_DEBUG,
+                            "Not queueing packet to ",
+                            UDPC_atostr((UDPC_HContext)this,
+                                next.value().receiver.addr),
+                            ", port = ",
+                            next.value().receiver.port,
+                            ", connection's queue reached max size");
+                        if(sendIter.next()) {
+                            continue;
+                        } else {
+                            break;
+                        }
+                    }
                     iter->second.sendPkts.push_back(next.value());
+                    if(sendIter.remove()) {
+                        continue;
+                    } else {
+                        break;
+                    }
                 } else {
                     UDPC_CHECK_LOG(this,
                         UDPC_LoggingType::UDPC_WARNING,
@@ -332,9 +361,16 @@ void UDPC::Context::update_impl() {
                         ", port = ",
                         next.value().receiver.port,
                         " due to connection not existing");
+                    if(sendIter.remove()) {
+                        continue;
+                    } else {
+                        break;
+                    }
                 }
+            } else {
+                break;
             }
-        } while(rsize != 0);
+        }
     }
 
     // update send (only if triggerSend flag is set)
@@ -618,7 +654,7 @@ void UDPC::Context::update_impl() {
     else if(bytes < UDPC_MIN_HEADER_SIZE) {
         // packet size is too small, invalid packet
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_INFO,
+            UDPC_LoggingType::UDPC_VERBOSE,
             "Received packet is smaller than header, ignoring packet from ",
             UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
             ", port = ",
@@ -630,7 +666,7 @@ void UDPC::Context::update_impl() {
     if(temp != protocolID) {
         // Invalid protocol id in packet
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_INFO,
+            UDPC_LoggingType::UDPC_VERBOSE,
             "Received packet has invalid protocol id, ignoring packet from ",
             UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
             ", port = ",
@@ -652,7 +688,7 @@ void UDPC::Context::update_impl() {
     if(isConnect && bytes != UDPC_CON_HEADER_SIZE) {
         // invalid packet size
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_INFO,
+            UDPC_LoggingType::UDPC_VERBOSE,
             "Got connect packet of invalid size from ",
             UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
             ", port = ",
@@ -662,7 +698,7 @@ void UDPC::Context::update_impl() {
     } else if (!isConnect && bytes < (int)UDPC_FULL_HEADER_SIZE) {
         // packet is too small
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_INFO,
+            UDPC_LoggingType::UDPC_VERBOSE,
             "Got non-connect packet of invalid size from ",
             UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
             ", port = ",
@@ -692,7 +728,7 @@ void UDPC::Context::update_impl() {
             std::memcpy(newConnection.peer_pk, recvBuf + UDPC_MIN_HEADER_SIZE,
                 crypto_sign_PUBLICKEYBYTES);
             UDPC_CHECK_LOG(this,
-                UDPC_LoggingType::UDPC_VERBOSE,
+                UDPC_LoggingType::UDPC_INFO,
                 "Establishing connection with client ",
                 UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
                 ", port = ",
@@ -726,7 +762,7 @@ void UDPC::Context::update_impl() {
             std::memcpy(iter->second.peer_pk, recvBuf + UDPC_MIN_HEADER_SIZE,
                 crypto_sign_PUBLICKEYBYTES);
             UDPC_CHECK_LOG(this,
-                UDPC_LoggingType::UDPC_VERBOSE,
+                UDPC_LoggingType::UDPC_INFO,
                 "Established connection with server ",
                 UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
                 ", port = ",
@@ -753,7 +789,7 @@ void UDPC::Context::update_impl() {
         iter->second.peer_pk) != 0) {
         UDPC_CHECK_LOG(
             this,
-            UDPC_LoggingType::UDPC_VERBOSE,
+            UDPC_LoggingType::UDPC_INFO,
             "Failed to verify received packet from",
             UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
             ", port = ",
@@ -764,7 +800,7 @@ void UDPC::Context::update_impl() {
 
     // packet is valid
     UDPC_CHECK_LOG(this,
-        UDPC_LoggingType::UDPC_INFO,
+        UDPC_LoggingType::UDPC_VERBOSE,
         "Received valid packet from ",
         UDPC_atostr((UDPC_HContext)this, receivedData.sin6_addr),
         ", port = ",
@@ -790,7 +826,7 @@ void UDPC::Context::update_impl() {
             iter->second.flags.set(2, iter->second.rtt <= UDPC::GOOD_RTT_LIMIT);
 
             UDPC_CHECK_LOG(this,
-                UDPC_LoggingType::UDPC_INFO,
+                UDPC_LoggingType::UDPC_VERBOSE,
                 "RTT: ",
                 UDPC::durationToFSec(iter->second.rtt) * 1000.0f,
                 " milliseconds");
@@ -823,7 +859,7 @@ void UDPC::Context::update_impl() {
                 if(duration > UDPC::PACKET_TIMEOUT_TIME) {
                     if(sentIter->dataSize <= UDPC_FULL_HEADER_SIZE) {
                         UDPC_CHECK_LOG(this,
-                            UDPC_LoggingType::UDPC_INFO,
+                            UDPC_LoggingType::UDPC_VERBOSE,
                             "Timed out packet has no payload (probably "
                             "heartbeat packet), ignoring it");
                         sentIter->flags |= 0x8;
@@ -858,7 +894,7 @@ void UDPC::Context::update_impl() {
             if((iter->second.ack & (0x80000000 >> (diff - 1))) != 0) {
                 // already received packet
                 UDPC_CHECK_LOG(this,
-                    UDPC_LoggingType::UDPC_INFO,
+                    UDPC_LoggingType::UDPC_VERBOSE,
                     "Received packet is already marked as received, ignoring it");
                 return;
             }
@@ -872,7 +908,7 @@ void UDPC::Context::update_impl() {
             if((iter->second.ack & (0x80000000 >> (diff - 1))) != 0) {
                 // already received packet
                 UDPC_CHECK_LOG(this,
-                    UDPC_LoggingType::UDPC_INFO,
+                    UDPC_LoggingType::UDPC_VERBOSE,
                     "Received packet is already marked as received, ignoring it");
                 return;
             }
@@ -887,14 +923,14 @@ void UDPC::Context::update_impl() {
     } else {
         // already received packet
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_INFO,
+            UDPC_LoggingType::UDPC_VERBOSE,
             "Received packet is already marked as received, ignoring it");
         return;
     }
 
     if(isOutOfOrder) {
         UDPC_CHECK_LOG(this,
-            UDPC_LoggingType::UDPC_VERBOSE,
+            UDPC_LoggingType::UDPC_INFO,
             "Received packet is out of order");
     }
 
@@ -912,13 +948,7 @@ void UDPC::Context::update_impl() {
         recPktInfo.sender.port = ntohs(receivedData.sin6_port);
         recPktInfo.receiver.port = ntohs(socketInfo.sin6_port);
 
-        if(!receivedPkts.push(recPktInfo)) {
-            UDPC_CHECK_LOG(this,
-                UDPC_LoggingType::UDPC_WARNING,
-                "receivedPkts is full, removing oldest entry to make room");
-            receivedPkts.pop();
-            receivedPkts.push(recPktInfo);
-        }
+        receivedPkts.push(recPktInfo);
     } else if(bytes == UDPC_FULL_HEADER_SIZE) {
         UDPC_CHECK_LOG(this,
             UDPC_LoggingType::UDPC_VERBOSE,
@@ -1228,21 +1258,12 @@ void UDPC_client_initiate_connection(UDPC_HContext ctx, UDPC_ConnectionId connec
             addrConIter = insertResult.first;
         }
         addrConIter->second.insert(connectionId);
-        UDPC_CHECK_LOG(c, UDPC_LoggingType::UDPC_VERBOSE, "client_initiate_connection: Initiating connection...");
+        UDPC_CHECK_LOG(c, UDPC_LoggingType::UDPC_INFO, "client_initiate_connection: Initiating connection...");
     } else {
         UDPC_CHECK_LOG(c, UDPC_LoggingType::UDPC_ERROR, "client_initiate_connection: Already connected to peer");
     }
 }
 
-int UDPC_get_queue_send_available(UDPC_HContext ctx) {
-    UDPC::Context *c = UDPC::verifyContext(ctx);
-    if(!c) {
-        return 0;
-    }
-
-    return c->cSendPkts.remaining_capacity();
-}
-
 void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
                      int isChecked, void *data, uint32_t size) {
     if(size == 0 || !data) {
@@ -1252,15 +1273,6 @@ void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
     UDPC::Context *c = UDPC::verifyContext(ctx);
     if(!c) {
         return;
-    } else if(c->cSendPkts.full()) {
-        UDPC_CHECK_LOG(c,
-            UDPC_LoggingType::UDPC_ERROR,
-            "Failed to queue packet to ",
-            UDPC_atostr(ctx, destinationId.addr),
-            ", port = ",
-            destinationId.port,
-            " because queue is full");
-        return;
     }
 
     UDPC_PacketInfo sendInfo = UDPC::get_empty_pinfo();
@@ -1275,6 +1287,15 @@ void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
     c->cSendPkts.push(sendInfo);
 }
 
+unsigned long UDPC_get_queue_send_current_size(UDPC_HContext ctx) {
+    UDPC::Context *c = UDPC::verifyContext(ctx);
+    if(!c) {
+        return 0;
+    }
+
+    return c->cSendPkts.size();
+}
+
 int UDPC_set_accept_new_connections(UDPC_HContext ctx, int isAccepting) {
     UDPC::Context *c = UDPC::verifyContext(ctx);
     if(!c) {
@@ -1386,7 +1407,7 @@ UDPC_LoggingType UDPC_set_logging_type(UDPC_HContext ctx, UDPC_LoggingType loggi
     return static_cast<UDPC_LoggingType>(c->loggingType.exchange(loggingType));
 }
 
-UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx, unsigned int *remaining) {
+UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx, unsigned long *remaining) {
     UDPC::Context *c = UDPC::verifyContext(ctx);
     if(!c) {
         return UDPC::get_empty_pinfo();
@@ -1399,25 +1420,6 @@ UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx, unsigned int *remaining) {
     return UDPC::get_empty_pinfo();
 }
 
-int UDPC_set_received_capacity(UDPC_HContext ctx, unsigned int newCapacity) {
-    if(newCapacity == 0) {
-        return 0;
-    }
-
-    UDPC::Context *c = UDPC::verifyContext(ctx);
-    if(!c) {
-        return 0;
-    }
-
-    unsigned int status = 0;
-    c->receivedPkts.changeCapacity(newCapacity, &status);
-    if(status == 1) {
-        UDPC_CHECK_LOG(c, UDPC_LoggingType::UDPC_WARNING,
-            "Received Queue: Previous size was truncated to new capacity");
-    }
-    return 1;
-}
-
 const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId) {
     return UDPC_atostr(ctx, connectionId.addr);
 }
index 1783f3168742fcc2b7633e664e7391f8dcf9ac35..c5c7bae72ec71009e29dd8afb11170d1fec0c553 100644 (file)
@@ -65,7 +65,7 @@ extern "C" {
 struct UDPC_Context;
 typedef struct UDPC_Context *UDPC_HContext;
 
-typedef enum { UDPC_SILENT, UDPC_ERROR, UDPC_WARNING, UDPC_VERBOSE, UDPC_INFO } UDPC_LoggingType;
+typedef enum { UDPC_SILENT, UDPC_ERROR, UDPC_WARNING, UDPC_INFO, UDPC_VERBOSE, UDPC_DEBUG } UDPC_LoggingType;
 
 typedef struct {
     UDPC_IPV6_ADDR_TYPE addr;
@@ -105,11 +105,11 @@ void UDPC_update(UDPC_HContext ctx);
 
 void UDPC_client_initiate_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
 
-int UDPC_get_queue_send_available(UDPC_HContext ctx);
-
 void UDPC_queue_send(UDPC_HContext ctx, UDPC_ConnectionId destinationId,
                      int isChecked, void *data, uint32_t size);
 
+unsigned long UDPC_get_queue_send_current_size(UDPC_HContext ctx);
+
 int UDPC_set_accept_new_connections(UDPC_HContext ctx, int isAccepting);
 
 int UDPC_drop_connection(UDPC_HContext ctx, UDPC_ConnectionId connectionId, bool dropAllWithAddr);
@@ -124,9 +124,7 @@ uint32_t UDPC_set_protocol_id(UDPC_HContext ctx, uint32_t id);
 
 UDPC_LoggingType UDPC_set_logging_type(UDPC_HContext ctx, UDPC_LoggingType loggingType);
 
-UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx, unsigned int *remaining);
-
-int UDPC_set_received_capacity(UDPC_HContext ctx, unsigned int newCapacity);
+UDPC_PacketInfo UDPC_get_received(UDPC_HContext ctx, unsigned long *remaining);
 
 const char *UDPC_atostr_cid(UDPC_HContext ctx, UDPC_ConnectionId connectionId);
 
index 9fa55565372a31f3f98d0de94ea661b65bb86823..876cf525cf7652351da0fe898262160eb3494e74 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <UDPConnection.h>
 
+#define QUEUED_MAX_SIZE 32
+
 static const std::regex ipv6_regex_linkonly = std::regex(R"d(fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,})d");
 
 void usage() {
@@ -18,6 +20,7 @@ void usage() {
     puts("-cp <port> - connection port (client only)");
     puts("-t <tick_count>");
     puts("-n - do not add payload to packets");
+    puts("-l (silent|error|warning|info|verbose|debug) - log level, default debug");
 }
 
 int main(int argc, char **argv) {
@@ -34,6 +37,7 @@ int main(int argc, char **argv) {
     const char *connectionPort = nullptr;
     unsigned int tickLimit = 15;
     bool noPayload = false;
+    UDPC_LoggingType logLevel = UDPC_LoggingType::UDPC_DEBUG;
     while(argc > 0) {
         if(std::strcmp(argv[0], "-c") == 0) {
             isClient = true;
@@ -58,6 +62,26 @@ int main(int argc, char **argv) {
         } else if(std::strcmp(argv[0], "-n") == 0) {
             noPayload = true;
             puts("Disabling sending payload");
+        } else if(std::strcmp(argv[0], "-l") == 0) {
+            --argc; ++argv;
+            if(std::strcmp(argv[0], "silent") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_SILENT;
+            } else if(std::strcmp(argv[0], "error") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_ERROR;
+            } else if(std::strcmp(argv[0], "warning") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_WARNING;
+            } else if(std::strcmp(argv[0], "info") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_INFO;
+            } else if(std::strcmp(argv[0], "verbose") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_VERBOSE;
+            } else if(std::strcmp(argv[0], "debug") == 0) {
+                logLevel = UDPC_LoggingType::UDPC_DEBUG;
+            } else {
+                printf("ERROR: invalid argument \"%s\", expected "
+                    "silent|error|warning|info|verbose|debug", argv[0]);
+                usage();
+                return 1;
+            }
         } else {
             printf("ERROR: invalid argument \"%s\"\n", argv[0]);
             usage();
@@ -106,10 +130,11 @@ int main(int argc, char **argv) {
         puts("ERROR: context is NULL");
         return 1;
     }
-    UDPC_set_logging_type(context, UDPC_LoggingType::UDPC_INFO);
+    UDPC_set_logging_type(context, logLevel);
     unsigned int tick = 0;
     unsigned int temp = 0;
     unsigned int temp2, temp3;
+    unsigned long size;
     UDPC_ConnectionId *list = nullptr;
     std::vector<unsigned int> sendIds;
     UDPC_PacketInfo received;
@@ -126,7 +151,8 @@ int main(int argc, char **argv) {
                 } else if(sendIds.size() > temp) {
                     sendIds.resize(temp);
                 }
-                temp2 = UDPC_get_queue_send_available(context);
+                size = UDPC_get_queue_send_current_size(context);
+                temp2 = size < QUEUED_MAX_SIZE ? QUEUED_MAX_SIZE - size : 0;
                 for(unsigned int i = 0; i < temp2; ++i) {
                     temp3 = htonl(sendIds[i % temp]++);
                     UDPC_queue_send(context, list[i % temp], 0, &temp3, sizeof(unsigned int));
@@ -134,14 +160,14 @@ int main(int argc, char **argv) {
                 UDPC_free_list_connected(list);
             }
             do {
-                received = UDPC_get_received(context, &temp);
+                received = UDPC_get_received(context, &size);
                 if(received.dataSize == sizeof(unsigned int)) {
                     if((received.flags & 0x8) != 0) {
                         temp2 = ntohl(*((unsigned int*)received.data));
                         printf("Got out of order, data = %u\n", temp2);
                     }
                 }
-            } while (temp > 0);
+            } while (size > 0);
         }
         if(tick++ > tickLimit) {
             break;