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

📄 socket.c

📁 postgresql-odbc,跨平台应用
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------- * Module:			socket.c * * Description:		This module contains functions for low level socket *					operations (connecting/reading/writing to the backend) * * Classes:			SocketClass (Functions prefix: "SOCK_") * * API functions:	none * * Comments:		See "notice.txt" for copyright and license information. *------- */#include <libpq-fe.h>#include <openssl/ssl.h>#include "socket.h"#include "loadlib.h"#include "connection.h"#ifndef WIN32#include <stdlib.h>#include <string.h>				/* for memset */#ifdef TIME_WITH_SYS_TIME#include <sys/time.h>#include <time.h>#else#ifdef	HAVE_SYS_TIME_H#include <sys/time.h>#else#include <time.h>#endif /* HAVE_SYS_TIME_H */#endif /* TIME_WITH__SYS_TIME */#endif /* WIN32 */extern GLOBAL_VALUES globals;static void SOCK_set_error(SocketClass *s, int _no, const char *_msg){	int	gerrno = SOCK_ERRNO;	s->errornumber = _no;	if (NULL != s->_errormsg_)		free(s->_errormsg_);	if (NULL != _msg)		s->_errormsg_ = strdup(_msg);	else		s->_errormsg_ = NULL;	mylog("(%d)%s ERRNO=%d\n", _no, _msg, gerrno);}voidSOCK_clear_error(SocketClass *self){	self->errornumber = 0;	if (NULL != self->_errormsg_)		free(self->_errormsg_);	self->_errormsg_ = NULL;}SocketClass *SOCK_Constructor(const ConnectionClass *conn){	SocketClass *rv;	rv = (SocketClass *) malloc(sizeof(SocketClass));	if (rv != NULL)	{		rv->socket = (SOCKETFD) -1;		rv->via_libpq = FALSE;		rv->ssl = NULL;		rv->pqconn = NULL;		rv->pversion = 0;		rv->reslen = 0;		rv->buffer_filled_in = 0;		rv->buffer_filled_out = 0;		rv->buffer_read_in = 0;		if (conn)			rv->buffer_size = conn->connInfo.drivers.socket_buffersize;		else			rv->buffer_size = globals.socket_buffersize;		rv->buffer_in = (UCHAR *) malloc(rv->buffer_size);		if (!rv->buffer_in)		{			free(rv);			return NULL;		}		rv->buffer_out = (UCHAR *) malloc(rv->buffer_size);		if (!rv->buffer_out)		{			free(rv->buffer_in);			free(rv);			return NULL;		}		rv->_errormsg_ = NULL;		rv->errornumber = 0;		rv->reverse = FALSE;	}	return rv;}voidSOCK_Destructor(SocketClass *self){	mylog("SOCK_Destructor\n");	if (!self)		return;	if (self->socket != (SOCKETFD) -1)	{		if (self->pqconn)		{			if (self->via_libpq)			{				PQfinish(self->pqconn);				/* UnloadDelayLoadedDLLs(NULL != self->ssl); */			}			self->via_libpq = FALSE;			self->pqconn = NULL;			self->ssl = NULL;		}		else		{			SOCK_put_char(self, 'X');			if (PG_PROTOCOL_74 == self->pversion)				SOCK_put_int(self, 4, 4);			SOCK_flush_output(self);			closesocket(self->socket);		}	}	if (self->buffer_in)		free(self->buffer_in);	if (self->buffer_out)		free(self->buffer_out);	if (self->_errormsg_)		free(self->_errormsg_);	free(self);}#if defined(_MSC_VER) && (_MSC_VER < 1300)static freeaddrinfo_func freeaddrinfo_ptr = NULL;static getaddrinfo_func getaddrinfo_ptr = NULL;static getnameinfo_func getnameinfo_ptr = NULL;static	HMODULE ws2_hnd = NULL;#elsestatic freeaddrinfo_func freeaddrinfo_ptr = freeaddrinfo;static getaddrinfo_func getaddrinfo_ptr = getaddrinfo;static getnameinfo_func getnameinfo_ptr = getnameinfo;#endif /* _MSC_VER */static BOOL format_sockerr(char *errmsg, size_t buflen, int errnum, const char *cmd, const char *host, int portno){	BOOL ret = FALSE;#ifdef	WIN32	if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,		errnum, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),		errmsg, (DWORD)buflen, NULL))		ret = TRUE;#else#if defined(POSIX_MULTITHREAD_SUPPORT) && defined(HAVE_STRERROR_R)#ifdef	STRERROR_R_INT	if (0 == strerror_r(errnum, errmsg, buflen))		ret = TRUE;#else	const char *pchar;	pchar = (const char *) strerror_r(errnum, errmsg, buflen);	if (NULL != pchar)	{		if (pchar != errmsg)			strncpy(errmsg, pchar, buflen);		ret = TRUE;	}#endif /* STRERROR_R_INT */#else	strncpy(errmsg, strerror(errnum), buflen);	ret = TRUE;#endif /* POSIX_MULTITHREAD_SUPPORT */#endif /* WIN32 */	if (ret)	{		size_t	tlen = strlen(errmsg);		errmsg += tlen;		buflen -= tlen;		snprintf(errmsg, buflen, " [%s:%d]", host, portno);	}	else		snprintf(errmsg, buflen, "%s failed for [%s:%d] ", cmd, host, portno);	return ret;} charSOCK_connect_to(SocketClass *self, unsigned short port, char *hostname, long timeout){	struct addrinfo	rest, *addrs = NULL, *curadr = NULL;	int	family = 0; 	char	retval = 0;	int	gerrno;	if (self->socket != (SOCKETFD) -1)	{		SOCK_set_error(self, SOCKET_ALREADY_CONNECTED, "Socket is already connected");		return 0;	}#if defined(_MSC_VER) && (_MSC_VER < 1300)	if (ws2_hnd == NULL)		ws2_hnd = GetModuleHandle("ws2_32.dll");	if (freeaddrinfo_ptr == NULL)		freeaddrinfo_ptr = (freeaddrinfo_func)GetProcAddress(ws2_hnd, "freeaddrinfo"); 	if (getaddrinfo_ptr == NULL)		getaddrinfo_ptr = (getaddrinfo_func)GetProcAddress(ws2_hnd, "getaddrinfo"); 	if (getnameinfo_ptr == NULL)		getnameinfo_ptr = (getnameinfo_func)GetProcAddress(ws2_hnd, "getnameinfo"); #endif	/*	 * Hostname lookup.	 */	if (hostname && hostname[0]#ifndef	WIN32	    && '/' != hostname[0]#endif /* WIN32 */	   )	{		char	portstr[16];		int	ret;		memset(&rest, 0, sizeof(rest));		rest.ai_socktype = SOCK_STREAM;		rest.ai_family = AF_UNSPEC;		snprintf(portstr, sizeof(portstr), "%d", port);		if (inet_addr(hostname) != INADDR_NONE)			rest.ai_flags |= AI_NUMERICHOST;			ret = getaddrinfo_ptr(hostname, portstr, &rest, &addrs);		if (ret || !addrs)		{			SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Could not resolve hostname.");			if (addrs)				freeaddrinfo_ptr(addrs);			return 0;		}		curadr = addrs;	}	else#ifdef	HAVE_UNIX_SOCKETS	{		struct sockaddr_un *un = (struct sockaddr_un *) &(self->sadr_area);		family = un->sun_family = AF_UNIX;		/* passing NULL or '' means pg default "/tmp" */		UNIXSOCK_PATH(un, port, hostname);		self->sadr_len = UNIXSOCK_LEN(un);	}#else	{		SOCK_set_error(self, SOCKET_HOST_NOT_FOUND, "Hostname isn't specified.");		return 0;	}#endif /* HAVE_UNIX_SOCKETS */retry:	if (curadr)		family = curadr->ai_family;	self->socket = socket(family, SOCK_STREAM, 0);	if (self->socket == (SOCKETFD) -1)	{		SOCK_set_error(self, SOCKET_COULD_NOT_CREATE_SOCKET, "Could not create Socket.");		return 0;	}#ifdef	TCP_NODELAY	if (family != AF_UNIX)	{		int i;		socklen_t	len;		i = 1;		len = sizeof(i);		if (setsockopt(self->socket, IPPROTO_TCP, TCP_NODELAY, (char *) &i, len) < 0)		{			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not set socket to NODELAY.");			closesocket(self->socket);			self->socket = (SOCKETFD) -1;			return 0;		}	}#endif /* TCP_NODELAY */#ifdef	WIN32	{		long	ioctlsocket_ret = 1;		/* Returns non-0 on failure, while fcntl() returns -1 on failure */		ioctlsocket(self->socket, FIONBIO, &ioctlsocket_ret);	}#else        fcntl(self->socket, F_SETFL, O_NONBLOCK);#endif	if (curadr)	{		struct sockaddr *in = (struct sockaddr *) &(self->sadr_area);		memset((char *) in, 0, sizeof(self->sadr_area));		memcpy(in, curadr->ai_addr, curadr->ai_addrlen);		self->sadr_len = (int) curadr->ai_addrlen;	}	if (connect(self->socket, (struct sockaddr *) &(self->sadr_area), self->sadr_len) < 0)	{		int	ret, optval;		fd_set	fds, except_fds;		struct	timeval	tm;		socklen_t	optlen = sizeof(optval);		time_t	t_now, t_finish = 0;		BOOL	tm_exp = FALSE;		gerrno = SOCK_ERRNO;		switch (gerrno)		{			case 0:			case EINPROGRESS:			case EINTR:			case EWOULDBLOCK:		    		break;			default:				SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect to remote socket immedaitely");				goto cleanup;		}		if (timeout > 0)		{			t_now = time(NULL);			t_finish = t_now + timeout;			tm.tv_sec = timeout;			tm.tv_usec = 0;		}		do {			FD_ZERO(&fds);			FD_ZERO(&except_fds);			FD_SET(self->socket, &fds);			FD_SET(self->socket, &except_fds);			ret = select((int) self->socket + 1, NULL, &fds, &except_fds, timeout > 0 ? &tm : NULL);			gerrno = SOCK_ERRNO;			if (0 < ret)				break;			else if (0 == ret)				tm_exp = TRUE;			else if (EINTR != gerrno)				break;			else if (timeout > 0)			{				if (t_now = time(NULL), t_now >= t_finish)					tm_exp = TRUE;				else				{					tm.tv_sec = (long) (t_finish - t_now);					tm.tv_usec = 0;				}			}		} while (!tm_exp);		if (tm_exp)		{			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. timeout occured.");			goto cleanup;		}		else if (0 > ret)		{			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. select error occured.");			mylog("select error ret=%d ERROR=%d\n", ret, gerrno);			goto cleanup;		}		if (getsockopt(self->socket, SOL_SOCKET, SO_ERROR,				(char *) &optval, &optlen) == -1)		{			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, "Could not connect .. getsockopt error.");		}		else if (optval != 0)		{			char	errmsg[256], host[64];			host[0] = '\0';			getnameinfo_ptr((struct sockaddr *) &(self->sadr_area),					self->sadr_len, host, sizeof(host),					NULL, 0, NI_NUMERICHOST);			/* snprintf(errmsg, sizeof(errmsg), "connect getsockopt val %d addr=%s\n", optval, host); */			format_sockerr(errmsg, sizeof(errmsg), optval, "connect", host, port);			mylog(errmsg);			SOCK_set_error(self, SOCKET_COULD_NOT_CONNECT, errmsg);		}		else			retval = 1;	}	else		retval = 1;cleanup:	if (0 == retval)	{		if (self->socket >= 0)		{			closesocket(self->socket);			self->socket = (SOCKETFD) -1;		}		if (curadr && curadr->ai_next)		{			curadr = curadr->ai_next;			goto retry;		}	}	else		SOCK_set_error(self, 0, NULL);		if (addrs)		freeaddrinfo_ptr(addrs);	return retval;}/* *	To handle EWOULDBLOCK etc (mainly for libpq non-blocking connection). */#define	MAX_RETRY_COUNT	30static int SOCK_wait_for_ready(SocketClass *sock, BOOL output, int retry_count){	int	ret, gerrno;	fd_set	fds, except_fds;	struct	timeval	tm;	BOOL	no_timeout = (0 != retry_count && (retry_count < 0 || (!sock->ssl)));	do {		FD_ZERO(&fds);		FD_ZERO(&except_fds);		FD_SET(sock->socket, &fds);		FD_SET(sock->socket, &except_fds);		if (!no_timeout)		{			tm.tv_sec = retry_count;			tm.tv_usec = 0;		}		ret = select((int)sock->socket + 1, output ? NULL : &fds, output ? &fds : NULL, &except_fds, no_timeout ? NULL : &tm);		gerrno = SOCK_ERRNO;	} while (ret < 0 && EINTR == gerrno);	if (retry_count < 0)		retry_count *= -1;	if (0 == ret && retry_count > MAX_RETRY_COUNT)	{		ret = -1;		SOCK_set_error(sock, output ? SOCKET_WRITE_TIMEOUT : SOCKET_READ_TIMEOUT, "SOCK_wait_for_ready timeout");

⌨️ 快捷键说明

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