You've already forked mariadb-connector-c
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:
@@ -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
|
||||
|
@@ -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),
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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"
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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))");
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user