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

📄 stream.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission.  U.M. makes no representations about the * suitability of this software for any purpose.  It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group *			   Computer Science Department *			   University of Maryland at College Park *//* * $Id: stream.c,v 1.39 2006/08/24 01:57:15 paddy_s Exp $ * * functions for managing stream sockets */#include "amanda.h"#include "dgram.h"#include "stream.h"#include "util.h"#include "conffile.h"#include "security-util.h"#include "sockaddr-util.h"/* local functions */static void try_socksize(int sock, int which, size_t size);static int stream_client_internal(const char *hostname, in_port_t port,		size_t sendsize, size_t recvsize, in_port_t *localport,		int nonblock, int priv);intstream_server(    int family,    in_port_t *portp,    size_t sendsize,    size_t recvsize,    int    priv){    int server_socket, retries;    socklen_t len;#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)    const int on = 1;    int r;#endif    struct sockaddr_storage server;    int save_errno;    int *portrange;    socklen_t socklen;    int socket_family;    *portp = USHRT_MAX;				/* in case we error exit */    if (family == -1) {	socket_family = AF_NATIVE;    } else {	socket_family = family;    }    server_socket = socket(socket_family, SOCK_STREAM, 0);    #ifdef WORKING_IPV6    /* if that address family actually isn't supported, just try AF_INET */    if (server_socket == -1 && errno == EAFNOSUPPORT) {	socket_family = AF_INET;	server_socket = socket(AF_INET, SOCK_STREAM, 0);    }#endif    if (server_socket == -1) {	save_errno = errno;	dbprintf(_("stream_server: socket() failed: %s\n"),		  strerror(save_errno));	errno = save_errno;	return -1;    }    if(server_socket < 0 || server_socket >= (int)FD_SETSIZE) {	aclose(server_socket);	errno = EMFILE;				/* out of range */	save_errno = errno;	dbprintf(_("stream_server: socket out of range: %d\n"),		  server_socket);	errno = save_errno;	return -1;    }    SS_INIT(&server, socket_family);    SS_SET_INADDR_ANY(&server);#ifdef USE_REUSEADDR    r = setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR,	(void *)&on, (socklen_t)sizeof(on));    if (r < 0) {	dbprintf(_("stream_server: setsockopt(SO_REUSEADDR) failed: %s\n"),		  strerror(errno));    }#endif    try_socksize(server_socket, SO_SNDBUF, sendsize);    try_socksize(server_socket, SO_RCVBUF, recvsize);    /*     * If a port range was specified, we try to get a port in that     * range first.  Next, we try to get a reserved port.  If that     * fails, we just go for any port.     *      * In all cases, not to use port that's assigned to other services.      *     * It is up to the caller to make sure we have the proper permissions     * to get the desired port, and to make sure we return a port that     * is within the range it requires.     */    for (retries = 0; ; retries++) {	if (priv) {	    portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);	} else {	    portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);	}	if (portrange[0] != 0 && portrange[1] != 0) {	    if (bind_portrange(server_socket, &server, (in_port_t)portrange[0],			       (in_port_t)portrange[1], "tcp") == 0)		goto out;	    dbprintf(_("stream_server: Could not bind to port in range: %d - %d.\n"),		      portrange[0], portrange[1]);	} else {	    socklen = SS_LEN(&server);	    if (bind(server_socket, (struct sockaddr *)&server, socklen) == 0)		goto out;	    dbprintf(_("stream_server: Could not bind to any port: %s\n"),		      strerror(errno));	}	if (retries >= BIND_CYCLE_RETRIES)	    break;	dbprintf(_("stream_server: Retrying entire range after 10 second delay.\n"));	sleep(15);    }    save_errno = errno;    dbprintf(_("stream_server: bind(in6addr_any) failed: %s\n"),		  strerror(save_errno));    aclose(server_socket);    errno = save_errno;    return -1;out:    listen(server_socket, 1);    /* find out what port was actually used */    len = SIZEOF(server);    if(getsockname(server_socket, (struct sockaddr *)&server, &len) == -1) {	save_errno = errno;	dbprintf(_("stream_server: getsockname() failed: %s\n"),		  strerror(save_errno));	aclose(server_socket);	errno = save_errno;	return -1;    }#ifdef SO_KEEPALIVE    r = setsockopt(server_socket, SOL_SOCKET, SO_KEEPALIVE,	(void *)&on, (socklen_t)sizeof(on));    if(r == -1) {	save_errno = errno;	dbprintf(_("stream_server: setsockopt(SO_KEEPALIVE) failed: %s\n"),		  strerror(save_errno));        aclose(server_socket);	errno = save_errno;        return -1;    }#endif    *portp = SS_GET_PORT(&server);    dbprintf(_("stream_server: waiting for connection: %s\n"),	      str_sockaddr(&server));    return server_socket;}static intstream_client_internal(    const char *hostname,    in_port_t port,    size_t sendsize,    size_t recvsize,    in_port_t *localport,    int nonblock,    int priv){    struct sockaddr_storage svaddr, claddr;    int save_errno;    char *f;    int client_socket;    int *portrange;    int result;    struct addrinfo *res, *res_addr;    f = priv ? "stream_client_privileged" : "stream_client";    result = resolve_hostname(hostname, SOCK_STREAM, &res, NULL);    if(result != 0) {	dbprintf(_("resolve_hostname(%s): %s\n"), hostname, gai_strerror(result));	errno = EHOSTUNREACH;	return -1;    }    if(!res) {	dbprintf(_("resolve_hostname(%s): no results\n"), hostname);	errno = EHOSTUNREACH;	return -1;    }    for (res_addr = res; res_addr != NULL; res_addr = res_addr->ai_next) {	/* copy the first (preferred) address we found */	copy_sockaddr(&svaddr, res_addr->ai_addr);	SS_SET_PORT(&svaddr, port);	SS_INIT(&claddr, svaddr.ss_family);	SS_SET_INADDR_ANY(&claddr);	/*	 * If a privileged port range was requested, we try to get a port in	 * that range first and fail if it is not available.  Next, we try	 * to get a port in the range built in when Amanda was configured.	 * If that fails, we just go for any port.	 *	 * It is up to the caller to make sure we have the proper permissions	 * to get the desired port, and to make sure we return a port that	 * is within the range it requires.	 */	if (priv) {	    portrange = getconf_intrange(CNF_RESERVED_TCP_PORT);	} else {	    portrange = getconf_intrange(CNF_UNRESERVED_TCP_PORT);	}	client_socket = connect_portrange(&claddr, (in_port_t)portrange[0],					  (in_port_t)portrange[1],					  "tcp", &svaddr, nonblock);	save_errno = errno;	if (client_socket > 0)	    break;    }    freeaddrinfo(res);					      if (client_socket > 0)	goto out;    dbprintf(_("stream_client: Could not bind to port in range %d-%d.\n"),	      portrange[0], portrange[1]);    errno = save_errno;    return -1;out:    try_socksize(client_socket, SO_SNDBUF, sendsize);    try_socksize(client_socket, SO_RCVBUF, recvsize);    if (localport != NULL)	*localport = SS_GET_PORT(&claddr);    return client_socket;}intstream_client_privileged(    const char *hostname,    in_port_t port,    size_t sendsize,    size_t recvsize,    in_port_t *localport,    int nonblock){    return stream_client_internal(hostname,				  port,				  sendsize,				  recvsize,				  localport,				  nonblock,				  1);}intstream_client(    const char *hostname,    in_port_t port,    size_t sendsize,    size_t recvsize,    in_port_t *localport,    int nonblock){    return stream_client_internal(hostname,				  port,				  sendsize,				  recvsize,				  localport,				  nonblock,				  0);}/* don't care about these values */static struct sockaddr_storage addr;static socklen_t addrlen;intstream_accept(    int server_socket,    int timeout,    size_t sendsize,    size_t recvsize){    SELECT_ARG_TYPE readset;    struct timeval tv;    int nfound, connected_socket;    int save_errno;    int ntries = 0;    in_port_t port;    assert(server_socket >= 0);    do {	ntries++;	memset(&tv, 0, SIZEOF(tv));	tv.tv_sec = timeout;	memset(&readset, 0, SIZEOF(readset));	FD_ZERO(&readset);	FD_SET(server_socket, &readset);	nfound = select(server_socket+1, &readset, NULL, NULL, &tv);	if(nfound <= 0 || !FD_ISSET(server_socket, &readset)) {	    save_errno = errno;	    if(nfound < 0) {		dbprintf(_("stream_accept: select() failed: %s\n"),		      strerror(save_errno));	    } else if(nfound == 0) {		dbprintf(plural(_("stream_accept: timeout after %d second\n"),			        _("stream_accept: timeout after %d seconds\n"),			       timeout),			 timeout);		errno = ENOENT;			/* ??? */		return -1;	    } else if (!FD_ISSET(server_socket, &readset)) {		int i;		for(i = 0; i < server_socket + 1; i++) {		    if(FD_ISSET(i, &readset)) {			dbprintf(_("stream_accept: got fd %d instead of %d\n"),			      i,			      server_socket);		    }		}	        save_errno = EBADF;	    }	    if (ntries > 5) {		errno = save_errno;		return -1;	    }        }    } while (nfound <= 0);    while(1) {	addrlen = (socklen_t)sizeof(struct sockaddr_storage);	connected_socket = accept(server_socket,				  (struct sockaddr *)&addr,				  &addrlen);	if(connected_socket < 0) {	    break;	}	dbprintf(_("stream_accept: connection from %s\n"),	          str_sockaddr(&addr));	/*	 * Make certain we got an inet connection and that it is not	 * from port 20 (a favorite unauthorized entry tool).	 */	if (addr.ss_family == (sa_family_t)AF_INET#ifdef WORKING_IPV6	    || addr.ss_family == (sa_family_t)AF_INET6#endif	    ){	    port = SS_GET_PORT(&addr);	    if (port != (in_port_t)20) {		try_socksize(connected_socket, SO_SNDBUF, sendsize);		try_socksize(connected_socket, SO_RCVBUF, recvsize);		return connected_socket;	    } else {		dbprintf(_("remote port is %u: ignored\n"),			  (unsigned int)port);	    }	} else {#ifdef WORKING_IPV6	    dbprintf(_("family is %d instead of %d(AF_INET)"		      " or %d(AF_INET6): ignored\n"),		      addr.ss_family,		      AF_INET, AF_INET6);#else	    dbprintf(_("family is %d instead of %d(AF_INET)"		      ": ignored\n"),		      addr.ss_family,		      AF_INET);#endif	}	aclose(connected_socket);    }    save_errno = errno;    dbprintf(_("stream_accept: accept() failed: %s\n"),	      strerror(save_errno));    errno = save_errno;    return -1;}static voidtry_socksize(    int sock,    int which,    size_t size){    size_t origsize;    int    isize;    if (size == 0)	return;    origsize = size;    isize = size;    /* keep trying, get as big a buffer as possible */    while((isize > 1024) &&	  (setsockopt(sock, SOL_SOCKET,		      which, (void *) &isize, (socklen_t)sizeof(isize)) < 0)) {	isize -= 1024;    }    if(isize > 1024) {	dbprintf(_("try_socksize: %s buffer size is %d\n"),		  (which == SO_SNDBUF) ? _("send") : _("receive"),		  isize);    } else {	dbprintf(_("try_socksize: could not allocate %s buffer of %zu\n"),		  (which == SO_SNDBUF) ? _("send") : _("receive"),		  origsize);    }}

⌨️ 快捷键说明

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