예제 #1
0
파일: net.c 프로젝트: jujubha/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;
}
예제 #2
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;
		}
	}
}
예제 #3
0
파일: util.c 프로젝트: DoubleQuantZ/freetds
int
pool_write(TDS_SYS_SOCKET sock, const void *buf, size_t len)
{
	int ret;
	const unsigned char *p = (const unsigned char *) buf;

	while (len) {
		ret = WRITESOCKET(sock, p, len);
		if (ret <= 0) {
			int err = errno;
			if (TDSSOCK_WOULDBLOCK(err) || err == EINTR)
				break;
			return -1;
		}
		p   += ret;
		len -= ret;
	}
	return p - (const unsigned char *) buf;
}
예제 #4
0
파일: net.c 프로젝트: alex-fang/freetds
/**
 * Write to an OS socket
 * @returns 0 if blocking, <0 error >0 bytes readed
 */
static int
tds_socket_write(TDSCONNECTION *conn, TDSSOCKET *tds, const unsigned char *buf, int buflen)
{
	int err, len;
	char *errstr;

#if ENABLE_EXTRA_CHECKS
	/* this simulate the fact that send can return less bytes */
	if (buflen >= 5) {
		static int cnt = 0;
		if (++cnt == 5) {
			cnt = 0;
			buflen -= 3;
		}
	}
#endif

#if defined(__APPLE__) && defined(SO_NOSIGPIPE)
	len = send(conn->s, buf, buflen, 0);
#else
	len = WRITESOCKET(conn->s, buf, buflen);
#endif
	if (len > 0)
		return len;

	err = sock_errno;
	if (0 == len || TDSSOCK_WOULDBLOCK(err))
		return 0;

	assert(len < 0);

	/* detect connection close */
	errstr = sock_strerror(err);
	tdsdump_log(TDS_DBG_NETWORK, "send(2) failed: %d (%s)\n", err, errstr);
	sock_strerror_free(errstr);
	tds_connection_close(conn);
	tdserror(conn->tds_ctx, tds, TDSEWRIT, err);
	return -1;
}
예제 #5
0
파일: util.c 프로젝트: alex-fang/freetds
bool
pool_packet_read(TDSSOCKET *tds)
{
	int packet_len;
	int readed, err;

	tdsdump_log(TDS_DBG_INFO1, "tds in_len %d in_pos %d\n", tds->in_len, tds->in_pos);

	/* determine how much we should read */
	packet_len = 8;
	if (tds->in_len >= 4)
		packet_len = TDS_GET_A2BE(&tds->in_buf[2]);

	if (tds->in_len >= packet_len) {
		tds->in_pos = 0;
		tds->in_len = 0;
		packet_len = 8;
	}
	tdsdump_log(TDS_DBG_INFO1, "packet_len %d capacity %d\n", packet_len, tds->recv_packet->capacity);
	assert(packet_len > tds->in_len);
	assert(packet_len <= tds->recv_packet->capacity);
	assert(tds->in_len < tds->recv_packet->capacity);

	readed = read(tds_get_s(tds), &tds->in_buf[tds->in_len], packet_len - tds->in_len);
	tdsdump_log(TDS_DBG_INFO1, "readed %d\n", readed);
	if (readed == 0) {
		/* socket closed */
		tds->in_len = 0;
		return false;
	}
	if (readed < 0) {
		/* error */
		err = sock_errno;
		if (err == EINTR || TDSSOCK_WOULDBLOCK(err))
			return true;
		goto failure;
	}
	tds->in_len += readed;
	if (tds->in_len >= 4) {
		packet_len = TDS_GET_A2BE(&tds->in_buf[2]);
		if (packet_len < 8)
			goto failure;
		tdsdump_log(TDS_DBG_INFO1, "packet_len %d in_len %d after\n", packet_len, tds->in_len);
		/* resize packet if not enough */
		if (packet_len > tds->recv_packet->capacity) {
			TDSPACKET *packet;

			packet = tds_realloc_packet(tds->recv_packet, packet_len);
			if (!packet)
				goto failure;
			tds->in_buf = packet->buf;
			tds->recv_packet = packet;
		}
		CHECK_TDS_EXTRA(tds);
		return tds->in_len < packet_len;
	}
	return true;

failure:
	tds->in_len = -1;
	return false;
}
예제 #6
0
파일: util.c 프로젝트: DoubleQuantZ/freetds
/**
 * Read part of packet. Function does not block.
 * @return true if packet is not complete and we must call again,
 *         false on full packet or error.
 */
bool
pool_packet_read(TDSSOCKET *tds)
{
	int packet_len;
	int readed, err;

	tdsdump_log(TDS_DBG_INFO1, "tds in_len %d in_pos %d\n", tds->in_len, tds->in_pos);

	// TODO MARS

	/* determine packet size */
	packet_len = tds->in_len >= 4 ? TDS_GET_A2BE(&tds->in_buf[2]) : 8;
	if (TDS_UNLIKELY(packet_len < 8)) {
		tds->in_len = 0;
		return false;
	}

	/* get another packet */
	if (tds->in_len >= packet_len) {
		tds->in_pos = 0;
		tds->in_len = 0;
	}

	for (;;) {
		/* determine packet size */
		packet_len = 8;
		if (tds->in_len >= 4) {
			packet_len = TDS_GET_A2BE(&tds->in_buf[2]);
			if (packet_len < 8)
				break;
			tdsdump_log(TDS_DBG_INFO1, "packet_len %d in_len %d\n", packet_len, tds->in_len);
			/* resize packet if not enough */
			if (packet_len > tds->recv_packet->capacity) {
				TDSPACKET *packet;

				packet = tds_realloc_packet(tds->recv_packet, packet_len);
				if (!packet)
					break;
				tds->in_buf = packet->buf;
				tds->recv_packet = packet;
			}
			CHECK_TDS_EXTRA(tds);
			if (tds->in_len >= packet_len)
				return false;
		}

		assert(packet_len > tds->in_len);
		assert(packet_len <= tds->recv_packet->capacity);
		assert(tds->in_len < tds->recv_packet->capacity);

		readed = read(tds_get_s(tds), &tds->in_buf[tds->in_len], packet_len - tds->in_len);
		tdsdump_log(TDS_DBG_INFO1, "readed %d\n", readed);

		/* socket closed */
		if (readed == 0)
			break;

		/* error */
		if (readed < 0) {
			err = sock_errno;
			if (err == EINTR)
				continue;
			if (TDSSOCK_WOULDBLOCK(err))
				return true;
			break;
		}

		/* got some data */
		tds->in_len += readed;
	}

	/* failure */
	tds->in_len = 0;
	return false;
}
예제 #7
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;
}
예제 #8
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;
}