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

📄 sockutils.c

📁 用来监视网络通信数据的源代码和应用程序,方便网络程序底层开发.
💻 C
📖 第 1 页 / 共 3 页
字号:
	SOCK_ASSERT("I'm currently discarding data\n", 1);

	return 0;
}



/*!
	\brief Checks that one host (identified by the sockaddr_storage structure) belongs to an 'allowed list'.

	This function is useful after an accept() call in order to check if the connecting
	host is allowed to connect to me. To do that, we have a buffer that keeps the list of the
	allowed host; this function checks the sockaddr_storage structure of the connecting host 
	against this host list, and it returns '0' is the host is included in this list.

	\param hostlist: pointer to a string that contains the list of the allowed host.

	\param sep: a string that keeps the separators used between the hosts (for example the 
	space character) in the host list.

	\param from: a sockaddr_storage structure, as it is returned by the accept() call.

	\param errbuf: a pointer to an user-allocated buffer that will contain the complete
	error message. This buffer has to be at least 'errbuflen' in length.
	It can be NULL; in this case the error cannot be printed.

	\param errbuflen: length of the buffer that will contains the error. The error message cannot be
	larger than 'errbuflen - 1' because the last char is reserved for the string terminator.

	\return It returns:
	- '1' if the host list is empty
	- '0' if the host belongs to the host list (and therefore it is allowed to connect)
	- '-1' in case the host does not belong to the host list (and therefore it is not allowed to connect
	- '-2' in case or error. The error message is returned in the 'errbuf' variable.
*/
int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf, int errbuflen)
{
	// checks if the connecting host is among the ones allowed
	if ( (hostlist) && (hostlist[0]) )
	{
	char *token;					// temp, needed to separate items into the hostlist
	struct addrinfo *addrinfo, *ai_next;
	char *temphostlist;

		temphostlist= (char *) malloc (strlen(hostlist) + 1);
		if (temphostlist == NULL)
		{
			sock_geterror("sock_check_hostlist(), malloc() failed", errbuf, errbuflen);
			return -2;
		}
		
		// The problem is that strtok modifies the original variable by putting '0' at the end of each token
		// So, we have to create a new temporary string in which the original content is kept
		strcpy(temphostlist, hostlist);

		token= strtok(temphostlist, sep);

		// it avoids a warning in the compilation ('addrinfo used but not initialized')
		addrinfo = NULL;

		while( token != NULL )
		{
		struct addrinfo hints;
		int retval;

			addrinfo = NULL;
			memset(&hints, 0, sizeof (struct addrinfo) );
			hints.ai_family = PF_UNSPEC;
			hints.ai_socktype= SOCK_STREAM;
	
			retval = getaddrinfo(token, "0", &hints, &addrinfo);
			if (retval != 0)
			{
				if (errbuf)
				{
					snprintf(errbuf, errbuflen, "getaddrinfo() %s", gai_strerror(retval));
					errbuf[errbuflen - 1]= 0;
				}

				SOCK_ASSERT(errbuf, 1);

				// Get next token
				token = strtok( NULL, sep);
				continue;
			}

			// ai_next is required to preserve the content of addrinfo, in order to deallocate it properly
			ai_next= addrinfo;
			while(ai_next)
			{
				if (sock_cmpaddr(from, (struct sockaddr_storage *) ai_next->ai_addr) == 0)
				{
					free(temphostlist);
					return 0;
				}

				// If we are here, it means that the current address does not matches
				// Let's try with the next one in the header chain
				ai_next= ai_next->ai_next;
			}

			freeaddrinfo(addrinfo);
			addrinfo= NULL;

			// Get next token
			token = strtok( NULL, sep);
		}

		if (addrinfo)
		{
			freeaddrinfo(addrinfo);
			addrinfo= NULL;
		}

		if (errbuf)
		{
			snprintf(errbuf, errbuflen, "The host is not in the allowed host list. Connection refused.");
			errbuf[errbuflen - 1]= 0;
		}

		free(temphostlist);
		return -1;
	}

	// No hostlist, so we have to return 'empty list'
	return 1;
}


/*!
	\brief Compares two addresses contained into two sockaddr_storage structures.

	This function is useful to compare two addresses, given their internal representation,
	i.e. an sockaddr_storage structure.

	The two structures do not need to be sockaddr_storage; you can have both 'sockaddr_in' and
	sockaddr_in6, properly acsted in order to be compliant to the function interface.

	This function will return '0' if the two addresses matches, '-1' if not.

	\param first: a sockaddr_storage structure, (for example the one that is returned by an 
	accept() call), containing the first address to compare.

	\param second: a sockaddr_storage structure containing the second address to compare.

	\return '0' if the addresses are equal, '-1' if they are different.
*/
int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second)
{
	if (first->ss_family == second->ss_family)
	{
		if (first->ss_family == AF_INET)
		{
			if (memcmp(		&(((struct sockaddr_in *) first)->sin_addr), 
							&(((struct sockaddr_in *) second)->sin_addr),
							sizeof(struct in_addr) ) == 0)
								return 0;
		}
		else // address family is AF_INET6
		{
			if (memcmp(		&(((struct sockaddr_in6 *) first)->sin6_addr), 
							&(((struct sockaddr_in6 *) second)->sin6_addr),
							sizeof(struct in6_addr) ) == 0)
								return 0;
		}
	}

	return -1;
}



