PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/packet-socket/private/packet-socket-extension.c

https://github.com/tonyg/racket-packet-socket
C | 466 lines | 332 code | 80 blank | 54 comment | 47 complexity | 31e824b5836832e595cc7bb9358207e9 MD5 | raw file
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <sys/time.h>
  7. #include <sys/ioctl.h>
  8. #include <fcntl.h>
  9. #include <err.h>
  10. #include <errno.h>
  11. #include <unistd.h>
  12. #include <ifaddrs.h>
  13. #include <net/if.h>
  14. #include <net/ethernet.h>
  15. #if defined(__linux__)
  16. #include <net/if_arp.h>
  17. #include <netpacket/packet.h>
  18. #endif
  19. #if defined(__APPLE__)
  20. #include <net/if_dl.h>
  21. #include <net/bpf.h>
  22. #endif
  23. #include "escheme.h"
  24. /***************************************************************************/
  25. /* Linux-specific implementation */
  26. #if defined(__linux__)
  27. static int lookupInterfaceInfo(int sock, char const *interfaceName, int info, struct ifreq *ifr)
  28. XFORM_SKIP_PROC
  29. {
  30. strncpy(ifr->ifr_name, interfaceName, IFNAMSIZ);
  31. if (ioctl(sock, info, ifr) < 0) {
  32. perror("ioctl error while looking performing ioctl on interface");
  33. fprintf(stderr, "(ioctl number 0x%08x, interface %s)\n", info, interfaceName);
  34. return -1;
  35. } else {
  36. return 0;
  37. }
  38. }
  39. static int bindToInterface(int sock, char const *interfaceName)
  40. XFORM_SKIP_PROC
  41. {
  42. struct ifreq ifr;
  43. struct sockaddr_ll socketAddress;
  44. if (lookupInterfaceInfo(sock, interfaceName, SIOCGIFINDEX, &ifr) < 0) {
  45. return -1;
  46. }
  47. socketAddress.sll_family = AF_PACKET;
  48. socketAddress.sll_protocol = htons(ETH_P_ALL);
  49. socketAddress.sll_ifindex = ifr.ifr_ifindex;
  50. if (bind(sock, (struct sockaddr *) &socketAddress, sizeof(socketAddress)) < 0) {
  51. perror("Bind error");
  52. return -1;
  53. }
  54. return 0;
  55. }
  56. static int openSocket(char const *interfaceName)
  57. XFORM_SKIP_PROC
  58. {
  59. int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  60. if (sock < 0) {
  61. perror("Socket error");
  62. return -1;
  63. }
  64. if (bindToInterface(sock, interfaceName) == -1) {
  65. return -1;
  66. }
  67. return sock;
  68. }
  69. static int readBufferLength(int sock)
  70. XFORM_SKIP_PROC
  71. {
  72. /* If we supply ETHER_MAX_LEN here, then we miss out on the occasional larger (!) packet. */
  73. /* Instead, we supply something definitely large enough. */
  74. /* TODO: Consider returning something closer to around 9000 bytes,
  75. or whatever jumbo packet sizes are these days. */
  76. return 65536;
  77. }
  78. static int extractPacket(char * const bufbase, size_t limit, int o, int *basep, int *lenp) {
  79. *basep = 0;
  80. *lenp = (o == 0) ? limit : 0;
  81. return limit;
  82. }
  83. static Scheme_Object *socket_hwaddr(int argc, Scheme_Object **argv) {
  84. int sock = SCHEME_INT_VAL(argv[0]);
  85. char const *interfaceName = SCHEME_BYTE_STR_VAL(argv[1]);
  86. XFORM_CAN_IGNORE struct ifreq ifr;
  87. if (lookupInterfaceInfo(sock, interfaceName, SIOCGIFHWADDR, &ifr) < 0) {
  88. return scheme_false;
  89. }
  90. if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
  91. return scheme_false;
  92. }
  93. return scheme_make_sized_byte_string(ifr.ifr_hwaddr.sa_data, ETH_ALEN, 1);
  94. }
  95. /*
  96. static int setPromiscuousMode(int sock, int index)
  97. XFORM_SKIP_PROC
  98. {
  99. struct packet_mreq req;
  100. req.mr_ifindex = index;
  101. req.mr_type = PACKET_MR_PROMISC;
  102. if (setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &req, (socklen_t) sizeof(req)) < 0) {
  103. perror("set sock opt error");
  104. return -1;
  105. }
  106. return 0;
  107. }
  108. */
  109. #endif
  110. /***************************************************************************/
  111. /* OSX-specific implementation */
  112. #if defined(__APPLE__)
  113. static int openSocket(char const *interfaceName)
  114. XFORM_SKIP_PROC
  115. {
  116. int deviceIndex;
  117. for (deviceIndex = 0; deviceIndex < 10; deviceIndex++) {
  118. int fd = -1;
  119. {
  120. char deviceName[32];
  121. snprintf(deviceName, sizeof(deviceName), "/dev/bpf%d", deviceIndex);
  122. fd = open(deviceName, O_RDWR);
  123. if (fd == -1) {
  124. if (errno != ENOENT) {
  125. perror("open /dev/bpfX");
  126. }
  127. continue;
  128. }
  129. }
  130. {
  131. struct ifreq ifr;
  132. strncpy(ifr.ifr_name, interfaceName, IFNAMSIZ);
  133. if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
  134. perror("ioctl BIOCSETIF");
  135. close(fd);
  136. continue;
  137. }
  138. }
  139. /* { */
  140. /* u_int enable = 1; */
  141. /* if (ioctl(fd, BIOCSHDRCMPLT, &enable) < 0) { */
  142. /* perror("ioctl BIOCSHDRCMPLT"); */
  143. /* close(fd); */
  144. /* continue; */
  145. /* } */
  146. /* } */
  147. /* { */
  148. /* u_int enable = 1; */
  149. /* if (ioctl(fd, BIOCSSEESENT, &enable) < 0) { */
  150. /* perror("ioctl BIOCSSEESENT"); */
  151. /* close(fd); */
  152. /* continue; */
  153. /* } */
  154. /* } */
  155. {
  156. u_int enable = 1;
  157. if (ioctl(fd, BIOCIMMEDIATE, &enable) < 0) {
  158. perror("ioctl BIOCIMMEDIATE");
  159. close(fd);
  160. continue;
  161. }
  162. }
  163. return fd;
  164. }
  165. return -1;
  166. }
  167. static int readBufferLength(int fd)
  168. XFORM_SKIP_PROC
  169. {
  170. u_int buflen;
  171. if (ioctl(fd, BIOCGBLEN, &buflen) < 0) {
  172. perror("ioctl BIOCGBLEN");
  173. return -1;
  174. }
  175. return buflen;
  176. }
  177. static int extractPacket(char *bufbase, size_t limit, int o, int *basep, int *lenp)
  178. XFORM_SKIP_PROC
  179. {
  180. struct bpf_hdr *bh = (struct bpf_hdr *) (bufbase + o);
  181. struct ether_header *eh = (struct ether_header *) (bufbase + o + bh->bh_hdrlen);
  182. int nexto;
  183. *basep = o + bh->bh_hdrlen;
  184. *lenp = bh->bh_caplen;
  185. if (bh->bh_caplen != bh->bh_datalen) {
  186. fprintf(stderr, "packet-socket: Warning: packet truncated from %u to %u bytes\n",
  187. bh->bh_datalen,
  188. bh->bh_caplen);
  189. }
  190. nexto = o + BPF_WORDALIGN(bh->bh_hdrlen + bh->bh_caplen);
  191. /* printf("base %p limit %u o %d *basep now %d *lenp now %d nexto %d\n", */
  192. /* bufbase, limit, o, *basep, *lenp, nexto); */
  193. return nexto;
  194. }
  195. static Scheme_Object *socket_hwaddr(int argc, Scheme_Object **argv) {
  196. Scheme_Object *result = scheme_false;
  197. int sock = SCHEME_INT_VAL(argv[0]);
  198. char const *interfaceName = SCHEME_BYTE_STR_VAL(argv[1]);
  199. struct ifaddrs *addrs;
  200. struct ifaddrs *tmp;
  201. if (getifaddrs(&addrs) == -1) {
  202. perror("getifaddrs");
  203. return scheme_false;
  204. }
  205. for (tmp = addrs; tmp != NULL; tmp = tmp->ifa_next) {
  206. if (tmp->ifa_addr != NULL &&
  207. !strncmp(tmp->ifa_name, interfaceName, IFNAMSIZ) &&
  208. tmp->ifa_addr->sa_family == AF_LINK)
  209. {
  210. struct sockaddr_dl *sdl = (struct sockaddr_dl *) tmp->ifa_addr;
  211. result = scheme_make_sized_byte_string(LLADDR(sdl), sdl->sdl_alen, 1);
  212. break;
  213. }
  214. }
  215. freeifaddrs(addrs);
  216. return result;
  217. }
  218. #endif
  219. /***************************************************************************/
  220. /* Common implementation */
  221. static Scheme_Object *enumerate_interfaces(int argc, Scheme_Object **argv) {
  222. Scheme_Object *result = scheme_null;
  223. struct ifaddrs *addrs;
  224. struct ifaddrs *tmp;
  225. if (getifaddrs(&addrs) == -1) {
  226. perror("getifaddrs");
  227. return scheme_false;
  228. }
  229. for (tmp = addrs; tmp != NULL; tmp = tmp->ifa_next) {
  230. if (tmp->ifa_addr != NULL) {
  231. result = scheme_make_pair(scheme_make_utf8_string(tmp->ifa_name), result);
  232. }
  233. }
  234. freeifaddrs(addrs);
  235. return result;
  236. }
  237. static Scheme_Object *create_and_bind_socket(int argc, Scheme_Object **argv) {
  238. int sock;
  239. char const *interfaceName = SCHEME_BYTE_STR_VAL(argv[0]);
  240. sock = openSocket(interfaceName);
  241. return (sock == -1) ? scheme_false : scheme_make_integer(sock);
  242. }
  243. static Scheme_Object *close_socket(int argc, Scheme_Object **argv) {
  244. int sock;
  245. sock = SCHEME_INT_VAL(argv[0]);
  246. if (close(sock) < 0) {
  247. perror("close");
  248. return scheme_false;
  249. }
  250. return scheme_true;
  251. }
  252. static Scheme_Object *socket_read_buffer_length(int argc, Scheme_Object **argv) {
  253. int sock;
  254. sock = SCHEME_INT_VAL(argv[0]);
  255. return scheme_make_integer(readBufferLength(sock));
  256. }
  257. struct ReadArgs {
  258. int sock;
  259. unsigned char *buf;
  260. int blen;
  261. volatile int bytes_read;
  262. };
  263. static void *do_actual_read(void *read_args)
  264. XFORM_SKIP_PROC
  265. {
  266. struct ReadArgs *args = (struct ReadArgs *) read_args;
  267. #if defined(__APPLE__)
  268. ssize_t result = read(args->sock, args->buf, args->blen);
  269. #else
  270. ssize_t result = recv(args->sock, args->buf, args->blen, MSG_TRUNC);
  271. if (result > args->blen) {
  272. fprintf(stderr,
  273. "WARNING: packet-socket buffer size %d too small for received packet of %d bytes\n",
  274. args->blen,
  275. result);
  276. result = args->blen;
  277. }
  278. #endif
  279. if (result == -1) {
  280. perror("packet-socket read");
  281. }
  282. args->bytes_read = result;
  283. return NULL;
  284. }
  285. static int is_read_done(Scheme_Object *data) {
  286. struct ReadArgs *read_args = (struct ReadArgs*) data;
  287. return read_args->bytes_read != 0;
  288. }
  289. static void prepare_for_sleep(Scheme_Object *data, void *fds) {
  290. struct ReadArgs *read_args = (struct ReadArgs*) data;
  291. MZ_FD_SET(read_args->sock, MZ_GET_FDSET(fds, 0));
  292. MZ_FD_SET(read_args->sock, MZ_GET_FDSET(fds, 2));
  293. }
  294. Scheme_Object *socket_read(int argc, Scheme_Object **argv) {
  295. struct ReadArgs *read_args;
  296. size_t buffer_length;
  297. unsigned char *read_buffer;
  298. pthread_t read_thread;
  299. Scheme_Object *result = scheme_null;
  300. read_args = calloc(1, sizeof(*read_args));
  301. if (read_args == NULL) {
  302. perror("socket-read calloc read_args");
  303. return scheme_false;
  304. }
  305. buffer_length = SCHEME_BYTE_STRLEN_VAL(argv[1]);
  306. read_buffer = calloc(1, buffer_length);
  307. if (read_buffer == NULL) {
  308. perror("socket-read calloc read_buffer");
  309. free(read_args);
  310. return scheme_false;
  311. }
  312. read_args->sock = SCHEME_INT_VAL(argv[0]);
  313. read_args->buf = read_buffer;
  314. read_args->blen = buffer_length;
  315. read_args->bytes_read = 0;
  316. /* printf("original thread sock: %d, buf: %p, len: %d\n", */
  317. /* read_args.sock, */
  318. /* read_args.buf, */
  319. /* read_args.blen); */
  320. /* fflush(NULL); */
  321. pthread_create(&read_thread, NULL, do_actual_read, read_args);
  322. scheme_block_until(is_read_done, prepare_for_sleep, (Scheme_Object *) read_args, 0);
  323. if (read_args->bytes_read < 0) {
  324. result = scheme_false;
  325. } else {
  326. int extractionState = 0;
  327. int baseOffset = 0;
  328. int length = 0;
  329. Scheme_Object *entry = scheme_null;
  330. do {
  331. extractionState = extractPacket(read_args->buf, read_args->bytes_read, extractionState,
  332. &baseOffset,
  333. &length);
  334. entry = scheme_make_pair(scheme_make_integer(baseOffset), scheme_make_integer(length));
  335. result = scheme_make_pair(entry, result);
  336. } while (extractionState < read_args->bytes_read);
  337. /* It's a shame this is necessary, but the GC can move the buffer
  338. unpredictably so we can't read straight into it. TODO: see if
  339. there's some way of pinning the Racket buffer in order to avoid
  340. the copy? */
  341. memcpy(SCHEME_BYTE_STR_VAL(argv[1]), read_buffer, read_args->bytes_read);
  342. }
  343. free(read_buffer);
  344. free(read_args);
  345. return result;
  346. }
  347. static Scheme_Object *socket_write(int argc, Scheme_Object **argv) {
  348. int sock;
  349. char *buf;
  350. int blen, bytes_written;
  351. sock = SCHEME_INT_VAL(argv[0]);
  352. buf = SCHEME_BYTE_STR_VAL(argv[1]);
  353. blen = SCHEME_BYTE_STRLEN_VAL(argv[1]);
  354. bytes_written = write(sock, buf, blen);
  355. return scheme_make_integer(bytes_written);
  356. }
  357. Scheme_Object *scheme_reload(Scheme_Env *env) {
  358. Scheme_Env *module_env;
  359. Scheme_Object *proc;
  360. module_env = scheme_primitive_module(scheme_intern_symbol("packet-socket-extension"), env);
  361. proc = scheme_make_prim_w_arity(enumerate_interfaces, "enumerate-interfaces", 0, 0);
  362. scheme_add_global("enumerate-interfaces", proc, module_env);
  363. proc = scheme_make_prim_w_arity(close_socket, "socket-close", 1, 1);
  364. scheme_add_global("socket-close", proc, module_env);
  365. proc = scheme_make_prim_w_arity(create_and_bind_socket, "create-and-bind-socket", 1, 1);
  366. scheme_add_global("create-and-bind-socket", proc, module_env);
  367. proc = scheme_make_prim_w_arity(socket_read_buffer_length, "socket-read-buffer-length", 1, 1);
  368. scheme_add_global("socket-read-buffer-length", proc, module_env);
  369. proc = scheme_make_prim_w_arity(socket_read, "socket-read", 2, 2);
  370. scheme_add_global("socket-read", proc, module_env);
  371. proc = scheme_make_prim_w_arity(socket_write, "socket-write", 2, 2);
  372. scheme_add_global("socket-write", proc, module_env);
  373. proc = scheme_make_prim_w_arity(socket_hwaddr, "socket-hwaddr", 2, 2);
  374. scheme_add_global("socket-hwaddr", proc, module_env);
  375. scheme_finish_primitive_module(module_env);
  376. return scheme_void;
  377. }
  378. Scheme_Object *scheme_initialize(Scheme_Env *env) {
  379. scheme_reload(env);
  380. }
  381. Scheme_Object *scheme_module_name() {
  382. return scheme_intern_symbol("packet-socket-extension");
  383. }