예제 #1
0
파일: packet.c 프로젝트: FreeTDS/freetds
static int
tds_connection_put_packet(TDSSOCKET *tds, TDSPACKET *packet)
{
	TDSCONNECTION *conn = tds->conn;

	if (TDS_UNLIKELY(!packet)) {
		tds_close_socket(tds);
		return TDS_FAIL;
	}
	tds->out_pos = 0;

	tds_mutex_lock(&conn->list_mtx);
	for (;;) {
		int wait_res;

		if (IS_TDSDEAD(tds)) {
			tdsdump_log(TDS_DBG_NETWORK, "Write attempt when state is TDS_DEAD");
			break;
		}

		/* limit packet sending looking at sequence/window */
		if (tds->send_seq <= tds->send_wnd) {
			/* append packet */
			tds_append_packet(&conn->send_packets, packet);
			packet = NULL;
		}

		/* network ok ? process network */
		if (!conn->in_net_tds) {
			tds_connection_network(conn, tds, packet ? 0 : 1);
			if (packet) continue;
			/* FIXME we are not sure we sent the packet !!! */
			break;
		}

		/* signal thread processing network to handle our packet */
		/* TODO check result */
		tds_wakeup_send(&conn->wakeup, 0);

		/* wait local condition */
		wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
		if (wait_res == ETIMEDOUT
		    && tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
			tds_mutex_unlock(&conn->list_mtx);
			tds_close_socket(tds);
			tds_free_packets(packet);
			return TDS_FAIL;
		}
	}
	tds_mutex_unlock(&conn->list_mtx);
	if (TDS_UNLIKELY(packet)) {
		tds_free_packets(packet);
		return TDS_FAIL;
	}
	if (IS_TDSDEAD(tds))
		return TDS_FAIL;
	return TDS_SUCCESS;
}
예제 #2
0
파일: net.c 프로젝트: jujubha/freetds
static void
tds_check_cancel(TDSCONNECTION *conn)
{
	TDSSOCKET *tds;
	int rc;

	if (!tds_connection_signaled(conn))
		return;

	do {
		unsigned n = 0;

		rc = TDS_SUCCESS;
		tds_mutex_lock(&conn->list_mtx);
		/* Here we scan all list searching for sessions that should send cancel packets */
		for (; n < conn->num_sessions; ++n)
			if (TDSSOCKET_VALID(tds=conn->sessions[n]) && tds->in_cancel == 1) {
				/* send cancel */
				tds->in_cancel = 2;
				tds_mutex_unlock(&conn->list_mtx);
				rc = tds_append_cancel(tds);
				tds_mutex_lock(&conn->list_mtx);
				if (rc != TDS_SUCCESS)
					break;
			}
		tds_mutex_unlock(&conn->list_mtx);
		/* for all failed */
		/* this must be done outside loop cause it can alter list */
		/* this must be done unlocked cause it can lock again */
		if (rc != TDS_SUCCESS)
			tds_close_socket(tds);
	} while(rc != TDS_SUCCESS);
}
예제 #3
0
파일: net.c 프로젝트: alex-fang/freetds
/**
 * \param tds the famous socket
 * \param buffer data to send
 * \param buflen bytes in buffer
 * \param last 1 if this is the last packet, else 0
 * \return length written (>0), <0 on failure
 */
int
tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, size_t buflen)
{
	int len;
	size_t sent = 0;

	assert(tds && buffer);

	while (sent < buflen) {
		/* TODO if send buffer is full we block receive !!! */
		len = tds_select(tds, TDSSELWRITE, tds->query_timeout);

		if (len > 0) {
			len = tds_socket_write(tds->conn, tds, buffer + sent, buflen - sent);
			if (len == 0)
				continue;
			if (len < 0)
				return len;

			sent += len;
			continue;
		}

		/* error */
		if (len < 0) {
			int err = sock_errno;
			char *errstr;

			if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */
				continue;
			errstr = sock_strerror(err);
			tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n", err, errstr);
			sock_strerror_free(errstr);
			tds_connection_close(tds->conn);
			tdserror(tds_get_ctx(tds), tds, TDSEWRIT, err);
			return -1;
		}

		/* timeout */
		tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n");
		switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
		case TDS_INT_CONTINUE:
			break;
		default:
		case TDS_INT_CANCEL:
			tds_close_socket(tds);
			return -1;
		}
	}

	return (int) sent;
}
예제 #4
0
파일: common.c 프로젝트: DmitrySigaev/ncbi
/* Note that this always suceeds */
int
try_tds_logout(TDSLOGIN * login, TDSSOCKET * tds, int verbose)
{
	if (verbose) {
		fprintf(stdout, "Entered tds_try_logout()\n");
	}
	tds_close_socket(tds);
	tds_free_socket(tds);
	tds_free_login(login);
	tds_free_context(test_context);
	test_context = NULL;
	return TDS_SUCCESS;
}
예제 #5
0
파일: net.c 프로젝트: alex-fang/freetds
/**
 * Loops until we have received some characters
 * return -1 on failure
 */
