Sfoglia il codice sorgente

BTap: use a simple send function instead of PacketPassInterface; we send packets immediately anyway.

ambrop7 14 anni fa
parent
commit
5b094de8b0
7 ha cambiato i file con 94 aggiunte e 300 eliminazioni
  1. 13 118
      client/DPReceive.c
  2. 5 13
      client/DPReceive.h
  3. 1 6
      client/client.c
  4. 13 30
      tun2socks/tun2socks.c
  5. 0 4
      tun2socks/tun2socks.h
  6. 50 115
      tuntap/BTap.c
  7. 12 14
      tuntap/BTap.h

+ 13 - 118
client/DPReceive.c

@@ -146,11 +146,12 @@ static void receiver_recv_handler_send (DPReceiveReceiver *o, uint8_t *packet, i
     }
     
 out:
-    // pass packet to device or accept right away
+    // accept packet
+    PacketPassInterface_Done(&o->recv_if);
+    
+    // pass packet to device
     if (local) {
-        PacketPassInterface_Sender_Send(o->qflow_if, data, data_len);
-    } else {
-        PacketPassInterface_Done(&o->recv_if);
+        o->device->output_func(o->device->output_func_user, data, data_len);
     }
     
     // relay frame
@@ -159,49 +160,20 @@ out:
     }
 }
 
