1
0
mirror of https://github.com/mariadb-corporation/mariadb-connector-c.git synced 2025-08-07 02:42:49 +03:00

Fixed vio for non-blocking API calls

This commit is contained in:
Georg Richter
2014-11-12 18:10:22 +01:00
parent b448d0313f
commit 088fdacfc1
13 changed files with 365 additions and 145 deletions

View File

@@ -87,7 +87,8 @@ size_t vio_write(Vio* vio, const gptr buf, size_t size);
* Whenever the socket is set to blocking mode or not.
*/
int vio_blocking( Vio* vio,
my_bool onoff);
my_bool onoff,
my_bool *prevmode);
my_bool vio_is_blocking( Vio* vio);
/*
* setsockopt TCP_NODELAY at IPPROTO_TCP level, when possible.
@@ -135,6 +136,7 @@ void vio_in_addr(Vio *vio, struct in_addr *in);
/* Return 1 if there is data to be read */
my_bool vio_poll_read(Vio *vio,uint timeout);
int vio_wait_or_timeout(Vio *vio, my_bool is_read, int timeout);
struct st_vio
@@ -146,7 +148,8 @@ struct st_vio
struct sockaddr_in local; /* Local internet address */
struct sockaddr_in remote; /* Remote internet address */
struct mysql_async_context *async_context; /* For non-blocking API */
int write_timeout;
int read_timeout;
enum enum_vio_type type; /* Type of connection */
char desc[30]; /* String description */
#ifdef HAVE_OPENSSL

View File

