列挙型 | |
enum | SOCK_OPT_TYPES { OPT_BOOL, OPT_INT, OPT_ON } |
関数 | |
static int | establish_proxy_connection (int fd, char *host, int port, char *proxy_user, char *proxy_pass) |
Establish a proxy connection on an open socket to a web proxy by using the CONNECT method. | |
int | try_bind_local (int s, int ai_family, int ai_socktype, const char *bind_addr) |
Try to set the local address for a newly-created socket. | |
int | open_socket_out (char *host, int port, const char *bind_addr, int af_hint) |
Open a socket to a tcp remote host with the specified port . | |
int | open_socket_out_wrapped (char *host, int port, const char *bind_addr, int af_hint) |
Open an outgoing socket, but allow for it to be intercepted by $RSYNC_CONNECT_PROG, which will execute a program across a TCP socketpair rather than really opening a socket. | |
static int * | open_socket_in (int type, int port, const char *bind_addr, int af_hint) |
Open one or more sockets for incoming data using the specified type, port, and address. | |
int | is_a_socket (int fd) |
static RETSIGTYPE | sigchld_handler (UNUSED(int val)) |
void | start_accept_loop (int port, int(*fn)(int, int)) |
void | set_socket_options (int fd, char *options) |
Set user socket options | |
void | become_daemon (void) |
Become a daemon, discarding the controlling terminal | |
static int | socketpair_tcp (int fd[2]) |
This is like socketpair but uses tcp. | |
int | sock_exec (const char *prog) |
Run a program on a local tcp socket, so that we can talk to it's stdin and stdout. | |
変数 | |
char * | bind_address |
Local address to bind. | |
int | default_af_hint |
Network address family. | |
static struct sigaction | sigact |
struct { | |
char * name | |
int level | |
int option | |
int value | |
int opttype | |
} | socket_options [] |
This file is now converted to use the new-style getaddrinfo() interface, which supports IPv6 but is also supported on recent IPv4-only machines. On systems that don't have that interface, we emulate it using the KAME implementation.
socket.c で定義されています。
enum SOCK_OPT_TYPES |
static int establish_proxy_connection | ( | int | fd, | |
char * | host, | |||
int | port, | |||
char * | proxy_user, | |||
char * | proxy_pass | |||
) | [static] |
Establish a proxy connection on an open socket to a web proxy by using the CONNECT method.
If proxy_user and proxy_pass are not NULL, they are used to authenticate to the proxy using the "Basic" proxy-authorization protocol
参照先 base64_encode()・errno・FERROR・rprintf()・rsyserr()・snprintf()・stringjoin().
00053 { 00054 char *cp, buffer[1024]; 00055 char *authhdr, authbuf[1024]; 00056 int len; 00057 00058 if (proxy_user && proxy_pass) { 00059 stringjoin(buffer, sizeof buffer, 00060 proxy_user, ":", proxy_pass, NULL); 00061 len = strlen(buffer); 00062 00063 if ((len*8 + 5) / 6 >= (int)sizeof authbuf - 3) { 00064 rprintf(FERROR, 00065 "authentication information is too long\n"); 00066 return -1; 00067 } 00068 00069 base64_encode(buffer, len, authbuf, 1); 00070 authhdr = "\r\nProxy-Authorization: Basic "; 00071 } else { 00072 *authbuf = '\0'; 00073 authhdr = ""; 00074 } 00075 00076 snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", 00077 host, port, authhdr, authbuf); 00078 len = strlen(buffer); 00079 if (write(fd, buffer, len) != len) { 00080 rsyserr(FERROR, errno, "failed to write to proxy"); 00081 return -1; 00082 } 00083 00084 for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) { 00085 if (read(fd, cp, 1) != 1) { 00086 rsyserr(FERROR, errno, "failed to read from proxy"); 00087 return -1; 00088 } 00089 if (*cp == '\n') 00090 break; 00091 } 00092 00093 if (*cp != '\n') 00094 cp++; 00095 *cp-- = '\0'; 00096 if (*cp == '\r') 00097 *cp = '\0'; 00098 if (strncmp(buffer, "HTTP/", 5) != 0) { 00099 rprintf(FERROR, "bad response from proxy -- %s\n", 00100 buffer); 00101 return -1; 00102 } 00103 for (cp = &buffer[5]; isdigit(*(uchar*)cp) || *cp == '.'; cp++) {} 00104 while (*cp == ' ') 00105 cp++; 00106 if (*cp != '2') { 00107 rprintf(FERROR, "bad response from proxy -- %s\n", 00108 buffer); 00109 return -1; 00110 } 00111 /* throw away the rest of the HTTP header */ 00112 while (1) { 00113 for (cp = buffer; cp < &buffer[sizeof buffer - 1]; cp++) { 00114 if (read(fd, cp, 1) != 1) { 00115 rsyserr(FERROR, errno, 00116 "failed to read from proxy"); 00117 return -1; 00118 } 00119 if (*cp == '\n') 00120 break; 00121 } 00122 if (cp > buffer && *cp == '\n') 00123 cp--; 00124 if (cp == buffer && (*cp == '\n' || *cp == '\r')) 00125 break; 00126 } 00127 return 0; 00128 }
int try_bind_local | ( | int | s, | |
int | ai_family, | |||
int | ai_socktype, | |||
const char * | bind_addr | |||
) |
Try to set the local address for a newly-created socket.
Return -1 if this fails.
参照先 addrinfo::ai_addr・addrinfo::ai_addrlen・addrinfo::ai_next・FERROR・freeaddrinfo()・gai_strerror()・getaddrinfo()・rprintf().
参照元 open_socket_out().
00137 { 00138 int error; 00139 struct addrinfo bhints, *bres_all, *r; 00140 00141 memset(&bhints, 0, sizeof bhints); 00142 bhints.ai_family = ai_family; 00143 bhints.ai_socktype = ai_socktype; 00144 bhints.ai_flags = AI_PASSIVE; 00145 if ((error = getaddrinfo(bind_addr, NULL, &bhints, &bres_all))) { 00146 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n", 00147 bind_addr, gai_strerror(error)); 00148 return -1; 00149 } 00150 00151 for (r = bres_all; r; r = r->ai_next) { 00152 if (bind(s, r->ai_addr, r->ai_addrlen) == -1) 00153 continue; 00154 freeaddrinfo(bres_all); 00155 return s; 00156 } 00157 00158 /* no error message; there might be some problem that allows 00159 * creation of the socket but not binding, perhaps if the 00160 * machine has no ipv6 address of this name. */ 00161 freeaddrinfo(bres_all); 00162 return -1; 00163 }
int open_socket_out | ( | char * | host, | |
int | port, | |||
const char * | bind_addr, | |||
int | af_hint | |||
) |
Open a socket to a tcp remote host with the specified port .
Based on code from Warren. Proxy support by Stephen Rothwell. getaddrinfo() rewrite contributed by KAME.net.
Now that we support IPv6 we need to look up the remote machine's address first, using af_hint
to set a preference for the type of address. Then depending on whether it has v4 or v6 addresses we try to open a connection.
The loop allows for machines with some addresses which may not be reachable, perhaps because we can't e.g. route ipv6 to that network but we can get ip4 packets through.
bind_addr | Local address to use. Normally NULL to bind the wildcard address. | |
af_hint | Address family, e.g. AF_INET or AF_INET6. |
参照先 addrinfo::ai_addr・addrinfo::ai_addrlen・addrinfo::ai_family・addrinfo::ai_next・addrinfo::ai_protocol・addrinfo::ai_socktype・FERROR・FINFO・gai_strerror()・getaddrinfo()・rprintf()・snprintf()・strlcpy()・try_bind_local()・verbose.
参照元 open_socket_out_wrapped().
00188 { 00189 int type = SOCK_STREAM; 00190 int error, s; 00191 struct addrinfo hints, *res0, *res; 00192 char portbuf[10]; 00193 char *h, *cp; 00194 int proxied = 0; 00195 char buffer[1024]; 00196 char *proxy_user = NULL, *proxy_pass = NULL; 00197 00198 /* if we have a RSYNC_PROXY env variable then redirect our 00199 * connetcion via a web proxy at the given address. */ 00200 h = getenv("RSYNC_PROXY"); 00201 proxied = h != NULL && *h != '\0'; 00202 00203 if (proxied) { 00204 strlcpy(buffer, h, sizeof buffer); 00205 00206 /* Is the USER:PASS@ prefix present? */ 00207 if ((cp = strrchr(buffer, '@')) != NULL) { 00208 *cp++ = '\0'; 00209 /* The remainder is the HOST:PORT part. */ 00210 h = cp; 00211 00212 if ((cp = strchr(buffer, ':')) == NULL) { 00213 rprintf(FERROR, 00214 "invalid proxy specification: should be USER:PASS@HOST:PORT\n"); 00215 return -1; 00216 } 00217 *cp++ = '\0'; 00218 00219 proxy_user = buffer; 00220 proxy_pass = cp; 00221 } else { 00222 /* The whole buffer is the HOST:PORT part. */ 00223 h = buffer; 00224 } 00225 00226 if ((cp = strchr(h, ':')) == NULL) { 00227 rprintf(FERROR, 00228 "invalid proxy specification: should be HOST:PORT\n"); 00229 return -1; 00230 } 00231 *cp++ = '\0'; 00232 strlcpy(portbuf, cp, sizeof portbuf); 00233 if (verbose >= 2) { 00234 rprintf(FINFO, "connection via http proxy %s port %s\n", 00235 h, portbuf); 00236 } 00237 } else { 00238 snprintf(portbuf, sizeof portbuf, "%d", port); 00239 h = host; 00240 } 00241 00242 memset(&hints, 0, sizeof hints); 00243 hints.ai_family = af_hint; 00244 hints.ai_socktype = type; 00245 error = getaddrinfo(h, portbuf, &hints, &res0); 00246 if (error) { 00247 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n", 00248 h, portbuf, gai_strerror(error)); 00249 return -1; 00250 } 00251 00252 s = -1; 00253 /* Try to connect to all addresses for this machine until we get 00254 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6 00255 * addresses. We need to create a socket for each record, since the 00256 * address record tells us what protocol to use to try to connect. */ 00257 for (res = res0; res; res = res->ai_next) { 00258 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 00259 if (s < 0) 00260 continue; 00261 00262 if (bind_addr 00263 && try_bind_local(s, res->ai_family, type, 00264 bind_addr) == -1) { 00265 close(s); 00266 s = -1; 00267 continue; 00268 } 00269 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 00270 close(s); 00271 s = -1; 00272 continue; 00273 } 00274 if (proxied 00275 && establish_proxy_connection(s, host, port, 00276 proxy_user, proxy_pass) != 0) { 00277 close(s); 00278 s = -1; 00279 continue; 00280 } 00281 break; 00282 } 00283 freeaddrinfo(res0); 00284 if (s < 0) { 00285 rsyserr(FERROR, errno, "failed to connect to %s", h); 00286 return -1; 00287 } 00288 return s; 00289 }
int open_socket_out_wrapped | ( | char * | host, | |
int | port, | |||
const char * | bind_addr, | |||
int | af_hint | |||
) |
Open an outgoing socket, but allow for it to be intercepted by $RSYNC_CONNECT_PROG, which will execute a program across a TCP socketpair rather than really opening a socket.
We use this primarily in testing to detect TCP flow bugs, but not cause security problems by really opening remote connections.
This is based on the Samba LIBSMB_PROG feature.
bind_addr | Local address to use. Normally NULL to get the stack default. |
参照先 FINFO・open_socket_out()・rprintf()・sock_exec()・verbose.
00306 { 00307 char *prog = getenv("RSYNC_CONNECT_PROG"); 00308 00309 if (verbose >= 2) { 00310 rprintf(FINFO, "%sopening tcp connection to %s port %d\n", 00311 prog ? "Using RSYNC_CONNECT_PROG instead of " : "", 00312 host, port); 00313 } 00314 if (prog) 00315 return sock_exec(prog); 00316 return open_socket_out(host, port, bind_addr, af_hint); 00317 }
static int* open_socket_in | ( | int | type, | |
int | port, | |||
const char * | bind_addr, | |||
int | af_hint | |||
) | [static] |
Open one or more sockets for incoming data using the specified type, port, and address.
The getaddrinfo() call may return several address results, e.g. for the machine's IPv4 and IPv6 name.
We return an array of file-descriptors to the sockets, with a trailing -1 value to indicate the end of the list.
bind_addr | Local address to bind, or NULL to allow it to default. |
参照先 addrinfo::ai_addr・addrinfo::ai_addrlen・addrinfo::ai_family・addrinfo::ai_next・addrinfo::ai_protocol・addrinfo::ai_socktype・asprintf()・default_af_hint・errno・FERROR・FLOG・freeaddrinfo()・gai_strerror()・getaddrinfo()・out_of_memory()・rprintf()・rwrite()・snprintf()・verbose.
参照元 start_accept_loop().
00336 { 00337 int one = 1; 00338 int s, *socks, maxs, i, ecnt; 00339 struct addrinfo hints, *all_ai, *resp; 00340 char portbuf[10], **errmsgs; 00341 int error; 00342 00343 memset(&hints, 0, sizeof hints); 00344 hints.ai_family = af_hint; 00345 hints.ai_socktype = type; 00346 hints.ai_flags = AI_PASSIVE; 00347 snprintf(portbuf, sizeof portbuf, "%d", port); 00348 error = getaddrinfo(bind_addr, portbuf, &hints, &all_ai); 00349 if (error) { 00350 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n", 00351 bind_addr, gai_strerror(error)); 00352 return NULL; 00353 } 00354 00355 /* Count max number of sockets we might open. */ 00356 for (maxs = 0, resp = all_ai; resp; resp = resp->ai_next, maxs++) {} 00357 00358 socks = new_array(int, maxs + 1); 00359 errmsgs = new_array(char *, maxs); 00360 if (!socks || !errmsgs) 00361 out_of_memory("open_socket_in"); 00362 00363 /* We may not be able to create the socket, if for example the 00364 * machine knows about IPv6 in the C library, but not in the 00365 * kernel. */ 00366 for (resp = all_ai, i = ecnt = 0; resp; resp = resp->ai_next) { 00367 s = socket(resp->ai_family, resp->ai_socktype, 00368 resp->ai_protocol); 00369 00370 if (s == -1) { 00371 int r = asprintf(&errmsgs[ecnt++], 00372 "socket(%d,%d,%d) failed: %s\n", 00373 (int)resp->ai_family, (int)resp->ai_socktype, 00374 (int)resp->ai_protocol, strerror(errno)); 00375 if (r < 0) 00376 out_of_memory("open_socket_in"); 00377 /* See if there's another address that will work... */ 00378 continue; 00379 } 00380 00381 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 00382 (char *)&one, sizeof one); 00383 00384 #ifdef IPV6_V6ONLY 00385 if (resp->ai_family == AF_INET6) { 00386 if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, 00387 (char *)&one, sizeof one) < 0 00388 && default_af_hint != AF_INET6) { 00389 close(s); 00390 continue; 00391 } 00392 } 00393 #endif 00394 00395 /* Now we've got a socket - we need to bind it. */ 00396 if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) { 00397 /* Nope, try another */ 00398 int r = asprintf(&errmsgs[ecnt++], 00399 "bind() failed: %s (address-family %d)\n", 00400 strerror(errno), (int)resp->ai_family); 00401 if (r < 0) 00402 out_of_memory("open_socket_in"); 00403 close(s); 00404 continue; 00405 } 00406 00407 socks[i++] = s; 00408 } 00409 socks[i] = -1; 00410 00411 if (all_ai) 00412 freeaddrinfo(all_ai); 00413 00414 /* Only output the socket()/bind() messages if we were totally 00415 * unsuccessful, or if the daemon is being run with -vv. */ 00416 for (s = 0; s < ecnt; s++) { 00417 if (!i || verbose > 1) 00418 rwrite(FLOG, errmsgs[s], strlen(errmsgs[s])); 00419 free(errmsgs[s]); 00420 } 00421 free(errmsgs); 00422 00423 if (!i) { 00424 rprintf(FERROR, 00425 "unable to bind any inbound sockets on port %d\n", 00426 port); 00427 free(socks); 00428 return NULL; 00429 } 00430 return socks; 00431 }
int is_a_socket | ( | int | fd | ) |
参照元 close_all()・daemon_main().
00438 { 00439 int v; 00440 socklen_t l = sizeof (int); 00441 00442 /* Parameters to getsockopt, setsockopt etc are very 00443 * unstandardized across platforms, so don't be surprised if 00444 * there are compiler warnings on e.g. SCO OpenSwerver or AIX. 00445 * It seems they all eventually get the right idea. 00446 * 00447 * Debian says: ``The fifth argument of getsockopt and 00448 * setsockopt is in reality an int [*] (and this is what BSD 00449 * 4.* and libc4 and libc5 have). Some POSIX confusion 00450 * resulted in the present socklen_t. The draft standard has 00451 * not been adopted yet, but glibc2 already follows it and 00452 * also has socklen_t [*]. See also accept(2).'' 00453 * 00454 * We now return to your regularly scheduled programming. */ 00455 return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0; 00456 }
static RETSIGTYPE sigchld_handler | ( | UNUSED(int val) | ) | [static] |
参照先 waitpid().
参照元 start_accept_loop().
00460 { 00461 #ifdef WNOHANG 00462 while (waitpid(-1, NULL, WNOHANG) > 0) {} 00463 #endif 00464 #ifndef HAVE_SIGACTION 00465 signal(SIGCHLD, sigchld_handler); 00466 #endif 00467 }
void start_accept_loop | ( | int | port, | |
int(*)(int, int) | fn | |||
) |
参照先 bind_address・close_all()・default_af_hint・errno・FERROR・FINFO・logfile_close()・logfile_reopen()・open_socket_in()・rprintf()・rsyserr()・sigact・sigchld_handler().
参照元 daemon_main().
00471 { 00472 fd_set deffds; 00473 int *sp, maxfd, i; 00474 00475 #ifdef HAVE_SIGACTION 00476 sigact.sa_flags = SA_NOCLDSTOP; 00477 #endif 00478 00479 /* open an incoming socket */ 00480 sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); 00481 if (sp == NULL) 00482 exit_cleanup(RERR_SOCKETIO); 00483 00484 /* ready to listen */ 00485 FD_ZERO(&deffds); 00486 for (i = 0, maxfd = -1; sp[i] >= 0; i++) { 00487 if (listen(sp[i], 5) < 0) { 00488 rsyserr(FERROR, errno, "listen() on socket failed"); 00489 #ifdef INET6 00490 if (errno == EADDRINUSE && i > 0) { 00491 rprintf(FINFO, 00492 "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); 00493 } 00494 #endif 00495 exit_cleanup(RERR_SOCKETIO); 00496 } 00497 FD_SET(sp[i], &deffds); 00498 if (maxfd < sp[i]) 00499 maxfd = sp[i]; 00500 } 00501 00502 /* now accept incoming connections - forking a new process 00503 * for each incoming connection */ 00504 while (1) { 00505 fd_set fds; 00506 pid_t pid; 00507 int fd; 00508 struct sockaddr_storage addr; 00509 socklen_t addrlen = sizeof addr; 00510 00511 /* close log file before the potentially very long select so 00512 * file can be trimmed by another process instead of growing 00513 * forever */ 00514 logfile_close(); 00515 00516 #ifdef FD_COPY 00517 FD_COPY(&deffds, &fds); 00518 #else 00519 fds = deffds; 00520 #endif 00521 00522 if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1) 00523 continue; 00524 00525 for (i = 0, fd = -1; sp[i] >= 0; i++) { 00526 if (FD_ISSET(sp[i], &fds)) { 00527 fd = accept(sp[i], (struct sockaddr *)&addr, 00528 &addrlen); 00529 break; 00530 } 00531 } 00532 00533 if (fd < 0) 00534 continue; 00535 00536 SIGACTION(SIGCHLD, sigchld_handler); 00537 00538 if ((pid = fork()) == 0) { 00539 int ret; 00540 for (i = 0; sp[i] >= 0; i++) 00541 close(sp[i]); 00542 /* Re-open log file in child before possibly giving 00543 * up privileges (see logfile_close() above). */ 00544 logfile_reopen(); 00545 ret = fn(fd, fd); 00546 close_all(); 00547 _exit(ret); 00548 } else if (pid < 0) { 00549 rsyserr(FERROR, errno, 00550 "could not create child server process"); 00551 close(fd); 00552 /* This might have happened because we're 00553 * overloaded. Sleep briefly before trying to 00554 * accept again. */ 00555 sleep(2); 00556 } else { 00557 /* Parent doesn't need this fd anymore. */ 00558 close(fd); 00559 } 00560 } 00561 }
void set_socket_options | ( | int | fd, | |
char * | options | |||
) |
Set user socket options
参照先 errno・FERROR・level・name・OPT_BOOL・OPT_INT・option・opttype・out_of_memory()・rprintf()・rsyserr()・socket_options・strdup()・value.
参照元 start_daemon()・start_socket_client().
00612 { 00613 char *tok; 00614 00615 if (!options || !*options) 00616 return; 00617 00618 options = strdup(options); 00619 00620 if (!options) 00621 out_of_memory("set_socket_options"); 00622 00623 for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) { 00624 int ret=0,i; 00625 int value = 1; 00626 char *p; 00627 int got_value = 0; 00628 00629 if ((p = strchr(tok,'='))) { 00630 *p = 0; 00631 value = atoi(p+1); 00632 got_value = 1; 00633 } 00634 00635 for (i = 0; socket_options[i].name; i++) { 00636 if (strcmp(socket_options[i].name,tok)==0) 00637 break; 00638 } 00639 00640 if (!socket_options[i].name) { 00641 rprintf(FERROR,"Unknown socket option %s\n",tok); 00642 continue; 00643 } 00644 00645 switch (socket_options[i].opttype) { 00646 case OPT_BOOL: 00647 case OPT_INT: 00648 ret = setsockopt(fd,socket_options[i].level, 00649 socket_options[i].option, 00650 (char *)&value, sizeof (int)); 00651 break; 00652 00653 case OPT_ON: 00654 if (got_value) 00655 rprintf(FERROR,"syntax error -- %s does not take a value\n",tok); 00656 00657 { 00658 int on = socket_options[i].value; 00659 ret = setsockopt(fd,socket_options[i].level, 00660 socket_options[i].option, 00661 (char *)&on, sizeof (int)); 00662 } 00663 break; 00664 } 00665 00666 if (ret != 0) { 00667 rsyserr(FERROR, errno, 00668 "failed to set socket option %s", tok); 00669 } 00670 } 00671 00672 free(options); 00673 }
void become_daemon | ( | void | ) |
Become a daemon, discarding the controlling terminal
参照元 daemon_main().
00679 { 00680 int i; 00681 00682 if (fork()) { 00683 _exit(0); 00684 } 00685 00686 /* detach from the terminal */ 00687 #ifdef HAVE_SETSID 00688 setsid(); 00689 #elif defined TIOCNOTTY 00690 i = open("/dev/tty", O_RDWR); 00691 if (i >= 0) { 00692 ioctl(i, (int)TIOCNOTTY, (char *)0); 00693 close(i); 00694 } 00695 #endif 00696 /* make sure that stdin, stdout an stderr don't stuff things 00697 * up (library functions, for example) */ 00698 for (i = 0; i < 3; i++) { 00699 close(i); 00700 open("/dev/null", O_RDWR); 00701 } 00702 }
static int socketpair_tcp | ( | int | fd[2] | ) | [static] |
This is like socketpair but uses tcp.
It is used by the Samba regression test code.
The function guarantees that nobody else can attach to the socket, or if they do that this function fails and the socket gets closed returns 0 on success, -1 on failure the resulting file descriptors are symmetrical.
参照先 errno・failed()・set_blocking()・set_nonblocking().
参照元 sock_exec().
00715 { 00716 int listener; 00717 struct sockaddr_in sock; 00718 struct sockaddr_in sock2; 00719 socklen_t socklen = sizeof sock; 00720 int connect_done = 0; 00721 00722 fd[0] = fd[1] = listener = -1; 00723 00724 memset(&sock, 0, sizeof sock); 00725 00726 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) 00727 goto failed; 00728 00729 memset(&sock2, 0, sizeof sock2); 00730 #ifdef HAVE_SOCKADDR_IN_LEN 00731 sock2.sin_len = sizeof sock2; 00732 #endif 00733 sock2.sin_family = PF_INET; 00734 00735 bind(listener, (struct sockaddr *)&sock2, sizeof sock2); 00736 00737 if (listen(listener, 1) != 0) 00738 goto failed; 00739 00740 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) 00741 goto failed; 00742 00743 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) 00744 goto failed; 00745 00746 set_nonblocking(fd[1]); 00747 00748 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 00749 00750 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) { 00751 if (errno != EINPROGRESS) 00752 goto failed; 00753 } else 00754 connect_done = 1; 00755 00756 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) 00757 goto failed; 00758 00759 close(listener); 00760 listener = -1; 00761 00762 set_blocking(fd[1]); 00763 00764 if (connect_done == 0) { 00765 if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 00766 && errno != EISCONN) 00767 goto failed; 00768 } 00769 00770 /* all OK! */ 00771 return 0; 00772 00773 failed: 00774 if (fd[0] != -1) 00775 close(fd[0]); 00776 if (fd[1] != -1) 00777 close(fd[1]); 00778 if (listener != -1) 00779 close(listener); 00780 return -1; 00781 }
int sock_exec | ( | const char * | prog | ) |
Run a program on a local tcp socket, so that we can talk to it's stdin and stdout.
This is used to fake a connection to a daemon for testing -- not for the normal case of running SSH.
参照先 errno・FERROR・FINFO・rprintf()・rsyserr()・socketpair_tcp()・verbose.
参照元 open_socket_out_wrapped().
00795 { 00796 int fd[2]; 00797 00798 if (socketpair_tcp(fd) != 0) { 00799 rsyserr(FERROR, errno, "socketpair_tcp failed"); 00800 return -1; 00801 } 00802 if (verbose >= 2) 00803 rprintf(FINFO, "Running socket program: \"%s\"\n", prog); 00804 if (fork() == 0) { 00805 close(fd[0]); 00806 close(0); 00807 close(1); 00808 dup(fd[1]); 00809 dup(fd[1]); 00810 exit(system(prog)); 00811 } 00812 close(fd[1]); 00813 return fd[0]; 00814 }
char* bind_address |
int default_af_hint |
int level |
int option |
int opttype |
struct { ... } socket_options[] |
参照元 set_socket_options().