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; }
/** * 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; }