Go to the source code of this file.
Enumerations | |
enum | SOCK_OPT_TYPES { OPT_BOOL, OPT_INT, OPT_ON } |
Functions | |
int | establish_proxy_connection (int fd, char *host, int port) |
Establish a proxy connection on an open socket to a web proxy by using the HTTP CONNECT method. More... | |
int | try_bind_local (int s, int ai_family, int ai_socktype, const char *bind_address) |
Try to set the local address for a newly-created socket. More... | |
int | open_socket_out (char *host, int port, const char *bind_address, int af_hint) |
Open a socket to a tcp remote host with the specified port . More... | |
int | open_socket_out_wrapped (char *host, int port, const char *bind_address, 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. More... | |
int | open_socket_in (int type, int port, const char *bind_address, int af_hint) |
Open a socket of the specified type, port and address for incoming data. More... | |
int | is_a_socket (int fd) |
void | start_accept_loop (int port, int(*fn)(int)) |
void | set_socket_options (int fd, char *options) |
Set user socket options. More... | |
void | become_daemon (void) |
Become a daemon, discarding the controlling terminal. More... | |
int | socketpair_tcp (int fd[2]) |
This is like socketpair but uses tcp. More... | |
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. More... | |
Variables | |
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.
Definition in file socket.c.
|
Definition at line 455 of file socket.c.
|
|
Establish a proxy connection on an open socket to a web proxy by using the HTTP CONNECT method.
Definition at line 41 of file socket.c. References FERROR, host, rprintf(), and snprintf(). Referenced by open_socket_out().
00042 { 00043 char buffer[1024]; 00044 char *cp; 00045 00046 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port); 00047 if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) { 00048 rprintf(FERROR, "failed to write to proxy: %s\n", 00049 strerror(errno)); 00050 return -1; 00051 } 00052 00053 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) { 00054 if (read(fd, cp, 1) != 1) { 00055 rprintf(FERROR, "failed to read from proxy: %s\n", 00056 strerror(errno)); 00057 return -1; 00058 } 00059 if (*cp == '\n') 00060 break; 00061 } 00062 00063 if (*cp != '\n') 00064 cp++; 00065 *cp-- = '\0'; 00066 if (*cp == '\r') 00067 *cp = '\0'; 00068 if (strncmp(buffer, "HTTP/", 5) != 0) { 00069 rprintf(FERROR, "bad response from proxy - %s\n", 00070 buffer); 00071 return -1; 00072 } 00073 for (cp = &buffer[5]; isdigit(* (unsigned char *) cp) || (*cp == '.'); cp++) 00074 ; 00075 while (*cp == ' ') 00076 cp++; 00077 if (*cp != '2') { 00078 rprintf(FERROR, "bad response from proxy - %s\n", 00079 buffer); 00080 return -1; 00081 } 00082 /* throw away the rest of the HTTP header */ 00083 while (1) { 00084 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; 00085 cp++) { 00086 if (read(fd, cp, 1) != 1) { 00087 rprintf(FERROR, "failed to read from proxy: %s\n", 00088 strerror(errno)); 00089 return -1; 00090 } 00091 if (*cp == '\n') 00092 break; 00093 } 00094 if ((cp > buffer) && (*cp == '\n')) 00095 cp--; 00096 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r'))) 00097 break; 00098 } 00099 return 0; 00100 } |
|
Try to set the local address for a newly-created socket. Return -1 if this fails. Definition at line 107 of file socket.c. References addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, addrinfo::ai_socktype, bind_address, FERROR, gai_strerror(), and rprintf(). Referenced by open_socket_out().
00110 { 00111 int error; 00112 struct addrinfo bhints, *bres_all, *r; 00113 00114 memset(&bhints, 0, sizeof(bhints)); 00115 bhints.ai_family = ai_family; 00116 bhints.ai_socktype = ai_socktype; 00117 bhints.ai_flags = AI_PASSIVE; 00118 if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) { 00119 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n", 00120 bind_address, gai_strerror(error)); 00121 return -1; 00122 } 00123 00124 for (r = bres_all; r; r = r->ai_next) { 00125 if (bind(s, r->ai_addr, r->ai_addrlen) == -1) 00126 continue; 00127 freeaddrinfo(bres_all); 00128 return s; 00129 } 00130 00131 /* no error message; there might be some problem that allows 00132 * creation of the socket but not binding, perhaps if the 00133 * machine has no ipv6 address of this name. */ 00134 freeaddrinfo(bres_all); 00135 return -1; 00136 } |
|
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 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.
Definition at line 159 of file socket.c. References addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_family, addrinfo::ai_next, addrinfo::ai_protocol, addrinfo::ai_socktype, bind_address, establish_proxy_connection(), FERROR, FINFO, gai_strerror(), getenv(), host, rprintf(), snprintf(), strlcpy(), and try_bind_local(). Referenced by open_socket_out_wrapped().
00161 { 00162 int type = SOCK_STREAM; 00163 int error; 00164 int s; 00165 struct addrinfo hints, *res0, *res; 00166 char portbuf[10]; 00167 char *h; 00168 int proxied = 0; 00169 char buffer[1024]; 00170 char *cp; 00171 00172 /* if we have a RSYNC_PROXY env variable then redirect our 00173 * connetcion via a web proxy at the given address. The format 00174 * is hostname:port */ 00175 h = getenv("RSYNC_PROXY"); 00176 proxied = (h != NULL) && (*h != '\0'); 00177 00178 if (proxied) { 00179 strlcpy(buffer, h, sizeof(buffer)); 00180 cp = strchr(buffer, ':'); 00181 if (cp == NULL) { 00182 rprintf(FERROR, 00183 "invalid proxy specification: should be HOST:PORT\n"); 00184 return -1; 00185 } 00186 *cp++ = '\0'; 00187 strcpy(portbuf, cp); 00188 h = buffer; 00189 if (verbose >= 2) { 00190 rprintf(FINFO, "connection via http proxy %s port %s\n", 00191 h, portbuf); 00192 } 00193 } else { 00194 snprintf(portbuf, sizeof(portbuf), "%d", port); 00195 h = host; 00196 } 00197 00198 memset(&hints, 0, sizeof(hints)); 00199 hints.ai_family = af_hint; 00200 hints.ai_socktype = type; 00201 error = getaddrinfo(h, portbuf, &hints, &res0); 00202 if (error) { 00203 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n", 00204 h, portbuf, gai_strerror(error)); 00205 return -1; 00206 } 00207 00208 s = -1; 00209 /* Try to connect to all addresses for this machine until we get 00210 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6 00211 * addresses. We need to create a socket for each record, since the 00212 * address record tells us what protocol to use to try to connect. */ 00213 for (res = res0; res; res = res->ai_next) { 00214 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 00215 if (s < 0) 00216 continue; 00217 00218 if (bind_address) 00219 if (try_bind_local(s, res->ai_family, type, 00220 bind_address) == -1) { 00221 close(s); 00222 s = -1; 00223 continue; 00224 } 00225 00226 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { 00227 close(s); 00228 s = -1; 00229 continue; 00230 } 00231 if (proxied && 00232 establish_proxy_connection(s, host, port) != 0) { 00233 close(s); 00234 s = -1; 00235 continue; 00236 } else 00237 break; 00238 } 00239 freeaddrinfo(res0); 00240 if (s < 0) { 00241 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n", 00242 h, strerror(errno)); 00243 return -1; 00244 } 00245 return s; 00246 } |
|
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.
Definition at line 261 of file socket.c. References bind_address, getenv(), host, open_socket_out(), and sock_exec(). Referenced by start_socket_client().
00265 { 00266 char *prog; 00267 00268 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL) 00269 return sock_exec (prog); 00270 else 00271 return open_socket_out (host, port, bind_address, 00272 af_hint); 00273 } |
|
Open a socket of the specified type, port and address for incoming data. Try to be better about handling the results of getaddrinfo(): when opening an inbound socket, we might get several address results, e.g. for the machine's ipv4 and ipv6 name. If binding a wildcard, then any one of them should do. If an address was specified but it's insufficiently specific then that's not our fault. However, some of the advertized addresses may not work because e.g. we don't have IPv6 support in the kernel. In that case go on and try all addresses until one succeeds.
Definition at line 295 of file socket.c. References addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, addrinfo::ai_protocol, addrinfo::ai_socktype, bind_address, FERROR, gai_strerror(), rprintf(), and snprintf(). Referenced by start_accept_loop().
00297 { 00298 int one=1; 00299 int s; 00300 struct addrinfo hints, *all_ai, *resp; 00301 char portbuf[10]; 00302 int error; 00303 00304 memset(&hints, 0, sizeof(hints)); 00305 hints.ai_family = af_hint; 00306 hints.ai_socktype = type; 00307 hints.ai_flags = AI_PASSIVE; 00308 snprintf(portbuf, sizeof(portbuf), "%d", port); 00309 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai); 00310 if (error) { 00311 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n", 00312 bind_address, gai_strerror(error)); 00313 return -1; 00314 } 00315 00316 /* We may not be able to create the socket, if for example the 00317 * machine knows about IPv6 in the C library, but not in the 00318 * kernel. */ 00319 for (resp = all_ai; resp; resp = resp->ai_next) { 00320 s = socket(resp->ai_family, resp->ai_socktype, 00321 resp->ai_protocol); 00322 00323 if (s == -1) 00324 /* See if there's another address that will work... */ 00325 continue; 00326 00327 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 00328 (char *)&one, sizeof one); 00329 00330 /* now we've got a socket - we need to bind it */ 00331 if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) { 00332 /* Nope, try another */ 00333 close(s); 00334 continue; 00335 } 00336 00337 freeaddrinfo(all_ai); 00338 return s; 00339 } 00340 00341 rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: " 00342 "%s\n", 00343 port, 00344 strerror(errno)); 00345 00346 freeaddrinfo(all_ai); 00347 return -1; 00348 } |
|
Definition at line 354 of file socket.c. Referenced by daemon_main().
00355 { 00356 int v; 00357 socklen_t l; 00358 l = sizeof(int); 00359 00360 /* Parameters to getsockopt, setsockopt etc are very 00361 * unstandardized across platforms, so don't be surprised if 00362 * there are compiler warnings on e.g. SCO OpenSwerver or AIX. 00363 * It seems they all eventually get the right idea. 00364 * 00365 * Debian says: ``The fifth argument of getsockopt and 00366 * setsockopt is in reality an int [*] (and this is what BSD 00367 * 4.* and libc4 and libc5 have). Some POSIX confusion 00368 * resulted in the present socklen_t. The draft standard has 00369 * not been adopted yet, but glibc2 already follows it and 00370 * also has socklen_t [*]. See also accept(2).'' 00371 * 00372 * We now return to your regularly scheduled programming. */ 00373 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0); 00374 } |
|
Definition at line 377 of file socket.c. References bind_address, default_af_hint, FERROR, log_close(), log_open(), open_socket_in(), rprintf(), and waitpid(). Referenced by daemon_main().
00378 { 00379 int s; 00380 extern char *bind_address; 00381 extern int default_af_hint; 00382 00383 /* open an incoming socket */ 00384 s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint); 00385 if (s == -1) 00386 exit_cleanup(RERR_SOCKETIO); 00387 00388 /* ready to listen */ 00389 if (listen(s, 5) == -1) { 00390 close(s); 00391 exit_cleanup(RERR_SOCKETIO); 00392 } 00393 00394 00395 /* now accept incoming connections - forking a new process 00396 for each incoming connection */ 00397 while (1) { 00398 fd_set fds; 00399 pid_t pid; 00400 int fd; 00401 struct sockaddr_storage addr; 00402 socklen_t addrlen = sizeof addr; 00403 00404 /* close log file before the potentially very long select so 00405 file can be trimmed by another process instead of growing 00406 forever */ 00407 log_close(); 00408 00409 FD_ZERO(&fds); 00410 FD_SET(s, &fds); 00411 00412 if (select(s+1, &fds, NULL, NULL, NULL) != 1) { 00413 continue; 00414 } 00415 00416 if(!FD_ISSET(s, &fds)) continue; 00417 00418 fd = accept(s,(struct sockaddr *)&addr,&addrlen); 00419 00420 if (fd == -1) continue; 00421 00422 signal(SIGCHLD, SIG_IGN); 00423 00424 /* we shouldn't have any children left hanging around 00425 but I have had reports that on Digital Unix zombies 00426 are produced, so this ensures that they are reaped */ 00427 #ifdef WNOHANG 00428 while (waitpid(-1, NULL, WNOHANG) > 0); 00429 #endif 00430 00431 if ((pid = fork()) == 0) { 00432 close(s); 00433 /* open log file in child before possibly giving 00434 up privileges */ 00435 log_open(); 00436 _exit(fn(fd)); 00437 } else if (pid < 0) { 00438 rprintf(FERROR, 00439 RSYNC_NAME 00440 ": could not create child server process: %s\n", 00441 strerror(errno)); 00442 close(fd); 00443 /* This might have happened because we're 00444 * overloaded. Sleep briefly before trying to 00445 * accept again. */ 00446 sleep(2); 00447 } else { 00448 /* Parent doesn't need this fd anymore. */ 00449 close(fd); 00450 } 00451 } 00452 } |
|
Set user socket options.
Definition at line 502 of file socket.c. References FERROR, level, name, OPT_BOOL, OPT_INT, OPT_ON, option, out_of_memory(), rprintf(), socket_options, strdup(), and value. Referenced by start_daemon().
00503 { 00504 char *tok; 00505 if (!options || !*options) return; 00506 00507 options = strdup(options); 00508 00509 if (!options) out_of_memory("set_socket_options"); 00510 00511 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) { 00512 int ret=0,i; 00513 int value = 1; 00514 char *p; 00515 int got_value = 0; 00516 00517 if ((p = strchr(tok,'='))) { 00518 *p = 0; 00519 value = atoi(p+1); 00520 got_value = 1; 00521 } 00522 00523 for (i=0;socket_options[i].name;i++) 00524 if (strcmp(socket_options[i].name,tok)==0) 00525 break; 00526 00527 if (!socket_options[i].name) { 00528 rprintf(FERROR,"Unknown socket option %s\n",tok); 00529 continue; 00530 } 00531 00532 switch (socket_options[i].opttype) { 00533 case OPT_BOOL: 00534 case OPT_INT: 00535 ret = setsockopt(fd,socket_options[i].level, 00536 socket_options[i].option,(char *)&value,sizeof(int)); 00537 break; 00538 00539 case OPT_ON: 00540 if (got_value) 00541 rprintf(FERROR,"syntax error - %s does not take a value\n",tok); 00542 00543 { 00544 int on = socket_options[i].value; 00545 ret = setsockopt(fd,socket_options[i].level, 00546 socket_options[i].option,(char *)&on,sizeof(int)); 00547 } 00548 break; 00549 } 00550 00551 if (ret != 0) 00552 rprintf(FERROR, "failed to set socket option %s: %s\n", tok, 00553 strerror(errno)); 00554 } 00555 00556 free(options); 00557 } |
|
Become a daemon, discarding the controlling terminal.
Definition at line 562 of file socket.c. Referenced by daemon_main().
00563 { 00564 int i; 00565 00566 if (fork()) { 00567 _exit(0); 00568 } 00569 00570 /* detach from the terminal */ 00571 #ifdef HAVE_SETSID 00572 setsid(); 00573 #else 00574 #ifdef TIOCNOTTY 00575 i = open("/dev/tty", O_RDWR); 00576 if (i >= 0) { 00577 ioctl(i, (int) TIOCNOTTY, (char *)0); 00578 close(i); 00579 } 00580 #endif /* TIOCNOTTY */ 00581 #endif 00582 /* make sure that stdin, stdout an stderr don't stuff things 00583 up (library functions, for example) */ 00584 for (i=0;i<3;i++) { 00585 close(i); 00586 open("/dev/null", O_RDWR); 00587 } 00588 } |
|
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. Definition at line 600 of file socket.c. References set_blocking(), and set_nonblocking(). Referenced by sock_exec().
00601 { 00602 int listener; 00603 struct sockaddr_in sock; 00604 struct sockaddr_in sock2; 00605 socklen_t socklen = sizeof(sock); 00606 int connect_done = 0; 00607 00608 fd[0] = fd[1] = listener = -1; 00609 00610 memset(&sock, 0, sizeof(sock)); 00611 00612 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; 00613 00614 memset(&sock2, 0, sizeof(sock2)); 00615 #ifdef HAVE_SOCKADDR_LEN 00616 sock2.sin_len = sizeof(sock2); 00617 #endif 00618 sock2.sin_family = PF_INET; 00619 00620 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2)); 00621 00622 if (listen(listener, 1) != 0) goto failed; 00623 00624 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed; 00625 00626 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed; 00627 00628 set_nonblocking(fd[1]); 00629 00630 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 00631 00632 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) { 00633 if (errno != EINPROGRESS) goto failed; 00634 } else { 00635 connect_done = 1; 00636 } 00637 00638 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed; 00639 00640 close(listener); 00641 if (connect_done == 0) { 00642 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0 00643 && errno != EISCONN) goto failed; 00644 } 00645 00646 set_blocking (fd[1]); 00647 00648 /* all OK! */ 00649 return 0; 00650 00651 failed: 00652 if (fd[0] != -1) close(fd[0]); 00653 if (fd[1] != -1) close(fd[1]); 00654 if (listener != -1) close(listener); 00655 return -1; 00656 } |
|
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.
Definition at line 669 of file socket.c. References FERROR, rprintf(), and socketpair_tcp(). Referenced by open_socket_out_wrapped().
00670 { 00671 int fd[2]; 00672 00673 if (socketpair_tcp(fd) != 0) { 00674 rprintf (FERROR, RSYNC_NAME 00675 ": socketpair_tcp failed (%s)\n", 00676 strerror(errno)); 00677 return -1; 00678 } 00679 if (fork() == 0) { 00680 close(fd[0]); 00681 close(0); 00682 close(1); 00683 dup(fd[1]); 00684 dup(fd[1]); 00685 if (verbose > 3) { 00686 /* Can't use rprintf because we've forked. */ 00687 fprintf (stderr, 00688 RSYNC_NAME ": execute socket program \"%s\"\n", 00689 prog); 00690 } 00691 exit (system (prog)); 00692 } 00693 close (fd[1]); 00694 return fd[0]; 00695 } |
|
Definition at line 459 of file socket.c. Referenced by set_socket_options(). |
|
Definition at line 460 of file socket.c. Referenced by set_socket_options(). |
|
Definition at line 461 of file socket.c. Referenced by set_socket_options(). |
|
Definition at line 462 of file socket.c. Referenced by abs_val(), dopr(), fmtint(), fmtstr(), ROUND(), and set_socket_options(). |
|
|
|
Referenced by set_socket_options(). |