int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen)
{
	if (tds == NULL || buf == NULL || buflen < 1)
		return -1;

	for (;;) {
		int len, err;

		/* FIXME this block writing from other sessions */
		len = tds_select(tds, TDSSELREAD, tds->query_timeout);
#if !ENABLE_ODBC_MARS
		if (len > 0 && (len & TDSPOLLURG)) {
			char buf[32];
			READSOCKET(tds->conn->s_signaled, buf, sizeof(buf));
			/* send cancel */
			if (!tds->in_cancel)
				tds_put_cancel(tds);
			continue;
		}
#endif
		if (len > 0) {
			len = tds_socket_read(tds->conn, tds, buf, buflen);
			if (len == 0)
				continue;
			return len;
		}

		/* error */
		if (len < 0) {
			if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
				continue;
			err = sock_errno;
			tds_connection_close(tds->conn);
			tdserror(tds_get_ctx(tds), tds, TDSEREAD, err);
			return -1;
		}

		/* timeout */
		switch (tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
		case TDS_INT_CONTINUE:
			break;
		default:
		case TDS_INT_CANCEL:
			tds_close_socket(tds);
			return -1;
		}
	}
}
예제 #6
0
파일: member.c 프로젝트: Distrotech/freetds
void
pool_free_member(TDS_POOL_MEMBER * pmbr)
{
	if (!IS_TDSDEAD(pmbr->tds)) {
		tds_close_socket(pmbr->tds);
	}
	pmbr->tds = NULL;
	/*
	 * if he is allocated disconnect the client 
	 * otherwise we end up with broken client.
	 */
	if (pmbr->current_user) {
		pool_free_user(pmbr->current_user);
		pmbr->current_user = NULL;
	}
	pmbr->state = TDS_IDLE;
}
예제 #7
0
파일: member.c 프로젝트: alex-fang/freetds
void
pool_free_member(TDS_POOL_MEMBER * pmbr)
{
	TDSSOCKET *tds = pmbr->tds;
	if (!IS_TDSDEAD(tds))
		tds_close_socket(tds);
	if (tds)
		tds_free_socket(tds);
	pmbr->tds = NULL;
	/*
	 * if he is allocated disconnect the client 
	 * otherwise we end up with broken client.
	 */
	if (pmbr->current_user) {
		pmbr->current_user->assigned_member = NULL;
		pool_free_user(pmbr->current_user);
		pmbr->current_user = NULL;
	}
	memset(pmbr, 0, sizeof(*pmbr));
	pmbr->state = TDS_IDLE;
}
예제 #8
0
파일: main.c 프로젝트: kozmaz87/freetds
/* 
 * pool_main_loop
 * Accept new connections from clients, and handle all input from clients and
 * pool members.
 */
