1 module libtun.adapter;
2 
3 extern (C) int ioctl(int fd, ulong request, void* data);
4 extern (C) int open(char* path, int flags);
5 
6 import core.stdc.stdio;
7 
8 
9 /**
10 * TUN maintenance routines in `tunctl.c`
11 */
12 extern (C) int createTun(char* interfaceName, int iffFlags);
13 extern (C) int destroyTun(int fd);
14 extern (C) int tunWrite(int fd, char* data, int length);
15 extern (C) int tunRead(int fd, char* data, int amount);
16 
17 public class TUNAdapter
18 {
19     /* Tunnel device descriptor */
20     private int tunFD;
21     private bool isClosed;
22 
23     /* Temporary scratchpad buffer */
24     private byte[] scratch;
25         
26 
27     this(string interfaceName, AdapterType adapterType = AdapterType.TAP)
28     {
29         init(interfaceName, adapterType);
30     }
31 
32     private void init(string interfaceName, AdapterType adapterType)
33     {
34         tunFD = createTun(cast(char*)interfaceName, 4096|adapterType);
35         if(tunFD < 0)
36         {
37             throw new TUNException("Error creating tun device");
38         }
39 
40         /* TODO: Get device MTU and add functions for setting it */
41         ushort mtu = cast(ushort)-1;
42         scratch.length = mtu;
43     }
44 
45     private void sanityCheck()
46     {
47         if(isClosed)
48         {
49             throw new TUNException("Cannot operate on closed tunnel device");
50         }
51     }
52 
53     public void close()
54     {
55         sanityCheck();
56 
57         isClosed = true;
58         destroyTun(tunFD);
59     }
60 
61     
62     public void receive(ref byte[] buffer)
63     {
64         sanityCheck();
65 
66         
67 
68         /**
69         * We read with a request of maximum possible
70         * Ethernet frame size (-1 -> 2 bytes) 65535,
71         * this ensures our buffer fills up in all cases
72         * but we get returned either < 0 or > 0.
73         *
74         * Former, systemcall read error
75         * Latter, ethernet frame size
76         */
77         int status = tunRead(tunFD, cast(char*)scratch.ptr, cast(int)scratch.length);
78 
79       
80         if(status < 0)
81         {
82             throw new TUNException("Read failed");
83         }
84         else if(status == 0)
85         {
86             assert(false);
87         }
88         else
89         {
90             /* Copy the data into their buffer (and of correct length) */
91             buffer = scratch[0..status].dup;
92         }
93 
94         
95 
96       
97 
98 
99 
100 
101         
102     }
103 
104     public void send(byte[] buffer)
105     {
106         sanityCheck();
107 
108         tunWrite(tunFD, cast(char*)buffer.ptr, cast(int)buffer.length);
109     }
110 
111 
112     public void setDeviceMTU(ushort mtu)
113     {
114         /* TODO: Set the MTU on the device */
115 
116         /* TODO: Set the scratchpad to match the MTU */
117         scratch.length = mtu;
118     }
119 
120    
121 }
122 
123 public final class TUNException : Exception
124 {
125     this(string msg)
126     {
127         super(msg);
128     }
129 }
130 
131 public enum AdapterType : byte
132 {
133     TUN = 1,
134     TAP = 2
135 }