static void write_all(TDS_SYS_SOCKET s, const void *buf, size_t len) { int res, l; fd_set fds_write; for (; len > 0;) { FD_ZERO(&fds_write); FD_SET(s, &fds_write); res = select(s + 1, NULL, &fds_write, NULL, NULL); if (res <= 0) { if (errno == EINTR) continue; perror("select"); exit(1); } l = WRITESOCKET(s, buf, len); if (l <= 0) { perror("write socket"); exit(1); } buf = ((const char *) buf) + l; len -= l; } }
void pool_event_add(TDS_POOL *pool, TDS_POOL_EVENT *ev, TDS_POOL_EXECUTE execute) { tds_mutex_lock(&pool->events_mtx); ev->execute = execute; ev->next = pool->events; pool->events = ev; tds_mutex_unlock(&pool->events_mtx); WRITESOCKET(pool->event_fd, "x", 1); }
/* write data to a nonblocking socket Inputs: <fd> socket <buf> point to the data <len> length of data Returns: < 0 on failure otherwise the number of bytes written */ int tcp_nonblocking_write(int fd, char *buf, int len, void *dummy) { int n; (void) dummy; n = WRITESOCKET (fd, buf, len); if (n == -1) { if (NET_ERRNO != EWOULDBLOCK && NET_ERRNO != ENOBUFS) return -1; n = 0; } return n; }
int pool_write_all(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); /* write failed, cleanup member */ if (ret <= 0) { return ret; } p += ret; len -= ret; } return 1; }
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; }
/** * 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; }
/* * pool_process_members * check the fd_set for members returning data to the client, lookup the * client holding this member and forward the results. */ int pool_process_members(TDS_POOL * pool, fd_set * fds) { TDS_POOL_MEMBER *pmbr; TDS_POOL_USER *puser; TDSSOCKET *tds; int i, age, ret; int cnt = 0; unsigned char *buf; time_t time_now; for (i = 0; i < pool->num_members; i++) { pmbr = (TDS_POOL_MEMBER *) & pool->members[i]; if (!pmbr->tds) break; /* dead connection */ tds = pmbr->tds; time_now = time(NULL); if (FD_ISSET(tds->s, fds)) { pmbr->last_used_tm = time_now; cnt++; /* tds->in_len = read(tds->s, tds->in_buf, BLOCKSIZ); */ if (pool_packet_read(pmbr)) continue; if (tds->in_len == 0) { fprintf(stderr, "Uh oh! member %d disconnected\n", i); /* mark as dead */ pool_free_member(pmbr); } else if (tds->in_len == -1) { fprintf(stderr, "Uh oh! member %d disconnected\n", i); perror("read"); pool_free_member(pmbr); } else { /* fprintf(stderr, "read %d bytes from member %d\n", tds->in_len, i); */ if (pmbr->current_user) { puser = pmbr->current_user; buf = tds->in_buf; /* * check the netlib final packet flag * instead of looking for done tokens. * It's more efficient and generic to * all protocol versions. -- bsb * 2004-12-12 */ if (buf[1]) { /* if (pool_find_end_token(pmbr, buf + 8, tds->in_len - 8)) { */ /* we are done...deallocate member */ fprintf(stdout, "deassigning user from member %d\n",i); pool_deassign_member(pmbr); pmbr->state = TDS_IDLE; puser->user_state = TDS_SRV_IDLE; } /* cf. net.c for better technique. */ ret = WRITESOCKET(puser->tds->s, buf, tds->in_len); if (ret < 0) { /* couldn't write, ditch the user */ fprintf(stdout, "member %d received error while writing\n",i); pool_free_user(pmbr->current_user); pool_deassign_member(pmbr); pool_reset_member(pmbr); } } } } age = time_now - pmbr->last_used_tm; if (age > pool->max_member_age && i >= pool->min_open_conn) { fprintf(stderr, "member %d is %d seconds old...closing\n", i, age); pool_free_member(pmbr); } } return cnt; }
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; }