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

Generated by: LCOV version 1.13