@@ -211,7 +211,7 @@ static int connect2(my_socket s, const struct sockaddr *name, size_t namelen,
poll_fd.fd= s;
/* connection timeout in milliseconds */
res= poll(&poll_fd, 1, (timeout > -1) ? timeout * 1000 : timeout);
res= poll(&poll_fd, 1, timeout);
switch(res)
{
@@ -248,6 +248,24 @@ static int connect2(my_socket s, const struct sockaddr *name, size_t namelen,
return (0); /* ok */
}
static int
connect_sync_or_async(MYSQL *mysql, NET *net, my_socket fd,
const struct sockaddr *name, uint namelen)
{
int vio_timeout= (mysql->options.connect_timeout >= 0) ?
mysql->options.connect_timeout * 1000 : -1;
if (mysql->options.extension && mysql->options.extension->async_context &&
mysql->options.extension->async_context->active)
{
my_bool old_mode;
vio_blocking(net->vio, FALSE, &old_mode);
return my_connect_async(mysql->options.extension->async_context, fd,
name, namelen, vio_timeout);
}
return connect2(fd, name, namelen, vio_timeout);
}
/*
** Create a named pipe connection
*/
@@ -291,7 +309,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host,
return INVALID_HANDLE_VALUE;
}
/* wait for for an other instance */
if (! WaitNamedPipe(szPipeName, connect_timeout*1000) )
if (! WaitNamedPipe(szPipeName, connect_timeout) )
{
net->last_errno=CR_NAMEDPIPEWAIT_ERROR;
sprintf(net->last_error,ER(net->last_errno),host, unix_socket,
@@ -936,7 +954,7 @@ static void mysql_read_default_options(struct st_mysql_options *options,
options->named_pipe=1; /* Force named pipe */
break;
case OPT_connect_timeout:
case OPT_timeout:
case OPT_timeout:
if (opt_arg)
options->connect_timeout=atoi(opt_arg);
break;
@@ -1577,10 +1595,9 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
bzero((char*) &UNIXaddr,sizeof(UNIXaddr));
UNIXaddr.sun_family = AF_UNIX;
strmov(UNIXaddr.sun_path, unix_socket);
if (connect2(sock,(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr),
mysql->options.connect_timeout) <0)
if (connect_sync_or_async(mysql, net, sock,
(struct sockaddr *) &UNIXaddr, sizeof(UNIXaddr)))
{
printf("err\n");
DBUG_PRINT("error",("Got error %d on connect to local server",socket_errno));
my_set_error(mysql, CR_CONNECTION_ERROR, SQLSTATE_UNKNOWN, ER(CR_CONNECTION_ERROR),
unix_socket, socket_errno);
@@ -1675,17 +1692,20 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
freeaddrinfo(res);
goto error;
}
if (!(rc= connect2(sock, save_res->ai_addr, save_res->ai_addrlen,
mysql->options.connect_timeout)))
rc= connect_sync_or_async(mysql, net, sock,
save_res->ai_addr, save_res->ai_addrlen);
if (!rc)
{
if (socket_block(sock, 1) == SOCKET_ERROR)
if (mysql->options.extension && mysql->options.extension->async_context &&
mysql->options.extension->async_context->active)
break;
else if (socket_block(sock, 1) == SOCKET_ERROR)
{
closesocket(sock);
continue;
closesocket(sock);
continue;
}
break; /* success! */
}
vio_delete(mysql->net.vio);
mysql->net.vio= NULL;
}
@@ -1708,6 +1728,13 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
}
}
/* set timeouts */
net->vio->read_timeout= mysql->options.read_timeout;
net->vio->write_timeout= mysql->options.write_timeout;
if (mysql->options.extension && mysql->options.extension->async_context)
net->vio->async_context= mysql->options.extension->async_context;
if (!net->vio || my_net_init(net, net->vio))
{
vio_delete(net->vio);
@@ -1720,16 +1747,16 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user,
/* set read timeout */
if (mysql->options.read_timeout)
if (mysql->options.read_timeout >= 0)
vio_read_timeout(net->vio, mysql->options.read_timeout);
/* set write timeout */
if (mysql->options.write_timeout)
if (mysql->options.write_timeout >= 0)
vio_write_timeout(net->vio, mysql->options.read_timeout);
/* Get version info */
mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */
if (mysql->options.connect_timeout &&
vio_poll_read(net->vio, mysql->options.connect_timeout))
if (mysql->options.connect_timeout >= 0 &&
vio_wait_or_timeout(net->vio, FALSE, mysql->options.connect_timeout * 1000) < 1)
{
my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN,
ER(CR_SERVER_LOST_EXTENDED),

View File

@@ -109,7 +109,6 @@ EXPORTS
mysql_ping
mysql_ping_cont
mysql_ping_start
mysql_plugin_options
mysql_ps_fetch_functions DATA
mysql_query
mysql_query_cont

View File

@@ -25,6 +25,8 @@
#include <ma_secure.h>
#include <errmsg.h>
#include <violite.h>
#include <mysql_async.h>
#include <my_context.h>
static my_bool my_ssl_initialized= FALSE;
static SSL_CTX *SSL_context= NULL;
@@ -395,7 +397,7 @@ int my_ssl_connect(SSL *ssl)
/* Set socket to blocking if not already set */
if (!(blocking= vio_is_blocking(mysql->net.vio)))
vio_blocking(mysql->net.vio, TRUE);
vio_blocking(mysql->net.vio, TRUE, 0);
SSL_clear(ssl);
SSL_SESSION_set_timeout(SSL_get_session(ssl),
@@ -407,7 +409,7 @@ int my_ssl_connect(SSL *ssl)
my_SSL_error(mysql);
/* restore blocking mode */
if (!blocking)
vio_blocking(mysql->net.vio, FALSE);
vio_blocking(mysql->net.vio, FALSE, 0);
DBUG_RETURN(1);
}
@@ -489,8 +491,11 @@ size_t my_ssl_write(Vio *vio, const uchar* buf, size_t size)
{
size_t written;
DBUG_ENTER("my_ssl_write");
written= SSL_write((SSL*) vio->ssl, buf, size);
if (vio->async_context && vio->async_context->active)
written= my_ssl_write_async(vio->async_context, (SSL *)vio->ssl, buf,
size);
else
written= SSL_write((SSL*) vio->ssl, buf, size);
DBUG_RETURN(written);
}
@@ -511,7 +516,10 @@ size_t my_ssl_read(Vio *vio, uchar* buf, size_t size)
size_t read;
DBUG_ENTER("my_ssl_read");
read= SSL_read((SSL*) vio->ssl, buf, size);
if (vio->async_context && vio->async_context->active)
read= my_ssl_read_async(vio->async_context, (SSL *)vio->ssl, buf, size);
else
read= SSL_read((SSL*) vio->ssl, buf, size);
DBUG_RETURN(read);
}

View File

@@ -41,12 +41,14 @@
*/
#define WIN_SET_NONBLOCKING(mysql) { \
my_bool old_mode; \
if ((mysql)->net.vio) vio_blocking((mysql)->net.vio, FALSE); \
if ((mysql)->net.vio) vio_blocking((mysql)->net.vio, FALSE, &old_mode); \
}
#else
#define WIN_SET_NONBLOCKING(mysql)
#endif
extern void mysql_close_slow_part(MYSQL *mysql);
void
my_context_install_suspend_resume_hook(struct mysql_async_context *b,

View File

@@ -132,7 +132,7 @@ int my_net_init(NET *net, Vio* vio)
net->fd = vio_fd(vio); /* For perl DBI/DBD */
#if defined(MYSQL_SERVER) && !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
if (!(test_flags & TEST_BLOCKING))
vio_blocking(vio, FALSE);
vio_blocking(vio, FALSE, 0);
#endif
vio_fastsend(vio);
}
@@ -441,7 +441,7 @@ net_real_write(NET *net,const char *packet,size_t len)
{ /* Always true for client */
if (!vio_is_blocking(net->vio))
{
while (vio_blocking(net->vio, TRUE) < 0)
while (vio_blocking(net->vio, TRUE, 0) < 0)
{
if (vio_should_retry(net->vio) && retry_count++ < RETRY_COUNT)
continue;
@@ -497,7 +497,7 @@ net_real_write(NET *net,const char *packet,size_t len)
if (thr_alarm_in_use(&alarmed))
{
thr_end_alarm(&alarmed);
vio_blocking(net->vio, net_blocking);
vio_blocking(net->vio, net_blocking, 0);
}
net->reading_or_writing=0;
DBUG_RETURN(((int) (pos != end)));
@@ -522,7 +522,7 @@ static void my_net_skip_rest(NET *net, ulong remain, thr_alarm_t *alarmed,
if (!thr_alarm_in_use(alarmed))
{
if (thr_alarm(alarmed,net->timeout,alarm_buff) ||
(!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE) < 0))
(!vio_is_blocking(net->vio) && vio_blocking(net->vio,TRUE, 0) < 0))
return; /* Can't setup, abort */
}
while (remain > 0)
@@ -592,7 +592,7 @@ my_real_read(NET *net, size_t *complen)
{
if (!vio_is_blocking(net->vio))
{
while (vio_blocking(net->vio,TRUE) < 0)
while (vio_blocking(net->vio,TRUE, 0) < 0)
{
if (vio_should_retry(net->vio) &&
retry_count++ < RETRY_COUNT)
@@ -702,7 +702,7 @@ end:
if (thr_alarm_in_use(&alarmed))
{
thr_end_alarm(&alarmed);
vio_blocking(net->vio, net_blocking);
vio_blocking(net->vio, net_blocking, 0);
}
net->reading_or_writing=0;
return(len);

View File

@@ -19,7 +19,7 @@
#include <my_global.h>
#include <m_string.h>
#if !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
#if !defined(_WIN32) && !defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
#define USE_LONGLONG
#define strtoll glob_strtoll /* Fix for True64 */

View File

@@ -19,7 +19,7 @@
#include <my_global.h>
#include <m_string.h>
#if !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
#if !defined(_WIN32) && !defined(HAVE_STRTOULL) && defined(HAVE_LONG_LONG)
#define USE_UNSIGNED
#define USE_LONGLONG
#include "strto.c"

View File

@@ -69,6 +69,14 @@
#define SOCKET_EWOULDBLOCK SOCKET_EAGAIN
#endif
#include <mysql_async.h>
#include <my_context.h>
#ifdef _WIN32
#define ma_get_error() WSAGetLastError()
#else
#define ma_get_error() errno
#endif
typedef void *vio_ptr;
typedef char *vio_cstring;
@@ -82,6 +90,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
my_bool localhost)
{
uchar *save_cache= vio->cache;
int save_timeouts[2]= {vio->read_timeout, vio->write_timeout};
bzero((char*) vio, sizeof(*vio));
vio->type= type;
vio->sd= sd;
@@ -90,16 +99,18 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
/* do not clear cache */
vio->cache= vio->cache_pos= save_cache;
vio->cache_size= 0;
vio->read_timeout= save_timeouts[0];
vio->write_timeout= save_timeouts[1];
}
void vio_timeout(Vio *vio, int type, uint seconds)
void vio_timeout(Vio *vio, int type, uint timeval)
{
#ifdef _WIN32
uint timeout= seconds * 1000; /* milli secs */
uint timeout= timeval; /* milli secs */
#else
struct timeval timeout;
timeout.tv_sec= seconds;
timeout.tv_usec= 0;
timeout.tv_sec= timeval;
timeout.tv_usec= (timeval % 1000) * 1000;
#endif
if (setsockopt(vio->sd, SOL_SOCKET, type,
@@ -114,14 +125,16 @@ void vio_timeout(Vio *vio, int type, uint seconds)
}
}
void vio_read_timeout(Vio *vio, uint seconds)
void vio_read_timeout(Vio *vio, uint timeout)
{
vio_timeout(vio, SO_RCVTIMEO, seconds);
vio->read_timeout= (timeout >= 0) ? timeout * 1000 : -1;
vio_timeout(vio, SO_RCVTIMEO, vio->read_timeout);
}
void vio_write_timeout(Vio *vio, uint seconds)
void vio_write_timeout(Vio *vio, uint timeout)
{
vio_timeout(vio, SO_SNDTIMEO, seconds);
vio->write_timeout= (timeout >= 0) ? timeout * 1000 : -1;
vio_timeout(vio, SO_SNDTIMEO, vio->write_timeout);
}
/* Open the socket or TCP/IP connection and read the fnctl() status */
@@ -197,8 +210,75 @@ int vio_errno(Vio *vio __attribute__((unused)))
return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
}
int vio_wait_or_timeout(Vio *vio, my_bool is_read, int timeout)
{
int rc;
#ifndef _WIN32
struct pollfd p_fd;
#else
struct timeval tv= {0,0};
fd_set fds, exc_fds;
#endif
/* we don't support it via named pipes yet.
* maybe this could be handled via PeekNamedPipe somehow !? */
if (vio->type == VIO_TYPE_NAMEDPIPE)
return 1;
/*
Note that if zero timeout, then we will not block, so we do not need to
yield to calling application in the async case.
*/
if (timeout != 0 && vio->async_context && vio->async_context->active)
{
rc= my_io_wait_async(vio->async_context,
(is_read) ? VIO_IO_EVENT_READ : VIO_IO_EVENT_WRITE,
timeout);
return(rc);
}
else
{
#ifndef _WIN32
p_fd.fd= vio->sd;
p_fd.events= (is_read) ? POLLIN : POLLOUT;
do {
rc= poll(&p_fd, 1, timeout);
} while (rc == -1 || errno == EINTR);
if (rc == 0)
errno= ETIMEDOUT;
#else
FD_ZERO(&fds);
FD_ZERO(&exc_fds);
FD_SET(vio->sd, &fds);
FD_SET(vio->sd, &exc_fds);
if (timeout >= 0)
{
tv.tv_sec= timeout / 1000;
tv.tv_usec= (timeout % 1000) * 1000;
}
rc= select(0, (is_read) ? &fds : NULL,
(is_read) ? NULL : &fds,
&exc_fds,
(timeout >= 0) ? &tv : NULL);
if (rc == SOCKET_ERROR)
errno= WSAGetLastError();
if (rc == 0)
errno= ETIMEDOUT;
#endif
}
return rc;
}
size_t vio_real_read(Vio *vio, gptr buf, size_t size)
{
size_t r;
switch(vio->type) {
#ifdef HAVE_OPENSSL
case VIO_TYPE_SSL:
@@ -216,13 +296,56 @@ size_t vio_real_read(Vio *vio, gptr buf, size_t size)
break;
#endif
default:
return recv(vio->sd, buf,
#ifdef _WIN32
(int)
#endif
size, 0);
if (vio->async_context && vio->async_context->active)
r= my_recv_async(vio->async_context,
vio->sd,
buf, size, vio->read_timeout);
else
{
if (vio->async_context)
{
/*
If switching from non-blocking to blocking API usage, set the socket
back to blocking mode.
*/
my_bool old_mode;
vio_blocking(vio, TRUE, &old_mode);
}
#ifndef _WIN32
do {
r= read(vio->sd, buf, size);
} while (r == -1 && errno == EINTR);
while (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)
&& vio->read_timeout > 0)
{
if (vio_wait_or_timeout(vio, TRUE, vio->write_timeout) < 1)
return 0;
do {
r= read(vio->sd, buf, size);
} while (r == -1 && errno == EINTR);
}
#else
{
WSABUF wsaData;
DWORD dwBytes = 0;
DWORD flags = 0;
wsaData.len= size;
wsaData.buf= buf;
if (WSARecv(vio->sd, &wsaData, 1, &dwBytes, &flags, NULL, NULL) == SOCKET_ERROR)
{
errno= WSAGetLastError();
return 0;
}
r= (size_t)dwBytes;
}
#endif
}
break;
}
return r;
}
@@ -283,7 +406,7 @@ my_bool vio_read_peek(Vio *vio, size_t *bytes)
char buffer[1024];
ssize_t length;
vio_blocking(vio, 0);
vio_blocking(vio, 0, 0);
length= recv(vio->sd, &buffer, sizeof(buffer), MSG_PEEK);
if (length < 0)
return TRUE;
@@ -305,23 +428,60 @@ size_t vio_write(Vio * vio, const gptr buf, size_t size)
DBUG_RETURN(r);
}
#endif
#if defined( _WIN32) || defined(OS2)
#ifdef _WIN32
if ( vio->type == VIO_TYPE_NAMEDPIPE)
{
DWORD length;
#ifdef OS2
if (!DosWrite((HFILE)vio->hPipe, (char*) buf, size, &length))
DBUG_RETURN(-1);
#else
if (!WriteFile(vio->hPipe, (char*) buf, (DWORD)size, &length, NULL))
DBUG_RETURN(-1);
#endif
DBUG_RETURN(length);
}
r = send(vio->sd, buf, (int)size,0);
#endif
if (vio->async_context && vio->async_context->active)
r= my_send_async(vio->async_context, vio->sd, buf, size,
vio->write_timeout);
else
{
if (vio->async_context)
{
/*
If switching from non-blocking to blocking API usage, set the socket
back to blocking mode.
*/
my_bool old_mode;
vio_blocking(vio, TRUE, &old_mode);
}
#ifndef _WIN32
do {
r= send(vio->sd, buf, size, vio->write_timeout ? MSG_DONTWAIT : MSG_WAITALL);
} while (r == -1 && errno == EINTR);
while (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) &&
vio->write_timeout > 0)
{
if (vio_wait_or_timeout(vio, FALSE, vio->write_timeout) < 1)
return 0;
do {
r= send(vio->sd, buf, size, vio->write_timeout ? MSG_DONTWAIT : MSG_WAITALL);
} while (r == -1 && errno == EINTR);
}
#else
r = write(vio->sd, buf, size);
#endif /* _WIN32 */
{
WSABUF wsaData;
DWORD dwBytes = 0;
wsaData.len= size;
wsaData.buf= (char *)buf;
if (WSASend(vio->sd, &wsaData, 1, &dwBytes, 0, NULL, NULL) == SOCKET_ERROR)
{
errno= WSAGetLastError();
DBUG_RETURN(0);
}
r= (size_t)dwBytes;
}
#endif
}
#ifndef DBUG_OFF
if ((size_t)r == -1)
{
@@ -333,48 +493,50 @@ size_t vio_write(Vio * vio, const gptr buf, size_t size)
}
int vio_blocking(Vio * vio, my_bool set_blocking_mode)
int vio_blocking(Vio *vio, my_bool block, my_bool *previous_mode)
{
int r=0;
DBUG_ENTER("vio_blocking");
DBUG_PRINT("enter", ("set_blocking_mode: %d", (int) set_blocking_mode));
int *sd_flags= &vio->fcntl_mode;
int save_flags= vio->fcntl_mode;
my_bool tmp;
my_socket sock= vio->sd;
#if !defined(__WIN32) && !defined(__EMX__) && !defined(OS2)
#if !defined(NO_FCNTL_NONBLOCK)
if (vio->type == VIO_TYPE_NAMEDPIPE)
return 0;
if (vio->sd >= 0)
if (!previous_mode)
previous_mode= &tmp;
#ifdef _WIN32
*previous_mode= (*sd_flags & O_NONBLOCK) != 0;
*sd_flags = (block) ? *sd_flags & ~O_NONBLOCK : *sd_flags | O_NONBLOCK;
{
int old_fcntl=vio->fcntl_mode;
if (set_blocking_mode)
vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
else
vio->fcntl_mode |= O_NONBLOCK; /* set bit */
if (old_fcntl != vio->fcntl_mode)
r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
ulong arg= 1 - block;
if (ioctlsocket(sock, FIONBIO, (void *)&arg))
{
vio->fcntl_mode= save_flags;
return(WSAGetLastError());
}
}
#endif /* !defined(NO_FCNTL_NONBLOCK) */
#else /* !defined(_WIN32) && !defined(__EMX__) */
#ifndef __EMX__
if (vio->type != VIO_TYPE_NAMEDPIPE)
#else
#if defined(O_NONBLOCK)
*previous_mode= (*sd_flags & O_NONBLOCK) != 0;
*sd_flags = (block) ? *sd_flags & ~O_NONBLOCK : *sd_flags | O_NONBLOCK;
#elif defined(O_NDELAY)
*previous_mode= (*sd_flags & O_NODELAY) != 0;
*sd_flags = (block) ? *sd_flags & ~O_NODELAY : *sd_flags | O_NODELAY;
#elif defined(FNDELAY)
*previous_mode= (*sd_flags & O_FNDELAY) != 0;
*sd_flags = (block) ? *sd_flags & ~O_FNDELAY : *sd_flags | O_FNDELAY;
#else
#error socket blocking is not supported on this platform
#endif
{
ulong arg;
int old_fcntl=vio->fcntl_mode;
if (set_blocking_mode)
{
arg = 0;
vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
}
else
{
arg = 1;
vio->fcntl_mode |= O_NONBLOCK; /* set bit */
}
if (old_fcntl != vio->fcntl_mode)
r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg);
if (fcntl(sock, F_SETFL, *sd_flags) == -1)
{
vio->fcntl_mode= save_flags;
return errno;
}
#endif /* !defined(_WIN32) && !defined(__EMX__) */
DBUG_RETURN(r);
#endif
return 0;
}
my_bool
@@ -527,7 +689,7 @@ void vio_in_addr(Vio *vio, struct in_addr *in)
/* Return 0 if there is data to be read */
/*
my_bool vio_poll_read(Vio *vio,uint timeout)
{
#ifndef HAVE_POLL
@@ -541,10 +703,11 @@ my_bool vio_poll_read(Vio *vio,uint timeout)
fds.revents=0;
if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
{
DBUG_RETURN(res < 0 ? 0 : 1); /* Don't return 1 on errors */
DBUG_RETURN(res < 0 ? 0 : 1);
}
DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
#endif
}
*/
#endif /* HAVE_VIO */