static void
pool_main_loop(TDS_POOL * pool)
{
	TDS_POOL_USER *puser;
	TDS_POOL_MEMBER *pmbr;
	struct sockaddr_in sin;
	int s, maxfd, i;
	fd_set rfds;
	int socktrue = 1;

	/* FIXME -- read the interfaces file and bind accordingly */
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons(pool->port);
	sin.sin_family = AF_INET;

	if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_STREAM, 0))) {
		perror("socket");
		exit(1);
	}
	/* don't keep addr in use from [email protected] */
	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &socktrue, sizeof(socktrue));

	fprintf(stderr, "Listening on port %d\n", pool->port);
	if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
		perror("bind");
		exit(1);
	}
	listen(s, 5);

	FD_ZERO(&rfds);
	FD_SET(s, &rfds);
	maxfd = s;

	while (!term) {
		/* fprintf(stderr, "waiting for a connect\n"); */
		/* FIXME check return value */
		select(maxfd + 1, &rfds, NULL, NULL, NULL);
		if (term)
			break;

		/* process the sockets */
		if (FD_ISSET(s, &rfds)) {
			pool_user_create(pool, s, &sin);
		}
		pool_process_users(pool, &rfds);
		pool_process_members(pool, &rfds);
		/* back from members */
		if (waiters) {
			pool_schedule_waiters(pool);
		}

		FD_ZERO(&rfds);
		/* add the listening socket to the read list */
		FD_SET(s, &rfds);
		maxfd = s;

		/* add the user sockets to the read list */
		for (i = 0; i < pool->max_users; i++) {
			puser = (TDS_POOL_USER *) & pool->users[i];
			/* skip dead connections */
			if (!IS_TDSDEAD(puser->tds)) {
				if (tds_get_s(puser->tds) > maxfd)
					maxfd = tds_get_s(puser->tds);
				FD_SET(tds_get_s(puser->tds), &rfds);
			}
		}

		/* add the pool member sockets to the read list */
		for (i = 0; i < pool->num_members; i++) {
			pmbr = (TDS_POOL_MEMBER *) & pool->members[i];
			if (!IS_TDSDEAD(pmbr->tds)) {
				if (tds_get_s(pmbr->tds) > maxfd)
					maxfd = tds_get_s(pmbr->tds);
				FD_SET(tds_get_s(pmbr->tds), &rfds);
			}
		}
	}			/* while !term */
	CLOSESOCKET(s);
	for (i = 0; i < pool->max_users; i++) {
		puser = (TDS_POOL_USER *) & pool->users[i];
		if (!IS_TDSDEAD(puser->tds)) {
			fprintf(stderr, "Closing user %d\n", i);
			tds_close_socket(puser->tds);
		}
	}
	for (i = 0; i < pool->num_members; i++) {
		pmbr = (TDS_POOL_MEMBER *) & pool->members[i];
		if (!IS_TDSDEAD(pmbr->tds)) {
			fprintf(stderr, "Closing member %d\n", i);
			tds_close_socket(pmbr->tds);
		}
	}
}
예제 #9
0
파일: packet.c 프로젝트: FreeTDS/freetds
/**
 * Read in one 'packet' from the server.  This is a wrapped outer packet of
 * the protocol (they bundle result packets into chunks and wrap them at
 * what appears to be 512 bytes regardless of how that breaks internal packet
 * up.   (tetherow\@nol.org)
 * @return bytes read or -1 on failure
 */
