1
0

TAPInterface.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 <https://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/Er.h"
  19. #include "exception/WinEr.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 Er_DEFUN(void getVersion(
  47. HANDLE tap,
  48. struct TAPInterface_Version_pvt* version,
  49. struct Allocator* alloc))
  50. {
  51. ULONG version_len;
  52. BOOL bret = DeviceIoControl(tap,
  53. TAP_IOCTL_GET_VERSION,
  54. version,
  55. sizeof(struct TAPInterface_Version_pvt),
  56. version,
  57. sizeof(struct TAPInterface_Version_pvt),
  58. &version_len,
  59. NULL);
  60. if (!bret) {
  61. DWORD err = GetLastError();
  62. CloseHandle(tap);
  63. WinEr_fail(alloc, "DeviceIoControl(TAP_IOCTL_GET_VERSION)", err);
  64. }
  65. if (version_len != sizeof(struct TAPInterface_Version_pvt)) {
  66. CloseHandle(tap);
  67. Er_raise(alloc, "DeviceIoControl(TAP_IOCTL_GET_VERSION) out size [%d] expected [%d]",
  68. (int)version_len, (int)sizeof(struct TAPInterface_Version_pvt));
  69. }
  70. Er_ret();
  71. }
  72. static Er_DEFUN(void setEnabled(HANDLE tap, int status, struct Allocator* alloc))
  73. {
  74. unsigned long len = 0;
  75. BOOL bret = DeviceIoControl(tap, TAP_IOCTL_SET_MEDIA_STATUS,
  76. &status, sizeof (status),
  77. &status, sizeof (status), &len, NULL);
  78. if (!bret) {
  79. DWORD err = GetLastError();
  80. CloseHandle(tap);
  81. WinEr_fail(alloc, "DeviceIoControl(TAP_IOCTL_SET_MEDIA_STATUS)", err);
  82. }
  83. Er_ret();
  84. }
  85. #define WRITE_MESSAGE_SLOTS 20
  86. struct TAPInterface_pvt
  87. {
  88. struct TAPInterface pub;
  89. uv_iocp_t readIocp;
  90. struct Message* readMsg;
  91. uv_iocp_t writeIocp;
  92. struct Message* writeMsgs[WRITE_MESSAGE_SLOTS];
  93. /** This allocator holds messages pending write in memory until they are complete. */
  94. struct Allocator* pendingWritesAlloc;
  95. int writeMessageCount;
  96. int isPendingWrite;
  97. HANDLE handle;
  98. struct Log* log;
  99. struct Allocator* alloc;
  100. struct EventBase* base;
  101. Identity
  102. };
  103. static void readCallbackB(struct TAPInterface_pvt* tap);
  104. static void postRead(struct TAPInterface_pvt* tap)
  105. {
  106. struct Allocator* alloc = Allocator_child(tap->alloc);
  107. // Choose odd numbers so that the message will be aligned despite the weird header size.
  108. struct Message* msg = tap->readMsg = Message_new(1534, 514, alloc);
  109. OVERLAPPED* readol = (OVERLAPPED*) tap->readIocp.overlapped;
  110. if (!ReadFile(tap->handle, msg->msgbytes, 1534, NULL, readol)) {
  111. switch (GetLastError()) {
  112. case ERROR_IO_PENDING:
  113. case ERROR_IO_INCOMPLETE: break;
  114. default: Assert_failure("ReadFile(tap): %s\n", WinEr_strerror(GetLastError()));
  115. }
  116. } else {
  117. // It doesn't matter if it returns immediately, it will also return async.
  118. //Log_debug(tap->log, "Read returned immediately");
  119. }
  120. Log_debug(tap->log, "Posted read");
  121. }
  122. static void readCallbackB(struct TAPInterface_pvt* tap)
  123. {
  124. struct Message* msg = tap->readMsg;
  125. tap->readMsg = NULL;
  126. DWORD bytesRead;
  127. OVERLAPPED* readol = (OVERLAPPED*) tap->readIocp.overlapped;
  128. if (!GetOverlappedResult(tap->handle, readol, &bytesRead, FALSE)) {
  129. Assert_failure("GetOverlappedResult(read, tap): %s\n", WinEr_strerror(GetLastError()));
  130. }
  131. Er_assert(Message_truncate(msg, bytesRead));
  132. Log_debug(tap->log, "Read [%d] bytes", Message_getLength(msg));
  133. Iface_send(&tap->pub.generic, msg);
  134. Allocator_free(Message_getAlloc(msg));
  135. postRead(tap);
  136. }
  137. static void readCallback(uv_iocp_t* readIocp)
  138. {
  139. void *glock = Rffi_glock();
  140. struct TAPInterface_pvt* tap =
  141. Identity_check((struct TAPInterface_pvt*)
  142. (((char*)readIocp) - offsetof(struct TAPInterface_pvt, readIocp)));
  143. readCallbackB(tap);
  144. Rffi_gunlock(glock);
  145. }
  146. static void writeCallbackB(struct TAPInterface_pvt* tap);
  147. static void postWrite(struct TAPInterface_pvt* tap)
  148. {
  149. Assert_true(!tap->isPendingWrite);
  150. tap->isPendingWrite = 1;
  151. struct Message* msg = tap->writeMsgs[0];
  152. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  153. if (!WriteFile(tap->handle, msg->msgbytes, Message_getLength(msg), NULL, writeol)) {
  154. switch (GetLastError()) {
  155. case ERROR_IO_PENDING:
  156. case ERROR_IO_INCOMPLETE: break;
  157. default: Assert_failure("WriteFile(tap): %s\n", WinEr_strerror(GetLastError()));
  158. }
  159. } else {
  160. // It doesn't matter if it returns immediately, it will also return async.
  161. //Log_debug(tap->log, "Write returned immediately");
  162. }
  163. Log_debug(tap->log, "Posted write [%d] bytes", Message_getLength(msg));
  164. }
  165. static void writeCallbackB(struct TAPInterface_pvt* tap)
  166. {
  167. DWORD bytesWritten;
  168. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  169. if (!GetOverlappedResult(tap->handle, writeol, &bytesWritten, FALSE)) {
  170. Assert_failure("GetOverlappedResult(write, tap): %s\n", WinEr_strerror(GetLastError()));
  171. }
  172. Assert_true(tap->isPendingWrite);
  173. tap->isPendingWrite = 0;
  174. Assert_true(tap->writeMessageCount--);
  175. struct Message* msg = tap->writeMsgs[0];
  176. if (Message_getLength(msg) != (int)bytesWritten) {
  177. Log_info(tap->log, "Message of length [%d] truncated to [%d]",
  178. Message_getLength(msg), (int)bytesWritten);
  179. Assert_true(Message_getLength(msg) > (int)bytesWritten);
  180. }
  181. if (tap->writeMessageCount) {
  182. for (int i = 0; i < tap->writeMessageCount; i++) {
  183. tap->writeMsgs[i] = tap->writeMsgs[i+1];
  184. }
  185. postWrite(tap);
  186. } else {
  187. Log_debug(tap->log, "All pending writes are complete");
  188. Allocator_free(tap->pendingWritesAlloc);
  189. tap->pendingWritesAlloc = NULL;
  190. }
  191. }
  192. static void writeCallback(uv_iocp_t* writeIocp)
  193. {
  194. void *glock = Rffi_glock();
  195. struct TAPInterface_pvt* tap =
  196. Identity_check((struct TAPInterface_pvt*)
  197. (((char*)writeIocp) - offsetof(struct TAPInterface_pvt, writeIocp)));
  198. writeCallbackB(tap);
  199. Rffi_gunlock(glock);
  200. }
  201. static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
  202. {
  203. struct TAPInterface_pvt* tap = Identity_check((struct TAPInterface_pvt*) iface);
  204. if (tap->writeMessageCount >= WRITE_MESSAGE_SLOTS) {
  205. Log_info(tap->log, "DROP message because the tap is lagging");
  206. return Error(msg, "OVERFLOW");
  207. }
  208. if (!tap->pendingWritesAlloc) {
  209. tap->pendingWritesAlloc = Allocator_child(tap->alloc);
  210. }
  211. tap->writeMsgs[tap->writeMessageCount++] = msg;
  212. Allocator_adopt(tap->pendingWritesAlloc, Message_getAlloc(msg));
  213. if (tap->writeMessageCount == 1) {
  214. postWrite(tap);
  215. }
  216. return NULL;
  217. }
  218. Er_DEFUN(struct TAPInterface* TAPInterface_new(const char* preferredName,
  219. struct Log* logger,
  220. struct EventBase* base,
  221. struct Allocator* alloc))
  222. {
  223. Log_debug(logger, "Getting TAP-Windows device name");
  224. struct TAPDevice* dev = Er(TAPDevice_find(preferredName, alloc));
  225. Er(NetDev_flushAddresses(dev->name, alloc));
  226. Log_debug(logger, "Opening TAP-Windows device [%s] at location [%s]", dev->name, dev->path);
  227. struct TAPInterface_pvt* tap = Allocator_calloc(alloc, sizeof(struct TAPInterface_pvt), 1);
  228. Identity_set(tap);
  229. tap->base = base;
  230. tap->alloc = alloc;
  231. tap->log = logger;
  232. tap->pub.assignedName = dev->name;
  233. tap->pub.generic.send = sendMessage;
  234. tap->handle = CreateFile(dev->path,
  235. GENERIC_READ | GENERIC_WRITE,
  236. 0,
  237. 0,
  238. OPEN_EXISTING,
  239. FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  240. 0);
  241. if (tap->handle == INVALID_HANDLE_VALUE) {
  242. WinEr_fail(alloc, "CreateFile(tapDevice)", GetLastError());
  243. }
  244. struct EventBase_pvt* ebp = EventBase_privatize(tap->base);
  245. int ret;
  246. if ((ret = uv_iocp_start(ebp->loop, &tap->readIocp, tap->handle, readCallback))) {
  247. Er_raise(alloc, "uv_iocp_start(readIocp): %s", uv_strerror(ret));
  248. }
  249. if ((ret = uv_iocp_start(ebp->loop, &tap->writeIocp, tap->handle, writeCallback))) {
  250. Er_raise(alloc, "uv_iocp_start(writeIocp): %s", uv_strerror(ret));
  251. }
  252. struct TAPInterface_Version_pvt ver = { .major = 0 };
  253. Er(getVersion(tap->handle, &ver, alloc));
  254. Er(setEnabled(tap->handle, 1, alloc));
  255. Log_info(logger, "Opened TAP-Windows device [%s] version [%lu.%lu.%lu] at location [%s]",
  256. dev->name, ver.major, ver.minor, ver.debug, dev->path);
  257. // begin listening.
  258. postRead(tap);
  259. Er_ret(&tap->pub);
  260. }