1
0

TAPInterface.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. // TODO(cjd): this is nasty, we need a wrapper.
  16. #include "util/events/libuv/UvWrapper.h"
  17. #include "util/events/libuv/EventBase_pvt.h"
  18. #include "exception/Except.h"
  19. #include "exception/WinFail.h"
  20. #include "memory/Allocator.h"
  21. #include "interface/tuntap/windows/TAPInterface.h"
  22. #include "interface/tuntap/windows/TAPDevice.h"
  23. #include "util/events/EventBase.h"
  24. #include "util/platform/netdev/NetDev.h"
  25. #include "wire/Error.h"
  26. #include "wire/Message.h"
  27. #include <stdio.h>
  28. #include <windows.h>
  29. #include <io.h>
  30. #define TAP_CONTROL_CODE(request,method) \
  31. CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
  32. #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
  33. #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
  34. #define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
  35. #define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
  36. #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
  37. #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
  38. #define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
  39. #define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
  40. #define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
  41. struct TAPInterface_Version_pvt {
  42. unsigned long major;
  43. unsigned long minor;
  44. unsigned long debug;
  45. };
  46. static void getVersion(HANDLE tap, struct TAPInterface_Version_pvt* version, struct Except* eh)
  47. {
  48. ULONG version_len;
  49. BOOL bret = DeviceIoControl(tap,
  50. TAP_IOCTL_GET_VERSION,
  51. version,
  52. sizeof(struct TAPInterface_Version_pvt),
  53. version,
  54. sizeof(struct TAPInterface_Version_pvt),
  55. &version_len,
  56. NULL);
  57. if (!bret) {
  58. DWORD err = GetLastError();
  59. CloseHandle(tap);
  60. WinFail_fail(eh, "DeviceIoControl(TAP_IOCTL_GET_VERSION)", err);
  61. }
  62. if (version_len != sizeof(struct TAPInterface_Version_pvt)) {
  63. CloseHandle(tap);
  64. Except_throw(eh, "DeviceIoControl(TAP_IOCTL_GET_VERSION) out size [%d] expected [%d]",
  65. (int)version_len, (int)sizeof(struct TAPInterface_Version_pvt));
  66. }
  67. }
  68. static void setEnabled(HANDLE tap, int status, struct Except* eh)
  69. {
  70. unsigned long len = 0;
  71. BOOL bret = DeviceIoControl(tap, TAP_IOCTL_SET_MEDIA_STATUS,
  72. &status, sizeof (status),
  73. &status, sizeof (status), &len, NULL);
  74. if (!bret) {
  75. DWORD err = GetLastError();
  76. CloseHandle(tap);
  77. WinFail_fail(eh, "DeviceIoControl(TAP_IOCTL_SET_MEDIA_STATUS)", err);
  78. }
  79. }
  80. #define WRITE_MESSAGE_SLOTS 20
  81. struct TAPInterface_pvt
  82. {
  83. struct TAPInterface pub;
  84. uv_iocp_t readIocp;
  85. struct Message* readMsg;
  86. uv_iocp_t writeIocp;
  87. struct Message* writeMsgs[WRITE_MESSAGE_SLOTS];
  88. /** This allocator holds messages pending write in memory until they are complete. */
  89. struct Allocator* pendingWritesAlloc;
  90. int writeMessageCount;
  91. int isPendingWrite;
  92. HANDLE handle;
  93. struct Log* log;
  94. struct Allocator* alloc;
  95. struct EventBase* base;
  96. Identity
  97. };
  98. static void readCallbackB(struct TAPInterface_pvt* tap);
  99. static void postRead(struct TAPInterface_pvt* tap)
  100. {
  101. struct Allocator* alloc = Allocator_child(tap->alloc);
  102. // Choose odd numbers so that the message will be aligned despite the weird header size.
  103. struct Message* msg = tap->readMsg = Message_new(1534, 514, alloc);
  104. OVERLAPPED* readol = (OVERLAPPED*) tap->readIocp.overlapped;
  105. if (!ReadFile(tap->handle, msg->bytes, 1534, NULL, readol)) {
  106. switch (GetLastError()) {
  107. case ERROR_IO_PENDING:
  108. case ERROR_IO_INCOMPLETE: break;
  109. default: Assert_failure("ReadFile(tap): %s\n", WinFail_strerror(GetLastError()));
  110. }
  111. } else {
  112. // It doesn't matter if it returns immediately, it will also return async.
  113. //Log_debug(tap->log, "Read returned immediately");
  114. }
  115. Log_debug(tap->log, "Posted read");
  116. }
  117. static void readCallbackB(struct TAPInterface_pvt* tap)
  118. {
  119. struct Message* msg = tap->readMsg;
  120. tap->readMsg = NULL;
  121. DWORD bytesRead;
  122. OVERLAPPED* readol = (OVERLAPPED*) tap->readIocp.overlapped;
  123. if (!GetOverlappedResult(tap->handle, readol, &bytesRead, FALSE)) {
  124. Assert_failure("GetOverlappedResult(read, tap): %s\n", WinFail_strerror(GetLastError()));
  125. }
  126. msg->length = bytesRead;
  127. Log_debug(tap->log, "Read [%d] bytes", msg->length);
  128. Iface_send(&tap->pub.generic, msg);
  129. Allocator_free(msg->alloc);
  130. postRead(tap);
  131. }
  132. static void readCallback(uv_iocp_t* readIocp)
  133. {
  134. struct TAPInterface_pvt* tap =
  135. Identity_check((struct TAPInterface_pvt*)
  136. (((char*)readIocp) - offsetof(struct TAPInterface_pvt, readIocp)));
  137. readCallbackB(tap);
  138. }
  139. static void writeCallbackB(struct TAPInterface_pvt* tap);
  140. static void postWrite(struct TAPInterface_pvt* tap)
  141. {
  142. Assert_true(!tap->isPendingWrite);
  143. tap->isPendingWrite = 1;
  144. struct Message* msg = tap->writeMsgs[0];
  145. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  146. if (!WriteFile(tap->handle, msg->bytes, msg->length, NULL, writeol)) {
  147. switch (GetLastError()) {
  148. case ERROR_IO_PENDING:
  149. case ERROR_IO_INCOMPLETE: break;
  150. default: Assert_failure("WriteFile(tap): %s\n", WinFail_strerror(GetLastError()));
  151. }
  152. } else {
  153. // It doesn't matter if it returns immediately, it will also return async.
  154. //Log_debug(tap->log, "Write returned immediately");
  155. }
  156. Log_debug(tap->log, "Posted write [%d] bytes", msg->length);
  157. }
  158. static void writeCallbackB(struct TAPInterface_pvt* tap)
  159. {
  160. DWORD bytesWritten;
  161. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  162. if (!GetOverlappedResult(tap->handle, writeol, &bytesWritten, FALSE)) {
  163. Assert_failure("GetOverlappedResult(write, tap): %s\n", WinFail_strerror(GetLastError()));
  164. }
  165. Assert_true(tap->isPendingWrite);
  166. tap->isPendingWrite = 0;
  167. Assert_true(tap->writeMessageCount--);
  168. struct Message* msg = tap->writeMsgs[0];
  169. if (msg->length != (int)bytesWritten) {
  170. Log_info(tap->log, "Message of length [%d] truncated to [%d]",
  171. msg->length, (int)bytesWritten);
  172. Assert_true(msg->length > (int)bytesWritten);
  173. }
  174. if (tap->writeMessageCount) {
  175. for (int i = 0; i < tap->writeMessageCount; i++) {
  176. tap->writeMsgs[i] = tap->writeMsgs[i+1];
  177. }
  178. postWrite(tap);
  179. } else {
  180. Log_debug(tap->log, "All pending writes are complete");
  181. Allocator_free(tap->pendingWritesAlloc);
  182. tap->pendingWritesAlloc = NULL;
  183. }
  184. }
  185. static void writeCallback(uv_iocp_t* writeIocp)
  186. {
  187. struct TAPInterface_pvt* tap =
  188. Identity_check((struct TAPInterface_pvt*)
  189. (((char*)writeIocp) - offsetof(struct TAPInterface_pvt, writeIocp)));
  190. writeCallbackB(tap);
  191. }
  192. static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
  193. {
  194. struct TAPInterface_pvt* tap = Identity_check((struct TAPInterface_pvt*) iface);
  195. if (tap->writeMessageCount >= WRITE_MESSAGE_SLOTS) {
  196. Log_info(tap->log, "DROP message because the tap is lagging");
  197. return 0;
  198. }
  199. if (!tap->pendingWritesAlloc) {
  200. tap->pendingWritesAlloc = Allocator_child(tap->alloc);
  201. }
  202. tap->writeMsgs[tap->writeMessageCount++] = msg;
  203. Allocator_adopt(tap->pendingWritesAlloc, msg->alloc);
  204. if (tap->writeMessageCount == 1) {
  205. postWrite(tap);
  206. }
  207. return 0;
  208. }
  209. struct TAPInterface* TAPInterface_new(const char* preferredName,
  210. struct Except* eh,
  211. struct Log* logger,
  212. struct EventBase* base,
  213. struct Allocator* alloc)
  214. {
  215. Log_debug(logger, "Getting TAP-Windows device name");
  216. struct TAPDevice* dev = TAPDevice_find(preferredName, eh, alloc);
  217. NetDev_flushAddresses(dev->name, eh);
  218. Log_debug(logger, "Opening TAP-Windows device [%s] at location [%s]", dev->name, dev->path);
  219. struct TAPInterface_pvt* tap = Allocator_calloc(alloc, sizeof(struct TAPInterface_pvt), 1);
  220. Identity_set(tap);
  221. tap->base = base;
  222. tap->alloc = alloc;
  223. tap->log = logger;
  224. tap->pub.assignedName = dev->name;
  225. tap->pub.generic.send = sendMessage;
  226. tap->handle = CreateFile(dev->path,
  227. GENERIC_READ | GENERIC_WRITE,
  228. 0,
  229. 0,
  230. OPEN_EXISTING,
  231. FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  232. 0);
  233. if (tap->handle == INVALID_HANDLE_VALUE) {
  234. WinFail_fail(eh, "CreateFile(tapDevice)", GetLastError());
  235. }
  236. struct EventBase_pvt* ebp = EventBase_privatize(tap->base);
  237. int ret;
  238. if ((ret = uv_iocp_start(ebp->loop, &tap->readIocp, tap->handle, readCallback))) {
  239. Except_throw(eh, "uv_iocp_start(readIocp): %s", uv_strerror(ret));
  240. }
  241. if ((ret = uv_iocp_start(ebp->loop, &tap->writeIocp, tap->handle, writeCallback))) {
  242. Except_throw(eh, "uv_iocp_start(writeIocp): %s", uv_strerror(ret));
  243. }
  244. struct TAPInterface_Version_pvt ver = { .major = 0 };
  245. getVersion(tap->handle, &ver, eh);
  246. setEnabled(tap->handle, 1, eh);
  247. Log_info(logger, "Opened TAP-Windows device [%s] version [%lu.%lu.%lu] at location [%s]",
  248. dev->name, ver.major, ver.minor, ver.debug, dev->path);
  249. // begin listening.
  250. postRead(tap);
  251. return &tap->pub;
  252. }