~maria-captains/mariadb-native-client/trunk

« back to all changes in this revision

Viewing changes to libmariadb/libmariadb.c

  • Committer: holzboote at googlemail
  • Date: 2013-08-01 07:56:36 UTC
  • Revision ID: holzboote@googlemail.com-20130801075636-oys87aewsz75qnkd
Fixed crash/undefined behaviour when running large amount of threads:
  replaced select() with poll()
Added conneciton timeout support for windows platforms

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
#ifdef HAVE_OPENSSL
64
64
#include <ma_secure.h>
65
65
#endif
 
66
#ifndef _WIN32
 
67
#include <poll.h>
 
68
#endif
66
69
 
67
70
static my_bool mysql_client_init=0;
68
71
static void mysql_close_options(MYSQL *mysql);
145
148
* Base version coded by Steve Bernacki, Jr. <steve@navinet.net>
146
149
*****************************************************************************/
147
150
 
 
151
int socket_block(my_socket s,my_bool blocked)
 
152
{
 
153
#ifdef _WIN32
 
154
  unsigned long socket_blocked= blocked ? 0 : 1;
 
155
  return ioctlsocket(s, FIONBIO, &socket_blocked);
 
156
#else
 
157
  int flags= fcntl(s, F_GETFL, 0);
 
158
  if (blocked)
 
159
    flags&= ~O_NONBLOCK;
 
160
  else 
 
161
    flags|= O_NONBLOCK;
 
162
  return fcntl(s, F_SETFL, flags);
 
163
#endif
 
164
}
 
165
 
148
166
static int connect2(my_socket s, const struct sockaddr *name, uint namelen,
149
167
                    uint timeout)
