+ if(!len) {
+ return true;
+ }
+
+ if(!data) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ // Prepare the packet
+ vpn_packet_t *packet = malloc(sizeof(*packet));
+
+ if(!packet) {
+ meshlink_errno = MESHLINK_ENOMEM;
+ return false;
+ }
+
+ if(!prepare_packet(mesh, destination, data, len, packet)) {
+ free(packet);
+ return false;
+ }
+
+ // Queue it
+ if(!meshlink_queue_push(&mesh->outpacketqueue, packet)) {
+ free(packet);
+ meshlink_errno = MESHLINK_ENOMEM;
+ return false;
+ }
+
+ logger(mesh, MESHLINK_DEBUG, "Adding packet of %zu bytes to packet queue", len);
+
+ // Notify event loop
+ signal_trigger(&mesh->loop, &mesh->datafromapp);
+
+ return true;
+}
+
+void meshlink_send_from_queue(event_loop_t *loop, void *data) {
+ (void)loop;
+ meshlink_handle_t *mesh = data;
+
+ logger(mesh, MESHLINK_DEBUG, "Flushing the packet queue");
+
+ for(vpn_packet_t *packet; (packet = meshlink_queue_pop(&mesh->outpacketqueue));) {
+ logger(mesh, MESHLINK_DEBUG, "Removing packet of %d bytes from packet queue", packet->len);
+ mesh->self->in_packets++;
+ mesh->self->in_bytes += packet->len;
+ route(mesh, mesh->self, packet);
+ free(packet);
+ }
+}
+
+ssize_t meshlink_get_pmtu(meshlink_handle_t *mesh, meshlink_node_t *destination) {
+ if(!mesh || !destination) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return -1;
+ }
+
+ if(pthread_mutex_lock(&mesh->mutex) != 0) {
+ abort();
+ }
+
+ node_t *n = (node_t *)destination;