diff --git a/include/violite.h b/include/violite.h index 61a2e0fe..cc66a775 100644 --- a/include/violite.h +++ b/include/violite.h @@ -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 diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index aff94cd3..4d5c9509 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -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), diff --git a/libmariadb/libmariadb_exports.def b/libmariadb/libmariadb_exports.def index 94a2ecec..176f447a 100644 --- a/libmariadb/libmariadb_exports.def +++ b/libmariadb/libmariadb_exports.def @@ -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 diff --git a/libmariadb/ma_secure.c b/libmariadb/ma_secure.c index 967d846c..39a1794c 100644 --- a/libmariadb/ma_secure.c +++ b/libmariadb/ma_secure.c @@ -25,6 +25,8 @@ #include #include #include +#include +#include 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); } diff --git a/libmariadb/mysql_async.c b/libmariadb/mysql_async.c index 57c33aab..5606e52c 100644 --- a/libmariadb/mysql_async.c +++ b/libmariadb/mysql_async.c @@ -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, diff --git a/libmariadb/net.c b/libmariadb/net.c index 32e0ff83..19463b7a 100644 --- a/libmariadb/net.c +++ b/libmariadb/net.c @@ -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); diff --git a/libmariadb/strtoll.c b/libmariadb/strtoll.c index ba72a83f..a71996bc 100644 --- a/libmariadb/strtoll.c +++ b/libmariadb/strtoll.c @@ -19,7 +19,7 @@ #include #include -#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 */ diff --git a/libmariadb/strtoull.c b/libmariadb/strtoull.c index 104885e7..c33e911f 100644 --- a/libmariadb/strtoull.c +++ b/libmariadb/strtoull.c @@ -19,7 +19,7 @@ #include #include -#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" diff --git a/libmariadb/violite.c b/libmariadb/violite.c index 22c1438e..5686392e 100644 --- a/libmariadb/violite.c +++ b/libmariadb/violite.c @@ -69,6 +69,14 @@ #define SOCKET_EWOULDBLOCK SOCKET_EAGAIN #endif +#include +#include + +#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 */ diff --git a/unittest/libmariadb/async.c b/unittest/libmariadb/async.c index 336e43c2..fbdbc53e 100644 --- a/unittest/libmariadb/async.c +++ b/unittest/libmariadb/async.c @@ -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; } diff --git a/unittest/libmariadb/basic-t.c b/unittest/libmariadb/basic-t.c index 46041da0..c99ad24b 100644 --- a/unittest/libmariadb/basic-t.c +++ b/unittest/libmariadb/basic-t.c @@ -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))"); diff --git a/unittest/libmariadb/certs/create_certs.sh b/unittest/libmariadb/certs/create_certs.sh index a5d4600d..47ea98e8 100755 --- a/unittest/libmariadb/certs/create_certs.sh +++ b/unittest/libmariadb/certs/create_certs.sh @@ -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 diff --git a/unittest/libmariadb/misc.c b/unittest/libmariadb/misc.c index f649d37b..4a246575 100644 --- a/unittest/libmariadb/misc.c +++ b/unittest/libmariadb/misc.c @@ -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);