1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <sys/sysctl.h> 4 #include <sys/usched.h> 5 6 #include <arpa/inet.h> 7 #include <netinet/in.h> 8 9 #include <err.h> 10 #include <stdio.h> 11 #include <stdint.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <unistd.h> 15 16 #define RCVBUF_SIZE (256 * 1024) 17 #define BUFLEN 2048 18 19 #define FLAG_NOREPLY 0x0001 20 #define FLAG_BINDCPU 0x0002 21 22 static void mainloop(struct sockaddr_in *, int, int, uint32_t); 23 24 static void 25 usage(const char *cmd) 26 { 27 fprintf(stderr, "%s -4 addr4 -p port [-i ninst] [-r rcvbuf] " 28 "[-N] [-B]\n", cmd); 29 exit(2); 30 } 31 32 int 33 main(int argc, char *argv[]) 34 { 35 struct sockaddr_in in; 36 int opt, ninst, i, s, rcvbuf, flags; 37 size_t prm_len; 38 39 prm_len = sizeof(ninst); 40 if (sysctlbyname("hw.ncpu", &ninst, &prm_len, NULL, 0) != 0) 41 err(2, "sysctl hw.ncpu failed"); 42 43 memset(&in, 0, sizeof(in)); 44 in.sin_family = AF_INET; 45 46 flags = 0; 47 rcvbuf = RCVBUF_SIZE; 48 49 while ((opt = getopt(argc, argv, "4:p:i:r:NB")) != -1) { 50 switch (opt) { 51 case '4': 52 if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0) 53 errx(1, "invalid -4 %s\n", optarg); 54 break; 55 56 case 'p': 57 in.sin_port = strtoul(optarg, NULL, 10); 58 in.sin_port = htons(in.sin_port); 59 break; 60 61 case 'i': 62 ninst = strtoul(optarg, NULL, 10); 63 break; 64 65 case 'r': 66 rcvbuf = strtoul(optarg, NULL, 10); 67 rcvbuf *= 1024; 68 break; 69 70 case 'N': 71 flags |= FLAG_NOREPLY; 72 break; 73 74 case 'B': 75 flags |= FLAG_BINDCPU; 76 break; 77 78 default: 79 usage(argv[0]); 80 } 81 } 82 83 if (in.sin_port == 0 || in.sin_addr.s_addr == INADDR_ANY) 84 usage(argv[0]); 85 86 s = -1; 87 88 for (i = 0; i < ninst - 1; ++i) { 89 pid_t pid; 90 91 pid = fork(); 92 if (pid == 0) 93 mainloop(&in, s, rcvbuf, flags); 94 else if (pid < 0) 95 err(1, "fork %d failed", i); 96 } 97 98 mainloop(&in, s, rcvbuf, flags); 99 exit(0); 100 } 101 102 static void 103 mainloop(struct sockaddr_in *in, int s, int rcvbuf, uint32_t flags) 104 { 105 int on; 106 void *buf; 107 108 if (s < 0) { 109 s = socket(AF_INET, SOCK_DGRAM, 0); 110 if (s < 0) 111 err(1, "socket(INET, DGRAM) failed"); 112 } 113 114 buf = malloc(BUFLEN); 115 if (buf == NULL) 116 err(1, "malloc buf failed"); 117 118 on = 1; 119 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) 120 err(1, "setsockopt(SOCK, REUSEPORT) failed"); 121 122 if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) 123 err(1, "setsockopt(SOCK, RCVBUF) failed"); 124 125 if (bind(s, (const struct sockaddr *)in, sizeof(*in)) < 0) 126 err(1, "bind failed"); 127 128 if (flags & FLAG_BINDCPU) { 129 socklen_t cpu_len; 130 int cpu; 131 132 cpu_len = sizeof(cpu); 133 if (getsockopt(s, SOL_SOCKET, SO_CPUHINT, &cpu, &cpu_len) < 0) 134 err(1, "getsockopt(SOCK, CPUHINT) failed"); 135 if (cpu >= 0) 136 usched_set(getpid(), USCHED_SET_CPU, &cpu, sizeof(cpu)); 137 } 138 139 for (;;) { 140 struct sockaddr_in cli; 141 socklen_t cli_len; 142 int n; 143 144 cli_len = sizeof(cli); 145 n = recvfrom(s, buf, BUFLEN, 0, 146 (struct sockaddr *)&cli, &cli_len); 147 if (n > 0 && (flags & FLAG_NOREPLY) == 0) { 148 sendto(s, buf, n, 0, 149 (const struct sockaddr *)&cli, cli_len); 150 } 151 } 152 exit(0); 153 } 154