LCOV - code coverage report
Current view: top level - src/odbc/unittests - freeclose.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 149 193 77.2 %
Date: 2025-01-18 12:13:41 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #if HAVE_UNISTD_H
       4             : #include <unistd.h>
       5             : #endif /* HAVE_UNISTD_H */
       6             : 
       7             : #include <freetds/time.h>
       8             : 
       9             : #if HAVE_ERRNO_H
      10             : #include <errno.h>
      11             : #endif /* HAVE_ERRNO_H */
      12             : 
      13             : #if HAVE_SYS_SOCKET_H
      14             : #include <sys/socket.h>
      15             : #endif /* HAVE_SYS_SOCKET_H */
      16             : 
      17             : #if HAVE_SYS_STAT_H
      18             : #include <sys/stat.h>
      19             : #endif /* HAVE_SYS_STAT_H */
      20             : 
      21             : #if HAVE_SYS_IOCTL_H
      22             : #include <sys/ioctl.h>
      23             : #endif /* HAVE_SYS_IOCTL_H */
      24             : 
      25             : #if HAVE_SYS_WAIT_H
      26             : #include <sys/wait.h>
      27             : #endif /* HAVE_SYS_WAIT_H */
      28             : 
      29             : #if HAVE_NETINET_IN_H
      30             : #include <netinet/in.h>
      31             : #endif /* HAVE_NETINET_IN_H */
      32             : 
      33             : #if (!defined(TDS_NO_THREADSAFE) && HAVE_ALARM && HAVE_FSTAT && defined(S_IFSOCK)) || defined(_WIN32)
      34             : 
      35             : #include <ctype.h>
      36             : 
      37             : #include <freetds/tds.h>
      38             : #include <freetds/thread.h>
      39             : 
      40             : /* this crazy test tests that we do not send too much prepare ... */
      41             : 
      42             : static tds_mutex mtx;
      43             : 
      44             : typedef union {
      45             :         struct sockaddr sa;
      46             :         struct sockaddr_in sin;
      47             :         char dummy[256];
      48             : } long_sockaddr;
      49             : 
      50             : static long_sockaddr remote_addr;
      51             : static socklen_t remote_addr_len;
      52             : 
      53             : static TDS_SYS_SOCKET fake_sock;
      54             : 
      55             : static tds_thread fake_thread;
      56             : #ifdef _WIN32
      57             : #define alarm(n) do { ; } while(0)
      58             : #endif
      59             : static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg);
      60             : 
      61             : static int
      62          11 : init_fake_server(int ip_port)
      63             : {
      64             :         struct sockaddr_in sin;
      65             :         TDS_SYS_SOCKET s;
      66             : 
      67          11 :         memset(&sin, 0, sizeof(sin));
      68          11 :         sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
      69          11 :         sin.sin_port = htons((short) ip_port);
      70          11 :         sin.sin_family = AF_INET;
      71             : 
      72          11 :         if (TDS_IS_SOCKET_INVALID(s = socket(AF_INET, SOCK_STREAM, 0))) {
      73           0 :                 perror("socket");
      74           0 :                 exit(1);
      75             :         }
      76          11 :         if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
      77           3 :                 perror("bind");
      78           3 :                 CLOSESOCKET(s);
      79           3 :                 return 1;
      80             :         }
      81           8 :         if (listen(s, 5) < 0) {
      82           0 :                 perror("listen");
      83           0 :                 CLOSESOCKET(s);
      84           0 :                 return 1;
      85             :         }
      86          16 :         if (tds_thread_create(&fake_thread, fake_thread_proc, TDS_INT2PTR(s)) != 0) {
      87           0 :                 perror("tds_thread_create");
      88           0 :                 exit(1);
      89             :         }
      90             :         return 0;
      91             : }
      92             : 
      93             : static void
      94         569 : write_all(TDS_SYS_SOCKET s, const void *buf, size_t len)
      95             : {
      96             :         int res, l;
      97             :         fd_set fds_write;
      98             : 
      99        1707 :         for (; len > 0;) {
     100         569 :                 FD_ZERO(&fds_write);
     101         569 :                 FD_SET(s, &fds_write);
     102             : 
     103         569 :                 res = select(s + 1, NULL, &fds_write, NULL, NULL);
     104         569 :                 if (res <= 0) {
     105           0 :                         if (errno == EINTR)
     106           0 :                                 continue;
     107           0 :                         perror("select");
     108           0 :                         exit(1);
     109             :                 }
     110             : 
     111         569 :                 l = WRITESOCKET(s, buf, len);
     112         569 :                 if (l <= 0) {
     113           0 :                         perror("write socket");
     114           0 :                         exit(1);
     115             :                 }
     116         569 :                 buf = ((const char *) buf) + l;
     117         569 :                 len -= l;
     118             :         }
     119         569 : }
     120             : 
     121             : static unsigned int inserts = 0;
     122             : static char insert_buf[256] = "";
     123             : 
     124             : static void
     125         301 : count_insert(const char* buf, size_t len)
     126             : {
     127             :         static const char search[] = "insert into";
     128             :         static unsigned char prev = 'x';
     129             :         char *p;
     130             :         unsigned char c;
     131             :         size_t insert_len;
     132             : 
     133             :         /* add to buffer */
     134       24124 :         for (p = strchr(insert_buf, 0); len > 0; --len, ++buf) {
     135       23823 :                 c = (unsigned char) buf[0];
     136       23823 :                 if (prev == 0 || c != 0)
     137       20822 :                         *p++ = (c >= ' ' && c < 128) ? tolower(c) : '_';
     138       23823 :                 prev = c;
     139             :         }
     140         301 :         *p = 0;
     141             : 
     142             :         /* check it */
     143         608 :         while ((p=strstr(insert_buf, search)) != NULL) {
     144           6 :                 tds_mutex_lock(&mtx);
     145           6 :                 ++inserts;
     146           6 :                 tds_mutex_unlock(&mtx);
     147             :                 /* do not find again */
     148           6 :                 p[0] = '_';
     149             :         }
     150             : 
     151             :         /* avoid buffer too long */
     152         301 :         insert_len = strlen(insert_buf);
     153         301 :         if (insert_len > sizeof(search)) {
     154         301 :                 p = insert_buf + insert_len - sizeof(search);
     155         301 :                 memmove(insert_buf, p, strlen(p) + 1);
     156             :         }
     157         301 : }
     158             : 
     159             : static unsigned int round_trips = 0;
     160             : static enum { sending, receiving } flow = sending;
     161             : 
     162           8 : static TDS_THREAD_PROC_DECLARE(fake_thread_proc, arg)
     163             : {
     164           8 :         TDS_SYS_SOCKET s = TDS_PTR2INT(arg), server_sock;
     165             :         socklen_t sock_len;
     166             :         int len;
     167             :         char buf[128];
     168             :         struct sockaddr_in sin;
     169             :         fd_set fds_read, fds_write, fds_error;
     170           8 :         TDS_SYS_SOCKET max_fd = 0;
     171             : 
     172           8 :         memset(&sin, 0, sizeof(sin));
     173           8 :         sock_len = sizeof(sin);
     174           8 :         alarm(30);
     175           8 :         fprintf(stderr, "waiting connect...\n");
     176           8 :         if ((fake_sock = tds_accept(s, (struct sockaddr *) &sin, &sock_len)) < 0) {
     177           0 :                 perror("accept");
     178           0 :                 exit(1);
     179             :         }
     180           8 :         CLOSESOCKET(s);
     181             : 
     182           8 :         if (TDS_IS_SOCKET_INVALID(server_sock = socket(remote_addr.sa.sa_family, SOCK_STREAM, 0))) {
     183           0 :                 perror("socket");
     184           0 :                 exit(1);
     185             :         }
     186             : 
     187           8 :         fprintf(stderr, "connecting to server...\n");
     188           8 :         if (remote_addr.sa.sa_family == AF_INET) {
     189           8 :                 fprintf(stderr, "connecting to %x:%d\n", (unsigned int) remote_addr.sin.sin_addr.s_addr,
     190           8 :                         ntohs(remote_addr.sin.sin_port));
     191             :         }
     192           8 :         if (connect(server_sock, &remote_addr.sa, remote_addr_len)) {
     193           0 :                 perror("connect");
     194           0 :                 exit(1);
     195             :         }
     196           8 :         alarm(0);
     197             : 
     198           8 :         if (fake_sock > max_fd) max_fd = fake_sock;
     199           8 :         if (server_sock > max_fd) max_fd = server_sock;
     200             : 
     201             :         for (;;) {
     202             :                 int res;
     203             : 
     204         577 :                 FD_ZERO(&fds_read);
     205         577 :                 FD_SET(fake_sock, &fds_read);
     206         577 :                 FD_SET(server_sock, &fds_read);
     207             : 
     208         577 :                 FD_ZERO(&fds_write);
     209             : 
     210         577 :                 FD_ZERO(&fds_error);
     211         577 :                 FD_SET(fake_sock, &fds_error);
     212         577 :                 FD_SET(server_sock, &fds_error);
     213             : 
     214         577 :                 alarm(30);
     215         577 :                 res = select(max_fd + 1, &fds_read, &fds_write, &fds_error, NULL);
     216         577 :                 alarm(0);
     217         577 :                 if (res < 0) {
     218           0 :                         if (sock_errno == TDSSOCK_EINTR)
     219           0 :                                 continue;
     220           0 :                         perror("select");
     221           0 :                         exit(1);
     222             :                 }
     223             : 
     224         577 :                 if (FD_ISSET(fake_sock, &fds_error) || FD_ISSET(server_sock, &fds_error)) {
     225           0 :                         fprintf(stderr, "error in select\n");
     226           0 :                         exit(1);
     227             :                 }
     228             : 
     229             :                 /* just read and forward */
     230         577 :                 if (FD_ISSET(fake_sock, &fds_read)) {
     231         307 :                         if (flow != sending) {
     232         218 :                                 tds_mutex_lock(&mtx);
     233         218 :                                 ++round_trips;
     234         218 :                                 tds_mutex_unlock(&mtx);
     235             :                         }
     236         307 :                         flow = sending;
     237             : 
     238         307 :                         len = READSOCKET(fake_sock, buf, sizeof(buf));
     239         307 :                         if (len == 0) {
     240           6 :                                 fprintf(stderr, "client connection closed\n");
     241           6 :                                 break;
     242             :                         }
     243         301 :                         if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS) {
     244           0 :                                 fprintf(stderr, "read client error %d\n", sock_errno);
     245           0 :                                 break;
     246             :                         }
     247         301 :                         count_insert(buf, len);
     248         301 :                         write_all(server_sock, buf, len);
     249             :                 }
     250             : 
     251         571 :                 if (FD_ISSET(server_sock, &fds_read)) {
     252         270 :                         if (flow != receiving) {
     253         220 :                                 tds_mutex_lock(&mtx);
     254         220 :                                 ++round_trips;
     255         220 :                                 tds_mutex_unlock(&mtx);
     256             :                         }
     257         270 :                         flow = receiving;
     258             : 
     259         270 :                         len = READSOCKET(server_sock, buf, sizeof(buf));
     260         270 :                         if (len == 0) {
     261           2 :                                 fprintf(stderr, "server connection closed\n");
     262           2 :                                 break;
     263             :                         }
     264         268 :                         if (len < 0 && sock_errno != TDSSOCK_EINPROGRESS) {
     265           0 :                                 fprintf(stderr, "read server error %d\n", sock_errno);
     266           0 :                                 break;
     267             :                         }
     268         268 :                         write_all(fake_sock, buf, len);
     269             :                 }
     270             :         }
     271           8 :         CLOSESOCKET(fake_sock);
     272           8 :         CLOSESOCKET(server_sock);
     273           8 :         return TDS_THREAD_RESULT(0);
     274             : }
     275             : 
     276             : int
     277           8 : main(int argc, char **argv)
     278             : {
     279           8 :         SQLLEN sql_nts = SQL_NTS;
     280             :         const char *query;
     281           8 :         SQLINTEGER id = 0;
     282             :         char string[64];
     283             :         TDS_SYS_SOCKET last_socket;
     284             :         int port;
     285           8 :         const int num_inserts = 20;
     286             :         int is_freetds;
     287             : 
     288             : #ifdef _WIN32
     289             :         WSADATA wsaData;
     290             :         WSAStartup(MAKEWORD(2, 2), &wsaData);
     291             : #endif
     292             : 
     293           8 :         if (tds_mutex_init(&mtx))
     294             :                 return 1;
     295             : 
     296           8 :         odbc_mark_sockets_opened();
     297             : 
     298           8 :         odbc_connect();
     299             : 
     300             :         /*
     301             :          * this does not work if server is not connected with socket
     302             :          * (ie ms driver connected locally)
     303             :          */
     304           8 :         last_socket = odbc_find_last_socket();
     305           8 :         if (TDS_IS_SOCKET_INVALID(last_socket)) {
     306           0 :                 fprintf(stderr, "Error finding last socket opened\n");
     307           0 :                 return 1;
     308             :         }
     309             : 
     310           8 :         remote_addr_len = sizeof(remote_addr);
     311           8 :         if (tds_getpeername(last_socket, &remote_addr.sa, &remote_addr_len)) {
     312           0 :                 fprintf(stderr, "Unable to get remote address %d\n", sock_errno);
     313           0 :                 return 1;
     314             :         }
     315             : 
     316           8 :         is_freetds = odbc_driver_is_freetds();
     317           8 :         odbc_disconnect();
     318             : 
     319             :         /* init fake server, behave like a proxy */
     320          11 :         for (port = 12340; port < 12350; ++port)
     321          11 :                 if (!init_fake_server(port))
     322             :                         break;
     323           8 :         if (port == 12350) {
     324           0 :                 fprintf(stderr, "Cannot bind to a port\n");
     325           0 :                 return 1;
     326             :         }
     327           8 :         printf("Fake server bound at port %d\n", port);
     328             : 
     329             :         /* override connections */
     330           8 :         if (is_freetds) {
     331           8 :                 setenv("TDSHOST", "127.0.0.1", 1);
     332           8 :                 sprintf(string, "%d", port);
     333           8 :                 setenv("TDSPORT", string, 1);
     334             : 
     335           8 :                 odbc_connect();
     336             :         } else {
     337             :                 char tmp[2048];
     338             :                 SQLSMALLINT len;
     339             : 
     340           0 :                 CHKAllocEnv(&odbc_env, "S");
     341           0 :                 CHKAllocConnect(&odbc_conn, "S");
     342           0 :                 sprintf(tmp, "DRIVER={SQL Server};SERVER=127.0.0.1,%d;UID=%s;PWD=%s;DATABASE=%s;Network=DBMSSOCN;", port, odbc_user, odbc_password, odbc_database);
     343           0 :                 printf("connection string: %s\n", tmp);
     344           0 :                 CHKDriverConnect(NULL, T(tmp), SQL_NTS, (SQLTCHAR *) tmp, sizeof(tmp)/sizeof(SQLTCHAR), &len, SQL_DRIVER_NOPROMPT, "SI");
     345           0 :                 CHKAllocStmt(&odbc_stmt, "S");
     346             :         }
     347             : 
     348             :         /* real test */
     349           8 :         odbc_command("CREATE TABLE #test(i int, c varchar(40))");
     350             : 
     351           8 :         odbc_reset_statement();
     352             : 
     353             :         /* do not take into account connection statistics */
     354           8 :         tds_mutex_lock(&mtx);
     355           8 :         round_trips = 0;
     356           8 :         inserts = 0;
     357           8 :         tds_mutex_unlock(&mtx);
     358             : 
     359           8 :         query = "insert into #test values (?, ?)";
     360             : 
     361           8 :         CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
     362           8 :         CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");
     363             : 
     364           8 :         CHKPrepare(T(query), SQL_NTS, "SI");
     365           8 :         tds_mutex_lock(&mtx);
     366           8 :         printf("%u round trips %u inserts\n", round_trips, inserts);
     367           8 :         tds_mutex_unlock(&mtx);
     368             : 
     369         168 :         for (id = 0; id < num_inserts; id++) {
     370         160 :                 sprintf(string, "This is a test (%d)", (int) id);
     371         160 :                 CHKExecute("SI");
     372         160 :                 CHKFreeStmt(SQL_CLOSE, "S");
     373             :         }
     374             : 
     375           8 :         tds_mutex_lock(&mtx);
     376           8 :         printf("%u round trips %u inserts\n", round_trips, inserts);
     377           8 :         tds_mutex_unlock(&mtx);
     378           8 :         odbc_reset_statement();
     379             : 
     380           8 :         tds_mutex_lock(&mtx);
     381           8 :         if (inserts > 1 || round_trips > (unsigned) (num_inserts * 2 + 6)) {
     382           0 :                 fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
     383           0 :                 tds_mutex_unlock(&mtx);
     384           0 :                 return 1;
     385             :         }
     386           8 :         printf("%u round trips %u inserts\n", round_trips, inserts);
     387           8 :         tds_mutex_unlock(&mtx);
     388             : 
     389             : #ifdef ENABLE_DEVELOPING
     390             :         /* check for SQL_RESET_PARAMS */
     391             :         tds_mutex_lock(&mtx);
     392             :         round_trips = 0;
     393             :         inserts = 0;
     394             :         tds_mutex_unlock(&mtx);
     395             : 
     396             :         CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
     397             :         CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");
     398             : 
     399             :         CHKPrepare((SQLCHAR *) query, SQL_NTS, "SI");
     400             :         tds_mutex_lock(&mtx);
     401             :         printf("%u round trips %u inserts\n", round_trips, inserts);
     402             :         tds_mutex_unlock(&mtx);
     403             : 
     404             :         for (id = 0; id < num_inserts; id++) {
     405             :                 CHKBindParameter(1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, sizeof(id), 0, &id, 0, &sql_nts, "SI");
     406             :                 CHKBindParameter(2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(string), 0, string, 0, &sql_nts, "SI");
     407             : 
     408             :                 sprintf(string, "This is a test (%d)", (int) id);
     409             :                 CHKExecute("SI");
     410             :                 CHKFreeStmt(SQL_RESET_PARAMS, "S");
     411             :         }
     412             : 
     413             :         tds_mutex_lock(&mtx);
     414             :         printf("%u round trips %u inserts\n", round_trips, inserts);
     415             :         tds_mutex_unlock(&mtx);
     416             :         odbc_reset_statement();
     417             : 
     418             :         tds_mutex_lock(&mtx);
     419             :         if (inserts > 1 || round_trips > num_inserts * 2 + 6) {
     420             :                 fprintf(stderr, "Too much round trips (%u) or insert (%u) !!!\n", round_trips, inserts);
     421             :                 tds_mutex_unlock(&mtx);
     422             :                 return 1;
     423             :         }
     424             :         printf("%u round trips %u inserts\n", round_trips, inserts);
     425             :         tds_mutex_unlock(&mtx);
     426             : #endif
     427             : 
     428           8 :         odbc_disconnect();
     429             : 
     430           8 :         alarm(10);
     431          16 :         tds_thread_join(fake_thread, NULL);
     432             : 
     433           8 :         return 0;
     434             : }
     435             : 
     436             : #else
     437             : int
     438             : main(void)
     439             : {
     440             :         printf("Not possible for this platform.\n");
     441             :         odbc_test_skipped();
     442             :         return 0;
     443             : }
     444             : #endif
     445             : 

Generated by: LCOV version 1.13