| 1 | /* |
|---|
| 2 | * network test suite. |
|---|
| 3 | * |
|---|
| 4 | * Written by Russ Allbery <rra@stanford.edu> |
|---|
| 5 | * Copyright 2009 Board of Trustees, Leland Stanford Jr. University |
|---|
| 6 | * Copyright (c) 2004, 2005, 2006, 2007 |
|---|
| 7 | * by Internet Systems Consortium, Inc. ("ISC") |
|---|
| 8 | * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
|---|
| 9 | * 2002, 2003 by The Internet Software Consortium and Rich Salz |
|---|
| 10 | * |
|---|
| 11 | * See LICENSE for licensing terms. |
|---|
| 12 | */ |
|---|
| 13 | |
|---|
| 14 | #include <config.h> |
|---|
| 15 | #include <portable/system.h> |
|---|
| 16 | #include <portable/socket.h> |
|---|
| 17 | |
|---|
| 18 | #include <ctype.h> |
|---|
| 19 | #include <errno.h> |
|---|
| 20 | #include <sys/wait.h> |
|---|
| 21 | |
|---|
| 22 | #include <tests/tap/basic.h> |
|---|
| 23 | #include <util/util.h> |
|---|
| 24 | |
|---|
| 25 | /* Set this globally to 0 if IPv6 is available but doesn't work. */ |
|---|
| 26 | static int ipv6 = 1; |
|---|
| 27 | |
|---|
| 28 | /* |
|---|
| 29 | * The server portion of the test. Listens to a socket and accepts a |
|---|
| 30 | * connection, making sure what is printed on that connection matches what the |
|---|
| 31 | * client is supposed to print. |
|---|
| 32 | */ |
|---|
| 33 | static void |
|---|
| 34 | listener(int fd) |
|---|
| 35 | { |
|---|
| 36 | int client; |
|---|
| 37 | FILE *out; |
|---|
| 38 | char buffer[512]; |
|---|
| 39 | |
|---|
| 40 | client = accept(fd, NULL, NULL); |
|---|
| 41 | close(fd); |
|---|
| 42 | if (client < 0) { |
|---|
| 43 | sysnotice("# cannot accept connection from socket"); |
|---|
| 44 | ok_block(2, 0, "...socket read test"); |
|---|
| 45 | } |
|---|
| 46 | ok(1, "...socket accept"); |
|---|
| 47 | out = fdopen(client, "r"); |
|---|
| 48 | if (fgets(buffer, sizeof(buffer), out) == NULL) { |
|---|
| 49 | sysnotice("# cannot read from socket"); |
|---|
| 50 | ok(0, "...socket read"); |
|---|
| 51 | } |
|---|
| 52 | is_string("socket test\r\n", buffer, "...socket read"); |
|---|
| 53 | fclose(out); |
|---|
| 54 | } |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | /* |
|---|
| 58 | * Connect to the given host on port 11119 and send a constant string to a |
|---|
| 59 | * socket, used to do the client side of the testing. Takes the source |
|---|
| 60 | * address as well to pass into network_connect_host. |
|---|
| 61 | */ |
|---|
| 62 | static void |
|---|
| 63 | client(const char *host, const char *source) |
|---|
| 64 | { |
|---|
| 65 | int fd; |
|---|
| 66 | FILE *out; |
|---|
| 67 | |
|---|
| 68 | fd = network_connect_host(host, 11119, source); |
|---|
| 69 | if (fd < 0) |
|---|
| 70 | sysdie("connect failed"); |
|---|
| 71 | out = fdopen(fd, "w"); |
|---|
| 72 | if (out == NULL) |
|---|
| 73 | sysdie("fdopen failed"); |
|---|
| 74 | fputs("socket test\r\n", out); |
|---|
| 75 | fclose(out); |
|---|
| 76 | _exit(0); |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | /* |
|---|
| 81 | * Bring up a server on port 11119 on the loopback address and test connecting |
|---|
| 82 | * to it via IPv4. Takes an optional source address to use for client |
|---|
| 83 | * connections. |
|---|
| 84 | */ |
|---|
| 85 | static void |
|---|
| 86 | test_ipv4(const char *source) |
|---|
| 87 | { |
|---|
| 88 | int fd; |
|---|
| 89 | pid_t child; |
|---|
| 90 | |
|---|
| 91 | fd = network_bind_ipv4("127.0.0.1", 11119); |
|---|
| 92 | if (fd < 0) |
|---|
| 93 | sysbail("cannot create or bind socket"); |
|---|
| 94 | if (listen(fd, 1) < 0) { |
|---|
| 95 | sysnotice("# cannot listen to socket"); |
|---|
| 96 | ok_block(3, 0, "IPv4 server test"); |
|---|
| 97 | } else { |
|---|
| 98 | ok(1, "IPv4 server test"); |
|---|
| 99 | child = fork(); |
|---|
| 100 | if (child < 0) |
|---|
| 101 | sysbail("cannot fork"); |
|---|
| 102 | else if (child == 0) |
|---|
| 103 | client("127.0.0.1", source); |
|---|
| 104 | else { |
|---|
| 105 | listener(fd); |
|---|
| 106 | waitpid(child, NULL, 0); |
|---|
| 107 | } |
|---|
| 108 | } |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | /* |
|---|
| 113 | * Bring up a server on port 11119 on the loopback address and test connecting |
|---|
| 114 | * to it via IPv6. Takes an optional source address to use for client |
|---|
| 115 | * connections. |
|---|
| 116 | */ |
|---|
| 117 | #ifdef HAVE_INET6 |
|---|
| 118 | static void |
|---|
| 119 | test_ipv6(const char *source) |
|---|
| 120 | { |
|---|
| 121 | int fd; |
|---|
| 122 | pid_t child; |
|---|
| 123 | |
|---|
| 124 | fd = network_bind_ipv6("::1", 11119); |
|---|
| 125 | if (fd < 0) { |
|---|
| 126 | if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT |
|---|
| 127 | || errno == EADDRNOTAVAIL) { |
|---|
| 128 | ipv6 = 0; |
|---|
| 129 | skip_block(3, "IPv6 not supported"); |
|---|
| 130 | } else |
|---|
| 131 | sysbail("cannot create socket"); |
|---|
| 132 | } |
|---|
| 133 | if (listen(fd, 1) < 0) { |
|---|
| 134 | sysnotice("# cannot listen to socket"); |
|---|
| 135 | ok_block(3, 0, "IPv6 server test"); |
|---|
| 136 | } else { |
|---|
| 137 | ok(1, "IPv6 server test"); |
|---|
| 138 | child = fork(); |
|---|
| 139 | if (child < 0) |
|---|
| 140 | sysbail("cannot fork"); |
|---|
| 141 | else if (child == 0) |
|---|
| 142 | client("::1", source); |
|---|
| 143 | else { |
|---|
| 144 | listener(fd); |
|---|
| 145 | waitpid(child, NULL, 0); |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | } |
|---|
| 149 | #else /* !HAVE_INET6 */ |
|---|
| 150 | static void |
|---|
| 151 | test_ipv6(const char *source UNUSED) |
|---|
| 152 | { |
|---|
| 153 | skip_block(3, "IPv6 not supported"); |
|---|
| 154 | } |
|---|
| 155 | #endif /* !HAVE_INET6 */ |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | /* |
|---|
| 159 | * Bring up a server on port 11119 on all addresses and try connecting to it |
|---|
| 160 | * via all of the available protocols. Takes an optional source address to |
|---|
| 161 | * use for client connections. |
|---|
| 162 | */ |
|---|
| 163 | static void |
|---|
| 164 | test_all(const char *source_ipv4, const char *source_ipv6) |
|---|
| 165 | { |
|---|
| 166 | int *fds, count, fd, i; |
|---|
| 167 | pid_t child; |
|---|
| 168 | struct sockaddr_storage saddr; |
|---|
| 169 | socklen_t size = sizeof(saddr); |
|---|
| 170 | |
|---|
| 171 | network_bind_all(11119, &fds, &count); |
|---|
| 172 | if (count == 0) |
|---|
| 173 | sysbail("cannot create or bind socket"); |
|---|
| 174 | if (count > 2) { |
|---|
| 175 | notice("# got more than two sockets, using just the first two"); |
|---|
| 176 | count = 2; |
|---|
| 177 | } |
|---|
| 178 | for (i = 0; i < count; i++) { |
|---|
| 179 | fd = fds[i]; |
|---|
| 180 | if (listen(fd, 1) < 0) { |
|---|
| 181 | sysnotice("# cannot listen to socket %d", fd); |
|---|
| 182 | ok_block(3, 0, "all address server test"); |
|---|
| 183 | } else { |
|---|
| 184 | ok(1, "all address server test (part %d)", i); |
|---|
| 185 | child = fork(); |
|---|
| 186 | if (child < 0) |
|---|
| 187 | sysbail("cannot fork"); |
|---|
| 188 | else if (child == 0) { |
|---|
| 189 | if (getsockname(fd, (struct sockaddr *) &saddr, &size) < 0) |
|---|
| 190 | sysbail("cannot getsockname"); |
|---|
| 191 | if (saddr.ss_family == AF_INET) |
|---|
| 192 | client("127.0.0.1", source_ipv4); |
|---|
| 193 | #ifdef HAVE_INET6 |
|---|
| 194 | else if (saddr.ss_family == AF_INET6) |
|---|
| 195 | client("::1", source_ipv6); |
|---|
| 196 | #endif |
|---|
| 197 | else |
|---|
| 198 | skip_block(2, "unknown socket family %d", saddr.ss_family); |
|---|
| 199 | size = sizeof(saddr); |
|---|
| 200 | } else { |
|---|
| 201 | listener(fd); |
|---|
| 202 | waitpid(child, NULL, 0); |
|---|
| 203 | } |
|---|
| 204 | } |
|---|
| 205 | } |
|---|
| 206 | if (count == 1) |
|---|
| 207 | skip_block(3, "only one listening socket"); |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | |
|---|
| 211 | /* |
|---|
| 212 | * Bring up a server on port 11119 on the loopback address and test connecting |
|---|
| 213 | * to it via IPv4 using network_client_create. Takes an optional source |
|---|
| 214 | * address to use for client connections. |
|---|
| 215 | */ |
|---|
| 216 | static void |
|---|
| 217 | test_create_ipv4(const char *source) |
|---|
| 218 | { |
|---|
| 219 | int fd; |
|---|
| 220 | pid_t child; |
|---|
| 221 | |
|---|
| 222 | fd = network_bind_ipv4("127.0.0.1", 11119); |
|---|
| 223 | if (fd < 0) |
|---|
| 224 | sysbail("cannot create or bind socket"); |
|---|
| 225 | if (listen(fd, 1) < 0) { |
|---|
| 226 | sysnotice("# cannot listen to socket"); |
|---|
| 227 | ok_block(3, 0, "IPv4 network client"); |
|---|
| 228 | } else { |
|---|
| 229 | ok(1, "IPv4 network client"); |
|---|
| 230 | child = fork(); |
|---|
| 231 | if (child < 0) |
|---|
| 232 | sysbail("cannot fork"); |
|---|
| 233 | else if (child == 0) { |
|---|
| 234 | struct sockaddr_in sin; |
|---|
| 235 | FILE *out; |
|---|
| 236 | |
|---|
| 237 | fd = network_client_create(PF_INET, SOCK_STREAM, source); |
|---|
| 238 | if (fd < 0) |
|---|
| 239 | _exit(1); |
|---|
| 240 | sin.sin_family = AF_INET; |
|---|
| 241 | sin.sin_port = htons(11119); |
|---|
| 242 | sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
|---|
| 243 | if (connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) |
|---|
| 244 | _exit(1); |
|---|
| 245 | out = fdopen(fd, "w"); |
|---|
| 246 | if (out == NULL) |
|---|
| 247 | _exit(1); |
|---|
| 248 | fputs("socket test\r\n", out); |
|---|
| 249 | fclose(out); |
|---|
| 250 | _exit(0); |
|---|
| 251 | } else { |
|---|
| 252 | listener(fd); |
|---|
| 253 | waitpid(child, NULL, 0); |
|---|
| 254 | } |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | |
|---|
| 259 | /* |
|---|
| 260 | * Tests network_addr_compare. Takes the expected result, the two addresses, |
|---|
| 261 | * and the mask. |
|---|
| 262 | */ |
|---|
| 263 | static void |
|---|
| 264 | ok_addr(int expected, const char *a, const char *b, const char *mask) |
|---|
| 265 | { |
|---|
| 266 | if (expected) |
|---|
| 267 | ok(network_addr_match(a, b, mask), "compare %s %s %s", a, b, mask); |
|---|
| 268 | else |
|---|
| 269 | ok(!network_addr_match(a, b, mask), "compare %s %s %s", a, b, mask); |
|---|
| 270 | } |
|---|
| 271 | |
|---|
| 272 | |
|---|
| 273 | int |
|---|
| 274 | main(void) |
|---|
| 275 | { |
|---|
| 276 | int status; |
|---|
| 277 | struct addrinfo *ai, *ai4; |
|---|
| 278 | struct addrinfo hints; |
|---|
| 279 | char addr[INET6_ADDRSTRLEN]; |
|---|
| 280 | static const char *port = "119"; |
|---|
| 281 | |
|---|
| 282 | #ifdef HAVE_INET6 |
|---|
| 283 | struct addrinfo *ai6; |
|---|
| 284 | char *p; |
|---|
| 285 | static const char *ipv6_addr = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210"; |
|---|
| 286 | #endif |
|---|
| 287 | |
|---|
| 288 | plan(87); |
|---|
| 289 | |
|---|
| 290 | /* |
|---|
| 291 | * If IPv6 support appears to be available but doesn't work, we have to |
|---|
| 292 | * skip the test_all tests since they'll create a socket that we then |
|---|
| 293 | * can't connect to. This is the case on Solaris 8 without IPv6 |
|---|
| 294 | * configured. |
|---|
| 295 | */ |
|---|
| 296 | test_ipv4(NULL); |
|---|
| 297 | test_ipv6(NULL); |
|---|
| 298 | if (ipv6) |
|---|
| 299 | test_all(NULL, NULL); |
|---|
| 300 | else |
|---|
| 301 | skip_block(6, "IPv6 not configured"); |
|---|
| 302 | test_create_ipv4(NULL); |
|---|
| 303 | |
|---|
| 304 | /* This won't make a difference for loopback connections. */ |
|---|
| 305 | test_ipv4("127.0.0.1"); |
|---|
| 306 | test_ipv6("::1"); |
|---|
| 307 | if (ipv6) |
|---|
| 308 | test_all("127.0.0.1", "::1"); |
|---|
| 309 | else |
|---|
| 310 | skip_block(6, "IPv6 not configured"); |
|---|
| 311 | test_create_ipv4("127.0.0.1"); |
|---|
| 312 | |
|---|
| 313 | /* |
|---|
| 314 | * Now, test network_sockaddr_sprint, network_sockaddr_equal, and |
|---|
| 315 | * network_sockaddr_port. |
|---|
| 316 | */ |
|---|
| 317 | memset(&hints, 0, sizeof(hints)); |
|---|
| 318 | hints.ai_flags = AI_NUMERICHOST; |
|---|
| 319 | hints.ai_socktype = SOCK_STREAM; |
|---|
| 320 | status = getaddrinfo("127.0.0.1", port, &hints, &ai4); |
|---|
| 321 | if (status != 0) |
|---|
| 322 | bail("getaddrinfo on 127.0.0.1 failed: %s", gai_strerror(status)); |
|---|
| 323 | ok(network_sockaddr_sprint(addr, sizeof(addr), ai4->ai_addr), |
|---|
| 324 | "sprint of 127.0.0.1"); |
|---|
| 325 | is_string("127.0.0.1", addr, "...with right results"); |
|---|
| 326 | is_int(119, network_sockaddr_port(ai4->ai_addr), |
|---|
| 327 | "sockaddr_port"); |
|---|
| 328 | ok(network_sockaddr_equal(ai4->ai_addr, ai4->ai_addr), "sockaddr_equal"); |
|---|
| 329 | status = getaddrinfo("127.0.0.2", NULL, &hints, &ai); |
|---|
| 330 | if (status != 0) |
|---|
| 331 | bail("getaddrinfo on 127.0.0.2 failed: %s", gai_strerror(status)); |
|---|
| 332 | ok(!network_sockaddr_equal(ai->ai_addr, ai4->ai_addr), |
|---|
| 333 | "sockaddr_equal of unequal addresses"); |
|---|
| 334 | ok(!network_sockaddr_equal(ai4->ai_addr, ai->ai_addr), |
|---|
| 335 | "...and the other way around"); |
|---|
| 336 | |
|---|
| 337 | /* The same for IPv6. */ |
|---|
| 338 | #ifdef HAVE_INET6 |
|---|
| 339 | status = getaddrinfo(ipv6_addr, port, &hints, &ai6); |
|---|
| 340 | if (status != 0) |
|---|
| 341 | bail("getaddr on %s failed: %s", ipv6_addr, gai_strerror(status)); |
|---|
| 342 | ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr), |
|---|
| 343 | "sprint of IPv6 address"); |
|---|
| 344 | for (p = addr; *p != '\0'; p++) |
|---|
| 345 | if (islower((unsigned char) *p)) |
|---|
| 346 | *p = toupper((unsigned char) *p); |
|---|
| 347 | is_string(ipv6_addr, addr, "...with right results"); |
|---|
| 348 | is_int(119, network_sockaddr_port(ai6->ai_addr), "sockaddr_port IPv6"); |
|---|
| 349 | ok(network_sockaddr_equal(ai6->ai_addr, ai6->ai_addr), |
|---|
| 350 | "sockaddr_equal IPv6"); |
|---|
| 351 | ok(!network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr), |
|---|
| 352 | "...and not equal to IPv4"); |
|---|
| 353 | ok(!network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr), |
|---|
| 354 | "...other way around"); |
|---|
| 355 | |
|---|
| 356 | /* Test IPv4 mapped addresses. */ |
|---|
| 357 | status = getaddrinfo("::ffff:7f00:1", NULL, &hints, &ai6); |
|---|
| 358 | if (status != 0) |
|---|
| 359 | bail("getaddr on ::ffff:7f00:1 failed: %s", gai_strerror(status)); |
|---|
| 360 | ok(network_sockaddr_sprint(addr, sizeof(addr), ai6->ai_addr), |
|---|
| 361 | "sprint of IPv4-mapped address"); |
|---|
| 362 | is_string("127.0.0.1", addr, "...with right IPv4 result"); |
|---|
| 363 | ok(network_sockaddr_equal(ai4->ai_addr, ai6->ai_addr), |
|---|
| 364 | "sockaddr_equal of IPv4-mapped address"); |
|---|
| 365 | ok(network_sockaddr_equal(ai6->ai_addr, ai4->ai_addr), |
|---|
| 366 | "...and other way around"); |
|---|
| 367 | ok(!network_sockaddr_equal(ai->ai_addr, ai6->ai_addr), |
|---|
| 368 | "...but not some other address"); |
|---|
| 369 | ok(!network_sockaddr_equal(ai6->ai_addr, ai->ai_addr), |
|---|
| 370 | "...and the other way around"); |
|---|
| 371 | freeaddrinfo(ai6); |
|---|
| 372 | #else |
|---|
| 373 | skip_block(12, "IPv6 not supported"); |
|---|
| 374 | #endif |
|---|
| 375 | |
|---|
| 376 | /* Check the domains of functions and their error handling. */ |
|---|
| 377 | ai4->ai_addr->sa_family = AF_UNIX; |
|---|
| 378 | ok(!network_sockaddr_equal(ai4->ai_addr, ai4->ai_addr), |
|---|
| 379 | "equal not equal with address mismatches"); |
|---|
| 380 | is_int(0, network_sockaddr_port(ai4->ai_addr), |
|---|
| 381 | "port meaningless for AF_UNIX"); |
|---|
| 382 | |
|---|
| 383 | /* Tests for network_addr_compare. */ |
|---|
| 384 | ok_addr(1, "127.0.0.1", "127.0.0.1", NULL); |
|---|
| 385 | ok_addr(0, "127.0.0.1", "127.0.0.2", NULL); |
|---|
| 386 | ok_addr(1, "127.0.0.1", "127.0.0.0", "31"); |
|---|
| 387 | ok_addr(0, "127.0.0.1", "127.0.0.0", "32"); |
|---|
| 388 | ok_addr(0, "127.0.0.1", "127.0.0.0", "255.255.255.255"); |
|---|
| 389 | ok_addr(1, "127.0.0.1", "127.0.0.0", "255.255.255.254"); |
|---|
| 390 | ok_addr(1, "10.10.4.5", "10.10.4.255", "24"); |
|---|
| 391 | ok_addr(0, "10.10.4.5", "10.10.4.255", "25"); |
|---|
| 392 | ok_addr(1, "10.10.4.5", "10.10.4.255", "255.255.255.0"); |
|---|
| 393 | ok_addr(0, "10.10.4.5", "10.10.4.255", "255.255.255.128"); |
|---|
| 394 | ok_addr(0, "129.0.0.0", "1.0.0.0", "1"); |
|---|
| 395 | ok_addr(1, "129.0.0.0", "1.0.0.0", "0"); |
|---|
| 396 | ok_addr(1, "129.0.0.0", "1.0.0.0", "0.0.0.0"); |
|---|
| 397 | |
|---|
| 398 | /* Try some IPv6 addresses. */ |
|---|
| 399 | #ifdef HAVE_INET6 |
|---|
| 400 | ok_addr(1, ipv6_addr, ipv6_addr, NULL); |
|---|
| 401 | ok_addr(1, ipv6_addr, ipv6_addr, "128"); |
|---|
| 402 | ok_addr(1, ipv6_addr, ipv6_addr, "60"); |
|---|
| 403 | ok_addr(1, "::127", "0:0::127", "128"); |
|---|
| 404 | ok_addr(1, "::127", "0:0::128", "120"); |
|---|
| 405 | ok_addr(0, "::127", "0:0::128", "128"); |
|---|
| 406 | ok_addr(0, "::7fff", "0:0::8000", "113"); |
|---|
| 407 | ok_addr(1, "::7fff", "0:0::8000", "112"); |
|---|
| 408 | ok_addr(0, "::3:ffff", "::2:ffff", "120"); |
|---|
| 409 | ok_addr(0, "::3:ffff", "::2:ffff", "119"); |
|---|
| 410 | ok_addr(0, "ffff::1", "7fff::1", "1"); |
|---|
| 411 | ok_addr(1, "ffff::1", "7fff::1", "0"); |
|---|
| 412 | ok_addr(0, "fffg::1", "fffg::1", NULL); |
|---|
| 413 | ok_addr(0, "ffff::1", "7fff::1", "-1"); |
|---|
| 414 | ok_addr(0, "ffff::1", "ffff::1", "-1"); |
|---|
| 415 | ok_addr(0, "ffff::1", "ffff::1", "129"); |
|---|
| 416 | #else |
|---|
| 417 | skip_block(16, "IPv6 not supported"); |
|---|
| 418 | #endif |
|---|
| 419 | |
|---|
| 420 | /* Test some invalid addresses. */ |
|---|
| 421 | ok_addr(0, "fred", "fred", NULL); |
|---|
| 422 | ok_addr(0, "", "", NULL); |
|---|
| 423 | ok_addr(0, "", "", "0"); |
|---|
| 424 | ok_addr(0, "127.0.0.1", "127.0.0.1", "pete"); |
|---|
| 425 | ok_addr(0, "127.0.0.1", "127.0.0.1", "1p"); |
|---|
| 426 | ok_addr(0, "127.0.0.1", "127.0.0.1", "1p"); |
|---|
| 427 | ok_addr(0, "127.0.0.1", "127.0.0.1", "-1"); |
|---|
| 428 | ok_addr(0, "127.0.0.1", "127.0.0.1", "33"); |
|---|
| 429 | |
|---|
| 430 | return 0; |
|---|
| 431 | } |
|---|