-static void receiver_qflow_handler_done (DPReceiveReceiver *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->peer)
-    
-    PacketPassInterface_Done(&o->recv_if);
-}
-
-static void device_call_forgotten_cb (DPReceiveDevice *o)
+int DPReceiveDevice_Init (DPReceiveDevice *o, int device_mtu, DPReceiveDevice_output_func output_func, void *output_func_user, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time)
 {
-    ASSERT(o->forgotten_receiver)
-    
-    DPReceiveReceiver *r = o->forgotten_receiver;
-    ASSERT(!r->peer)
-    
-    r->forgotten_cb(r->forgotten_user);
-    
-    ASSERT(!o->forgotten_receiver)
-}
-
-static void receiver_qflow_handler_busy (DPReceiveReceiver *o)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(!o->peer)
-    DPReceiveDevice *device = o->device;
-    ASSERT(device->forgotten_receiver == o)
-    
-    device_call_forgotten_cb(device);
-}
-
-int DPReceiveDevice_Init (DPReceiveDevice *o, PacketPassInterface *output, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time)
-{
-    ASSERT(PacketPassInterface_GetMTU(output) <= INT_MAX - DATAPROTO_MAX_OVERHEAD)
+    ASSERT(device_mtu >= 0)
+    ASSERT(device_mtu <= INT_MAX - DATAPROTO_MAX_OVERHEAD)
     ASSERT(relay_flow_buffer_size > 0)
     
     // init arguments
+    o->device_mtu = device_mtu;
+    o->output_func = output_func;
+    o->output_func_user = output_func_user;
     o->reactor = reactor;
     o->relay_flow_buffer_size = relay_flow_buffer_size;
     o->relay_flow_inactivity_time = relay_flow_inactivity_time;
     
-    // remember device MTU
-    o->device_mtu = PacketPassInterface_GetMTU(output);
-    
     // remember packet MTU
     o->packet_mtu = DATAPROTO_MAX_OVERHEAD + o->device_mtu;
     
@@ -211,9 +183,6 @@ int DPReceiveDevice_Init (DPReceiveDevice *o, PacketPassInterface *output, BReac
         goto fail0;
     }
     
-    // init queue
-    PacketPassFairQueue_Init(&o->queue, output, BReactor_PendingGroup(o->reactor), 0, 1);
-    
     // have no peer ID
     o->have_peer_id = 0;
     
@@ -223,9 +192,6 @@ int DPReceiveDevice_Init (DPReceiveDevice *o, PacketPassInterface *output, BReac
     // init peers list
     LinkedList2_Init(&o->peers_list);
     
-    // set no forgotten receiver
-    o->forgotten_receiver = NULL;
-    
     DebugObject_Init(&o->d_obj);
     return 1;
     
@@ -236,32 +202,12 @@ fail0:
 void DPReceiveDevice_Free (DPReceiveDevice *o)
 {
     DebugObject_Free(&o->d_obj);
-    ASSERT(!o->forgotten_receiver)
     ASSERT(LinkedList2_IsEmpty(&o->peers_list))
     
-    // free queue
-    PacketPassFairQueue_Free(&o->queue);
-    
     // free relay router
     DPRelayRouter_Free(&o->relay_router);
 }
 
-void DPReceiveDevice_PrepareFree (DPReceiveDevice *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    // prepare queue for freeing
-    PacketPassFairQueue_PrepareFree(&o->queue);
-    
-    // set freeing
-    o->freeing = 1;
-    
-    // call callback for forgotten receiver
-    if (o->forgotten_receiver) {
-        device_call_forgotten_cb(o);
-    }
-}
-
 void DPReceiveDevice_SetPeerID (DPReceiveDevice *o, peerid_t peer_id)
 {
     DebugObject_Access(&o->d_obj);
@@ -342,45 +288,26 @@ void DPReceiveReceiver_Init (DPReceiveReceiver *o, DPReceivePeer *peer)
     DebugObject_Access(&peer->d_obj);
     DPReceiveDevice *device = peer->device;
     
-    // remember peer
+    // init arguments
     o->peer = peer;
     
     // remember device
     o->device = device;
     
-    // init queue flow
-    PacketPassFairQueueFlow_Init(&o->qflow, &device->queue);
-    o->qflow_if = PacketPassFairQueueFlow_GetInput(&o->qflow);
-    PacketPassInterface_Sender_Init(o->qflow_if, (PacketPassInterface_handler_done)receiver_qflow_handler_done, o);
-    
     // init receive interface
     PacketPassInterface_Init(&o->recv_if, device->packet_mtu, (PacketPassInterface_handler_send)receiver_recv_handler_send, o, BReactor_PendingGroup(device->reactor));
     
-    // increment peer's receivers counter
     DebugCounter_Increment(&peer->d_receivers_ctr);
-    
     DebugObject_Init(&o->d_obj);
 }
 
 void DPReceiveReceiver_Free (DPReceiveReceiver *o)
 {
     DebugObject_Free(&o->d_obj);
-    PacketPassFairQueueFlow_AssertFree(&o->qflow);
-    
-    if (o->peer) {
-        // decrement peer's receivers counter
-        DebugCounter_Decrement(&o->peer->d_receivers_ctr);
-    } else {
-        // clear forgotten receiver reference in the device
-        ASSERT(o->device->forgotten_receiver == o)
-        o->device->forgotten_receiver = NULL;
-    }
+    DebugCounter_Decrement(&o->peer->d_receivers_ctr);
     
     // free receive interface
     PacketPassInterface_Free(&o->recv_if);
-    
-    // free queue flow
-    PacketPassFairQueueFlow_Free(&o->qflow);
 }
 
 PacketPassInterface * DPReceiveReceiver_GetInput (DPReceiveReceiver *o)
@@ -389,35 +316,3 @@ PacketPassInterface * DPReceiveReceiver_GetInput (DPReceiveReceiver *o)
     
     return &o->recv_if;
 }
-
-int DPReceiveReceiver_IsBusy (DPReceiveReceiver *o)
-{
-    DebugObject_Access(&o->d_obj);
-    
-    return (o->device->freeing ? 0 : PacketPassFairQueueFlow_IsBusy(&o->qflow));
-}
-
-void DPReceiveReceiver_Forget (DPReceiveReceiver *o, DPReceiveReceiver_forgotten_cb forgotten_cb, void *user)
-{
-    DebugObject_Access(&o->d_obj);
-    ASSERT(o->peer)
-    ASSERT(!o->device->freeing)
-    ASSERT(PacketPassFairQueueFlow_IsBusy(&o->qflow))
-    
-    // decrement peer's receivers counter
-    DebugCounter_Decrement(&o->peer->d_receivers_ctr);
-    
-    // add forgotten receiver reference in the device
-    ASSERT(!o->device->forgotten_receiver)
-    o->device->forgotten_receiver = o;
-    
-    // set queue flow's busy handler
-    PacketPassFairQueueFlow_SetBusyHandler(&o->qflow, (PacketPassFairQueue_handler_busy)receiver_qflow_handler_busy, o);
-    
-    // remember callback
-    o->forgotten_cb = forgotten_cb;
-    o->forgotten_user = user;
-    
-    // forget peer
-    o->peer = NULL;
-}

+ 5 - 13
client/DPReceive.h

@@ -32,28 +32,27 @@
 #include <misc/debug.h>
 #include <structure/LinkedList2.h>
 #include <base/DebugObject.h>
-#include <flow/PacketPassFairQueue.h>
 #include <client/DataProto.h>
 #include <client/DPRelay.h>
 #include <client/FrameDecider.h>
 
-typedef void (*DPReceiveReceiver_forgotten_cb) (void *user);
+typedef void (*DPReceiveDevice_output_func) (void *output_user, uint8_t *data, int data_len);
 
 struct DPReceiveReceiver_s;
 
 typedef struct {
+    int device_mtu;
+    DPReceiveDevice_output_func output_func;
+    void *output_func_user;
     BReactor *reactor;
     int relay_flow_buffer_size;
     int relay_flow_inactivity_time;
-    int device_mtu;
     int packet_mtu;
     DPRelayRouter relay_router;
-    PacketPassFairQueue queue;
     int have_peer_id;
     peerid_t peer_id;
     int freeing;
     LinkedList2 peers_list;
-    struct DPReceiveReceiver_s *forgotten_receiver;
     DebugObject d_obj;
 } DPReceiveDevice;
 
@@ -73,17 +72,12 @@ typedef struct {
 typedef struct DPReceiveReceiver_s {
     DPReceivePeer *peer;
     DPReceiveDevice *device;
-    PacketPassFairQueueFlow qflow;
-    PacketPassInterface *qflow_if;
     PacketPassInterface recv_if;
-    DPReceiveReceiver_forgotten_cb forgotten_cb;
-    void *forgotten_user;
     DebugObject d_obj;
 } DPReceiveReceiver;
 
-int DPReceiveDevice_Init (DPReceiveDevice *o, PacketPassInterface *output, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time) WARN_UNUSED;
+int DPReceiveDevice_Init (DPReceiveDevice *o, int device_mtu, DPReceiveDevice_output_func output_func, void *output_func_user, BReactor *reactor, int relay_flow_buffer_size, int relay_flow_inactivity_time) WARN_UNUSED;
 void DPReceiveDevice_Free (DPReceiveDevice *o);
-void DPReceiveDevice_PrepareFree (DPReceiveDevice *o);
 void DPReceiveDevice_SetPeerID (DPReceiveDevice *o, peerid_t peer_id);
 
 void DPReceivePeer_Init (DPReceivePeer *o, DPReceiveDevice *device, peerid_t peer_id, FrameDeciderPeer *decider_peer, int is_relay_client);
@@ -94,7 +88,5 @@ void DPReceivePeer_DetachSink (DPReceivePeer *o);
 void DPReceiveReceiver_Init (DPReceiveReceiver *o, DPReceivePeer *peer);
 void DPReceiveReceiver_Free (DPReceiveReceiver *o);
 PacketPassInterface * DPReceiveReceiver_GetInput (DPReceiveReceiver *o);
-int DPReceiveReceiver_IsBusy (DPReceiveReceiver *o);
-void DPReceiveReceiver_Forget (DPReceiveReceiver *o, DPReceiveReceiver_forgotten_cb forgotten_cb, void *user);
 
 #endif

+ 1 - 6
client/client.c

@@ -492,7 +492,7 @@ int main (int argc, char *argv[])
     }
     
     // init device output
-    if (!DPReceiveDevice_Init(&device_output_dprd, BTap_GetInput(&device), &ss, options.send_buffer_relay_size, PEER_RELAY_FLOW_INACTIVITY_TIME)) {
+    if (!DPReceiveDevice_Init(&device_output_dprd, device_mtu, (DPReceiveDevice_output_func)BTap_Send, &device, &ss, options.send_buffer_relay_size, PEER_RELAY_FLOW_INACTIVITY_TIME)) {
         BLog(BLOG_ERROR, "DPReceiveDevice_Init failed");
         goto fail7a;
     }
@@ -530,9 +530,6 @@ int main (int argc, char *argv[])
     BLog(BLOG_NOTICE, "entering event loop");
     BReactor_Exec(&ss);
     
-    // allow freeing receive receivers in peers' links
-    DPReceiveDevice_PrepareFree(&device_output_dprd);
-    
     // free peers
     LinkedList2Node *node;
     while (node = LinkedList2_GetFirst(&peers)) {
@@ -1525,8 +1522,6 @@ void peer_free_link (struct peer_data *peer)
     ASSERT(!peer->relaying_peer)
     ASSERT(!peer->waiting_relay)
     
-    ASSERT(!DPReceiveReceiver_IsBusy(&peer->receive_receiver)) // TODO
-    
     // detach receive peer from our DataProtoSink
     DPReceivePeer_DetachSink(&peer->receive_peer);
     

+ 13 - 30
tun2socks/tun2socks.c

@@ -34,14 +34,13 @@
 #include <misc/ipv4_proto.h>
 #include <misc/udp_proto.h>
 #include <misc/byteorder.h>
+#include <misc/balloc.h>
 #include <structure/LinkedList2.h>
 #include <base/BLog.h>
 #include <system/BReactor.h>
 #include <system/BSignal.h>
 #include <system/BAddr.h>
 #include <system/BNetwork.h>
-#include <flow/PacketBuffer.h>
-#include <flow/BufferWriter.h>
 #include <flow/SinglePacketBuffer.h>
 #include <socksclient/BSocksClient.h>
 #include <tuntap/BTap.h>
@@ -140,9 +139,8 @@ int quitting;
 // TUN device
 BTap device;
 
-// device writing
-BufferWriter device_write_writer;
-PacketBuffer device_write_buffer;
+// device write buffer
+uint8_t *device_write_buf;
 
 // device reading
 SinglePacketBuffer device_read_buffer;
@@ -322,10 +320,9 @@ int main (int argc, char **argv)
     BPending_Init(&lwip_init_job, BReactor_PendingGroup(&ss), lwip_init_job_hadler, NULL);
     BPending_Set(&lwip_init_job);
     
-    // init device writing
-    BufferWriter_Init(&device_write_writer, BTap_GetMTU(&device), BReactor_PendingGroup(&ss));
-    if (!PacketBuffer_Init(&device_write_buffer, BufferWriter_GetOutput(&device_write_writer), BTap_GetInput(&device), DEVICE_WRITE_BUFFER_SIZE, BReactor_PendingGroup(&ss))) {
-        BLog(BLOG_ERROR, "PacketBuffer_Init failed");
+    // init device write buffer
+    if (!(device_write_buf = BAlloc(BTap_GetMTU(&device)))) {
+        BLog(BLOG_ERROR, "BAlloc failed");
         goto fail5;
     }
     
@@ -368,9 +365,8 @@ int main (int argc, char **argv)
     }
     
     BReactor_RemoveTimer(&ss, &tcp_timer);
-    PacketBuffer_Free(&device_write_buffer);
+    BFree(device_write_buf);
 fail5:
-    BufferWriter_Free(&device_write_writer);
     BPending_Free(&lwip_init_job);
     if (options.udpgw_remote_server_addr) {
         SocksUdpGwClient_Free(&udpgw_client);
@@ -897,12 +893,6 @@ err_t netif_output_func (struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
         return ERR_OK;
     }
     
-    uint8_t *out;
-    if (!BufferWriter_StartPacket(&device_write_writer, &out)) {
-        BLog(BLOG_ERROR, "netif func output: BufferWriter_StartPacket failed");
-        return ERR_OK;
-    }
-    
     int len = 0;
     while (p) {
         int remain = BTap_GetMTU(&device) - len;
@@ -910,13 +900,13 @@ err_t netif_output_func (struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr)
             BLog(BLOG_WARNING, "netif func output: no space left");
             break;
         }
-        memcpy(out + len, p->payload, p->len);
+        memcpy(device_write_buf + len, p->payload, p->len);
         len += p->len;
         p = p->next;
     }
     
     SYNC_FROMHERE
-    BufferWriter_EndPacket(&device_write_writer, len);
+    BTap_Send(&device, device_write_buf, len);
     SYNC_COMMIT
     
     return ERR_OK;
@@ -1480,15 +1470,8 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote
     
     BLog(BLOG_INFO, "UDP: from udpgw %d bytes", data_len);
     
-    // obtain buffer location
-    uint8_t *out;
-    if (!BufferWriter_StartPacket(&device_write_writer, &out)) {
-        BLog(BLOG_ERROR, "UDP: out of device buffer");
-        return;
-    }
-    
     // write IP header
-    struct ipv4_header *iph = (struct ipv4_header *)out;
+    struct ipv4_header *iph = (struct ipv4_header *)device_write_buf;
     iph->version4_ihl4 = IPV4_MAKE_VERSION_IHL(sizeof(*iph));
     iph->ds = hton8(0);
     iph->total_length = hton16(sizeof(*iph) + sizeof(struct udp_header) + data_len);
@@ -1505,19 +1488,19 @@ void udpgw_client_handler_received (void *unused, BAddr local_addr, BAddr remote
     iph->checksum = checksum;
     
     // write UDP header
-    struct udp_header *udph = (struct udp_header *)(out + sizeof(*iph));
+    struct udp_header *udph = (struct udp_header *)(device_write_buf + sizeof(*iph));
     udph->source_port = remote_addr.ipv4.port;
     udph->dest_port = local_addr.ipv4.port;
     udph->length = hton16(sizeof(*udph) + data_len);
     udph->checksum = hton16(0);
     
     // write data
-    memcpy(out + sizeof(*iph) + sizeof(struct udp_header), data, data_len);
+    memcpy(device_write_buf + sizeof(*iph) + sizeof(struct udp_header), data, data_len);
     
     // compute checksum
     checksum = udp_checksum((uint8_t *)udph, sizeof(*udph) + data_len, iph->source_address, iph->destination_address);
     udph->checksum = checksum;
     
     // submit packet
-    BufferWriter_EndPacket(&device_write_writer, sizeof(*iph) + sizeof(*udph) + data_len);
+    BTap_Send(&device, device_write_buf, sizeof(*iph) + sizeof(*udph) + data_len);
 }

+ 0 - 4
tun2socks/tun2socks.h

@@ -23,10 +23,6 @@
 // name of the program
 #define PROGRAM_NAME "tun2socks"
 
-// device write buffer size, in number of packets
-// WARNING: each packet takes at least 65535 bytes
-#define DEVICE_WRITE_BUFFER_SIZE 1
-
 // size of temporary buffer for passing data from the SOCKS server to TCP for sending
 #define CLIENT_SOCKS_RECV_BUF_SIZE 8192
 

+ 50 - 115
tuntap/BTap.c

@@ -56,7 +56,6 @@
 #include <generated/blog_channel_BTap.h>
 
 static void report_error (BTap *o);
-static void input_handler_send (BTap *o, uint8_t *data, int data_len);
 static void output_handler_recv (BTap *o, uint8_t *data);
 
 #ifdef BADVPN_USE_WINAPI
@@ -94,34 +93,6 @@ static void fd_handler (BTap *o, int events)
         BLog(BLOG_WARNING, "device fd reports error?");
     }
     
-    if (events&BREACTOR_WRITE) do {
-        ASSERT(o->input_packet_len >= 0)
-        
-        int bytes = write(o->fd, o->input_packet, o->input_packet_len);
-        if (bytes < 0) {
-            if (errno == EAGAIN || errno == EWOULDBLOCK) {
-                // retry later
-                break;
-            }
-            // malformed packets will cause errors, ignore them and act like
-            // the packet was accepeted
-        } else {
-            if (bytes != o->input_packet_len) {
-                BLog(BLOG_WARNING, "written %d expected %d", bytes, o->input_packet_len);
-            }
-        }
-        
-        // set no input packet
-        o->input_packet_len = -1;
-        
-        // update events
-        o->poll_events &= ~BREACTOR_WRITE;
-        BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->poll_events);
-        
-        // inform sender we finished the packet
-        PacketPassInterface_Done(&o->input);
-    } while (0);
-    
     if (events&BREACTOR_READ) do {
         ASSERT(o->output_packet)
         
@@ -158,74 +129,6 @@ void report_error (BTap *o)
     DEBUGERROR(&o->d_err, o->handler_error(o->handler_error_user));
 }
 
-void input_handler_send (BTap *o, uint8_t *data, int data_len)
-{
-    ASSERT(data_len >= 0)
-    ASSERT(data_len <= o->frame_mtu)
-    ASSERT(o->input_packet_len == -1)
-    DebugError_AssertNoError(&o->d_err);
-    DebugObject_Access(&o->d_obj);
-    
-    #ifdef BADVPN_USE_WINAPI
-    
-    // ignore frames without an Ethernet header, or we get errors in WriteFile
-    if (data_len < 14) {
-        goto accept;
-    }
-    
-    memset(&o->send_olap.olap, 0, sizeof(o->send_olap.olap));
-    
-    // write
-    BOOL res = WriteFile(o->device, data, data_len, NULL, &o->send_olap.olap);
-    if (res == FALSE && GetLastError() != ERROR_IO_PENDING) {
-        BLog(BLOG_ERROR, "WriteFile failed (%u)", GetLastError());
-        goto accept;
-    }
-    
-    // wait
-    int succeeded;
-    DWORD bytes;
-    BReactorIOCPOverlapped_Wait(&o->send_olap, &succeeded, &bytes);
-    
-    if (!succeeded) {
-        BLog(BLOG_ERROR, "write operation failed");
-    } else {
-        ASSERT(bytes >= 0)
-        ASSERT(bytes <= data_len)
-        
-        if (bytes < data_len) {
-            BLog(BLOG_ERROR, "write operation didn't write everything");
-        }
-    }
-    
-    #else
-    
-    int bytes = write(o->fd, data, data_len);
-    if (bytes < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            // retry later in fd_handler
-            // remember packet
-            o->input_packet = data;
-            o->input_packet_len = data_len;
-            // update events
-            o->poll_events |= BREACTOR_WRITE;
-            BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->poll_events);
-            return;
-        }
-        // malformed packets will cause errors, ignore them and act like
-        // the packet was accepeted
-    } else {
-        if (bytes != data_len) {
-            BLog(BLOG_WARNING, "written %d expected %d", bytes, data_len);
-        }
-    }
-    
-    #endif
-    
-accept:
-    PacketPassInterface_Done(&o->input);
-}
-
 void output_handler_recv (BTap *o, uint8_t *data)
 {
     ASSERT(data)
@@ -507,15 +410,9 @@ fail0:
     #endif
     
 success:
-    // init input
-    PacketPassInterface_Init(&o->input, o->frame_mtu, (PacketPassInterface_handler_send)input_handler_send, o, BReactor_PendingGroup(o->reactor));
-    
     // init output
     PacketRecvInterface_Init(&o->output, o->frame_mtu, (PacketRecvInterface_handler_recv)output_handler_recv, o, BReactor_PendingGroup(o->reactor));
     
-    // set no input packet
-    o->input_packet_len = -1;
-    
     // set no output packet
     o->output_packet = NULL;
     
@@ -533,9 +430,6 @@ void BTap_Free (BTap *o)
     // free output
     PacketRecvInterface_Free(&o->output);
     
-    // free input
-    PacketPassInterface_Free(&o->input);
-    
 #ifdef BADVPN_USE_WINAPI
     
     // cancel I/O
@@ -543,16 +437,10 @@ void BTap_Free (BTap *o)
     
     // wait receiving to finish
     if (o->output_packet) {
-        BLog(BLOG_DEBUG, "waiting for sending to finish");
+        BLog(BLOG_DEBUG, "waiting for receiving to finish");
         BReactorIOCPOverlapped_Wait(&o->recv_olap, NULL, NULL);
     }
     
-    // wait sending to finish
-    if (o->input_packet_len >= 0) {
-        BLog(BLOG_DEBUG, "waiting for sending to finish");
-        BReactorIOCPOverlapped_Wait(&o->send_olap, NULL, NULL);
-    }
-    
     // free recv olap
     BReactorIOCPOverlapped_Free(&o->recv_olap);
     
@@ -580,11 +468,58 @@ int BTap_GetMTU (BTap *o)
     return o->frame_mtu;
 }
 