/*!
	\brief It gets the address/port the system picked for this socket (on connected sockets).

	It is used to return the addess and port the server picked for our socket on the local machine.
	It works only on:
	- connected sockets
	- server sockets

	On unconnected client sockets it does not work because the system dynamically chooses a port
	only when the socket calls a send() call.

	\param sock: the connected socket currently opened.

	\param address: it contains the address that will be returned by the function. This buffer
	must be properly allocated by the user. The address can be either literal or numeric depending
	on the value of 'Flags'.

	\param addrlen: the length of the 'address' buffer.

	\param port: it contains the port that will be returned by the function. This buffer
	must be properly allocated by the user.

	\param portlen: the length of the 'port' buffer.

	\param flags: a set of flags (the ones defined into the getnameinfo() standard socket function)
	that determine if the resulting address must be in numeric / literal form, and so on.

	\param errbuf: a pointer to an user-allocated buffer that will contain the complete
	error message. This buffer has to be at least 'errbuflen' in length.
	It can be NULL; in this case the error cannot be printed.

	\param errbuflen: length of the buffer that will contains the error. The error message cannot be
	larger than 'errbuflen - 1' because the last char is reserved for the string terminator.

	\return It returns '-1' if this function succeedes, '0' otherwise.
	The address and port corresponding are returned back in the buffers 'address' and 'port'.
	In any case, the returned strings are '0' terminated.

	\warning If the socket is using a connectionless protocol, the address may not be available 
	until I/O occurs on the socket.
*/
int sock_getmyinfo(SOCKET sock, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
{
struct sockaddr_storage mysockaddr;
socklen_t sockaddrlen;


	sockaddrlen = sizeof(struct sockaddr_storage);

	if (getsockname(sock, (struct sockaddr *) &mysockaddr, &sockaddrlen) == -1)
	{
		sock_geterror("getsockname(): ", errbuf, errbuflen);
		return 0;
	}
	else
	{
		// Returns the numeric address of the host that triggered the error
		return sock_getascii_addrport(&mysockaddr, address, addrlen, port, portlen, flags, errbuf, errbuflen);
	}

	return 0;
}



/*!
	\brief It retrieves two strings containing the address and the port of a given 'sockaddr' variable.

	This function is basically an extended version of the inet_ntop(), which does not exist in
	WIN32 because the same result can be obtained by using the getnameinfo().
	However, differently from inet_ntop(), this function is able to return also literal names
	(e.g. 'locahost') dependingly from the 'Flags' parameter.

	The function accepts a sockaddr_storage variable (which can be returned by several functions
	like bind(), connect(), accept(), and more) and it transforms its content into a 'human'
	form. So, for instance, it is able to translate an hex address (stored in bynary form) into
	a standard IPv6 address like "::1".

	The behaviour of this function depends on the parameters we have in the 'Flags' variable, which
	are the ones allowed in the standard getnameinfo() socket function.
	
	\param sockaddr: a 'sockaddr_in' or 'sockaddr_in6' structure containing the address that 
	need to be translated from network form into the presentation form. This structure must be 
	zero-ed prior using it, and the address family field must be filled with the proper value. 
	The user must cast any 'sockaddr_in' or 'sockaddr_in6' structures to 'sockaddr_storage' before 
	calling this function.

	\param address: it contains the address that will be returned by the function. This buffer
	must be properly allocated by the user. The address can be either literal or numeric depending
	on the value of 'Flags'.

	\param addrlen: the length of the 'address' buffer.

	\param port: it contains the port that will be returned by the function. This buffer
	must be properly allocated by the user.

	\param portlen: the length of the 'port' buffer.

	\param flags: a set of flags (the ones defined into the getnameinfo() standard socket function)
	that determine if the resulting address must be in numeric / literal form, and so on.

	\param errbuf: a pointer to an user-allocated buffer that will contain the complete
	error message. This buffer has to be at least 'errbuflen' in length.
	It can be NULL; in this case the error cannot be printed.

	\param errbuflen: length of the buffer that will contains the error. The error message cannot be
	larger than 'errbuflen - 1' because the last char is reserved for the string terminator.

	\return It returns '-1' if this function succeedes, '0' otherwise.
	The address and port corresponding to the given SockAddr are returned back in the buffers 'address'
	and 'port'.
	In any case, the returned strings are '0' terminated.
*/
int sock_getascii_addrport(const struct sockaddr_storage *sockaddr, char *address, int addrlen, char *port, int portlen, int flags, char *errbuf, int errbuflen)
{
socklen_t sockaddrlen;
int retval;					// Variable that keeps the return value;

	retval= -1;

#ifdef WIN32
	if (sockaddr->ss_family == AF_INET)
		sockaddrlen = sizeof(struct sockaddr_in);
	else
		sockaddrlen = sizeof(struct sockaddr_in6);
#else
	sockaddrlen = sizeof(struct sockaddr_storage);
#endif

	if ((flags & NI_NUMERICHOST) == 0)	// Check that we want literal names
	{
		if ( (sockaddr->ss_family == AF_INET6) &&
			(memcmp( &((struct sockaddr_in6 *) sockaddr)->sin6_addr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(struct in6_addr) ) == 0) )
		{
			if (address)
				strncpy(address, SOCKET_NAME_NULL_DAD, addrlen);
			return retval;
		}
	}

	if ( getnameinfo((struct sockaddr *) sockaddr, sockaddrlen, address, addrlen, port, portlen, flags) != 0)
	{
		// If the user wants to receive an error message
		if (errbuf)
		{
			sock_geterror("getnameinfo(): ", errbuf, errbuflen);
			errbuf[errbuflen-1]= 0;
		}

		if (address)
		{
			strncpy(address, SOCKET_NO_NAME_AVAILABLE, addrlen);
			address[addrlen-1]= 0;
		}

		if (port)
		{
			strncpy(port, SOCKET_NO_PORT_AVAILABLE, portlen);
			port[portlen-1]= 0;
		}

		retval= 0;
	}

	return retval;
}



/*!
	\brief It translates an address from the 'presentation' form into the 'network' form.

	This function basically replaces inet_pton(), which does not exist in WIN32 because
	the same result can be obtained by using the getaddrinfo().
	An addictional advantage is that 'Address' can be both a numeric address (e.g. '127.0.0.1',
	like in inet_pton() ) and a literal name (e.g. 'localhost').

	This function does the reverse job of sock_getascii_addrport().

	\param address: a zero-terminated string which contains the name you have to
	translate. The name can be either literal (e.g. 'localhost') or numeric (e.g. '::1').

	\param sockaddr: a user-allocated sockaddr_storage structure which will contains the
	'network' form of the requested address.

	\param addr_family: a constant which can assume the following values:
		- 'AF_INET' if we want to ping an IPv4 host
		- 'AF_INET6' if we want to ping an IPv6 host
		- 'AF_UNSPEC' if we do not have preferences about the protocol used to ping the host 

	\param errbuf: a pointer to an user-allocated buffer that will contain the complete
	error message. This buffer has to be at least 'errbuflen' in length.
	It can be NULL; in this case the error cannot be printed.

	\param errbuflen: length of the buffer that will contains the error. The error message cannot be
	larger than 'errbuflen - 1' because the last char is reserved for the string terminator.

	\return '-1' if the translation succeded, '-2' if there was some non critical error, '0' 
	otherwise. In case it fails, the content of the SockAddr variable remains unchanged.
	A 'non critical error' can occur in case the 'Address' is a literal name, which can be mapped
	to several network addresses (e.g. 'foo.bar.com' => '10.2.2.2' and '10.2.2.3'). In this case
	the content of the SockAddr parameter will be the address corresponding to the first mapping.

	\warning The sockaddr_storage structure MUST be allocated by the user.
*/
int sock_present2network(const char *address, struct sockaddr_storage *sockaddr, int addr_family, char *errbuf, int errbuflen)
{
int retval;
struct addrinfo *addrinfo;
struct addrinfo hints;

	memset(&hints, 0, sizeof(hints) );

	hints.ai_family= addr_family;

	if ( (retval= sock_initaddress(address, "22222" /* fake port */, &hints, &addrinfo, errbuf, errbuflen)) == -1 )
		return 0;

	if (addrinfo->ai_family == PF_INET)
		memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in) );
	else
		memcpy(sockaddr, addrinfo->ai_addr, sizeof(struct sockaddr_in6) );

	if (addrinfo->ai_next != NULL)
	{
		freeaddrinfo(addrinfo);

		if (errbuf)
		{
			snprintf(errbuf, errbuflen, "More than one socket requested; using the first one returned");
			errbuf[errbuflen - 1]= 0;
		}

		return -2;
	}

	freeaddrinfo(addrinfo);
	return -1;
}


⌨️ 快捷键说明

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