LCOV - code coverage report
Current view: top level - src/pool - member.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 225 284 79.2 %
Date: 2025-04-15 09:57:00 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /* TDSPool - Connection pooling for TDS based databases
       2             :  * Copyright (C) 2001, 2002, 2003, 2004, 2005  Brian Bruns
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation; either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program; if not, write to the Free Software
      16             :  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             :  *
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : 
      22             : #include <stdarg.h>
      23             : #include <stdio.h>
      24             : #include <assert.h>
      25             : 
      26             : #if HAVE_STDLIB_H
      27             : #include <stdlib.h>
      28             : #endif /* HAVE_STDLIB_H */
      29             : 
      30             : #if HAVE_STRING_H
      31             : #include <string.h>
      32             : #endif /* HAVE_STRING_H */
      33             : 
      34             : #if HAVE_UNISTD_H
      35             : #include <unistd.h>
      36             : #endif /* HAVE_UNISTD_H */
      37             : 
      38             : #if HAVE_SYS_PARAM_H
      39             : #include <sys/param.h>
      40             : #endif /* HAVE_SYS_PARAM_H */
      41             : 
      42             : #if HAVE_SYS_SOCKET_H
      43             : #include <sys/socket.h>
      44             : #endif /* HAVE_SYS_SOCKET_H */
      45             : 
      46             : #if HAVE_NETINET_IN_H
      47             : #include <netinet/in.h>
      48             : #endif /* HAVE_NETINET_IN_H */
      49             : 
      50             : #if HAVE_ARPA_INET_H
      51             : #include <arpa/inet.h>
      52             : #endif /* HAVE_ARPA_INET_H */
      53             : 
      54             : #include "pool.h"
      55             : #include <freetds/utils/string.h>
      56             : 
      57             : #ifndef MAXHOSTNAMELEN
      58             : #define MAXHOSTNAMELEN 256
      59             : #endif /* MAXHOSTNAMELEN */
      60             : 
      61             : static void
      62          24 : pool_mbr_free_socket(TDSSOCKET *tds)
      63             : {
      64          24 :         if (tds) {
      65          24 :                 TDSCONTEXT *ctx = (TDSCONTEXT *) tds->conn->tds_ctx;
      66             : 
      67          24 :                 tds_free_socket(tds);
      68          24 :                 tds_free_context(ctx);
      69             :         }
      70          24 : }
      71             : 
      72             : /*
      73             :  * pool_mbr_login open a single pool login, to be call at init time or
      74             :  * to reconnect.
      75             :  */
      76             : static TDSSOCKET *
      77          24 : pool_mbr_login(const TDS_POOL * pool, int tds_version)
      78             : {
      79             :         TDSCONTEXT *context;
      80             :         TDSLOGIN *login;
      81             :         TDSSOCKET *tds;
      82             :         TDSLOGIN *connection;
      83             :         char hostname[MAXHOSTNAMELEN];
      84             : 
      85          24 :         login = tds_alloc_login(true);
      86          24 :         if (!login) {
      87           0 :                 fprintf(stderr, "out of memory");
      88           0 :                 return NULL;
      89             :         }
      90          24 :         if (gethostname(hostname, MAXHOSTNAMELEN) < 0)
      91           0 :                 strlcpy(hostname, "tdspool", MAXHOSTNAMELEN);
      92          24 :         if (!tds_set_passwd(login, pool->server_password)
      93          24 :             || !tds_set_user(login, pool->server_user)
      94          24 :             || !tds_set_app(login, "tdspool")
      95          24 :             || !tds_set_host(login, hostname)
      96          24 :             || !tds_set_library(login, "TDS-Library")
      97          24 :             || !tds_set_server(login, pool->server)
      98          24 :             || !tds_set_client_charset(login, "iso_1")
      99          24 :             || !tds_set_language(login, "us_english")) {
     100           0 :                 tds_free_login(login);
     101           0 :                 return NULL;
     102             :         }
     103          24 :         if (tds_version > 0)
     104          22 :                 login->tds_version = tds_version;
     105          24 :         if (pool->database && strlen(pool->database)) {
     106          24 :                 if (!tds_dstr_copy(&login->database, pool->database)) {
     107           0 :                         tds_free_login(login);
     108           0 :                         return NULL;
     109             :                 }
     110             :         }
     111          24 :         context = tds_alloc_context(NULL);
     112          24 :         if (!context) {
     113           0 :                 fprintf(stderr, "Context cannot be null\n");
     114           0 :                 tds_free_login(login);
     115           0 :                 return NULL;
     116             :         }
     117          24 :         tds = tds_alloc_socket(context, 512);
     118          24 :         if (!tds) {
     119           0 :                 fprintf(stderr, "tds cannot be null\n");
     120           0 :                 tds_free_context(context);
     121           0 :                 tds_free_login(login);
     122           0 :                 return NULL;
     123             :         }
     124          24 :         connection = tds_read_config_info(tds, login, context->locale);
     125          24 :         tds_free_login(login);
     126          24 :         if (!connection || TDS_FAILED(tds_connect_and_login(tds, connection))) {
     127           0 :                 pool_mbr_free_socket(tds);
     128           0 :                 tds_free_login(connection);
     129             :                 /* what to do? */
     130           0 :                 fprintf(stderr, "Could not open connection to server %s\n", pool->server);
     131           0 :                 return NULL;
     132             :         }
     133          24 :         tds_free_login(connection);
     134             : 
     135          24 :         if (pool->database && strlen(pool->database)) {
     136          24 :                 if (strcasecmp(tds->conn->env.database, pool->database) != 0) {
     137           0 :                         fprintf(stderr, "changing database failed\n");
     138           0 :                         pool_mbr_free_socket(tds);
     139           0 :                         return NULL;
     140             :                 }
     141             :         }
     142             : 
     143             :         return tds;
     144             : }
     145             : 
     146             : void
     147         720 : pool_assign_member(TDS_POOL *pool, TDS_POOL_MEMBER * pmbr, TDS_POOL_USER *puser)
     148             : {
     149         720 :         pool_mbr_check(pool);
     150         720 :         assert(pmbr->current_user == NULL);
     151             :         if (pmbr->current_user) {
     152             :                 pmbr->current_user->assigned_member = NULL;
     153             :         } else {
     154         720 :                 dlist_member_remove(&pool->idle_members, pmbr);
     155         720 :                 dlist_member_append(&pool->active_members, pmbr);
     156             :         }
     157         720 :         pmbr->current_user = puser;
     158         720 :         puser->assigned_member = pmbr;
     159         720 :         pool_mbr_check(pool);
     160         720 : }
     161             : 
     162             : void
     163         720 : pool_deassign_member(TDS_POOL *pool, TDS_POOL_MEMBER * pmbr)
     164             : {
     165         720 :         if (pmbr->current_user) {
     166         720 :                 pmbr->current_user->assigned_member = NULL;
     167         720 :                 pmbr->current_user = NULL;
     168         720 :                 dlist_member_remove(&pool->active_members, pmbr);
     169         720 :                 dlist_member_append(&pool->idle_members, pmbr);
     170             :         }
     171         720 :         pmbr->sock.poll_send = false;
     172         720 : }
     173             : 
     174             : /*
     175             :  * if a dead connection on the client side left this member in a questionable
     176             :  * state, let's bring in a correct one
     177             :  * We are not sure what the client did so we must try to clean as much as
     178             :  * possible.
     179             :  * Use pool_free_member if the state is really broken.
     180             :  */
     181             : void
     182         718 : pool_reset_member(TDS_POOL * pool, TDS_POOL_MEMBER * pmbr)
     183             : {
     184             :         // FIXME not wait for server !!! asyncronous
     185         718 :         TDSSOCKET *tds = pmbr->sock.tds;
     186             :         TDS_POOL_USER *puser;
     187             : 
     188         718 :         puser = pmbr->current_user;
     189         718 :         if (puser) {
     190           0 :                 pool_deassign_member(pool, pmbr);
     191           0 :                 pool_free_user(pool, puser);
     192             :         }
     193             : 
     194             :         /* cancel whatever pending */
     195         718 :         tds_init_write_buf(tds);
     196         718 :         if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING)
     197             :                 goto failure;
     198         718 :         tds->out_flag = TDS_CANCEL;
     199         718 :         if (TDS_FAILED(tds_flush_packet(tds)))
     200             :                 goto failure;
     201         718 :         tds_set_state(tds, TDS_PENDING);
     202         718 :         tds->in_cancel = 2;
     203             : 
     204         718 :         if (TDS_FAILED(tds_process_cancel(tds)))
     205             :                 goto failure;
     206             : 
     207         718 :         if (IS_TDS71_PLUS(tds->conn)) {
     208             :                 /* this 0x9 final reset the state from mssql 2000 */
     209         718 :                 if (tds_set_state(tds, TDS_WRITING) != TDS_WRITING)
     210             :                         goto failure;
     211         718 :                 tds_start_query(tds, TDS_QUERY);
     212         718 :                 tds_put_string(tds, "WHILE @@TRANCOUNT > 0 ROLLBACK SET TRANSACTION ISOLATION LEVEL READ COMMITTED", -1);
     213         718 :                 tds_write_packet(tds, 0x9);
     214         718 :                 tds_set_state(tds, TDS_PENDING);
     215             : 
     216         718 :                 if (TDS_FAILED(tds_process_simple_query(tds)))
     217             :                         goto failure;
     218             :         }
     219             :         return;
     220             : 
     221           0 : failure:
     222           0 :         pool_free_member(pool, pmbr);
     223             : }
     224             : 
     225             : void
     226          24 : pool_free_member(TDS_POOL * pool, TDS_POOL_MEMBER * pmbr)
     227             : {
     228             :         TDSSOCKET *tds;
     229             :         TDS_POOL_USER *puser;
     230             : 
     231          24 :         tds = pmbr->sock.tds;
     232          24 :         if (tds) {
     233          24 :                 if (!IS_TDSDEAD(tds))
     234          24 :                         tds_close_socket(tds);
     235          24 :                 pool_mbr_free_socket(tds);
     236          24 :                 pmbr->sock.tds = NULL;
     237             :         }
     238             : 
     239             :         /*
     240             :          * if he is allocated disconnect the client 
     241             :          * otherwise we end up with broken client.
     242             :          */
     243          24 :         puser = pmbr->current_user;
     244          24 :         if (puser) {
     245           2 :                 pool_deassign_member(pool, pmbr);
     246           2 :                 pool_free_user(pool, puser);
     247             :         }
     248             : 
     249          48 :         if (dlist_member_in_list(&pool->active_members, pmbr)) {
     250          24 :                 pool->num_active_members--;
     251          24 :                 dlist_member_remove(&pool->active_members, pmbr);
     252             :         }
     253          24 :         free(pmbr);
     254          24 :         pool_mbr_check(pool);
     255          24 : }
     256             : 
     257             : void
     258           2 : pool_mbr_init(TDS_POOL * pool)
     259             : {
     260             :         TDS_POOL_MEMBER *pmbr;
     261             : 
     262             :         /* allocate room for pool members */
     263             : 
     264           2 :         pool->num_active_members = 0;
     265           4 :         dlist_member_init(&pool->active_members);
     266           4 :         dlist_member_init(&pool->idle_members);
     267           2 :         pool_mbr_check(pool);
     268             : 
     269             :         /* open connections for each member */
     270           6 :         while (pool->num_active_members < pool->min_open_conn) {
     271           2 :                 pmbr = tds_new0(TDS_POOL_MEMBER, 1);
     272           2 :                 if (!pmbr) {
     273           0 :                         fprintf(stderr, "Out of memory\n");
     274           0 :                         exit(1);
     275             :                 }
     276           2 :                 pmbr->sock.poll_recv = true;
     277             : 
     278           2 :                 pmbr->sock.tds = pool_mbr_login(pool, 0);
     279           2 :                 if (!pmbr->sock.tds) {
     280           0 :                         fprintf(stderr, "Could not open initial connection\n");
     281           0 :                         exit(1);
     282             :                 }
     283           2 :                 pmbr->last_used_tm = time(NULL);
     284           2 :                 pool->num_active_members++;
     285           2 :                 dlist_member_append(&pool->idle_members, pmbr);
     286           2 :                 if (!IS_TDS71_PLUS(pmbr->sock.tds->conn)) {
     287           0 :                         fprintf(stderr, "Current pool implementation does not support protocol versions former than 7.1\n");
     288           0 :                         exit(1);
     289             :                 }
     290           2 :                 pool->member_logins++;
     291             :         }
     292           2 :         pool_mbr_check(pool);
     293           2 : }
     294             : 
     295             : void
     296           2 : pool_mbr_destroy(TDS_POOL * pool)
     297             : {
     298           4 :         while (dlist_member_first(&pool->active_members))
     299           0 :                 pool_free_member(pool, dlist_member_first(&pool->active_members));
     300          46 :         while (dlist_member_first(&pool->idle_members))
     301          22 :                 pool_free_member(pool, dlist_member_first(&pool->idle_members));
     302             : 
     303           2 :         assert(pool->num_active_members == 0);
     304           2 :         pool->num_active_members = 0;
     305           2 : }
     306             : 
     307             : static bool
     308       18315 : pool_process_data(TDS_POOL *pool, TDS_POOL_MEMBER *pmbr)
     309             : {
     310       18315 :         TDSSOCKET *tds = pmbr->sock.tds;
     311       18315 :         TDS_POOL_USER *puser = NULL;
     312             : 
     313             :         for (;;) {
     314       35386 :                 if (pool_packet_read(tds))
     315             :                         break;
     316             : 
     317             :                 /* disconnected */
     318       17073 :                 if (tds->in_len == 0) {
     319           2 :                         tdsdump_log(TDS_DBG_INFO1, "Uh oh! member disconnected\n");
     320             :                         /* mark as dead */
     321           2 :                         pool_free_member(pool, pmbr);
     322           2 :                         return false;
     323             :                 }
     324             : 
     325       17071 :                 tdsdump_dump_buf(TDS_DBG_NETWORK, "Got packet from server:", tds->in_buf, tds->in_len);
     326       17071 :                 puser = pmbr->current_user;
     327       17071 :                 if (!puser)
     328             :                         break;
     329             : 
     330       17071 :                 tdsdump_log(TDS_DBG_INFO1, "writing it sock %d\n", (int) tds_get_s(puser->sock.tds));
     331       17071 :                 if (!pool_write_data(&pmbr->sock, &puser->sock)) {
     332           0 :                         tdsdump_log(TDS_DBG_ERROR, "member received error while writing\n");
     333           0 :                         pool_free_user(pool, puser);
     334           0 :                         return false;
     335             :                 }
     336       17071 :                 if (tds->in_pos < tds->in_len)
     337             :                         /* partial write, schedule a future write */
     338             :                         break;
     339             :         }
     340       18313 :         if (puser && !puser->sock.poll_send)
     341       16940 :                 tds_socket_flush(tds_get_s(puser->sock.tds));
     342             :         return true;
     343             : }
     344             : 
     345             : /* 
     346             :  * pool_process_members
     347             :  * check the fd_set for members returning data to the client, lookup the 
     348             :  * client holding this member and forward the results.
     349             :  * @return Timeout you should call this function again or -1 for infinite
     350             :  */
     351             : int
     352       36402 : pool_process_members(TDS_POOL * pool, struct pollfd *fds, unsigned num_fds)
     353             : {
     354             :         TDS_POOL_MEMBER *pmbr, *next;
     355             :         time_t age;
     356             :         time_t time_now;
     357       36402 :         int min_expire_left = -1;
     358             :         short revents;
     359             : 
     360       36402 :         pool_mbr_check(pool);
     361      146356 :         for (next = dlist_member_first(&pool->active_members); (pmbr = next) != NULL; ) {
     362       73552 :                 bool processed = false;
     363             : 
     364      147104 :                 next = dlist_member_next(&pool->active_members, pmbr);
     365             : 
     366       73552 :                 assert(pmbr->current_user);
     367       73552 :                 if (pmbr->doing_async || pmbr->sock.poll_index > num_fds)
     368        1374 :                         continue;
     369             : 
     370       72178 :                 revents = fds[pmbr->sock.poll_index].revents;
     371       72178 :                 assert(pmbr->sock.tds);
     372             : 
     373       72178 :                 time_now = time(NULL);
     374       72178 :                 if (pmbr->sock.poll_recv && (revents & (POLLIN|POLLHUP)) != 0) {
     375       18315 :                         if (!pool_process_data(pool, pmbr))
     376           2 :                                 continue;
     377             :                         processed = true;
     378             :                 }
     379       72176 :                 if (pmbr->sock.poll_send && (revents & POLLOUT) != 0) {
     380           1 :                         if (!pool_write_data(&pmbr->current_user->sock, &pmbr->sock)) {
     381           0 :                                 pool_free_member(pool, pmbr);
     382           0 :                                 continue;
     383             :                         }
     384             :                         processed = true;
     385             :                 }
     386       72175 :                 if (processed)
     387       18314 :                         pmbr->last_used_tm = time_now;
     388             :         }
     389             : 
     390       36402 :         if (pool->num_active_members <= pool->min_open_conn)
     391             :                 return min_expire_left;
     392             : 
     393             :         /* close old connections */
     394       27614 :         time_now = time(NULL);
     395      269813 :         for (next = dlist_member_first(&pool->idle_members); (pmbr = next) != NULL; ) {
     396             : 
     397      429170 :                 next = dlist_member_next(&pool->idle_members, pmbr);
     398             : 
     399      214585 :                 assert(pmbr->sock.tds);
     400      214585 :                 assert(!pmbr->current_user);
     401             : 
     402      214585 :                 age = time_now - pmbr->last_used_tm;
     403      214585 :                 if (age >= pool->max_member_age) {
     404           0 :                         tdsdump_log(TDS_DBG_INFO1, "member is %ld seconds old...closing\n", (long int) age);
     405           0 :                         pool_free_member(pool, pmbr);
     406             :                 } else {
     407      214585 :                         int left = (int) (pool->max_member_age - age);
     408      214585 :                         if (min_expire_left < 0 || left < min_expire_left)
     409       22898 :                                 min_expire_left = left;
     410             :                 }
     411             :         }
     412             :         return min_expire_left;
     413             : }
     414             : 
     415             : static bool
     416             : compatible_versions(const TDSSOCKET *tds, const TDS_POOL_USER *user)
     417             : {
     418         698 :         if (tds->conn->tds_version != user->login->tds_version)
     419             :                 return false;
     420             :         return true;
     421             : }
     422             : 
     423             : typedef struct {
     424             :         TDS_POOL_EVENT common;
     425             :         TDS_POOL *pool;
     426             :         TDS_POOL_MEMBER *pmbr;
     427             :         int tds_version;
     428             : } CONNECT_EVENT;
     429             : 
     430             : static void connect_execute_ok(TDS_POOL_EVENT *base_event);
     431             : static void connect_execute_ko(TDS_POOL_EVENT *base_event);
     432             : 
     433          22 : static TDS_THREAD_PROC_DECLARE(connect_proc, arg)
     434             : {
     435          22 :         CONNECT_EVENT *ev = (CONNECT_EVENT *) arg;
     436          22 :         TDS_POOL_MEMBER *pmbr = ev->pmbr;
     437          22 :         TDS_POOL *pool = ev->pool;
     438             : 
     439             :         for (;;) {
     440          22 :                 pmbr->sock.tds = pool_mbr_login(pool, ev->tds_version);
     441          22 :                 if (!pmbr->sock.tds) {
     442           0 :                         tdsdump_log(TDS_DBG_ERROR, "Error opening a new connection to server\n");
     443             :                         break;
     444             :                 }
     445          22 :                 if (!IS_TDS71_PLUS(pmbr->sock.tds->conn)) {
     446           0 :                         tdsdump_log(TDS_DBG_ERROR, "Protocol server version not supported\n");
     447             :                         break;
     448             :                 }
     449             : 
     450             :                 /* if already attached to a user we can send login directly */
     451          22 :                 if (pmbr->current_user)
     452          22 :                         if (!pool_user_send_login_ack(pool, pmbr->current_user))
     453             :                                 break;
     454             : 
     455          22 :                 pool_event_add(pool, &ev->common, connect_execute_ok);
     456          22 :                 return TDS_THREAD_RESULT(0);
     457             :         }
     458             : 
     459             :         /* failure */
     460           0 :         pool_event_add(pool, &ev->common, connect_execute_ko);
     461           0 :         return TDS_THREAD_RESULT(0);
     462             : }
     463             : 
     464             : static void
     465           0 : connect_execute_ko(TDS_POOL_EVENT *base_event)
     466             : {
     467           0 :         CONNECT_EVENT *ev = (CONNECT_EVENT *) base_event;
     468             : 
     469           0 :         pool_free_member(ev->pool, ev->pmbr);
     470           0 : }
     471             : 
     472             : static void
     473          22 : connect_execute_ok(TDS_POOL_EVENT *base_event)
     474             : {
     475          22 :         CONNECT_EVENT *ev = (CONNECT_EVENT *) base_event;
     476          22 :         TDS_POOL_MEMBER *pmbr = ev->pmbr;
     477          22 :         TDS_POOL_USER *puser = pmbr->current_user;
     478             : 
     479          22 :         ev->pool->member_logins++;
     480          22 :         pmbr->doing_async = false;
     481             : 
     482          22 :         pmbr->last_used_tm = time(NULL);
     483             : 
     484          22 :         if (puser) {
     485          22 :                 pmbr->sock.poll_recv = true;
     486          22 :                 puser->sock.poll_recv = true;
     487             : 
     488          22 :                 puser->user_state = TDS_SRV_QUERY;
     489             :         }
     490          22 : }
     491             : 
     492             : /*
     493             :  * pool_assign_idle_member
     494             :  * assign a member to the user specified
     495             :  */
     496             : TDS_POOL_MEMBER *
     497         720 : pool_assign_idle_member(TDS_POOL * pool, TDS_POOL_USER *puser)
     498             : {
     499             :         TDS_POOL_MEMBER *pmbr;
     500             :         CONNECT_EVENT *ev;
     501             : 
     502         720 :         puser->sock.poll_recv = false;
     503         720 :         puser->sock.poll_send = false;
     504             : 
     505         720 :         pool_mbr_check(pool);
     506         720 :         DLIST_FOREACH(dlist_member, &pool->idle_members, pmbr) {
     507         698 :                 assert(pmbr->current_user == NULL);
     508         698 :                 assert(!pmbr->doing_async);
     509             : 
     510         698 :                 assert(pmbr->sock.tds);
     511             : 
     512        1396 :                 if (!compatible_versions(pmbr->sock.tds, puser))
     513           0 :                         continue;
     514             : 
     515         698 :                 pool_assign_member(pool, pmbr, puser);
     516             : 
     517             :                 /*
     518             :                  * make sure member wasn't idle more that the timeout
     519             :                  * otherwise it'll send the query and close leaving a
     520             :                  * hung client
     521             :                  */
     522         698 :                 pmbr->last_used_tm = time(NULL);
     523         698 :                 pmbr->sock.poll_recv = false;
     524         698 :                 pmbr->sock.poll_send = false;
     525             : 
     526         698 :                 pool_user_finish_login(pool, puser);
     527         698 :                 return pmbr;
     528             :         }
     529             : 
     530             :         /* if we can open a new connection open it */
     531          22 :         if (pool->num_active_members >= pool->max_open_conn) {
     532           0 :                 fprintf(stderr, "No idle members left, increase \"max pool conn\"\n");
     533           0 :                 return NULL;
     534             :         }
     535             : 
     536          22 :         pmbr = tds_new0(TDS_POOL_MEMBER, 1);
     537          22 :         if (!pmbr) {
     538           0 :                 fprintf(stderr, "Out of memory\n");
     539           0 :                 return NULL;
     540             :         }
     541             : 
     542          22 :         tdsdump_log(TDS_DBG_INFO1, "No open connections left, opening new member\n");
     543             : 
     544          22 :         ev = tds_new0(CONNECT_EVENT, 1);
     545          22 :         if (!ev) {
     546           0 :                 free(pmbr);
     547           0 :                 fprintf(stderr, "Out of memory\n");
     548           0 :                 return NULL;
     549             :         }
     550          22 :         ev->pmbr = pmbr;
     551          22 :         ev->pool = pool;
     552          22 :         ev->tds_version = puser->login->tds_version;
     553             : 
     554          22 :         if (tds_thread_create_detached(connect_proc, ev) != 0) {
     555           0 :                 free(pmbr);
     556           0 :                 free(ev);
     557           0 :                 fprintf(stderr, "error creating thread\n");
     558           0 :                 return NULL;
     559             :         }
     560          22 :         pmbr->doing_async = true;
     561             : 
     562          22 :         pool_mbr_check(pool);
     563          22 :         pool->num_active_members++;
     564          22 :         dlist_member_append(&pool->idle_members, pmbr);
     565          22 :         pool_mbr_check(pool);
     566             : 
     567          22 :         pool_assign_member(pool, pmbr, puser);
     568          22 :         puser->sock.poll_send = false;
     569          22 :         puser->sock.poll_recv = false;
     570             : 
     571          22 :         return pmbr;
     572             : }
     573             : 
     574             : #if ENABLE_EXTRA_CHECKS
     575       38634 : void pool_mbr_check(TDS_POOL *pool)
     576             : {
     577             :         TDS_POOL_MEMBER *pmbr;
     578       38634 :         unsigned total = 0;
     579             : 
     580      227044 :         DLIST_FOREACH(dlist_member, &pool->active_members, pmbr) {
     581       74888 :                 assert(pmbr->doing_async || pmbr->sock.tds);
     582       74888 :                 assert(pmbr->current_user);
     583       74888 :                 ++total;
     584             :         }
     585      531654 :         DLIST_FOREACH(dlist_member, &pool->idle_members, pmbr) {
     586      227193 :                 assert(pmbr->doing_async || pmbr->sock.tds);
     587      227193 :                 assert(!pmbr->current_user);
     588      227193 :                 ++total;
     589             :         }
     590       38634 :         assert(pool->num_active_members == total);
     591       38634 : }
     592             : #endif

Generated by: LCOV version 1.13