-PacketPassInterface * BTap_GetInput (BTap *o)
+void BTap_Send (BTap *o, uint8_t *data, int data_len)
 {
     DebugObject_Access(&o->d_obj);
+    DebugError_AssertNoError(&o->d_err);
+    ASSERT(data_len >= 0)
+    ASSERT(data_len <= o->frame_mtu)
+    
+#ifdef BADVPN_USE_WINAPI
+    
+    // ignore frames without an Ethernet header, or we get errors in WriteFile
+    if (data_len < 14) {
+        return;
+    }
+    
+    memset(&o->send_olap.olap, 0, sizeof(o->send_olap.olap));
     
-    return &o->input;
+    // write
+    BOOL res = WriteFile(o->device, data, data_len, NULL, &o->send_olap.olap);
+    if (res == FALSE && GetLastError() != ERROR_IO_PENDING) {
+        BLog(BLOG_ERROR, "WriteFile failed (%u)", GetLastError());
+        return;
+    }
+    
+    // wait
+    int succeeded;
+    DWORD bytes;
+    BReactorIOCPOverlapped_Wait(&o->send_olap, &succeeded, &bytes);
+    
+    if (!succeeded) {
+        BLog(BLOG_ERROR, "write operation failed");
+    } else {
+        ASSERT(bytes >= 0)
+        ASSERT(bytes <= data_len)
+        
+        if (bytes < data_len) {
+            BLog(BLOG_ERROR, "write operation didn't write everything");
+        }
+    }
+    
+#else
+    
+    int bytes = write(o->fd, data, data_len);
+    if (bytes < 0) {
+        // malformed packets will cause errors, ignore them and act like
+        // the packet was accepeted
+    } else {
+        if (bytes != data_len) {
+            BLog(BLOG_WARNING, "written %d expected %d", bytes, data_len);
+        }
+    }
+    
+#endif
 }
 
 PacketRecvInterface * BTap_GetOutput (BTap *o)

