Exemple #1
0
int aocSendQueuePacket(aocConnection *aoc, aocPacket *p, int sent)
{
	aocSendQueue *q;

	aoc->send_queue_size += p->len - sent;
	if(aoc->send_queue_max > 0 &&
		aoc->send_queue_size > aoc->send_queue_max)
	{
		set_sock_errno(0);
		return 0;
	}

	q = malloc(sizeof(aocSendQueue));
	if(q == NULL)
		return 0;

	if(aoc->send_queue == NULL)
	{
		aoc->send_queue = q;
		aoc->send_queue_last = q;
	}
	else
	{
		aoc->send_queue_last->next = q;
		aoc->send_queue_last = q;
	}

	q->next = NULL;
	q->len = p->len;
	q->packet = p->data;
	q->sent = sent;

	MAYBE_DEBUG
		aocDebugMsg("Queue packet: length %d, sent %d, queuesize %d, max %d.",
			q->len, q->sent, aoc->send_queue_size, aoc->send_queue_max);

	return 1;
}
Exemple #2
0
/**
 * 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.   
 */
int
tds_select(TDSSOCKET * tds, unsigned tds_sel, int timeout_seconds)
{
	int rc, seconds;
	unsigned int poll_seconds;

	assert(tds != NULL);
	assert(timeout_seconds >= 0);

	/* 
	 * 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_get_ctx(tds) && tds_get_ctx(tds)->int_handler)? 1 : timeout_seconds;
	for (seconds = timeout_seconds; timeout_seconds == 0 || seconds > 0; seconds -= poll_seconds) {
		struct pollfd fds[2];
		int timeout = poll_seconds ? poll_seconds * 1000 : -1;

		if (TDS_IS_SOCKET_INVALID(tds_get_s(tds)))
			return -1;

		if ((tds_sel & TDSSELREAD) != 0 && tds->conn->tls_session && tds_ssl_pending(tds->conn))
			return POLLIN;

		fds[0].fd = tds_get_s(tds);
		fds[0].events = tds_sel;
		fds[0].revents = 0;
		fds[1].fd = tds_wakeup_get_fd(&tds->conn->wakeup);
		fds[1].events = POLLIN;
		fds[1].revents = 0;
		rc = poll(fds, 2, timeout);

		if (rc > 0 ) {
			if (fds[0].revents & POLLERR) {
				set_sock_errno(TDSSOCK_ECONNRESET);
				return -1;
			}
			rc = fds[0].revents;
			if (fds[1].revents) {
#if ENABLE_ODBC_MARS
				tds_check_cancel(tds->conn);
#endif
				rc |= TDSPOLLURG;
			}
			return rc;
		}

		if (rc < 0) {
			char *errstr;

			switch (sock_errno) {
			case TDSSOCK_EINTR:
				/* FIXME this should be global maximun, not loop one */
				seconds += poll_seconds;
				break;	/* let interrupt handler be called */
			default: /* documented: EFAULT, EBADF, EINVAL */
				errstr = sock_strerror(sock_errno);
				tdsdump_log(TDS_DBG_ERROR, "error: poll(2) returned %d, \"%s\"\n",
						sock_errno, errstr);
				sock_strerror_free(errstr);
				return rc;
			}
		}

		assert(rc == 0 || (rc < 0 && sock_errno == TDSSOCK_EINTR));

		if (tds_get_ctx(tds) && tds_get_ctx(tds)->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_get_ctx(tds)->int_handler) (tds_get_parent(tds));
			switch (timeout_action) {
			case TDS_INT_CONTINUE:		/* keep waiting */
				continue;
			case TDS_INT_CANCEL:		/* abort the current command batch */
							/* FIXME tell tds_goodread() not to call tdserror() */
				return 0;
			default:
				tdsdump_log(TDS_DBG_NETWORK, 
					"tds_select: invalid interupt handler return code: %d\n", timeout_action);
				return -1;
			}
		}
		/* 
		 * We can reach here if no interrupt handler was installed and we either timed out or got EINTR. 
		 * We cannot be polling, so we are about to drop out of the loop. 
		 */
		assert(poll_seconds == timeout_seconds);
	}
	
	return 0;
}