int
tds_read_packet(TDSSOCKET * tds)
{
#if ENABLE_ODBC_MARS
	TDSCONNECTION *conn = tds->conn;

	tds_mutex_lock(&conn->list_mtx);

	for (;;) {
		int wait_res;
		TDSPACKET **p_packet;

		if (IS_TDSDEAD(tds)) {
			tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD\n");
			break;
		}

		/* if there is a packet for me return it */
		for (p_packet = &conn->packets; *p_packet; p_packet = &(*p_packet)->next)
			if ((*p_packet)->sid == tds->sid)
				break;

		if (*p_packet) {
			size_t hdr_size;

			/* remove our packet from list */
			TDSPACKET *packet = *p_packet;
			*p_packet = packet->next;
			tds_packet_cache_add(conn, tds->recv_packet);
			tds_mutex_unlock(&conn->list_mtx);

			packet->next = NULL;
			tds->recv_packet = packet;

			hdr_size = packet->buf[0] == TDS72_SMP ? sizeof(TDS72_SMP_HEADER) : 0;
			tds->in_buf = packet->buf + hdr_size;
			tds->in_len = packet->len - hdr_size;
			tds->in_pos  = 8;
			tds->in_flag = tds->in_buf[0];

			/* send acknowledge if needed */
			if (tds->recv_seq + 2 >= tds->recv_wnd)
				tds_update_recv_wnd(tds, tds->recv_seq + 4);

			return tds->in_len;
		}

		/* network ok ? process network */
		if (!conn->in_net_tds) {
			tds_connection_network(conn, tds, 0);
			continue;
		}

		/* wait local condition */
		wait_res = tds_cond_timedwait(&tds->packet_cond, &conn->list_mtx, tds->query_timeout);
		if (wait_res == ETIMEDOUT
		    && tdserror(tds_get_ctx(tds), tds, TDSETIME, ETIMEDOUT) != TDS_INT_CONTINUE) {
			tds_mutex_unlock(&conn->list_mtx);
			tds_close_socket(tds);
			return -1;
		}
	}

	tds_mutex_unlock(&conn->list_mtx);
	return -1;
#else /* !ENABLE_ODBC_MARS */
	unsigned char *pkt = tds->in_buf, *p, *end;

	if (IS_TDSDEAD(tds)) {
		tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD");
		return -1;
	}

	tds->in_len = 0;
	tds->in_pos = 0;
	for (p = pkt, end = p+8; p < end;) {
		int len = tds_connection_read(tds, p, end - p);
		if (len <= 0) {
			tds_close_socket(tds);
			return -1;
		}

		p += len;
		if (p - pkt >= 4) {
			unsigned pktlen = TDS_GET_A2BE(pkt+2);
			/* packet must at least contains header */
			if (TDS_UNLIKELY(pktlen < 8)) {
				tds_close_socket(tds);
				return -1;
			}
			if (TDS_UNLIKELY(pktlen > tds->recv_packet->capacity)) {
				TDSPACKET *packet = tds_realloc_packet(tds->recv_packet, pktlen);
				if (TDS_UNLIKELY(!packet)) {
					tds_close_socket(tds);
					return -1;
				}
				tds->recv_packet = packet;
				pkt = packet->buf;
				p = pkt + (p-tds->in_buf);
				tds->in_buf = pkt;
			}
			end = pkt + pktlen;
		}
	}

	/* set the received packet type flag */
	tds->in_flag = pkt[0];

	/* Set the length and pos (not sure what pos is used for now */
	tds->in_len = p - pkt;
	tds->in_pos = 8;
	tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len);

	return tds->in_len;
