TAPInterface.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  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. struct TAPInterface_pvt* tap =
  140. Identity_check((struct TAPInterface_pvt*)
  141. (((char*)readIocp) - offsetof(struct TAPInterface_pvt, readIocp)));
  142. readCallbackB(tap);
  143. }
  144. static void writeCallbackB(struct TAPInterface_pvt* tap);
  145. static void postWrite(struct TAPInterface_pvt* tap)
  146. {
  147. Assert_true(!tap->isPendingWrite);
  148. tap->isPendingWrite = 1;
  149. struct Message* msg = tap->writeMsgs[0];
  150. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  151. if (!WriteFile(tap->handle, msg->msgbytes, Message_getLength(msg), NULL, writeol)) {
  152. switch (GetLastError()) {
  153. case ERROR_IO_PENDING:
  154. case ERROR_IO_INCOMPLETE: break;
  155. default: Assert_failure("WriteFile(tap): %s\n", WinEr_strerror(GetLastError()));
  156. }
  157. } else {
  158. // It doesn't matter if it returns immediately, it will also return async.
  159. //Log_debug(tap->log, "Write returned immediately");
  160. }
  161. Log_debug(tap->log, "Posted write [%d] bytes", Message_getLength(msg));
  162. }
  163. static void writeCallbackB(struct TAPInterface_pvt* tap)
  164. {
  165. DWORD bytesWritten;
  166. OVERLAPPED* writeol = (OVERLAPPED*) tap->writeIocp.overlapped;
  167. if (!GetOverlappedResult(tap->handle, writeol, &bytesWritten, FALSE)) {
  168. Assert_failure("GetOverlappedResult(write, tap): %s\n", WinEr_strerror(GetLastError()));
  169. }
  170. Assert_true(tap->isPendingWrite);
  171. tap->isPendingWrite = 0;
  172. Assert_true(tap->writeMessageCount--);
  173. struct Message* msg = tap->writeMsgs[0];
  174. if (Message_getLength(msg) != (int)bytesWritten) {
  175. Log_info(tap->log, "Message of length [%d] truncated to [%d]",
  176. Message_getLength(msg), (int)bytesWritten);
  177. Assert_true(Message_getLength(msg) > (int)bytesWritten);
  178. }
  179. if (tap->writeMessageCount) {
  180. for (int i = 0; i < tap->writeMessageCount; i++) {
  181. tap->writeMsgs[i] = tap->writeMsgs[i+1];
  182. }
  183. postWrite(tap);
  184. } else {
  185. Log_debug(tap->log, "All pending writes are complete");
  186. Allocator_free(tap->pendingWritesAlloc);
  187. tap->pendingWritesAlloc = NULL;
  188. }
  189. }
  190. static void writeCallback(uv_iocp_t* writeIocp)
  191. {
  192. struct TAPInterface_pvt* tap =
  193. Identity_check((struct TAPInterface_pvt*)
  194. (((char*)writeIocp) - offsetof(struct TAPInterface_pvt, writeIocp)));
  195. writeCallbackB(tap);
  196. }
  197. static Iface_DEFUN sendMessage(struct Message* msg, struct Iface* iface)
  198. {
  199. struct TAPInterface_pvt* tap = Identity_check((struct TAPInterface_pvt*) iface);
  200. if (tap->writeMessageCount >= WRITE_MESSAGE_SLOTS) {
  201. Log_info(tap->log, "DROP message because the tap is lagging");
  202. return Error(msg, "OVERFLOW");
  203. }
  204. if (!tap->pendingWritesAlloc) {
  205. tap->pendingWritesAlloc = Allocator_child(tap->alloc);
  206. }
  207. tap->writeMsgs[tap->writeMessageCount++] = msg;
  208. Allocator_adopt(tap->pendingWritesAlloc, Message_getAlloc(msg));
  209. if (tap->writeMessageCount == 1) {
  210. postWrite(tap);
  211. }
  212. return NULL;
  213. }
  214. Er_DEFUN(struct TAPInterface* TAPInterface_new(const char* preferredName,
  215. struct Log* logger,
  216. struct EventBase* base,
  217. struct Allocator* alloc))
  218. {
  219. Log_debug(logger, "Getting TAP-Windows device name");
  220. struct TAPDevice* dev = Er(TAPDevice_find(preferredName, alloc));
  221. Er(NetDev_flushAddresses(dev->name, alloc));
  222. Log_debug(logger, "Opening TAP-Windows device [%s] at location [%s]", dev->name, dev->path);
  223. struct TAPInterface_pvt* tap = Allocator_calloc(alloc, sizeof(struct TAPInterface_pvt), 1);
  224. Identity_set(tap);
  225. tap->base = base;
  226. tap->alloc = alloc;
  227. tap->log = logger;
  228. tap->pub.assignedName = dev->name;
  229. tap->pub.generic.send = sendMessage;
  230. tap->handle = CreateFile(dev->path,
  231. GENERIC_READ | GENERIC_WRITE,
  232. 0,
  233. 0,
  234. OPEN_EXISTING,
  235. FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  236. 0);
  237. if (tap->handle == INVALID_HANDLE_VALUE) {
  238. WinEr_fail(alloc, "CreateFile(tapDevice)", GetLastError());
  239. }
  240. struct EventBase_pvt* ebp = EventBase_privatize(tap->base);
  241. int ret;
  242. if ((ret = uv_iocp_start(ebp->loop, &tap->readIocp, tap->handle, readCallback))) {
  243. Er_raise(alloc, "uv_iocp_start(readIocp): %s", uv_strerror(ret));
  244. }
  245. if ((ret = uv_iocp_start(ebp->loop, &tap->writeIocp, tap->handle, writeCallback))) {
  246. Er_raise(alloc, "uv_iocp_start(writeIocp): %s", uv_strerror(ret));
  247. }
  248. struct TAPInterface_Version_pvt ver = { .major = 0 };
  249. Er(getVersion(tap->handle, &ver, alloc));
  250. Er(setEnabled(tap->handle, 1, alloc));
  251. Log_info(logger, "Opened TAP-Windows device [%s] version [%lu.%lu.%lu] at location [%s]",
  252. dev->name, ver.major, ver.minor, ver.debug, dev->path);
  253. // begin listening.
  254. postRead(tap);
  255. Er_ret(&tap->pub);
  256. }