|
NCBI C++ ToolKit
|
00001 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases 00002 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Brian Bruns 00003 * Copyright (C) 2004, 2005 Ziglio Frediano 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public 00016 * License along with this library; if not, write to the 00017 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 * Boston, MA 02111-1307, USA. 00019 */ 00020 00021 #if HAVE_CONFIG_H 00022 #include <config.h> 00023 #endif /* HAVE_CONFIG_H */ 00024 00025 #if TIME_WITH_SYS_TIME 00026 # if HAVE_SYS_TIME_H 00027 # include <sys/time.h> 00028 # endif 00029 # include <time.h> 00030 #else 00031 # if HAVE_SYS_TIME_H 00032 # include <sys/time.h> 00033 # else 00034 # include <time.h> 00035 # endif 00036 #endif 00037 00038 #ifdef NCBI_OS_MSWIN 00039 # include <windows.h> 00040 #endif 00041 00042 #if HAVE_SYS_TYPES_H 00043 #include <sys/types.h> 00044 #endif /* HAVE_SYS_TYPES_H */ 00045 00046 #if HAVE_ERRNO_H 00047 #include <errno.h> 00048 #endif /* HAVE_ERRNO_H */ 00049 00050 #include <stdio.h> 00051 00052 #if HAVE_UNISTD_H 00053 #include <unistd.h> 00054 #endif /* HAVE_UNISTD_H */ 00055 00056 #if HAVE_STDLIB_H 00057 #include <stdlib.h> 00058 #endif /* HAVE_STDLIB_H */ 00059 00060 #if HAVE_STRING_H 00061 #include <string.h> 00062 #endif /* HAVE_STRING_H */ 00063 00064 #if HAVE_SYS_SOCKET_H 00065 #include <sys/socket.h> 00066 #endif /* HAVE_SYS_SOCKET_H */ 00067 00068 #if HAVE_NETINET_IN_H 00069 #include <netinet/in.h> 00070 #endif /* HAVE_NETINET_IN_H */ 00071 00072 #if HAVE_NETINET_TCP_H 00073 #include <netinet/tcp.h> 00074 #endif /* HAVE_NETINET_TCP_H */ 00075 00076 #if HAVE_ARPA_INET_H 00077 #include <arpa/inet.h> 00078 #endif /* HAVE_ARPA_INET_H */ 00079 00080 #if HAVE_SYS_IOCTL_H 00081 #include <sys/ioctl.h> 00082 #endif /* HAVE_SYS_IOCTL_H */ 00083 00084 #if HAVE_SELECT_H 00085 #include <sys/select.h> 00086 #endif /* HAVE_SELECT_H */ 00087 00088 #include "tds.h" 00089 #include "tdsstring.h" 00090 #include "replacements.h" 00091 00092 #include <signal.h> 00093 #include <assert.h> 00094 00095 #ifdef NCBI_FTDS_ALLOW_TDS_80 00096 #ifdef HAVE_GNUTLS 00097 #include <gnutls/gnutls.h> 00098 #elif defined(HAVE_OPENSSL) 00099 #include <openssl/ssl.h> 00100 #endif 00101 #endif 00102 00103 #ifdef DMALLOC 00104 #include <dmalloc.h> 00105 #endif 00106 00107 TDS_RCSID(var, "$Id: net.c 53287 2012-03-06 18:21:30Z ivanovp $"); 00108 00109 /** 00110 * \addtogroup network 00111 * \@{ 00112 */ 00113 00114 #if !defined(SOL_TCP) && defined(IPPROTO_TCP) 00115 #define SOL_TCP IPPROTO_TCP 00116 #endif 00117 00118 /* Optimize the way we send packets */ 00119 #undef USE_MSGMORE 00120 #undef USE_CORK 00121 #undef USE_NODELAY 00122 /* On Linux 2.4.x we can use MSG_MORE */ 00123 #if defined(__linux__) && defined(MSG_MORE) 00124 #define USE_MSGMORE 1 00125 /* On early Linux use TCP_CORK if available */ 00126 #elif defined(__linux__) && defined(TCP_CORK) 00127 #define USE_CORK 1 00128 /* On *BSD try to use TCP_CORK */ 00129 /* 00130 * NOPUSH flag do not behave in the same way 00131 * cf ML "FreeBSD 5.0 performance problems with TCP_NOPUSH" 00132 */ 00133 #elif (defined(__FreeBSD__) || defined(__GNU_FreeBSD__) || defined(__OpenBSD__)) && defined(TCP_CORK) 00134 #define USE_CORK 1 00135 /* otherwise use NODELAY */ 00136 #elif defined(TCP_NODELAY) && defined(SOL_TCP) 00137 #define USE_NODELAY 1 00138 /* under VMS we have to define TCP_NODELAY */ 00139 #elif defined(__VMS) 00140 #define TCP_NODELAY 1 00141 #define USE_NODELAY 1 00142 #endif 00143 00144 00145 #define NCBI_INCLUDE_STRERROR_C 00146 #include "ncbi_strerror.c" 00147 00148 00149 static void 00150 tds_report_error(const TDSCONTEXT* tds_ctx, TDSSOCKET* tds, int x_errno, int msgno, const char* msg) 00151 { 00152 const char* str_err = s_StrError(x_errno); 00153 char err_msg[4096]; 00154 00155 snprintf(err_msg, sizeof(err_msg), "%s (%i, %s).", msg, x_errno, str_err); 00156 tds_client_msg(tds_ctx, tds, msgno, 6, 0, 0, err_msg); 00157 00158 UTIL_ReleaseBuffer(str_err); 00159 } 00160 00161 00162 int 00163 tds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout) 00164 { 00165 struct sockaddr_in sin; 00166 fd_set wfds, efds; 00167 #if !defined(DOS32X) 00168 unsigned long ioctl_blocking = 1; 00169 time_t start, now; 00170 struct timeval selecttimeout; 00171 int retval; 00172 #endif 00173 int len; 00174 int x_errno; 00175 char ip[20]; 00176 #if defined(DOS32X) || defined(WIN32) 00177 int optlen; 00178 #else 00179 socklen_t optlen; 00180 #endif 00181 00182 sin.sin_addr.s_addr = inet_addr(ip_addr); 00183 if (sin.sin_addr.s_addr == INADDR_NONE) { 00184 tdsdump_log(TDS_DBG_ERROR, "inet_addr() failed, IP = %s\n", ip_addr); 00185 return TDS_FAIL; 00186 } 00187 00188 sin.sin_family = AF_INET; 00189 sin.sin_port = htons(port); 00190 00191 tdsdump_log(TDS_DBG_INFO1, "Connecting to %s port %d.\n", tds_inet_ntoa_r(sin.sin_addr, ip, sizeof(ip)), ntohs(sin.sin_port)); 00192 00193 if (TDS_IS_SOCKET_INVALID(tds->s = socket(AF_INET, SOCK_STREAM, 0))) { 00194 tds_report_error(tds->tds_ctx, tds, sock_errno, 20008, "Unable to open socket"); 00195 return TDS_FAIL; 00196 } 00197 00198 #ifdef SO_KEEPALIVE 00199 len = 1; 00200 setsockopt(tds->s, SOL_SOCKET, SO_KEEPALIVE, (const void *) &len, sizeof(len)); 00201 #endif 00202 00203 len = 1; 00204 #if defined(USE_NODELAY) || defined(USE_MSGMORE) 00205 setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); 00206 #elif defined(USE_CORK) 00207 if (setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &len, sizeof(len)) < 0) 00208 setsockopt(tds->s, SOL_TCP, TCP_NODELAY, (const void *) &len, sizeof(len)); 00209 #else 00210 #error One should be defined 00211 #endif 00212 00213 #ifdef DOS32X /* the other connection doesn't work on WATTCP32 */ 00214 if (connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { 00215 char *message; 00216 00217 if (asprintf(&message, "src/tds/login.c: tds_connect: %s:%d", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)) >= 0) { 00218 perror(message); 00219 free(message); 00220 } 00221 tds_client_msg(tds->tds_ctx, tds, 20009, 9, 0, 0, "Server is unavailable or does not exist."); 00222 tds_free_socket(tds); 00223 return TDS_FAIL; 00224 } 00225 #else 00226 /* Jeff's hack *** START OF NEW CODE *** */ 00227 if (!timeout) 00228 /* I don't think anybody complains... */ 00229 timeout = 90000; 00230 00231 start = time(NULL); 00232 00233 /* enable no-blocking mode */ 00234 ioctl_blocking = 1; 00235 if (IOCTLSOCKET(tds->s, FIONBIO, &ioctl_blocking) < 0) { 00236 tds_close_socket(tds); 00237 return TDS_FAIL; 00238 } 00239 00240 retval = connect(tds->s, (struct sockaddr *) &sin, sizeof(sin)); 00241 x_errno = sock_errno; 00242 if (retval < 0 && x_errno == TDSSOCK_EINPROGRESS) 00243 retval = 0; 00244 /* if retval < 0 (error) fall through */ 00245 00246 /* Select on writeability for connect_timeout */ 00247 now = start; 00248 while ((retval == 0) && ((now - start) < timeout)) { 00249 FD_ZERO(&wfds); 00250 FD_SET(tds->s, &wfds); 00251 FD_ZERO(&efds); 00252 FD_SET(tds->s, &efds); 00253 selecttimeout.tv_sec = 1; 00254 selecttimeout.tv_usec = 0; 00255 retval = select(tds->s + 1, NULL, &wfds, &efds, &selecttimeout); 00256 x_errno = sock_errno; 00257 /* on interrupt ignore */ 00258 if (retval < 0 && x_errno == TDSSOCK_EINTR) 00259 retval = 0; 00260 now = time(NULL); 00261 } 00262 00263 if ((now - start) >= timeout) { 00264 tds_close_socket(tds); 00265 tds_client_msg(tds->tds_ctx, tds, 20015, 6, 0, 0, "SQL Server connection timed out."); 00266 return TDS_FAIL; 00267 } 00268 #endif 00269 /* END OF NEW CODE */ 00270 00271 /* check socket error */ 00272 if (retval > 0 && FD_ISSET(tds->s, &efds)) { 00273 optlen = sizeof(x_errno); 00274 if (getsockopt(tds->s, SOL_SOCKET, SO_ERROR, (char *) &x_errno, &optlen) != 0) { 00275 tds_report_error(tds->tds_ctx, tds, sock_errno, 20007, "Error in getsockopt"); 00276 tds_close_socket(tds); 00277 return TDS_FAIL; 00278 } 00279 retval = -1; 00280 } 00281 if (retval < 0) { 00282 tds_report_error(tds->tds_ctx, tds, x_errno, 20009, "Server is unavailable or does not exist"); 00283 tds_close_socket(tds); 00284 return TDS_FAIL; 00285 } 00286 00287 return TDS_SUCCEED; 00288 } 00289 00290 int 00291 tds_close_socket(TDSSOCKET * tds) 00292 { 00293 int rc = -1; 00294 00295 if (!IS_TDSDEAD(tds)) { 00296 rc = CLOSESOCKET(tds->s); 00297 tds->s = INVALID_SOCKET; 00298 tds_set_state(tds, TDS_DEAD); 00299 } 00300 return rc; 00301 } 00302 00303 /* Function from CStopWatch */ 00304 static double 00305 GetTimeMark(void) 00306 { 00307 #if defined(NCBI_OS_MSWIN) 00308 /* For Win32, we use QueryPerformanceCounter() */ 00309 00310 LARGE_INTEGER bigint; 00311 static double freq; 00312 static int first = 1; 00313 00314 if ( first ) { 00315 LARGE_INTEGER nfreq; 00316 QueryPerformanceFrequency(&nfreq); 00317 freq = (double)nfreq.QuadPart; 00318 first = 0; 00319 } 00320 00321 if ( !QueryPerformanceCounter(&bigint) ) { 00322 return 0.0; 00323 } 00324 return (double)bigint.QuadPart / freq; 00325 00326 #else 00327 /* For Unixes, we use gettimeofday() */ 00328 00329 struct timeval time; 00330 if ( gettimeofday (&time, 0) ) { 00331 return 0.0; 00332 } 00333 return (double)time.tv_sec + (double)time.tv_usec / 1e6; 00334 #endif 00335 } 00336 00337 /** 00338 * Loops until we have received buflen characters 00339 * return -1 on failure 00340 */ 00341 static int 00342 tds_goodread(TDSSOCKET * tds, unsigned char *buf, int buflen, unsigned char unfinished) 00343 { 00344 double start, global_start; 00345 int got = 0; 00346 fd_set rfds, efds; 00347 struct timeval tv; 00348 int canceled = 0; 00349 int retval, x_errno; 00350 #if defined(DOS32X) || defined(WIN32) 00351 int optlen; 00352 #else 00353 socklen_t optlen; 00354 #endif 00355 00356 if (buf == NULL || buflen < 1 || IS_TDSDEAD(tds)) 00357 return 0; 00358 00359 global_start = start = GetTimeMark(); 00360 00361 while (buflen > 0) { 00362 int len; 00363 double now; 00364 00365 if (IS_TDSDEAD(tds)) 00366 return -1; 00367 00368 FD_ZERO(&rfds); 00369 FD_SET(tds->s, &rfds); 00370 FD_ZERO(&efds); 00371 FD_SET(tds->s, &efds); 00372 00373 /* tv structure is modified inside select() on Linux, so we need to 00374 reinitialize it every time. */ 00375 tv.tv_usec = 0; 00376 tv.tv_sec = 1; 00377 00378 retval = select(tds->s + 1, &rfds, NULL, &efds, &tv); 00379 x_errno = sock_errno; 00380 len = 0; 00381 if (retval > 0) { 00382 if (FD_ISSET(tds->s, &efds)) { 00383 optlen = sizeof(x_errno); 00384 if (getsockopt(tds->s, SOL_SOCKET, SO_ERROR, (char *) &x_errno, &optlen) != 0) { 00385 tds_report_error(tds->tds_ctx, tds, sock_errno, 20016, "Error in getsockopt"); 00386 tds_close_socket(tds); 00387 return -1; 00388 } 00389 retval = -1; 00390 } 00391 else if (FD_ISSET(tds->s, &rfds)) { 00392 #ifndef MSG_NOSIGNAL 00393 retval = READSOCKET(tds->s, buf + got, buflen); 00394 #else 00395 retval = recv(tds->s, buf + got, buflen, MSG_NOSIGNAL); 00396 #endif 00397 /* detect connection close */ 00398 if (retval == 0) { 00399 tds_client_msg(tds->tds_ctx, tds, 20011, 6, 0, 0, "EOF in the socket."); 00400 tds_close_socket(tds); 00401 return -1; 00402 } 00403 len = retval; 00404 } 00405 } 00406 00407 if (retval < 0) { 00408 switch(x_errno) { 00409 case TDSSOCK_EINTR: 00410 case EAGAIN: 00411 case TDSSOCK_EINPROGRESS: 00412 break; 00413 default: 00414 tds_report_error(tds->tds_ctx, tds, x_errno, 20012, "select/recv finished with error"); 00415 return -1; 00416 } 00417 } 00418 00419 buflen -= len; 00420 got += len; 00421 00422 now = GetTimeMark(); 00423 if (tds->query_timeout > 0 && now - start >= tds->query_timeout) { 00424 00425 int timeout_action = TDS_INT_CONTINUE; 00426 00427 if (canceled) 00428 return got; 00429 00430 if (tds->query_timeout_func && tds->query_timeout) 00431 timeout_action = (*tds->query_timeout_func) (tds->query_timeout_param, (int)(now - global_start)); 00432 00433 switch (timeout_action) { 00434 case TDS_INT_EXIT: 00435 exit(EXIT_FAILURE); 00436 break; 00437 case TDS_INT_CANCEL: 00438 tds_send_cancel(tds); 00439 canceled = 1; 00440 /* fall through to wait while cancelling happens */ 00441 case TDS_INT_CONTINUE: 00442 start = now; 00443 default: 00444 break; 00445 } 00446 } 00447 00448 if (unfinished && got) 00449 return got; 00450 } 00451 return got; 00452 } 00453 00454 static int 00455 goodread(TDSSOCKET * tds, unsigned char *buf, int buflen) 00456 { 00457 #ifdef NCBI_FTDS_ALLOW_TDS_80 00458 #ifdef HAVE_GNUTLS 00459 if (tds->tls_session) 00460 return gnutls_record_recv(tds->tls_session, buf, buflen); 00461 #elif defined(HAVE_OPENSSL) 00462 if (tds->tls_session) 00463 return SSL_read((SSL*) tds->tls_session, buf, buflen); 00464 #endif 00465 #endif 00466 return tds_goodread(tds, buf, buflen, 0); 00467 } 00468 00469 /** 00470 * Read in one 'packet' from the server. This is a wrapped outer packet of 00471 * the protocol (they bundle result packets into chunks and wrap them at 00472 * what appears to be 512 bytes regardless of how that breaks internal packet 00473 * up. (tetherow\@nol.org) 00474 * @return bytes read or -1 on failure 00475 */ 00476 int 00477 tds_read_packet(TDSSOCKET * tds) 00478 { 00479 unsigned char header[8]; 00480 int len; 00481 int x = 0, have, need; 00482 00483 if (IS_TDSDEAD(tds)) { 00484 tdsdump_log(TDS_DBG_NETWORK, "Read attempt when state is TDS_DEAD"); 00485 return -1; 00486 } 00487 00488 /* 00489 * Read in the packet header. We use this to figure out our packet 00490 * length 00491 */ 00492 00493 /* 00494 * Cast to int are needed because some compiler seem to convert 00495 * len to unsigned (as FreeBSD 4.5 one) 00496 */ 00497 if ((len = goodread(tds, header, sizeof(header))) < (int) sizeof(header)) { 00498 /* GW ADDED */ 00499 if (len < 0) { 00500 tds_client_msg(tds->tds_ctx, tds, 20004, 6, 0, 0, "Read from SQL server failed."); 00501 tds_close_socket(tds); 00502 tds->in_len = 0; 00503 tds->in_pos = 0; 00504 return -1; 00505 } 00506 00507 /* GW ADDED */ 00508 /* 00509 * Not sure if this is the best way to do the error 00510 * handling here but this is the way it is currently 00511 * being done. 00512 */ 00513 00514 tds->in_len = 0; 00515 tds->in_pos = 0; 00516 tds->last_packet = 1; 00517 if (tds->state != TDS_IDLE && len == 0) { 00518 tds_close_socket(tds); 00519 } 00520 return -1; 00521 } 00522 tdsdump_dump_buf(TDS_DBG_NETWORK, "Received header", header, sizeof(header)); 00523 00524 #if 0 00525 /* 00526 * Note: 00527 * this was done by Gregg, I don't think its the real solution (it breaks 00528 * under 5.0, but I haven't gotten a result big enough to test this yet. 00529 */ 00530 if (IS_TDS42(tds)) { 00531 if (header[0] != 0x04 && header[0] != 0x0f) { 00532 tdsdump_log(TDS_DBG_ERROR, "Invalid packet header %d\n", header[0]); 00533 /* 00534 * Not sure if this is the best way to do the error 00535 * handling here but this is the way it is currently 00536 * being done. 00537 */ 00538 tds->in_len = 0; 00539 tds->in_pos = 0; 00540 tds->last_packet = 1; 00541 return (-1); 00542 } 00543 } 00544 #endif 00545 00546 /* Convert our packet length from network to host byte order */ 00547 len = ((((unsigned int) header[2]) << 8) | header[3]) - 8; 00548 need = len; 00549 00550 /* 00551 * If this packet size is the largest we have gotten allocate 00552 * space for it 00553 */ 00554 if ((unsigned int)len > tds->in_buf_max) { 00555 unsigned char *p; 00556 00557 if (!tds->in_buf) { 00558 p = (unsigned char *) malloc(len); 00559 } else { 00560 p = (unsigned char *) realloc(tds->in_buf, len); 00561 } 00562 if (!p) 00563 return -1; /* FIXME should close socket too */ 00564 tds->in_buf = p; 00565 /* Set the new maximum packet size */ 00566 tds->in_buf_max = len; 00567 } 00568 00569 /* Clean out the in_buf so we don't use old stuff by mistake */ 00570 memset(tds->in_buf, 0, tds->in_buf_max); 00571 00572 /* Now get exactly how many bytes the server told us to get */ 00573 have = 0; 00574 while (need > 0) { 00575 if ((x = goodread(tds, tds->in_buf + have, need)) < 1) { 00576 /* 00577 * Not sure if this is the best way to do the error 00578 * handling here but this is the way it is currently 00579 * being done. 00580 */ 00581 tds->in_len = 0; 00582 tds->in_pos = 0; 00583 tds->last_packet = 1; 00584 /* FIXME should this be "if (x == 0)" ? */ 00585 if (len == 0) { 00586 tds_close_socket(tds); 00587 } 00588 return (-1); 00589 } 00590 have += x; 00591 need -= x; 00592 } 00593 if (x < 1) { 00594 /* 00595 * Not sure if this is the best way to do the error handling 00596 * here but this is the way it is currently being done. 00597 */ 00598 tds->in_len = 0; 00599 tds->in_pos = 0; 00600 tds->last_packet = 1; 00601 /* return 0 if header found but no payload */ 00602 return len ? -1 : 0; 00603 } 00604 00605 /* Set the last packet flag */ 00606 if (header[1]) { 00607 tds->last_packet = 1; 00608 } else { 00609 tds->last_packet = 0; 00610 } 00611 00612 /* set the received packet type flag */ 00613 tds->in_flag = header[0]; 00614 00615 /* Set the length and pos (not sure what pos is used for now */ 00616 tds->in_len = have; 00617 tds->in_pos = 0; 00618 tdsdump_dump_buf(TDS_DBG_NETWORK, "Received packet", tds->in_buf, tds->in_len); 00619 00620 return (tds->in_len); 00621 } 00622 00623 /* goodwrite function adapted from patch by freddy77 */ 00624 static int 00625 tds_goodwrite(TDSSOCKET * tds, const unsigned char *p, int len, unsigned char last) 00626 { 00627 int retval = 0; 00628 double start, now; 00629 fd_set wfds, efds; 00630 struct timeval tv; 00631 int left = len; 00632 int x_errno; 00633 #if defined(DOS32X) || defined(WIN32) 00634 int optlen; 00635 #else 00636 socklen_t optlen; 00637 #endif 00638 00639 while (left > 0) { 00640 if (IS_TDSDEAD(tds)) 00641 return -1; 00642 00643 FD_ZERO(&wfds); 00644 FD_SET(tds->s, &wfds); 00645 FD_ZERO(&efds); 00646 FD_SET(tds->s, &efds); 00647 00648 /* tv structure is modified inside select() on Linux, so we need to 00649 reinitialize it every time. */ 00650 tv.tv_usec = 0; 00651 tv.tv_sec = 1; 00652 00653 start = GetTimeMark(); 00654 now = start; 00655 00656 retval = select(tds->s + 1, NULL, &wfds, &efds, &tv); 00657 x_errno = sock_errno; 00658 if (retval > 0) { 00659 if (FD_ISSET(tds->s, &efds)) { 00660 optlen = sizeof(x_errno); 00661 if (getsockopt(tds->s, SOL_SOCKET, SO_ERROR, (char *) &x_errno, &optlen) != 0) { 00662 tds_report_error(tds->tds_ctx, tds, sock_errno, 20001, "Error in getsockopt"); 00663 tds_close_socket(tds); 00664 return -1; 00665 } 00666 retval = -1; 00667 } 00668 else if (FD_ISSET(tds->s, &wfds)) { 00669 #ifdef USE_MSGMORE 00670 retval = send(tds->s, p, left, last ? MSG_NOSIGNAL : MSG_NOSIGNAL|MSG_MORE); 00671 #elif !defined(MSG_NOSIGNAL) 00672 retval = WRITESOCKET(tds->s, p, left); 00673 #else 00674 retval = send(tds->s, p, left, MSG_NOSIGNAL); 00675 #endif 00676 x_errno = sock_errno; 00677 /* detect connection close */ 00678 if (retval <= 0) { 00679 if (!retval || (x_errno != TDSSOCK_EINTR 00680 && x_errno != EAGAIN 00681 && x_errno != TDSSOCK_EINPROGRESS)) 00682 { 00683 tds_report_error(tds->tds_ctx, tds, x_errno, 20017, "Write to SQL Server failed"); 00684 tds->in_pos = 0; 00685 tds->in_len = 0; 00686 tds_close_socket(tds); 00687 return -1; 00688 } 00689 retval = 0; 00690 } 00691 } 00692 } 00693 00694 if (retval < 0) { 00695 switch(x_errno) { 00696 case TDSSOCK_EINTR: 00697 case EAGAIN: 00698 case TDSSOCK_EINPROGRESS: 00699 break; 00700 default: 00701 tds_report_error(tds->tds_ctx, tds, x_errno, 20005, "select/send finished with error"); 00702 return -1; 00703 } 00704 } 00705 00706 left -= retval; 00707 p += retval; 00708 00709 now = GetTimeMark(); 00710 if (tds->query_timeout && (now - start) >= tds->query_timeout) { 00711 tds_client_msg(tds->tds_ctx, tds, 20002, 6, 0, 0, "Writing to SQL server exceeded timeout"); 00712 tds_close_socket(tds); 00713 return -1; 00714 } 00715 } 00716 00717 #ifdef USE_CORK 00718 /* force packet flush */ 00719 if (last) { 00720 int opt; 00721 opt = 0; 00722 setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt)); 00723 opt = 1; 00724 setsockopt(tds->s, SOL_TCP, TCP_CORK, (const void *) &opt, sizeof(opt)); 00725 } 00726 #endif 00727 00728 return len; 00729 } 00730 00731 int 00732 tds_write_packet(TDSSOCKET * tds, unsigned char final) 00733 { 00734 int sent; 00735 unsigned int left = 0; 00736 00737 #if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) 00738 void (*oldsig) (int); 00739 #endif 00740 00741 #if TDS_ADDITIONAL_SPACE != 0 00742 if (tds->out_pos > tds->env.block_size) { 00743 left = tds->out_pos - tds->env.block_size; 00744 tds->out_pos = tds->env.block_size; 00745 } 00746 #endif 00747 00748 tds->out_buf[0] = tds->out_flag; 00749 tds->out_buf[1] = final; 00750 tds->out_buf[2] = (tds->out_pos) / 256u; 00751 tds->out_buf[3] = (tds->out_pos) % 256u; 00752 if (IS_TDS7_PLUS(tds) && !tds->connection) 00753 tds->out_buf[6] = 0x01; 00754 00755 tdsdump_dump_buf(TDS_DBG_NETWORK, "Sending packet", tds->out_buf, tds->out_pos); 00756 00757 #if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) 00758 oldsig = signal(SIGPIPE, SIG_IGN); 00759 if (oldsig == SIG_ERR) { 00760 tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't set SIGPIPE signal to be ignored\n"); 00761 } 00762 #endif 00763 00764 #ifdef NCBI_FTDS_ALLOW_TDS_80 00765 #ifdef HAVE_GNUTLS 00766 if (tds->tls_session) 00767 sent = gnutls_record_send(tds->tls_session, tds->out_buf, tds->out_pos); 00768 else 00769 #elif defined(HAVE_OPENSSL) 00770 if (tds->tls_session) 00771 sent = SSL_write((SSL*) tds->tls_session, tds->out_buf, tds->out_pos); 00772 else 00773 #endif 00774 #endif 00775 sent = tds_goodwrite(tds, tds->out_buf, tds->out_pos, final); 00776 00777 #if !defined(WIN32) && !defined(MSG_NOSIGNAL) && !defined(DOS32X) 00778 if (signal(SIGPIPE, oldsig) == SIG_ERR) { 00779 tdsdump_log(TDS_DBG_WARN, "TDS: Warning: Couldn't reset SIGPIPE signal to previous value\n"); 00780 } 00781 #endif 00782 00783 #if TDS_ADDITIONAL_SPACE != 0 00784 memcpy(tds->out_buf + 8, tds->out_buf + tds->env.block_size, left); 00785 #endif 00786 tds->out_pos = left + 8; 00787 00788 /* GW added in check for write() returning <0 and SIGPIPE checking */ 00789 return sent <= 0 ? TDS_FAIL : TDS_SUCCEED; 00790 } 00791 00792 /** 00793 * Get port of given instance 00794 * @return port number or 0 if error 00795 */ 00796 int 00797 tds7_get_instance_port(const char *ip_addr, const char *instance) 00798 { 00799 int num_try; 00800 struct sockaddr_in sin; 00801 unsigned long ioctl_blocking = 1; 00802 struct timeval selecttimeout; 00803 fd_set fds; 00804 int retval; 00805 TDS_SYS_SOCKET s; 00806 char msg[1024]; 00807 size_t msg_len; 00808 int port = 0; 00809 00810 sin.sin_addr.s_addr = inet_addr(ip_addr); 00811 if (sin.sin_addr.s_addr == INADDR_NONE) { 00812 tdsdump_log(TDS_DBG_ERROR, "inet_addr() failed, IP = %s\n", ip_addr); 00813 return 0; 00814 } 00815 00816 sin.sin_family = AF_INET; 00817 sin.sin_port = htons(1434); 00818 00819 /* create an UDP socket */ 00820 if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_DGRAM, 0))) { 00821 tdsdump_log(TDS_DBG_ERROR, "socket creation error: %s\n", strerror(sock_errno)); 00822 return 0; 00823 } 00824 00825 /* 00826 * on cluster environment is possible that reply packet came from 00827 * different IP so do not filter by ip with connect 00828 */ 00829 00830 ioctl_blocking = 1; 00831 if (IOCTLSOCKET(s, FIONBIO, &ioctl_blocking) < 0) { 00832 CLOSESOCKET(s); 00833 return 0; 00834 } 00835 00836 /* TODO is there a way to see if server reply with an ICMP (port not available) ?? */ 00837 00838 /* try to get port */ 00839 for (num_try = 0; num_try < 16; ++num_try) { 00840 /* request instance information */ 00841 msg[0] = 4; 00842 tds_strlcpy(msg + 1, instance, sizeof(msg) - 1); 00843 sendto(s, msg, strlen(msg) + 1, 0, (struct sockaddr *) &sin, sizeof(sin)); 00844 00845 FD_ZERO(&fds); 00846 FD_SET(s, &fds); 00847 selecttimeout.tv_sec = 1; 00848 selecttimeout.tv_usec = 0; 00849 retval = select(s + 1, &fds, NULL, NULL, &selecttimeout); 00850 tdsdump_log(TDS_DBG_INFO1, "select: retval %d err %d\n", retval, sock_errno); 00851 /* on interrupt ignore */ 00852 if (retval == 0 || (retval < 0 && sock_errno == TDSSOCK_EINTR)) 00853 continue; 00854 if (retval < 0) 00855 break; 00856 00857 /* TODO pass also connection and set instance/servername ?? */ 00858 00859 /* got data, read and parse */ 00860 if ((msg_len = recv(s, msg, sizeof(msg) - 1, 0)) > 3 && msg[0] == 5) { 00861 char *p; 00862 long l = 0; 00863 int instance_ok = 0, port_ok = 0; 00864 00865 /* assure null terminated */ 00866 msg[msg_len] = 0; 00867 tdsdump_dump_buf(TDS_DBG_INFO1, "instance info", msg, msg_len); 00868 00869 /* 00870 * parse message and check instance name and port 00871 * we don't check servername cause it can be very 00872 * different from client one 00873 */ 00874 p = msg + 3; 00875 for (;;) { 00876 char *name, *value; 00877 00878 name = p; 00879 p = strchr(p, ';'); 00880 if (!p) 00881 break; 00882 *p++ = 0; 00883 00884 value = p; 00885 p = strchr(p, ';'); 00886 if (!p) 00887 break; 00888 *p++ = 0; 00889 00890 if (strcasecmp(name, "InstanceName") == 0) { 00891 if (strcasecmp(value, instance) != 0) 00892 break; 00893 instance_ok = 1; 00894 } else if (strcasecmp(name, "tcp") == 0) { 00895 l = strtol(value, &p, 10); 00896 if (l > 0 && l <= 0xffff && *p == 0) 00897 port_ok = 1; 00898 } 00899 } 00900 if (port_ok && instance_ok) { 00901 port = l; 00902 break; 00903 } 00904 } 00905 } 00906 CLOSESOCKET(s); 00907 return port; 00908 } 00909 00910 #ifdef NCBI_FTDS_ALLOW_TDS_80 00911 #if defined(HAVE_GNUTLS) || defined(HAVE_OPENSSL) 00912 00913 #ifdef HAVE_GNUTLS 00914 static ssize_t 00915 tds_pull_func(gnutls_transport_ptr ptr, void* data, size_t len) 00916 { 00917 TDSSOCKET *tds = (TDSSOCKET *) ptr; 00918 #else 00919 static int 00920 tds_ssl_read(BIO *b, char* data, int len) 00921 { 00922 TDSSOCKET *tds = (TDSSOCKET *) b->ptr; 00923 #endif 00924 00925 int have; 00926 00927 tdsdump_log(TDS_DBG_INFO1, "in tds_pull_func\n"); 00928 00929 /* if we have some data send it */ 00930 if (tds->out_pos > 8) 00931 tds_flush_packet(tds); 00932 00933 if (tds->tls_session) { 00934 /* read directly from socket */ 00935 return tds_goodread(tds, data, len, 1); 00936 } 00937 00938 for(;;) { 00939 have = tds->in_len - tds->in_pos; 00940 tdsdump_log(TDS_DBG_INFO1, "have %d\n", have); 00941 assert(have >= 0); 00942 if (have > 0) 00943 break; 00944 tdsdump_log(TDS_DBG_INFO1, "before read\n"); 00945 if (tds_read_packet(tds) < 0) 00946 return -1; 00947 tdsdump_log(TDS_DBG_INFO1, "after read\n"); 00948 } 00949 if (len > have) 00950 len = have; 00951 tdsdump_log(TDS_DBG_INFO1, "read %d bytes\n", len); 00952 memcpy(data, tds->in_buf + tds->in_pos, len); 00953 tds->in_pos += len; 00954 return len; 00955 } 00956 00957 #ifdef HAVE_GNUTLS 00958 static ssize_t 00959 tds_push_func(gnutls_transport_ptr ptr, const void* data, size_t len) 00960 { 00961 TDSSOCKET *tds = (TDSSOCKET *) ptr; 00962 #else 00963 static int 00964 tds_ssl_write(BIO *b, const char* data, int len) 00965 { 00966 TDSSOCKET *tds = (TDSSOCKET *) b->ptr; 00967 #endif 00968 tdsdump_log(TDS_DBG_INFO1, "in tds_push_func\n"); 00969 00970 if (tds->tls_session) { 00971 /* write to socket directly */ 00972 return tds_goodwrite(tds, data, len, 1); 00973 } 00974 tds_put_n(tds, data, len); 00975 return len; 00976 } 00977 00978 #ifdef HAVE_GNUTLS 00979 00980 static void 00981 tds_tls_log( int level, const char* s) 00982 { 00983 tdsdump_log(TDS_DBG_INFO1, "GNUTLS: level %d:\n %s", level, s); 00984 } 00985 00986 static int tls_initialized = 0; 00987 00988 #ifdef TDS_ATTRIBUTE_DESTRUCTOR 00989 static void __attribute__((destructor)) 00990 tds_tls_deinit(void) 00991 { 00992 if (tls_initialized) 00993 gnutls_global_deinit(); 00994 } 00995 #endif 00996 00997 int 00998 tds_ssl_init(TDSSOCKET *tds) 00999 { 01000 gnutls_session session; 01001 gnutls_certificate_credentials xcred; 01002 01003 static const int kx_priority[] = { 01004 GNUTLS_KX_RSA_EXPORT, 01005 GNUTLS_KX_RSA, GNUTLS_KX_DHE_DSS, GNUTLS_KX_DHE_RSA, 01006 0 01007 }; 01008 static const int cipher_priority[] = { 01009 GNUTLS_CIPHER_AES_256_CBC, GNUTLS_CIPHER_AES_128_CBC, 01010 GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR_128, 01011 #if 0 01012 GNUTLS_CIPHER_ARCFOUR_40, 01013 GNUTLS_CIPHER_DES_CBC, 01014 #endif 01015 0 01016 }; 01017 static const int comp_priority[] = { GNUTLS_COMP_NULL, 0 }; 01018 static const int mac_priority[] = { 01019 GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 01020 }; 01021 int ret; 01022 const char *tls_msg; 01023 01024 xcred = NULL; 01025 session = NULL; 01026 tls_msg = "initializing tls"; 01027 01028 /* FIXME place somewhere else, deinit at end */ 01029 ret = 0; 01030 if (!tls_initialized) 01031 ret = gnutls_global_init(); 01032 if (ret == 0) { 01033 tls_initialized = 1; 01034 01035 gnutls_global_set_log_level(11); 01036 gnutls_global_set_log_function(tds_tls_log); 01037 tls_msg = "allocating credentials"; 01038 ret = gnutls_certificate_allocate_credentials(&xcred); 01039 } 01040 01041 if (ret == 0) { 01042 /* Initialize TLS session */ 01043 tls_msg = "initializing session"; 01044 ret = gnutls_init(&session, GNUTLS_CLIENT); 01045 } 01046 01047 if (ret == 0) { 01048 gnutls_transport_set_ptr(session, tds); 01049 gnutls_transport_set_pull_function(session, tds_pull_func); 01050 gnutls_transport_set_push_function(session, tds_push_func); 01051 01052 /* NOTE: there functions return int however they cannot fail */ 01053 01054 /* use default priorities... */ 01055 gnutls_set_default_priority(session); 01056 01057 /* ... but overwrite some */ 01058 gnutls_cipher_set_priority(session, cipher_priority); 01059 gnutls_compression_set_priority(session, comp_priority); 01060 gnutls_kx_set_priority(session, kx_priority); 01061 gnutls_mac_set_priority(session, mac_priority); 01062 01063 /* put the anonymous credentials to the current session */ 01064 tls_msg = "setting credential"; 01065 ret = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); 01066 } 01067 01068 if (ret == 0) { 01069 /* Perform the TLS handshake */ 01070 tls_msg = "handshake"; 01071 ret = gnutls_handshake (session); 01072 } 01073 01074 if (ret != 0) { 01075 if (session) 01076 gnutls_deinit(session); 01077 if (xcred) 01078 gnutls_certificate_free_credentials(xcred); 01079 tdsdump_log(TDS_DBG_ERROR, "%s failed: %s\n", tls_msg, gnutls_strerror (ret)); 01080 return TDS_FAIL; 01081 } 01082 01083 tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n"); 01084 tds->tls_session = session; 01085 tds->tls_credentials = xcred; 01086 01087 return TDS_SUCCEED; 01088 } 01089 01090 void 01091 tds_ssl_deinit(TDSSOCKET *tds) 01092 { 01093 if (tds->tls_session) { 01094 gnutls_deinit(tds->tls_session); 01095 tds->tls_session = NULL; 01096 } 01097 if (tds->tls_credentials) { 01098 gnutls_certificate_free_credentials(tds->tls_credentials); 01099 tds->tls_credentials = NULL; 01100 } 01101 } 01102 01103 #else 01104 static long 01105 tds_ssl_ctrl(BIO *b, int cmd, long num, void *ptr) 01106 { 01107 TDSSOCKET *tds = (TDSSOCKET *) b->ptr; 01108 01109 switch (cmd) { 01110 case BIO_CTRL_FLUSH: 01111 if (tds->out_pos > 8) 01112 tds_flush_packet(tds); 01113 return 1; 01114 } 01115 return 0; 01116 } 01117 01118 static int 01119 tds_ssl_free(BIO *a) 01120 { 01121 /* nothing to do but required */ 01122 return 1; 01123 } 01124 01125 static BIO_METHOD tds_method = 01126 { 01127 BIO_TYPE_MEM, 01128 "tds", 01129 tds_ssl_write, 01130 tds_ssl_read, 01131 NULL, 01132 NULL, 01133 tds_ssl_ctrl, 01134 NULL, 01135 tds_ssl_free, 01136 NULL, 01137 }; 01138 01139 static SSL_CTX *ssl_ctx; 01140 01141 static int 01142 tds_init_openssl(void) 01143 { 01144 SSL_METHOD *meth; 01145 01146 SSL_library_init (); 01147 meth = TLSv1_client_method (); 01148 if (meth == NULL) 01149 return 1; 01150 ssl_ctx = SSL_CTX_new (meth); 01151 if (ssl_ctx == NULL) 01152 return 1; 01153 return 0; 01154 } 01155 01156 #ifdef TDS_ATTRIBUTE_DESTRUCTOR 01157 static void __attribute__((destructor)) 01158 tds_tls_deinit(void) 01159 { 01160 if (ssl_ctx) 01161 SSL_CTX_free (ssl_ctx); 01162 } 01163 #endif 01164 01165 int 01166 tds_ssl_init(TDSSOCKET *tds) 01167 { 01168 #define OPENSSL_CIPHERS \ 01169 SSL3_TXT_RSA_DES_64_CBC_SHA " " \ 01170 TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA " " \ 01171 TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA " " \ 01172 SSL3_TXT_RSA_RC4_40_MD5 " " \ 01173 SSL3_TXT_RSA_RC2_40_MD5 " " \ 01174 SSL3_TXT_EDH_DSS_DES_64_CBC_SHA " " \ 01175 TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 01176 01177 SSL *con; 01178 BIO *b; 01179 01180 int ret; 01181 const char *tls_msg; 01182 01183 con = NULL; 01184 b = NULL; 01185 tls_msg = "initializing tls"; 01186 01187 /* FIXME place somewhere else, deinit at end */ 01188 ret = 0; 01189 if (!ssl_ctx) 01190 ret = tds_init_openssl(); 01191 01192 if (ret == 0) { 01193 /* Initialize TLS session */ 01194 tls_msg = "initializing session"; 01195 con = SSL_new(ssl_ctx); 01196 } 01197 01198 if (con) { 01199 tls_msg = "creating bio"; 01200 b = BIO_new(&tds_method); 01201 } 01202 01203 ret = 0; 01204 if (b) { 01205 b->shutdown=1; 01206 b->init=1; 01207 b->num= -1; 01208 b->ptr = tds; 01209 SSL_set_bio(con, b, b); 01210 01211 /* use priorities... */ 01212 SSL_set_cipher_list(con, OPENSSL_CIPHERS); 01213 01214 /* Perform the TLS handshake */ 01215 tls_msg = "handshake"; 01216 SSL_set_connect_state(con); 01217 ret = SSL_connect(con) != 1 || con->state != SSL_ST_OK; 01218 } 01219 01220 if (ret != 0) { 01221 if (con) { 01222 SSL_shutdown(con); 01223 SSL_free(con); 01224 } 01225 tdsdump_log(TDS_DBG_ERROR, "%s failed\n", tls_msg); 01226 return TDS_FAIL; 01227 } 01228 01229 tdsdump_log(TDS_DBG_INFO1, "handshake succeeded!!\n"); 01230 tds->tls_session = con; 01231 tds->tls_credentials = NULL; 01232 01233 return TDS_SUCCEED; 01234 } 01235 01236 void 01237 tds_ssl_deinit(TDSSOCKET *tds) 01238 { 01239 if (tds->tls_session) { 01240 /* NOTE do not call SSL_shutdown here */ 01241 SSL_free(tds->tls_session); 01242 tds->tls_session = NULL; 01243 } 01244 } 01245 #endif 01246 01247 #endif 01248 #endif 01249 /** \@} */ 01250
1.7.5.1
Modified on Wed May 23 12:54:55 2012 by modify_doxy.py rev. 337098