#endif /* !ENABLE_ODBC_MARS */
}
예제 #10
0
파일: packet.c 프로젝트: FreeTDS/freetds
static void
tds_connection_network(TDSCONNECTION *conn, TDSSOCKET *tds, int send)
{
	assert(!conn->in_net_tds);
	conn->in_net_tds = tds;
	tds_mutex_unlock(&conn->list_mtx);

	for (;;) {
		/* wait packets or update */
		int rc = tds_select(tds, conn->send_packets ? TDSSELREAD|TDSSELWRITE : TDSSELREAD, tds->query_timeout);

		if (rc < 0) {
			/* FIXME better error report */
			tds_connection_close(conn);
			break;
		}

		/* change notify */
		/* TODO async */

		if (!rc) { /* timeout */
			tdsdump_log(TDS_DBG_INFO1, "timeout\n");
			switch (rc = tdserror(tds_get_ctx(tds), tds, TDSETIME, sock_errno)) {
			case TDS_INT_CONTINUE:
				continue;
			default:
			case TDS_INT_CANCEL:
				tds_close_socket(tds);
			}
			break;
		}

		/*
		 * we must write first to catch write errors as
		 * write errors, not as read
		 */
		/* something to send */
		if (conn->send_packets && (rc & POLLOUT) != 0) {
			TDSSOCKET *s;

			short sid = tds_packet_write(conn);
			if (sid == tds->sid) break;	/* return to caller */

			tds_mutex_lock(&conn->list_mtx);
			if (sid >= 0 && sid < conn->num_sessions) {
				s = conn->sessions[sid];
				if (TDSSOCKET_VALID(s))
					tds_cond_signal(&s->packet_cond);
			}
			tds_mutex_unlock(&conn->list_mtx);
			/* avoid using a possible closed connection */
			continue;
		}

		/* received */
		if (rc & POLLIN) {
			TDSPACKET *packet;
			TDSSOCKET *s;

			/* try to read a packet */
			tds_packet_read(conn, tds);
			packet = conn->recv_packet;
			if (!packet || conn->recv_pos < packet->len) continue;
			conn->recv_packet = NULL;
			conn->recv_pos = 0;

			tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", packet->buf, packet->len);

			tds_mutex_lock(&conn->list_mtx);
			if (packet->sid >= 0 && packet->sid < conn->num_sessions) {
				s = conn->sessions[packet->sid];
				if (TDSSOCKET_VALID(s)) {
					/* append to correct session */
					if (packet->buf[0] == TDS72_SMP && packet->buf[1] != TDS_SMP_DATA)
						tds_packet_cache_add(conn, packet);
					else
						tds_append_packet(&conn->packets, packet);
					packet = NULL;
					/* notify */
					tds_cond_signal(&s->packet_cond);
				}
			}
			tds_mutex_unlock(&conn->list_mtx);
			tds_free_packets(packet);
			/* if we are receiving return the packet */
			if (!send) break;
		}
	}

	tds_mutex_lock(&conn->list_mtx);
	conn->in_net_tds = NULL;
}
예제 #11
0
파일: net.c 프로젝트: DmitrySigaev/ncbi
static int
tds_goodwrite(TDSSOCKET * tds, const unsigned char *buffer, int len, unsigned char last)
{
    double start, now;
	const unsigned char *p = buffer;
	int rc;

	assert(tds && buffer);

	if (TDS_IS_SOCKET_INVALID(tds->s))
		return -1;

	while (p - buffer < len) {
        start = GetTimeMark();
        now = start;
		if ((rc = tds_select(tds, TDSSELWRITE, tds->query_timeout, start)) > 0) {
			int err;
			size_t remaining = len - (p - buffer);
#ifdef USE_MSGMORE
			ssize_t nput = send(tds->s, p, remaining, last ? MSG_NOSIGNAL : MSG_NOSIGNAL|MSG_MORE);
			/* In case the kernel does not support MSG_MORE, try again without it */
			if (nput < 0 && errno == EINVAL && !last)
				nput = send(tds->s, p, remaining, MSG_NOSIGNAL);
#elif defined(__APPLE__) && defined(SO_NOSIGPIPE)
			ssize_t nput = send(tds->s, p, remaining, 0);
#else
			ssize_t nput = WRITESOCKET(tds->s, p, remaining);
#endif
			if (nput > 0) {
				p += nput;
				continue;
			}

			err = sock_errno;
            if (0 == nput || TDSSOCK_WOULDBLOCK(err) || err == TDSSOCK_EINTR)
				continue;

			assert(nput < 0);

			tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n",
                        err, strerror(err));
            tds_report_error(tds->tds_ctx, tds, err, 20017,
                             "Write to SQL Server failed");
			tds_close_socket(tds);
			return -1;

		} else if (rc < 0) {
			int err = sock_errno;
			if (TDSSOCK_WOULDBLOCK(err)) /* shouldn't happen, but OK, retry */
				continue;
			tdsdump_log(TDS_DBG_NETWORK, "select(2) failed: %d (%s)\n",
                        err, strerror(err));
            tds_report_error(tds->tds_ctx, tds, err, 20005,
                             "select/send finished with error");
			tds_close_socket(tds);
			return -1;
		} else { /* timeout */
            now = GetTimeMark();
            if (tds->query_timeout  &&  (now - start) >= tds->query_timeout) {
                tds_client_msg(tds->tds_ctx, tds, 20002, 6, 0, 0,
                               "Writing to SQL server exceeded timeout");
                tds_close_socket(tds);
                return -1;
            }

			tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n");
			switch (rc = tds_client_msg(tds->tds_ctx, tds, 20002, 6, 0, 0,
                                        "Writing to SQL server exceeded timeout")) {
			case TDS_INT_CONTINUE:
				continue;
			case TDS_INT_TIMEOUT:
				/* 
				 * "Cancel the operation ... but leave the dbproc in working condition." 
				 * We must try to send the cancel packet, else we have to abandon the dbproc.  
				 * If it can't be done, a harder error e.g. ECONNRESET will bubble up.  
				 */
				tds_send_cancel(tds);
				continue; 
			default:
			case TDS_INT_CANCEL:
				tds_close_socket(tds);
				return -1;
			}
			assert(0); /* not reached */
		}
		assert(0); /* not reached */
	}

#ifdef USE_CORK
	/* force packet flush */
	if (last) {
		int opt;
		opt = 0;
		setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
		opt = 1;
		setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt));
	}
#endif

	return len;
}
예제 #12
0
파일: net.c 프로젝트: DmitrySigaev/ncbi
/**
 * Read in one 'packet' from the server.  This is a wrapped outer packet of
 * the protocol (they bundle result packets into chunks and wrap them at
 * what appears to be 512 bytes regardless of how that breaks internal packet
 * up.   (tetherow\@nol.org)
 * @return bytes read or -1 on failure
 */