View File

@@ -79,7 +79,7 @@ wait_for_mysql(MYSQL *mysql, int status)
#else
struct pollfd pfd;
int timeout;
int res;
int res= -1;
pfd.fd= mysql_get_socket(mysql);
pfd.events=
@@ -87,10 +87,12 @@ wait_for_mysql(MYSQL *mysql, int status)
(status & MYSQL_WAIT_WRITE ? POLLOUT : 0) |
(status & MYSQL_WAIT_EXCEPT ? POLLPRI : 0);
if (status & MYSQL_WAIT_TIMEOUT)
timeout= 1000*mysql_get_timeout_value(mysql);
timeout= mysql_get_timeout_value_ms(mysql);
else
timeout= -1;
res= poll(&pfd, 1, timeout);
do {
res= poll(&pfd, 1, timeout);
} while (res == -1 && errno == EINTR);
if (res == 0)
return MYSQL_WAIT_TIMEOUT;
else if (res < 0)
@@ -121,60 +123,70 @@ static int async1(MYSQL *my)
MYSQL_RES *res;
MYSQL_ROW row;
int status;
uint default_timeout;
int i;
mysql_init(&mysql);
mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp");
/* Returns 0 when done, else flag for what to wait for when need to block. */
status= mysql_real_connect_start(&ret, &mysql, hostname, username, password, NULL,
0, NULL, 0);
while (status)
for (i=0; i < 100; i++)
{
status= wait_for_mysql(&mysql, status);
status= mysql_real_connect_cont(&ret, &mysql, status);
}
FAIL_IF(!ret, "Failed to mysql_real_connect()");
mysql_init(&mysql);
mysql_options(&mysql, MYSQL_OPT_NONBLOCK, 0);
status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS"));
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_real_query_cont(&err, &mysql, status);
}
FAIL_IF(err, "mysql_real_query() returns error");
/* set timeouts to 300 microseconds */
default_timeout= 300;
mysql_options(&mysql, MYSQL_OPT_READ_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_OPT_CONNECT_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_OPT_WRITE_TIMEOUT, &default_timeout);
mysql_options(&mysql, MYSQL_READ_DEFAULT_GROUP, "myapp");
/* This method cannot block. */
res= mysql_use_result(&mysql);
FAIL_IF(!res, "mysql_use_result() returns error");
for (;;)
{
status= mysql_fetch_row_start(&row, res);
/* Returns 0 when done, else flag for what to wait for when need to block. */
status= mysql_real_connect_start(&ret, &mysql, hostname, username, password, NULL,
0, NULL, 0);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_fetch_row_cont(&row, res, status);
status= mysql_real_connect_cont(&ret, &mysql, status);
}
if (!row)
break;
diag("%s: %s", row[0], row[1]);
}
FAIL_IF(mysql_errno(&mysql), "Got error while retrieving rows");
mysql_free_result(res);
FAIL_IF(!ret, "Failed to mysql_real_connect()");
/*
mysql_close() sends a COM_QUIT packet, and so in principle could block
waiting for the socket to accept the data.
In practise, for many applications it will probably be fine to use the
blocking mysql_close().
*/
status= mysql_close_start(&mysql);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_close_cont(&mysql, status);
status= mysql_real_query_start(&err, &mysql, SL("SHOW STATUS"));
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_real_query_cont(&err, &mysql, status);
}
FAIL_IF(err, "mysql_real_query() returns error");
/* This method cannot block. */
res= mysql_use_result(&mysql);
FAIL_IF(!res, "mysql_use_result() returns error");
for (;;)
{
status= mysql_fetch_row_start(&row, res);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_fetch_row_cont(&row, res, status);
}
if (!row)
break;
}
FAIL_IF(mysql_errno(&mysql), "Got error while retrieving rows");
mysql_free_result(res);
/*
mysql_close() sends a COM_QUIT packet, and so in principle could block
waiting for the socket to accept the data.
In practise, for many applications it will probably be fine to use the
blocking mysql_close().
*/
status= mysql_close_start(&mysql);
while (status)
{
status= wait_for_mysql(&mysql, status);
status= mysql_close_cont(&mysql, status);
}
}
return OK;
}