150
168
{
151
 
#if defined(_WIN32) || defined(OS2)
152
 
  return connect(s, (struct sockaddr*) name, namelen);
153
 
#else
154
 
  int flags, res, s_err;
 
169
  int res, s_err;
155
170
  socklen_t s_err_size = sizeof(uint);
156
 
  fd_set sfds;
 
171
#ifndef _WIN32
 
172
  struct pollfd poll_fd;
 
173
#else
 
174
  FD_SET sfds, efds;
157
175
  struct timeval tv;
158
 
  time_t start_time, now_time;
159
 
 
160
 
  /*
161
 
    If they passed us a timeout of zero, we should behave
162
 
    exactly like the normal connect() call does.
163
 
  */
164
 
 
165
 
  if (timeout == 0)
 
176
#endif
 
177
 
 
178
  if (!timeout)
166
179
    return connect(s, (struct sockaddr*) name, namelen);
167
180
 
168
 
  flags = fcntl(s, F_GETFL, 0);           /* Set socket to not block */
169
 
#ifdef O_NONBLOCK
170
 
  fcntl(s, F_SETFL, flags | O_NONBLOCK);  /* and save the flags..  */
 
181
  /* set socket to non blocking */
 
182
  if (socket_block(s, 0) == SOCKET_ERROR)
 
183
    return -1;
 
184
 
 
185
  res= connect(s, (struct sockaddr*) name, namelen);
 
186
  if (res == 0)
 
187
    return res;
 
188
 
 
189
#ifdef _WIN32
 
190
  if (GetLastError() != WSAEWOULDBLOCK &&
 
191
      GetLastError() != WSAEINPROGRESS)
 
192
#else
 
193
  if (errno != EINPROGRESS)
171
194
#endif
172
 
 
173
 
  res = connect(s, (struct sockaddr*) name, namelen);
174
 
  s_err = errno;                        /* Save the error... */
175
 
  fcntl(s, F_SETFL, flags);
176
 
  if ((res != 0) && (s_err != EINPROGRESS))
 
195
     return -1;
 
196
#ifndef _WIN32
 
197
  memset(&poll_fd, 0, sizeof(struct pollfd));
 
198
  poll_fd.events= POLLOUT | POLLERR;
 
199
  poll_fd.fd= s;
 
200
 
 
201
  /* connection timeout in milliseconds */
 
202
  res= poll(&poll_fd, 1, (timeout > -1) ? timeout * 1000 : timeout);
 
203
 
 
204
  switch(res)
177
205
  {
178
 
    errno = s_err;                      /* Restore it */
179
 
    return(-1);
 
206
    /* Error= - 1, timeout = 0 */
 
207
    case -1:
 
208
      break;
 
209
    case 0: 
 
210
      errno= ETIMEDOUT;
 
211
      break;
180
212
  }
181
 
  if (res == 0)                         /* Connected quickly! */
182
 
    return(0);
183
 
 
184
 
  /*
185
 
    Otherwise, our connection is "in progress."  We can use
186
 
    the select() call to wait up to a specified period of time
187
 
    for the connection to suceed.  If select() returns 0
188
 
    (after waiting howevermany seconds), our socket never became
189
 
    writable (host is probably unreachable.)  Otherwise, if
190
 
    select() returns 1, then one of two conditions exist:
191
 
   
192
 
    1. An error occured.  We use getsockopt() to check for this.
193
 
    2. The connection was set up sucessfully: getsockopt() will
194
 
    return 0 as an error.
195
 
   
196
 
    Thanks goes to Andrew Gierth <andrew@erlenstar.demon.co.uk>
197
 
    who posted this method of timing out a connect() in
198
 
    comp.unix.programmer on August 15th, 1997.
199
 
  */
200
 
 
 
213
#else
201
214
  FD_ZERO(&sfds);
 
215
  FD_ZERO(&efds);
202
216
  FD_SET(s, &sfds);
203
 
  /*
204
 
    select could be interrupted by a signal, and if it is, 
205
 
    the timeout should be adjusted and the select restarted
206
 
    to work around OSes that don't restart select and 
207
 
    implementations of select that don't adjust tv upon
208
 
    failure to reflect the time remaining
209
 
   */
210
 
  start_time = time(NULL);
211
 
  for (;;)
212
 
  {
213
 
    tv.tv_sec = (long) timeout;
214
 
    tv.tv_usec = 0;
215
 
#if defined(HPUX) && defined(THREAD)
216
 
    if ((res = select(s+1, NULL, (int*) &sfds, NULL, &tv)) > 0)
217
 
      break;
218
 
#else
219
 
    if ((res = select(s+1, NULL, &sfds, NULL, &tv)) > 0)
220
 
      break;
 
217
  FD_SET(s, &efds);
 
218
 
 
219
  memset(&tv, 0, sizeof(struct timeval));
 
220
  tv.tv_sec= timeout;
 
221
 
 
222
  res= select(s+1, NULL, &sfds, &efds, &tv);
 
223
  if (res < 1)
 
224
    return -1;
221
225
#endif
222
 
    if (res == 0)                                       /* timeout */
223
 
      return -1;
224
 
    now_time=time(NULL);
225
 
    timeout-= (uint) (now_time - start_time);
226
 
    if (errno != EINTR || (int) timeout <= 0)
227
 
      return -1;
228
 
  }
229
 
 
230
 
  /*
231
 
    select() returned something more interesting than zero, let's
232
 
    see if we have any errors.  If the next two statements pass,
233
 
    we've got an open socket!
234
 
  */
235
226
 
236
227
  s_err=0;
237
228
  if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*) &s_err, &s_err_size) != 0)
243
234
    return(-1);                                 /* but return an error... */
244
235
  }
245
236
  return (0);                                   /* ok */
246
 
 
247
 
#endif
248
237
}
249
238
 
250
239
/*
1521
1510
                          unix_socket, socket_errno);
1522
1511
      goto error;
1523
1512
    }
 
1513
    if (socket_block(sock, 1) == SOCKET_ERROR)
 
1514
      goto error;
1524
1515
  }
1525
1516
  else
1526
1517
#elif defined(_WIN32)
1610
1601
      }
1611
1602
      if (!(rc= connect2(sock, save_res->ai_addr, save_res->ai_addrlen, 
1612
1603
                   mysql->options.connect_timeout)))
 
1604
      {
 
1605
        if (socket_block(sock, 1) == SOCKET_ERROR)
 
1606
        {
 
1607
          closesocket(sock);
 
1608
          continue;
 
1609
        }
1613
1610
        break; /* success! */
 
1611
      }
1614
1612
 
1615
1613
      vio_delete(mysql->net.vio);
1616
1614
      mysql->net.vio= NULL;