├── LICENSE ├── README.md └── proxy.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Michael Tuexen 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of Michael Tuexen nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Generic SCTP Proxy 2 | 3 | ## Features 4 | The proxy preserves message boundaries, the ordered/unordered property, the payload protocol identifier, and the stream identifier. 5 | It distributes the incoming SCTP associations to multiple servers in a round robin fashion using multiple threads. 6 | 7 | ## Supported Platforms and Compilation 8 | The proxy supports all operating systems with kernel SCTP support. 9 | The following table shows how to compile the code. 10 | 11 | |OS | Compile Command | 12 | |:-------|:-------------------------------------------| 13 | |FreeBSD |`cc -o proxy -pthread proxy.c` | 14 | |Linux |`gcc -o proxy -pthread proxy.c -lsctp` | 15 | |Solaris |`gcc -o proxy proxy.c -lsocket -lnsl -lsctp`| 16 | 17 | On Linux, you must have installed the `libsctp-dev` package. 18 | This provides the required header files and the required library. 19 | 20 | ## Command Line Arguments 21 | 22 | * `-4` 23 | * `-6` 24 | * `-i number_of_incoming_streams` 25 | * `-o number_of_outgoing_streams` 26 | * `-L address_1,address_2,...,address_N:port` 27 | * `-X address_1,address_2,...,address_N` 28 | * `-S address_1,address_2,...,address_N:port` 29 | 30 | ## Example 31 | ``` 32 | proxy -i 2048 -o 1024 -L 127.0.0.1,::1:5001 -X 127.0.0.1,::1 -S 127.0.0.1,::1:6001 -S 127.0.0.1,::1:6002 33 | ``` 34 | The proxy will allow 2048 incoming streams from clients and requests 1024 outgoing streams from them. 35 | It will listen for clients on port 5001 using the IP-addresses 127.0.0.1 and ::1 as specified by the `-L` option. 36 | When connecting to a server, the proxy will use the IP-addresses 127.0.0.1 and ::1 as specified by the `-X` option. 37 | The proxy will connect to two servers, one listening at the IP-addresses 127.0.0.1 and ::1 on port 6001, and one litening at the IP addresses 127.0.0.1 and ::1 on port 6002, as specified by the `-S` options. 38 | -------------------------------------------------------------------------------- /proxy.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 2016 Michael Tuexen 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 | * SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #ifdef __linux__ 30 | #include 31 | #endif 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | /* 44 | * proxy -i 10 45 | * -o 10 46 | * -4 47 | * -6 48 | * -L 127.0.0.1,::1,10.10.10.10:5001 -> sctp_bindx() 49 | * -X 127.0.0.1,::1 -> sctp_bindx() 50 | * -S 127.0.0.1,::1:5678 -> sctp_connectx() 51 | * -S 127.0.0.1,::1:4567 -> sctp_connectx() 52 | * 53 | * The following is preserved: 54 | * - message boundaries 55 | * - ordered / unordered 56 | * - sid/ssn 57 | * - ppid 58 | * 59 | * Supported platforms: 60 | * - FreeBSD cc -pthread -o proxy proxy.c 61 | * - Linux gcc -pthread -o proxy proxy.c -lsctp 62 | * - Solaris: gcc -o proxy proxy.c -lnsl -lsocket -lsctp 63 | */ 64 | 65 | #define LISTEN_QUEUE 10 66 | #define INITIAL_BUF_SIZE 10240 67 | 68 | struct server_info { 69 | struct sockaddr *server_addrs; 70 | int number_addrs; 71 | }; 72 | 73 | struct proxy_info { 74 | int ipv4only; 75 | int ipv6only; 76 | int client_fd; /* Used for the client <-> proxy association */ 77 | int server_fd; /* Used for the proxy <-> server association */ 78 | struct sockaddr *local_addrs; /* Used for the proxy <-> server association */ 79 | int number_local_addrs; 80 | struct sockaddr *server_addrs; /* Used for the proxy <-> server association */ 81 | int number_server_addrs; 82 | char *client_buf; /* Used for messages received from the client */ 83 | size_t client_buf_size; 84 | size_t client_buf_offset; 85 | char *server_buf; /* User for messages received from the server */ 86 | size_t server_buf_size; 87 | size_t server_buf_offset; 88 | }; 89 | 90 | static void * 91 | proxy(void *arg) 92 | { 93 | struct proxy_info *info; 94 | fd_set rset; 95 | int max_fd, flags; 96 | ssize_t n; 97 | struct sctp_sndrcvinfo sndrcvinfo; 98 | struct sctp_status status; 99 | struct sctp_initmsg initmsg; 100 | struct sctp_event_subscribe events; 101 | socklen_t len; 102 | 103 | pthread_detach(pthread_self()); 104 | info = (struct proxy_info *)arg; 105 | 106 | /* First, get the number of streams used by the client */ 107 | len = (socklen_t)sizeof(struct sctp_status); 108 | if (getsockopt(info->client_fd, IPPROTO_SCTP, SCTP_STATUS, &status, &len) < 0) { 109 | fprintf(stderr, "proxy: Can't get number of streams: %s\n", strerror(errno)); 110 | goto cleanup; 111 | } 112 | /* Second allocate message buffers for the client and server */ 113 | info->client_buf_size = INITIAL_BUF_SIZE; 114 | info->client_buf_offset = 0; 115 | info->client_buf = malloc(info->client_buf_size); 116 | if (info->client_buf == NULL) { 117 | fprintf(stderr, "proxy: Can't allocate memory for messages from the client\n"); 118 | goto cleanup; 119 | } 120 | info->server_buf_size = INITIAL_BUF_SIZE; 121 | info->server_buf_offset = 0; 122 | info->server_buf = malloc(info->server_buf_size); 123 | if (info->server_buf == NULL) { 124 | fprintf(stderr, "proxy: Can't allocate memory for messages from the server\n"); 125 | goto cleanup; 126 | } 127 | /* Now establish an SCTP association with the server */ 128 | if ((info->server_fd = socket(info->ipv4only ? AF_INET : AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) { 129 | fprintf(stderr, "proxy: Can't open a socket: %s\n", strerror(errno)); 130 | goto cleanup; 131 | } 132 | if (!info->ipv4only) { 133 | if (setsockopt(info->server_fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&info->ipv6only, (socklen_t)sizeof(int)) < 0) { 134 | fprintf(stderr, "proxy: Can't set IPV6 mode: %s\n", strerror(errno)); 135 | goto cleanup; 136 | } 137 | } 138 | memset(&initmsg, 0, sizeof(struct sctp_initmsg)); 139 | initmsg.sinit_num_ostreams = status.sstat_instrms; 140 | initmsg.sinit_max_instreams = status.sstat_outstrms; 141 | if (setsockopt(info->server_fd, IPPROTO_SCTP, SCTP_INITMSG, (const void *)&initmsg, (socklen_t)sizeof(struct sctp_initmsg)) < 0) { 142 | fprintf(stderr, "proxy: Can't set the number of streams: %s.\n", strerror(errno)); 143 | goto cleanup; 144 | } 145 | memset(&events, 0, sizeof(struct sctp_event_subscribe)); 146 | events.sctp_data_io_event = 1; 147 | if (setsockopt(info->server_fd, IPPROTO_SCTP, SCTP_EVENTS, (const void *)&events, (socklen_t)sizeof(struct sctp_event_subscribe)) < 0) { 148 | fprintf(stderr, "proxy: Can't subscribe to data_io event: %s\n", strerror(errno)); 149 | goto cleanup; 150 | } 151 | if (sctp_bindx(info->server_fd, info->local_addrs, info->number_local_addrs, SCTP_BINDX_ADD_ADDR) < 0) { 152 | fprintf(stderr, "proxy: Can't bind local addresses: %s\n", strerror(errno)); 153 | goto cleanup; 154 | } 155 | if (sctp_connectx(info->server_fd, info->server_addrs, info->number_server_addrs, NULL) < 0) { 156 | fprintf(stderr, "proxy: Can't connect to server: %s\n", strerror(errno)); 157 | goto cleanup; 158 | } 159 | /* Time for message relaying */ 160 | for (;;) { 161 | FD_ZERO(&rset); 162 | max_fd = -1; 163 | FD_SET(info->client_fd, &rset); 164 | if (info->client_fd > max_fd) { 165 | max_fd = info->client_fd; 166 | } 167 | FD_SET(info->server_fd, &rset); 168 | if (info->server_fd > max_fd) { 169 | max_fd = info->server_fd; 170 | } 171 | select(max_fd + 1, &rset, NULL, NULL, NULL); 172 | if (FD_ISSET(info->client_fd, &rset)) { 173 | flags = 0; 174 | n = sctp_recvmsg(info->client_fd, 175 | info->client_buf + info->client_buf_offset, 176 | info->client_buf_size - info->client_buf_offset, 177 | NULL, NULL, 178 | &sndrcvinfo, 179 | &flags); 180 | if (n <-0) { 181 | fprintf(stderr, "proxy: sctp_recvmsg: %s\n", strerror(errno)); 182 | goto cleanup; 183 | } else if (n == 0) { 184 | goto cleanup; 185 | } else { 186 | info->client_buf_offset += n; 187 | if (flags & MSG_EOR) { 188 | n = sctp_sendmsg(info->server_fd, 189 | info->client_buf, 190 | info->client_buf_offset, 191 | NULL, 0, 192 | sndrcvinfo.sinfo_ppid, 193 | sndrcvinfo.sinfo_flags & SCTP_UNORDERED, 194 | sndrcvinfo.sinfo_stream, 195 | 0, 0); 196 | if (n < 0) { 197 | fprintf(stderr, "proxy: sctp_sendmsg: %s\n", strerror(errno)); 198 | goto cleanup; 199 | } else { 200 | info->client_buf_offset = 0; 201 | } 202 | } else { 203 | if (info->client_buf_offset == info->client_buf_size) { 204 | info->client_buf_size *= 2; 205 | info->client_buf = realloc(info->client_buf, info->client_buf_size); 206 | if (info->client_buf == NULL) { 207 | fprintf(stderr, "proxy: Can't re-allocate memory for messages from the client\n"); 208 | goto cleanup; 209 | } 210 | } 211 | } 212 | } 213 | } 214 | if (FD_ISSET(info->server_fd, &rset)) { 215 | flags = 0; 216 | n = sctp_recvmsg(info->server_fd, 217 | info->server_buf + info->server_buf_offset, 218 | info->server_buf_size - info->server_buf_offset, 219 | NULL, NULL, 220 | &sndrcvinfo, 221 | &flags); 222 | if (n <-0) { 223 | fprintf(stderr, "proxy: sctp_recvmsg: %s\n", strerror(errno)); 224 | goto cleanup; 225 | } else if (n == 0) { 226 | goto cleanup; 227 | } else { 228 | info->server_buf_offset += n; 229 | if (flags & MSG_EOR) { 230 | n = sctp_sendmsg(info->client_fd, 231 | info->server_buf, 232 | info->server_buf_offset, 233 | NULL, 0, 234 | sndrcvinfo.sinfo_ppid, 235 | sndrcvinfo.sinfo_flags & SCTP_UNORDERED, 236 | sndrcvinfo.sinfo_stream, 237 | 0, 0); 238 | if (n < 0) { 239 | fprintf(stderr, "proxy: sctp_sendmsg: %s\n", strerror(errno)); 240 | goto cleanup; 241 | } else { 242 | info->server_buf_offset = 0; 243 | } 244 | } else { 245 | if (info->server_buf_offset == info->server_buf_size) { 246 | info->server_buf_size *= 2; 247 | info->server_buf = realloc(info->server_buf, info->server_buf_size); 248 | if (info->server_buf == NULL) { 249 | fprintf(stderr, "proxy: Can't re-allocate memory for messages from the client\n"); 250 | goto cleanup; 251 | } 252 | } 253 | } 254 | } 255 | } 256 | } 257 | cleanup: 258 | /* Free all resources */ 259 | if (info->server_fd >= 0) { 260 | close(info->server_fd); 261 | } 262 | if (info->client_fd >= 0) { 263 | close(info->client_fd); 264 | } 265 | free(info->client_buf); 266 | free(info->server_buf); 267 | free(info); 268 | return (NULL); 269 | } 270 | 271 | static int 272 | parse_addrs_list(char *addr_list, char *port, int ipv4only, int ipv6only, struct sockaddr **addrs) 273 | { 274 | struct addrinfo hints, *res; 275 | char *addr; 276 | char *tmp; 277 | size_t size; 278 | int number_local_addrs; 279 | 280 | if ((addr_list == NULL) || (port == NULL)) { 281 | return (-1); 282 | } 283 | number_local_addrs = 1; 284 | for (tmp = addr_list; *tmp != '\0'; tmp++) { 285 | if (*tmp == ',') { 286 | number_local_addrs++; 287 | } 288 | } 289 | if (ipv4only) { 290 | size = number_local_addrs * sizeof(struct sockaddr_in); 291 | } else { 292 | size = number_local_addrs * sizeof(struct sockaddr_in6); 293 | } 294 | *addrs = (struct sockaddr *)malloc(size); 295 | memset(&hints, 0, sizeof(hints)); 296 | if (ipv4only) { 297 | hints.ai_family = AF_INET; 298 | } else { 299 | hints.ai_family = AF_INET6; 300 | } 301 | hints.ai_socktype = SOCK_STREAM; 302 | hints.ai_protocol = IPPROTO_SCTP; 303 | hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; 304 | if (!ipv4only && !ipv6only) { 305 | hints.ai_flags |= AI_V4MAPPED; 306 | } 307 | tmp = (char *)*addrs; 308 | for (addr = strtok(addr_list, ","); addr != NULL; addr = strtok(NULL, ",")) { 309 | if (getaddrinfo(addr, port, &hints, &res) != 0) { 310 | return (-1); 311 | } 312 | memcpy(tmp, res->ai_addr, res->ai_addrlen); 313 | tmp += res->ai_addrlen; 314 | freeaddrinfo(res); 315 | } 316 | return (number_local_addrs); 317 | } 318 | 319 | static int 320 | parse_addrs_list_port(char *addr_list, int ipv4only, int ipv6only, struct sockaddr **addrs) 321 | { 322 | char *port; 323 | char *last_colon; 324 | 325 | if (addr_list == NULL) { 326 | return (-1); 327 | } 328 | last_colon = strrchr(addr_list, ':'); 329 | if (last_colon == NULL) { 330 | return (-1); 331 | } else { 332 | port = last_colon + 1; 333 | *last_colon = '\0'; 334 | return (parse_addrs_list(addr_list, port, ipv4only, ipv6only, addrs)); 335 | } 336 | } 337 | 338 | 339 | /* This functions implements a trivial round robin selection algorithm. 340 | * We might add other policies later 341 | */ 342 | 343 | static struct server_info * 344 | select_a_server(struct server_info server_infos[], int number_servers) { 345 | static int i = 0; 346 | 347 | if (i >= number_servers) { 348 | i = 0; 349 | } 350 | return (&server_infos[i++]); 351 | } 352 | 353 | int 354 | main(int argc, char **argv) 355 | { 356 | int fd; 357 | struct sockaddr *local_addrs; 358 | int number_local_addrs; 359 | pthread_t tid; 360 | int c; 361 | int ipv4only; 362 | int ipv6only; 363 | uint16_t i_streams, o_streams; 364 | struct sctp_initmsg initmsg; 365 | struct sctp_event_subscribe events; 366 | long value; 367 | int number_servers, i; 368 | struct server_info *server_infos, *server_info; 369 | char *L_arg, *X_arg, **S_args; 370 | struct proxy_info *proxy_info; 371 | 372 | ipv4only = 0; 373 | ipv6only = 0; 374 | i_streams = 1; 375 | o_streams = 1; 376 | L_arg = NULL; 377 | X_arg = NULL; 378 | S_args = calloc(argc, sizeof(char *)); 379 | number_servers = 0; 380 | 381 | while ((c = getopt(argc, argv, "i:L:o:S:X:46")) != -1) { 382 | switch(c) { 383 | case 'i': 384 | value = strtol(optarg, NULL, 10); 385 | if ((0 < value) && (value < 65536)) { 386 | i_streams = (uint16_t)value; 387 | } else { 388 | fprintf(stderr, "number of incoming streams out of range.\n"); 389 | return (1); 390 | } 391 | break; 392 | case 'L': 393 | if (L_arg != NULL) { 394 | fprintf(stderr, "addresses to be listening on provided multiple times.\n"); 395 | return (1); 396 | } else { 397 | L_arg = optarg; 398 | } 399 | break; 400 | case 'o': 401 | value = strtol(optarg, NULL, 10); 402 | if ((0 < value) && (value < 65536)) { 403 | o_streams = (uint16_t)value; 404 | } else { 405 | fprintf(stderr, "number of outgoing streams out of range.\n"); 406 | return (1); 407 | } 408 | break; 409 | case 'S': 410 | S_args[number_servers++]= optarg; 411 | break; 412 | case 'X': 413 | if (X_arg != NULL) { 414 | fprintf(stderr, "addresses to be uses as a client provided multiple times.\n"); 415 | return (1); 416 | } else { 417 | X_arg = optarg; 418 | } 419 | break; 420 | case '4': 421 | ipv4only = 1; 422 | if (ipv6only) { 423 | fprintf(stderr, "-4 and -6 can't be specified together.\n"); 424 | return (1); 425 | } 426 | break; 427 | case '6': 428 | ipv6only = 1; 429 | if (ipv4only) { 430 | fprintf(stderr, "-4 and -6 can't be specified together.\n"); 431 | return (1); 432 | } 433 | break; 434 | default: 435 | fprintf(stderr, "%s", "Unknown option.\n"); 436 | return (1); 437 | } 438 | } 439 | 440 | if ((fd = socket(ipv4only ? AF_INET : AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) { 441 | fprintf(stderr, "Can't open the listening socket: %s.\n", strerror(errno)); 442 | return (1); 443 | } 444 | if (!ipv4only) { 445 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const void *)&ipv6only, (socklen_t)sizeof(int)) < 0) { 446 | fprintf(stderr, "Can't set the listening socket to IPv6 only: %s.\n", strerror(errno)); 447 | } 448 | } 449 | memset(&initmsg, 0, sizeof(struct sctp_initmsg)); 450 | initmsg.sinit_num_ostreams = o_streams; 451 | initmsg.sinit_max_instreams = i_streams; 452 | if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, (const void *)&initmsg, (socklen_t)sizeof(struct sctp_initmsg)) < 0) { 453 | fprintf(stderr, "Can't set the number of streams: %s.\n", strerror(errno)); 454 | return (1); 455 | } 456 | memset(&events, 0, sizeof(struct sctp_event_subscribe)); 457 | events.sctp_data_io_event = 1; 458 | if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, (const void *)&events, (socklen_t)sizeof(struct sctp_event_subscribe)) < 0) { 459 | fprintf(stderr, "proxy: Can't subscribe to data_io event: %s\n", strerror(errno)); 460 | return (1); 461 | } 462 | 463 | number_local_addrs = parse_addrs_list_port(L_arg, ipv4only, ipv6only, &local_addrs); 464 | if (number_local_addrs > 0) { 465 | if (sctp_bindx(fd, local_addrs, number_local_addrs, SCTP_BINDX_ADD_ADDR) < 0) { 466 | fprintf(stderr, "Can't bind the listening socket: %s.\n", strerror(errno)); 467 | return (1); 468 | } 469 | free(local_addrs); 470 | } else { 471 | fprintf(stderr, "No valid local addresses to listen on are specified.\n"); 472 | return (1); 473 | } 474 | number_local_addrs = parse_addrs_list(X_arg, "0", ipv4only, ipv6only, &local_addrs); 475 | if (number_local_addrs <= 0) { 476 | fprintf(stderr, "No local addresses to be used as a client are specified.\n"); 477 | return (1); 478 | } 479 | server_infos = calloc(number_servers, sizeof(struct server_info)); 480 | for (i = 0; i < number_servers; i++) { 481 | server_infos[i].number_addrs = parse_addrs_list_port(S_args[i], ipv4only, ipv6only, &server_infos[i].server_addrs); 482 | if (server_infos[i].number_addrs <= 0) { 483 | fprintf(stderr, "No valid remote addresses specified for server %d.\n", i); 484 | return (1); 485 | } 486 | } 487 | if (listen(fd, LISTEN_QUEUE) < 0) { 488 | fprintf(stderr, "Can't set the listening socket to the LISTEN state: %s.\n", strerror(errno)); 489 | return (1); 490 | } 491 | for (;;) { 492 | proxy_info = calloc(1, sizeof(struct proxy_info)); 493 | if ((proxy_info->client_fd = accept(fd, NULL, NULL)) < 0) { 494 | fprintf(stderr, "Couldn't accept an association: %s.\n", strerror(errno)); 495 | free(proxy_info); 496 | } else { 497 | server_info = select_a_server(server_infos, number_servers); 498 | proxy_info->ipv4only = ipv4only; 499 | proxy_info->ipv6only = ipv6only; 500 | proxy_info->server_fd = -1; 501 | proxy_info->local_addrs = local_addrs; 502 | proxy_info->number_local_addrs = number_local_addrs; 503 | proxy_info->server_addrs = server_info->server_addrs; 504 | proxy_info->number_server_addrs = server_info->number_addrs; 505 | if (pthread_create(&tid, NULL, &proxy, (void *)proxy_info) != 0) { 506 | fprintf(stderr, "Couldn't start a thread.\n"); 507 | close(proxy_info->client_fd); 508 | free(proxy_info); 509 | } 510 | } 511 | } 512 | if (close(fd) < 0) { 513 | fprintf(stderr, "Couldn't close the listening socket.\n"); 514 | } 515 | return (0); 516 | } 517 | --------------------------------------------------------------------------------