+ 12 - 14
tuntap/BTap.h

@@ -43,27 +43,24 @@
 #include <base/DebugObject.h>
 #include <system/BReactor.h>
 #include <flow/PacketRecvInterface.h>
-#include <flow/PacketPassInterface.h>
 
 #define BTAP_ETHERNET_HEADER_LENGTH 14
 
-typedef void (*BTap_handler_error) (void *used);
-
 /**
- * TAP device abstraction.
+ * Handler called when an error occurs on the device.
+ * The object must be destroyed from the job context of this
+ * handler, and no further I/O may occur.
  * 
- * Frames are written to the device using {@link PacketPassInterface}
- * and read from the device using {@link PacketRecvInterface}.
+ * @param user as in {@link BTap_Init}
  */
+typedef void (*BTap_handler_error) (void *used);
+
 typedef struct {
     BReactor *reactor;
     BTap_handler_error handler_error;
     void *handler_error_user;
     int frame_mtu;
-    PacketPassInterface input;
     PacketRecvInterface output;
-    uint8_t *input_packet;
-    int input_packet_len;
     uint8_t *output_packet;
     
 #ifdef BADVPN_USE_WINAPI
@@ -119,13 +116,14 @@ void BTap_Free (BTap *o);
 int BTap_GetMTU (BTap *o);
 
 /**
- * Returns a {@link PacketPassInterface} for writing packets to the device.
- * The MTU of the interface will be {@link BTap_GetMTU}.
- *
+ * Sends a packet to the device.
+ * Any errors will be reported via a job.
+ * 
  * @param o the object
- * @return input interface
+ * @param data packet to send
+ * @param data_len length of packet. Must be >=0 and <=MTU, as reported by {@link BTap_GetMTU}.
  */
-PacketPassInterface * BTap_GetInput (BTap *o);
+void BTap_Send (BTap *o, uint8_t *data, int data_len);
 
 /**
  * Returns a {@link PacketRecvInterface} for reading packets from the device.