📄 net.c
字号:
tdsdump_log(TDS_DBG_ERROR, "tds_ctx->int_handler returned %d\n", timeout_action);#endif 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); exit(EXIT_FAILURE); break; } } /* * 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;}/** * Loops until we have received buflen characters * return -1 on failure * This function does not close the socket. Maybe it should. */static inttds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char unfinished){ int rc, got = 0; if (buf == NULL || buflen < 1 || tds == NULL) return 0; for (;;) { int len; if (IS_TDSDEAD(tds)) return -1; if ((len = tds_select(tds, TDSSELREAD, tds->query_timeout)) > 0) {#ifndef MSG_NOSIGNAL len = READSOCKET(tds->s, buf + got, buflen);#else len = recv(tds->s, buf + got, buflen, MSG_NOSIGNAL);#endif if (len < 0 && sock_errno == EAGAIN) continue; /* detect connection close */ if (len <= 0) { tdserror(tds->tds_ctx, tds, len == 0 ? TDSESEOF : TDSEREAD, sock_errno); tds_close_socket(tds); return -1; } } else if (len < 0) { if (sock_errno == EAGAIN) /* shouldn't happen, but OK */ continue; tdserror(tds->tds_ctx, tds, TDSEREAD, sock_errno); tds_close_socket(tds); return -1; } else { /* timeout */ switch (rc = tdserror(tds->tds_ctx, tds, TDSETIME, sock_errno)) { case TDS_INT_CONTINUE: continue; case TDS_INT_TIMEOUT: tds_send_cancel(tds); continue; /* fixme: or return? */ default: case TDS_INT_CANCEL: tds_close_socket(tds); return -1; } assert(0); /* not reached */ } got += len; buflen -= len; /* doing test here reduce number of syscalls required */ if (buflen <= 0) break; if (unfinished && got) break; } return got;}static intgoodread(TDSSOCKET * tds, unsigned char *buf, int buflen){#ifdef HAVE_GNUTLS if (tds->tls_session) return gnutls_record_recv(tds->tls_session, buf, buflen);#elif defined(HAVE_OPENSSL) if (tds->tls_session) return SSL_read((SSL*) tds->tls_session, buf, buflen);#endif return tds_goodread(tds, buf, buflen, 0);}/** * 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 */inttds_read_packet(TDSSOCKET * tds){ unsigned char header[8]; int len, have; 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) { /* not needed because goodread() already called: tdserror(tds->tds_ctx, tds, TDSEREAD, 0); */ 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; /* * If this packet size is the largest we have gotten allocate space for it */ if (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) { tds_close_socket(tds); return -1; } 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 (have < len) { int nbytes = goodread(tds, tds->in_buf + have, len - have); if (nbytes < 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. */ /* no need to call tdserror(), because goodread() already did */ tds->in_len = 0; tds->in_pos = 0; tds->last_packet = 1; tds_close_socket(tds); return -1; } have += nbytes; } /* Set the last packet flag */ tds->last_packet = (header[1] != 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);}/** * \param tds the famous socket * \param p pointer to buffer * \param len bytes in buffer * \param last 1 if this is the last packet, else 0 * \return len on success, <0 on failure */static inttds_goodwrite(TDSSOCKET * tds, const unsigned char *p, int len, unsigned char last){ int remaining = len; int nput, rc, err=0; /* Fix of SIGSEGV when FD_SET() called with negative fd (Sergey A. Cherukhin, 23/09/2005) */ if (TDS_IS_SOCKET_INVALID(tds->s)) return -1; while (remaining > 0) { if ((rc = tds_select(tds, TDSSELWRITE, tds->query_timeout)) > 0) {#ifdef USE_MSGMORE 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(MSG_NOSIGNAL) nput = WRITESOCKET(tds->s, p, remaining);#else nput = send(tds->s, p, remaining, MSG_NOSIGNAL);#endif if (nput < 0 && sock_errno == EAGAIN) continue; /* detect connection close */ if (nput <= 0) { tdserror(tds->tds_ctx, tds, nput == 0 ? TDSESEOF : TDSEWRIT, sock_errno); tds_close_socket(tds); return -1; } } else if (rc < 0) { if (sock_errno == EAGAIN) /* shouldn't happen, but OK, retry */ continue; tdsdump_log(TDS_DBG_NETWORK, "TDS: Write failed in tds_write_packet\nError: %d (%s)\n", err, strerror(err)); tdserror(tds->tds_ctx, tds, TDSEWRIT, sock_errno); tds_close_socket(tds); return -1; } else { /* timeout */ tdsdump_log(TDS_DBG_NETWORK, "tds_goodwrite(): timed out, asking client\n"); switch (rc = tdserror(tds->tds_ctx, tds, TDSETIME, sock_errno)) { case TDS_INT_CONTINUE: continue; case TDS_INT_TIMEOUT: /* FIXME we are not able to send a packet and we want to send a packet ?? */ tds_send_cancel(tds); continue; /* fixme: or return? */ default: case TDS_INT_CANCEL: tds_close_socket(tds); return -1; } assert(0); /* not reached */ } p += nput; remaining -= nput; }#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;}inttds_write_packet(TDSSOCKET * tds, unsigned char final){ int sent; unsigned int left = 0;#if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) void (*oldsig) (int);#endif#if TDS_ADDITIONAL_SPACE != 0 if (tds->out_pos > tds->env.block_size) { left = tds->out_pos - tds->env.block_size; tds->out_pos = tds->env.block_size; }#endif tds->out_buf[0] = tds->out_flag; tds->out_buf[1] = final; tds->out_buf[2] = (tds->out_pos) / 256u; tds->out_buf[3] = (tds->out_pos) % 256u; if (IS_TDS7_PLUS(tds) && !tds->connection) tds->out_buf[6] = 0x01; tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", tds->out_buf, tds->out_pos);#if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) oldsig = signal(SIGPIPE, SIG_IGN); if (oldsig == SIG_ERR) { tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't set SIGPIPE signal to be ignored\n"); }#endif#ifdef HAVE_GNUTLS if (tds->tls_session) sent = gnutls_record_send(tds->tls_session, tds->out_buf, tds->out_pos); else#elif defined(HAVE_OPENSSL) if (tds->tls_session) sent = SSL_write((SSL*) tds->tls_session, tds->out_buf, tds->out_pos); else#endif sent = tds_goodwrite(tds, tds->out_buf, tds->out_pos, final);#if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) if (signal(SIGPIPE, oldsig) == SIG_ERR) { tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't reset SIGPIPE signal to previous value\n"); }#endif#if TDS_ADDITIONAL_SPACE != 0 memcpy(tds->out_buf + 8, tds->out_buf + tds->env.block_size, left);#endif tds->out_pos = left + 8; /* GW added in check for write() returning <0 and SIGPIPE checking */ return sent <= 0 ? TDS_FAIL : TDS_SUCCEED;}/** * Get port of given instance * @return port number or 0 if error */inttds7_get_instance_port(const char *ip_addr, const char *instance){ int num_try; struct sockaddr_in sin; ioctl_nonblocking_t ioctl_nonblocking;#if USE_POLL struct pollfd fd;#else struct timeval selecttimeout; fd_set fds;#endif int retval; TDS_SYS_SOCKET s; char msg[1024]; size_t msg_len; int port = 0; tdsdump_log(TDS_DBG_ERROR, "tds7_get_instance_port(%s, %s)\n", ip_addr, instance); 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 0; } sin.sin_family = AF_INET; sin.sin_port = htons(1434); /* create an UDP socket */ if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_DGRAM, 0))) { tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", strerror(sock_errno)); return 0; }#if !USE_POLL#if !defined(WIN32) && defined(FD_SETSIZE) if (s >= FD_SETSIZE) { sock_errno = EINVAL; return 0; }#endif#endif /* * on cluster environment is possible that reply packet came from * different IP so do not filter by ip with connect */ ioctl_nonblocking = 1; if (IOCTLSOCKET(s, FIONBIO, &ioctl_nonblocking) < 0) { CLOSESOCKET(s); return 0; } /* * Request the instance's port from the server. * There is no easy way to detect if port is closed so we always try to * get a reply from server 16 times. */ for (num_try = 0; num_try < 16; ++num_try) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -