⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 socket.c

📁 Rsync 3.0.5 source code
💻 C
📖 第 1 页 / 共 2 页
字号:
				(int)resp->ai_protocol, strerror(errno));			if (r < 0)				out_of_memory("open_socket_in");			/* See if there's another address that will work... */			continue;		}		setsockopt(s, SOL_SOCKET, SO_REUSEADDR,			   (char *)&one, sizeof one);		if (sockopts)			set_socket_options(s, sockopts);		else			set_socket_options(s, lp_socket_options());#ifdef IPV6_V6ONLY		if (resp->ai_family == AF_INET6) {			if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,				       (char *)&one, sizeof one) < 0			    && default_af_hint != AF_INET6) {				close(s);				continue;			}		}#endif		/* Now we've got a socket - we need to bind it. */		if (bind(s, resp->ai_addr, resp->ai_addrlen) < 0) {			/* Nope, try another */			int r = asprintf(&errmsgs[ecnt++],				"bind() failed: %s (address-family %d)\n",				strerror(errno), (int)resp->ai_family);			if (r < 0)				out_of_memory("open_socket_in");			close(s);			continue;		}		socks[i++] = s;	}	socks[i] = -1;	if (all_ai)		freeaddrinfo(all_ai);	/* Only output the socket()/bind() messages if we were totally	 * unsuccessful, or if the daemon is being run with -vv. */	for (s = 0; s < ecnt; s++) {		if (!i || verbose > 1)			rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0);		free(errmsgs[s]);	}	free(errmsgs);	if (!i) {		rprintf(FERROR,			"unable to bind any inbound sockets on port %d\n",			port);		free(socks);		return NULL;	}	return socks;}/* * Determine if a file descriptor is in fact a socket */int is_a_socket(int fd){	int v;	socklen_t l = sizeof (int);	/* Parameters to getsockopt, setsockopt etc are very	 * unstandardized across platforms, so don't be surprised if	 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.	 * It seems they all eventually get the right idea.	 *	 * Debian says: ``The fifth argument of getsockopt and	 * setsockopt is in reality an int [*] (and this is what BSD	 * 4.* and libc4 and libc5 have).  Some POSIX confusion	 * resulted in the present socklen_t.  The draft standard has	 * not been adopted yet, but glibc2 already follows it and	 * also has socklen_t [*]. See also accept(2).''	 *	 * We now return to your regularly scheduled programming.  */	return getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0;}static RETSIGTYPE sigchld_handler(UNUSED(int val)){#ifdef WNOHANG	while (waitpid(-1, NULL, WNOHANG) > 0) {}#endif#ifndef HAVE_SIGACTION	signal(SIGCHLD, sigchld_handler);#endif}void start_accept_loop(int port, int (*fn)(int, int)){	fd_set deffds;	int *sp, maxfd, i;#ifdef HAVE_SIGACTION	sigact.sa_flags = SA_NOCLDSTOP;#endif	/* open an incoming socket */	sp = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);	if (sp == NULL)		exit_cleanup(RERR_SOCKETIO);	/* ready to listen */	FD_ZERO(&deffds);	for (i = 0, maxfd = -1; sp[i] >= 0; i++) {		if (listen(sp[i], 5) < 0) {			rsyserr(FERROR, errno, "listen() on socket failed");#ifdef INET6			if (errno == EADDRINUSE && i > 0) {				rprintf(FINFO,				    "Try using --ipv4 or --ipv6 to avoid this listen() error.\n");			}#endif			exit_cleanup(RERR_SOCKETIO);		}		FD_SET(sp[i], &deffds);		if (maxfd < sp[i])			maxfd = sp[i];	}	/* now accept incoming connections - forking a new process	 * for each incoming connection */	while (1) {		fd_set fds;		pid_t pid;		int fd;		struct sockaddr_storage addr;		socklen_t addrlen = sizeof addr;		/* close log file before the potentially very long select so		 * file can be trimmed by another process instead of growing		 * forever */		logfile_close();#ifdef FD_COPY		FD_COPY(&deffds, &fds);#else		fds = deffds;#endif		if (select(maxfd + 1, &fds, NULL, NULL, NULL) != 1)			continue;		for (i = 0, fd = -1; sp[i] >= 0; i++) {			if (FD_ISSET(sp[i], &fds)) {				fd = accept(sp[i], (struct sockaddr *)&addr,					    &addrlen);				break;			}		}		if (fd < 0)			continue;		SIGACTION(SIGCHLD, sigchld_handler);		if ((pid = fork()) == 0) {			int ret;			for (i = 0; sp[i] >= 0; i++)				close(sp[i]);			/* Re-open log file in child before possibly giving			 * up privileges (see logfile_close() above). */			logfile_reopen();			ret = fn(fd, fd);			close_all();			_exit(ret);		} else if (pid < 0) {			rsyserr(FERROR, errno,				"could not create child server process");			close(fd);			/* This might have happened because we're			 * overloaded.  Sleep briefly before trying to			 * accept again. */			sleep(2);		} else {			/* Parent doesn't need this fd anymore. */			close(fd);		}	}}enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};struct{  char *name;  int level;  int option;  int value;  int opttype;} socket_options[] = {  {"SO_KEEPALIVE",      SOL_SOCKET,    SO_KEEPALIVE,    0,                 OPT_BOOL},  {"SO_REUSEADDR",      SOL_SOCKET,    SO_REUSEADDR,    0,                 OPT_BOOL},  {"SO_BROADCAST",      SOL_SOCKET,    SO_BROADCAST,    0,                 OPT_BOOL},#ifdef TCP_NODELAY  {"TCP_NODELAY",       IPPROTO_TCP,   TCP_NODELAY,     0,                 OPT_BOOL},#endif#ifdef IPTOS_LOWDELAY  {"IPTOS_LOWDELAY",    IPPROTO_IP,    IP_TOS,          IPTOS_LOWDELAY,    OPT_ON},#endif#ifdef IPTOS_THROUGHPUT  {"IPTOS_THROUGHPUT",  IPPROTO_IP,    IP_TOS,          IPTOS_THROUGHPUT,  OPT_ON},#endif#ifdef SO_SNDBUF  {"SO_SNDBUF",         SOL_SOCKET,    SO_SNDBUF,       0,                 OPT_INT},#endif#ifdef SO_RCVBUF  {"SO_RCVBUF",         SOL_SOCKET,    SO_RCVBUF,       0,                 OPT_INT},#endif#ifdef SO_SNDLOWAT  {"SO_SNDLOWAT",       SOL_SOCKET,    SO_SNDLOWAT,     0,                 OPT_INT},#endif#ifdef SO_RCVLOWAT  {"SO_RCVLOWAT",       SOL_SOCKET,    SO_RCVLOWAT,     0,                 OPT_INT},#endif#ifdef SO_SNDTIMEO  {"SO_SNDTIMEO",       SOL_SOCKET,    SO_SNDTIMEO,     0,                 OPT_INT},#endif#ifdef SO_RCVTIMEO  {"SO_RCVTIMEO",       SOL_SOCKET,    SO_RCVTIMEO,     0,                 OPT_INT},#endif  {NULL,0,0,0,0}};/** * Set user socket options **/void set_socket_options(int fd, char *options){	char *tok;	if (!options || !*options)		return;	options = strdup(options);	if (!options)		out_of_memory("set_socket_options");	for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) {		int ret=0,i;		int value = 1;		char *p;		int got_value = 0;		if ((p = strchr(tok,'='))) {			*p = 0;			value = atoi(p+1);			got_value = 1;		}		for (i = 0; socket_options[i].name; i++) {			if (strcmp(socket_options[i].name,tok)==0)				break;		}		if (!socket_options[i].name) {			rprintf(FERROR,"Unknown socket option %s\n",tok);			continue;		}		switch (socket_options[i].opttype) {		case OPT_BOOL:		case OPT_INT:			ret = setsockopt(fd,socket_options[i].level,					 socket_options[i].option,					 (char *)&value, sizeof (int));			break;		case OPT_ON:			if (got_value)				rprintf(FERROR,"syntax error -- %s does not take a value\n",tok);			{				int on = socket_options[i].value;				ret = setsockopt(fd,socket_options[i].level,						 socket_options[i].option,						 (char *)&on, sizeof (int));			}			break;		}		if (ret != 0) {			rsyserr(FERROR, errno,				"failed to set socket option %s", tok);		}	}	free(options);}/** * 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. **/static int socketpair_tcp(int fd[2]){	int listener;	struct sockaddr_in sock;	struct sockaddr_in sock2;	socklen_t socklen = sizeof sock;	int connect_done = 0;	fd[0] = fd[1] = listener = -1;	memset(&sock, 0, sizeof sock);	if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1)		goto failed;	memset(&sock2, 0, sizeof sock2);#ifdef HAVE_SOCKADDR_IN_LEN	sock2.sin_len = sizeof sock2;#endif	sock2.sin_family = PF_INET;	bind(listener, (struct sockaddr *)&sock2, sizeof sock2);	if (listen(listener, 1) != 0)		goto failed;	if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0)		goto failed;	if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1)		goto failed;	set_nonblocking(fd[1]);	sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);	if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) == -1) {		if (errno != EINPROGRESS)			goto failed;	} else		connect_done = 1;	if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1)		goto failed;	close(listener);	listener = -1;	set_blocking(fd[1]);	if (connect_done == 0) {		if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0		    && errno != EISCONN)			goto failed;	}	/* all OK! */	return 0; failed:	if (fd[0] != -1)		close(fd[0]);	if (fd[1] != -1)		close(fd[1]);	if (listener != -1)		close(listener);	return -1;}/** * 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. * * @return a socket which is attached to a subprocess running * "prog". stdin and stdout are attached. stderr is left attached to * the original stderr **/int sock_exec(const char *prog){	pid_t pid;	int fd[2];	if (socketpair_tcp(fd) != 0) {		rsyserr(FERROR, errno, "socketpair_tcp failed");		return -1;	}	if (verbose >= 2)		rprintf(FINFO, "Running socket program: \"%s\"\n", prog);	pid = fork();	if (pid < 0) {		rsyserr(FERROR, errno, "fork");		exit_cleanup(RERR_IPC);	}	if (pid == 0) {		close(fd[0]);		if (dup2(fd[1], STDIN_FILENO) < 0		 || dup2(fd[1], STDOUT_FILENO) < 0) {			fprintf(stderr, "Failed to run \"%s\"\n", prog);			exit(1);		}		exit(system(prog));	}	close(fd[1]);	return fd[0];}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -