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

📄 net.c

📁 在Linux/Unix下面访问WINDOWS SQLSERVER 的ODBC驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* FreeTDS - Library of routines accessing Sybase and Microsoft databases * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003  Brian Bruns * Copyright (C) 2004, 2005, 2006, 2007  Ziglio Frediano * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#if HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <stdarg.h>#include <stdio.h>#if TIME_WITH_SYS_TIME# if HAVE_SYS_TIME_H#  include <sys/time.h># endif# include <time.h>#else# if HAVE_SYS_TIME_H#  include <sys/time.h># else#  include <time.h># endif#endif#if HAVE_SYS_TYPES_H#include <sys/types.h>#endif /* HAVE_SYS_TYPES_H */#if HAVE_ERRNO_H#include <errno.h>#endif /* HAVE_ERRNO_H */#if HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#if HAVE_STDLIB_H#include <stdlib.h>#endif /* HAVE_STDLIB_H */#if HAVE_STRING_H#include <string.h>#endif /* HAVE_STRING_H */#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif /* HAVE_SYS_SOCKET_H */#if HAVE_NETINET_IN_H#include <netinet/in.h>#endif /* HAVE_NETINET_IN_H */#if HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif /* HAVE_NETINET_TCP_H */#if HAVE_ARPA_INET_H#include <arpa/inet.h>#endif /* HAVE_ARPA_INET_H */#if HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif /* HAVE_SYS_IOCTL_H */#if HAVE_SELECT_H#include <sys/select.h>#endif /* HAVE_SELECT_H */#if HAVE_POLL_H#include <poll.h>#endif /* HAVE_POLL_H */#include "tds.h"#include "tdsstring.h"#include "replacements.h"#include <signal.h>#include <assert.h>#ifdef HAVE_GNUTLS#include <gnutls/gnutls.h>#elif defined(HAVE_OPENSSL)#include <openssl/ssl.h>#endif#ifdef DMALLOC#include <dmalloc.h>#endifTDS_RCSID(var, "$Id: net.c,v 1.71.2.1 2008/01/12 00:21:39 freddy77 Exp $");#undef USE_POLL#if defined(HAVE_POLL_H) && defined(HAVE_POLL)# define USE_POLL 1# define TDSSELREAD  POLLIN# define TDSSELWRITE POLLOUT/* error is always returned */# define TDSSELERR   0#else# define USE_POLL 0# define TDSSELREAD  1# define TDSSELWRITE 2# define TDSSELERR   4#endifstatic int tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds);/** * \addtogroup network * @{  */#ifdef WIN32int_tds_socket_init(void){	WSADATA wsadata;	return WSAStartup(MAKEWORD(1, 1), &wsadata);}void_tds_socket_done(void){	WSACleanup();}#endif#if !defined(SOL_TCP) && defined(IPPROTO_TCP)#define SOL_TCP IPPROTO_TCP#endif/* Optimize the way we send packets */#undef USE_MSGMORE#undef USE_CORK#undef USE_NODELAY/* On Linux 2.4.x we can use MSG_MORE */#if defined(__linux__) && defined(MSG_MORE)#define USE_MSGMORE 1/* On early Linux use TCP_CORK if available */#elif defined(__linux__) && defined(TCP_CORK)#define USE_CORK 1/* On *BSD try to use TCP_CORK *//* * NOPUSH flag do not behave in the same way * cf ML "FreeBSD 5.0 performance problems with TCP_NOPUSH" */#elif (defined(__FreeBSD__) || defined(__GNU_FreeBSD__) || defined(__OpenBSD__)) && defined(TCP_CORK)#define USE_CORK 1/* otherwise use NODELAY */#elif defined(TCP_NODELAY) && defined(SOL_TCP)#define USE_NODELAY 1/* under VMS we have to define TCP_NODELAY */#elif defined(__VMS)#define TCP_NODELAY 1#define USE_NODELAY 1#endif#if !defined(WIN32)typedef unsigned int ioctl_nonblocking_t;#elsetypedef u_long ioctl_nonblocking_t;#endifinttds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout){	struct sockaddr_in sin;#if !defined(DOS32X)	ioctl_nonblocking_t ioctl_nonblocking;	int retval;#endif	int len;	int tds_error = TDSECONN;	char ip[20];#if defined(DOS32X) || defined(WIN32)	int optlen;#else	socklen_t optlen;#endif	memset(&sin, 0, sizeof(sin));	sin.sin_addr.s_addr = inet_addr(ip_addr);	if (sin.sin_addr.s_addr == INADDR_NONE) {		tdsdump_log(TDS_DBG_ERROR, "inet_addr() failed, IP = %s\n", ip_addr);		return TDS_FAIL;	}	sin.sin_family = AF_INET;	sin.sin_port = htons(port);	tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d (TDS version %d.%d)\n", 			tds_inet_ntoa_r(sin.sin_addr, ip, sizeof(ip)), ntohs(sin.sin_port), 			tds->major_version, tds->minor_version);	if (TDS_IS_SOCKET_INVALID(tds->s = socket(AF_INET, SOCK_STREAM, 0))) {		tdserror(tds->tds_ctx, tds, TDSESOCK, 0);  		tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", strerror(sock_errno));		return TDS_FAIL;	}#ifdef SO_KEEPALIVE	len = 1;	setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len));#endif	len = 1;#if defined(USE_NODELAY) || defined(USE_MSGMORE)	setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));#elif defined(USE_CORK)	if (setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0)		setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len));#else#error One should be defined#endif#ifdef  DOS32X			/* the other connection doesn't work  on WATTCP32 */	if (connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {		char *message;		if (asprintf(&message, "tds_open_socket(): %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)) >= 0) {			perror(message);			free(message);		}		tds_close_socket(tds);		tdserror(tds->tds_ctx, tds, TDSECONN, 0);		return TDS_FAIL;	}#else	if (!timeout) {		/* A timeout of zero means wait forever; 90,000 seconds will feel like forever. */		timeout = 90000;	}	/* enable non-blocking mode */	ioctl_nonblocking = 1;	if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_nonblocking) < 0) {		tds_close_socket(tds);		return TDS_FAIL;	}	retval = connect(tds->s, (struct sockaddr *) &sin, sizeof(sin));	if (retval == 0) {		tdsdump_log(TDS_DBG_INFO2, "connection established\n");	} else {		tdsdump_log(TDS_DBG_ERROR, "tds_open_socket: connect(2) returned \"%s\"\n", strerror(sock_errno));#if DEBUGGING_CONNECTING_PROBLEM		if (sock_errno != ECONNREFUSED && sock_errno != ENETUNREACH && sock_errno != EINPROGRESS) {			tdsdump_dump_buf(TDS_DBG_ERROR, "Contents of sockaddr_in", &sin, sizeof(sin));			tdsdump_log(TDS_DBG_ERROR, 	" sockaddr_in:\t"							      "%s = %x\n" 							"\t\t\t%s = %x\n" 							"\t\t\t%s = %x\n"							"\t\t\t%s = '%s'\n"							, "sin_family", sin.sin_family							, "sin_port", sin.sin_port							, "sin_addr.s_addr", sin.sin_addr.s_addr							, "(param ip_addr)", ip_addr							);		}#endif		if (sock_errno != TDSSOCK_EINPROGRESS)			goto not_available;				if (tds_select(tds, TDSSELWRITE|TDSSELERR, timeout) <= 0) {			tds_error = TDSESOCK;			goto not_available;		}	}#endif	/* check socket error */	optlen = sizeof(len);	len = 0;	if (getsockopt(tds->s, SOL_SOCKET, SO_ERROR, (char *) &len, &optlen) != 0) {		tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) failed: %s\n", strerror(sock_errno));		goto not_available;	}	if (len != 0) {		tdsdump_log(TDS_DBG_ERROR, "getsockopt(2) reported: %s\n", strerror(len));		goto not_available;	}	tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() succeeded\n");	return TDS_SUCCEED;	    not_available:		tds_close_socket(tds);	tdserror(tds->tds_ctx, tds, tds_error, sock_errno);	tdsdump_log(TDS_DBG_ERROR, "tds_open_socket() failed\n");	return TDS_FAIL;}inttds_close_socket(TDSSOCKET * tds){	int rc = -1;	if (!IS_TDSDEAD(tds)) {		rc = CLOSESOCKET(tds->s);		tds->s = INVALID_SOCKET;		tds_set_state(tds, TDS_DEAD);		if (-1 == rc) 			tdserror(tds->tds_ctx, tds,  TDSECLOS, sock_errno);	}	return rc;}/** * Select on a socket until it's available or the timeout expires.  * Meanwhile, call the interrupt function.  * \return	>0 ready descriptors *		 0 timeout  * 		<0 error (cf. errno).  Caller should  close socket and return failure.  * This function does not call tdserror or close the socket because it can't know the context in which it's being called.    */static inttds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds){	int rc, seconds;	unsigned int poll_seconds;#if !USE_POLL	fd_set fds[3];	fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL;#endif	assert(tds != NULL);	assert(timeout_seconds >= 0);#if !USE_POLL#if !defined(WIN32) && defined(FD_SETSIZE)	if (tds->s >= FD_SETSIZE) {		sock_errno = EINVAL;		return -1;	}#endif	if ((tds_sel & TDSSELREAD) != 0) {		FD_ZERO(&fds[0]);		readfds = &fds[0];	}	if ((tds_sel & TDSSELWRITE) != 0) {		FD_ZERO(&fds[1]);		writefds = &fds[1];	}	if ((tds_sel & TDSSELERR) != 0) {		FD_ZERO(&fds[2]);		exceptfds = &fds[2];	}#endif	/* 	 * The select loop.  	 * If an interrupt handler is installed, we iterate once per second, 	 * 	else we try once, timing out after timeout_seconds (0 == never). 	 * If select(2) is interrupted by a signal (e.g. press ^C in sqsh), we timeout.	 * 	(The application can retry if desired by installing a signal handler.)	 *	 * We do not measure current time against end time, to avoid being tricked by ntpd(8) or similar. 	 * Instead, we just count down.  	 *	 * We exit on the first of these events:	 * 1.  a descriptor is ready. (return to caller)	 * 2.  select(2) returns an important error.  (return to caller)	 * A timeout of zero says "wait forever".  We do that by passing a NULL timeval pointer to select(2). 	 */	poll_seconds = (tds->tds_ctx && tds->tds_ctx->int_handler)? 1 : timeout_seconds;	for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) {#if USE_POLL		struct pollfd fd;		int timeout = poll_seconds ? poll_seconds * 1000 : -1;		fd.fd = tds->s;		fd.events = tds_sel;		fd.revents = 0;		rc = poll(&fd, 1, timeout);#else		struct timeval tv, *ptv = poll_seconds? &tv : NULL;		tv.tv_sec = poll_seconds;		tv.tv_usec = 0; 		if (readfds)			FD_SET(tds->s, readfds);		if (writefds)			FD_SET(tds->s, writefds);		if (exceptfds)			FD_SET(tds->s, exceptfds);		rc = select(tds->s + 1, readfds, writefds, exceptfds, ptv); #endif		if (rc > 0 ) {			return rc;		}		if (rc < 0) {			switch (sock_errno) {			case TDSSOCK_EINTR:				break;	/* let interrupt handler be called */			default: /* documented: EFAULT, EBADF, EINVAL */				tdsdump_log(TDS_DBG_ERROR, "error: select(2) returned 0x%x, \"%s\"\n", 						sock_errno, strerror(sock_errno));				return rc;			}		}		assert(rc == 0 || (rc < 0 && sock_errno == TDSSOCK_EINTR));		if (tds->tds_ctx && tds->tds_ctx->int_handler) {	/* interrupt handler installed */			/*			 * "If hndlintr() returns INT_CANCEL, DB-Library sends an attention token [TDS_BUFSTAT_ATTN]			 * to the server. This causes the server to discontinue command processing. 			 * The server may send additional results that have already been computed. 			 * When control returns to the mainline code, the mainline code should do 			 * one of the following: 			 * - Flush the results using dbcancel 			 * - Process the results normally"			 */			int timeout_action = (*tds->tds_ctx->int_handler) (tds->parent);#if 0

⌨️ 快捷键说明

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