TAPInterface.c 10 KB

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