View File

@@ -142,7 +142,7 @@ static int test_conc70(MYSQL *my)
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB)");
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB) engine=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");
@@ -188,7 +188,7 @@ static int test_conc68(MYSQL *my)
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB)");
rc= mysql_query(mysql, "CREATE TABLE t1 (a LONGBLOB) ENGINE=MyISAM");
check_mysql_rc(rc, mysql);
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (REPEAT('A', 1024 * 1024 * 20))");

View File

@@ -12,6 +12,4 @@ openssl req -x509 -newkey rsa:1024 \
openssl rsa -in client-key-enc.pem -out client-key.pem \
-passin pass:qwerty -passout pass:
cat server-cert.pem client-cert.pem > ca.pem
cat client-key.pem client-cert.pem ca.pem > combined.pem
cat server-cert.pem client-cert.pem > ca-cert.pem

View File

@@ -922,6 +922,14 @@ static int test_connect_attrs(MYSQL *my)
}
result= mysql_store_result(my);
/* MariaDB Connector/C already sent connection attrs after handshake. So if the table is
empty, it indicates that the performance schema is disabled */
if (!mysql_num_rows(result))
{
diag("skip: performance_schema not enabled");
mysql_free_result(result);
return SKIP;
}
mysql_free_result(result);
mysql= mysql_init(NULL);