int
tds_read_packet(TDSSOCKET * tds)
{
	unsigned char header[8];
	int len;
	int x = 0, have, need;

	if (IS_TDSDEAD(tds)) {
		tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD");
		return -1;
	}

	/*
	 * Read in the packet header.  We use this to figure out our packet
	 * length
	 */

	/*
	 * Cast to int are needed because some compiler seem to convert
	 * len to unsigned (as FreeBSD 4.5 one)
	 */
	if ((len = goodread(tds, header, sizeof(header))) < (int) sizeof(header)) {
		/* GW ADDED */
		if (len < 0) {
			tds_client_msg(tds->tds_ctx, tds, 20004, 6, 0, 0, "Read from SQL server failed.");
			tds_close_socket(tds);
			tds->in_len = 0;
			tds->in_pos = 0;
			return -1;
		}

		/* GW ADDED */
		/*
		 * Not sure if this is the best way to do the error
		 * handling here but this is the way it is currently
		 * being done.
		 */

		tds->in_len = 0;
		tds->in_pos = 0;
		tds->last_packet = 1;
		if (tds->state != TDS_IDLE && len == 0) {
			tds_close_socket(tds);
		}
		return -1;
	}
	tdsdump_dump_buf(TDS_DBG_NETWORK, "Received header", header, sizeof(header));

#if 0
	/*
	 * Note:
	 * this was done by Gregg, I don't think its the real solution (it breaks
	 * under 5.0, but I haven't gotten a result big enough to test this yet.
 	 */
	if (IS_TDS42(tds)) {
		if (header[0] != 0x04 && header[0] != 0x0f) {
			tdsdump_log(TDS_DBG_ERROR, "Invalid packet header %d\n", header[0]);
			/*
			 * Not sure if this is the best way to do the error
			 * handling here but this is the way it is currently
			 * being done.
			 */
			tds->in_len = 0;
			tds->in_pos = 0;
			tds->last_packet = 1;
			return (-1);
		}
	}
#endif

	/* Convert our packet length from network to host byte order */
	len = ((((unsigned int) header[2]) << 8) | header[3]) - 8;
	need = len;

	/*
	 * If this packet size is the largest we have gotten allocate
	 * space for it
	 */
	if ((unsigned int)len > tds->in_buf_max) {
		unsigned char *p;

		if (!tds->in_buf) {
			p = (unsigned char *) malloc(len);
		} else {
			p = (unsigned char *) realloc(tds->in_buf, len);
		}
		if (!p)
			return -1;	/* FIXME should close socket too */
		tds->in_buf = p;
		/* Set the new maximum packet size */
		tds->in_buf_max = len;
	}

	/* Clean out the in_buf so we don't use old stuff by mistake */
	memset(tds->in_buf, 0, tds->in_buf_max);

	/* Now get exactly how many bytes the server told us to get */
	have = 0;
	while (need > 0) {
		if ((x = goodread(tds, tds->in_buf + have, need)) < 1) {
			/*
			 * Not sure if this is the best way to do the error
			 * handling here but this is the way it is currently
			 * being done.
			 */
			tds->in_len = 0;
			tds->in_pos = 0;
			tds->last_packet = 1;
			/* FIXME should this be "if (x == 0)" ? */
			if (len == 0) {
				tds_close_socket(tds);
			}
			return (-1);
		}
		have += x;
		need -= x;
	}
	if (x < 1) {
		/*
		 * Not sure if this is the best way to do the error handling
		 * here but this is the way it is currently being done.
		 */
		tds->in_len = 0;
		tds->in_pos = 0;
		tds->last_packet = 1;
		/* return 0 if header found but no payload */
		return len ? -1 : 0;
	}

	/* Set the last packet flag */
	if (header[1]) {
		tds->last_packet = 1;
	} else {
		tds->last_packet = 0;
	}

	/* set the received packet type flag */
	tds->in_flag = header[0];

	/* Set the length and pos (not sure what pos is used for now */
	tds->in_len = have;
	tds->in_pos = 0;
	tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len);

	return (tds->in_len);
}
예제 #13
0
파일: net.c 프로젝트: DmitrySigaev/ncbi
/**
 * Loops until we have received buflen characters
 * return -1 on failure
 */
static int
tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char unfinished)
{
	double start, global_start;
	int got = 0;
    int canceled = 0;

	if (buf == NULL || buflen < 1 || IS_TDSDEAD(tds))
		return 0;

	global_start = start = GetTimeMark();

	while (buflen > 0) {
		int len;
		double now;

		if (IS_TDSDEAD(tds))
			return -1;

        if ((len = tds_select(tds, TDSSELREAD, tds->query_timeout,
                              global_start)) > 0) {

			len = READSOCKET(tds->s, buf + got, buflen);

			if (len < 0 && TDSSOCK_WOULDBLOCK(sock_errno))
				continue;
			/* detect connection close */
			if (len <= 0) {
                tds_close_socket(tds);
                if (len == 0) {
                    tds_client_msg(tds->tds_ctx, tds, 20011, 6, 0, 0,
                                   "EOF in the socket.");
                } else {
                    tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                                     "recv finished with an error.");
                }
				return -1;
			}
		} else if (len < 0) {
			if (TDSSOCK_WOULDBLOCK(sock_errno)) /* shouldn't happen, but OK */
				continue;
            tds_close_socket(tds);
            tds_report_error(tds->tds_ctx, tds, sock_errno, 20012,
                             "recv finished with an error.");
			return -1;
		} else { /* timeout */
    		now = GetTimeMark();
            if (tds->query_timeout > 0 && now - start >= tds->query_timeout) {
    
                int timeout_action = TDS_INT_CONTINUE;
    
                if (canceled)
                    return got ? got : -1;
    
                if (tds->query_timeout_func && tds->query_timeout)
                    timeout_action = (*tds->query_timeout_func)
                        (tds->query_timeout_param, (int)(now - global_start));
    
                switch (timeout_action) {
                case TDS_INT_EXIT:
                    exit(EXIT_FAILURE);
                    break;
                case TDS_INT_CANCEL:
                    tds_send_cancel(tds);
                    canceled = 1;
                    /* fall through to wait while cancelling happens */
                case TDS_INT_CONTINUE:
                    start = now;
                default:
                    break;
                }
            }
		}

		buflen -= len;
		got += len;

		if (unfinished && got)
			return got;
	}
	return got;
}
예제 #14
0
파일: net.c 프로젝트: DmitrySigaev/ncbi
int
tds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout)
{
	struct sockaddr_in sin;
#if !defined(DOS32X)
	unsigned long ioctl_blocking = 1;
    time_t start;
	int retval;
#endif
	int len;
    int x_errno;
	char ip[20];

	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.\n", tds_inet_ntoa_r(sin.sin_addr, ip, sizeof(ip)), ntohs(sin.sin_port));

	if (TDS_IS_SOCKET_INVALID(tds->s = socket(AF_INET, SOCK_STREAM, 0))) {
        tds_report_error(tds->tds_ctx, tds, sock_errno, 20008, "Unable to open socket");
		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, "src/tds/login.c: tds_connect: %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)) >= 0) {
			perror(message);
			free(message);
		}
		tds_client_msg(tds->tds_ctx, tds, 20009, 9, 0, 0, "Server is unavailable or does not exist.");
		tds_free_socket(tds);
		return TDS_FAIL;
	}
#else
	/* Jeff's hack *** START OF NEW CODE *** */
	if (!timeout)
		/* I don't think anybody complains... */
		timeout = 90000;

	start = time(NULL);

	/* enable no-blocking mode */
	ioctl_blocking = 1;
	if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_blocking) < 0) {
		tds_close_socket(tds);
		return TDS_FAIL;
	}

	retval = connect(tds->s, (struct sockaddr *) &sin, sizeof(sin));
    x_errno = sock_errno;
	if (retval < 0 && x_errno == TDSSOCK_EINPROGRESS)
		retval = 0;
	/* if retval < 0 (error) fall through */

    if (tds_select(tds, TDSSELWRITE|TDSSELERR, timeout, (double)start) <= 0) {
		tds_close_socket(tds);
		tds_client_msg(tds->tds_ctx, tds, 20015, 6, 0, 0, "SQL Server connection timed out.");
		return TDS_FAIL;
	}
#endif
	/* END OF NEW CODE */

	if (retval < 0) {
        tds_report_error(tds->tds_ctx, tds, x_errno, 20009, "Server is unavailable or does not exist");
		tds_close_socket(tds);
		return TDS_FAIL;
	}

	return TDS_SUCCEED;
}