/* {{{ size_t ma_pvio_read_async */ static size_t ma_pvio_read_async(MARIADB_PVIO *pvio, uchar *buffer, size_t length) { ssize_t res; struct mysql_async_context *b= pvio->mysql->options.extension->async_context; int timeout= pvio->timeout[PVIO_READ_TIMEOUT]; if (!pvio->methods->async_read) { PVIO_SET_ERROR(pvio->mysql, CR_ASYNC_NOT_SUPPORTED, unknown_sqlstate, 0); return -1; } for (;;) { if (pvio->methods->async_read) res= pvio->methods->async_read(pvio, buffer, length); if (res >= 0 || IS_BLOCKING_ERROR()) return res; b->events_to_wait_for= MYSQL_WAIT_READ; if (timeout >= 0) { b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; b->timeout_value= timeout; } if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); if (b->events_occured & MYSQL_WAIT_TIMEOUT) return -1; } }
/* {{{ ma_pvio_wait_async */ static my_bool ma_pvio_wait_async(struct mysql_async_context *b, enum enum_pvio_io_event event, int timeout) { switch (event) { case VIO_IO_EVENT_READ: b->events_to_wait_for = MYSQL_WAIT_READ; break; case VIO_IO_EVENT_WRITE: b->events_to_wait_for = MYSQL_WAIT_WRITE; break; case VIO_IO_EVENT_CONNECT: b->events_to_wait_for = MYSQL_WAIT_WRITE | IF_WIN(0, MYSQL_WAIT_EXCEPT); break; } if (timeout >= 0) { b->events_to_wait_for |= MYSQL_WAIT_TIMEOUT; b->timeout_value= timeout; } if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); return (b->events_occured & MYSQL_WAIT_TIMEOUT) ? 0 : 1; }
/* {{{ size_t ma_pvio_write_async */ static size_t ma_pvio_write_async(MARIADB_PVIO *pvio, const uchar *buffer, size_t length) { ssize_t res; struct mysql_async_context *b= pvio->mysql->options.extension->async_context; int timeout= pvio->timeout[PVIO_WRITE_TIMEOUT]; for (;;) { if (pvio->methods->async_write) res= pvio->methods->async_write(pvio, buffer, length); if (res >= 0 || IS_BLOCKING_ERROR()) return res; b->events_to_wait_for= MYSQL_WAIT_WRITE; if (timeout >= 0) { b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; b->timeout_value= timeout; } if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); if (b->events_occured & MYSQL_WAIT_TIMEOUT) return -1; } }
static my_bool my_ssl_async_check_result(int res, struct mysql_async_context *b, SSL *ssl) { int ssl_err; b->events_to_wait_for= 0; if (res >= 0) return 1; ssl_err= SSL_get_error(ssl, res); if (ssl_err == SSL_ERROR_WANT_READ) b->events_to_wait_for|= MYSQL_WAIT_READ; else if (ssl_err == SSL_ERROR_WANT_WRITE) b->events_to_wait_for|= MYSQL_WAIT_WRITE; else return 1; if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); return 0; }
/* Asynchronous connect(); socket must already be set non-blocking. */ int my_connect_async(struct mysql_async_context *b, my_socket fd, const struct sockaddr *name, uint namelen, int vio_timeout) { int res; size_socket s_err_size; /* Make the socket non-blocking. */ #ifdef __WIN__ ulong arg= 1; ioctlsocket(fd, FIONBIO, (void *)&arg); #else fcntl(fd, F_SETFL, O_NONBLOCK); #endif b->events_to_wait_for= 0; /* Start to connect asynchronously. If this will block, we suspend the call and return control to the application context. The application will then resume us when the socket polls ready for write, indicating that the connection attempt completed. */ res= connect(fd, name, namelen); if (res != 0) { #ifdef __WIN__ int wsa_err= WSAGetLastError(); if (wsa_err != WSAEWOULDBLOCK) return res; b->events_to_wait_for|= MYSQL_WAIT_EXCEPT; #else int err= errno; if (err != EINPROGRESS && err != EALREADY && err != EAGAIN) return res; #endif b->events_to_wait_for|= MYSQL_WAIT_WRITE; if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; } else b->timeout_value= 0; if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); if (b->events_occurred & MYSQL_WAIT_TIMEOUT) return -1; s_err_size= sizeof(res); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*) &res, &s_err_size) != 0) return -1; if (res) { errno= res; return -1; } } return res; }
/* Asynchronous connect(); socket must already be set non-blocking. */ int my_connect_async(MARIADB_PVIO *pvio, const struct sockaddr *name, uint namelen, int vio_timeout) { int res; size_socket s_err_size; struct mysql_async_context *b= pvio->mysql->options.extension->async_context; my_socket sock; ma_pvio_get_handle(pvio, &sock); /* Make the socket non-blocking. */ ma_pvio_blocking(pvio, 0, 0); b->events_to_wait_for= 0; /* Start to connect asynchronously. If this will block, we suspend the call and return control to the application context. The application will then resume us when the socket polls ready for write, indicating that the connection attempt completed. */ res= connect(sock, name, namelen); if (res != 0) { #ifdef _WIN32 int wsa_err= WSAGetLastError(); if (wsa_err != WSAEWOULDBLOCK) return res; b->events_to_wait_for|= MYSQL_WAIT_EXCEPT; #else int err= errno; if (err != EINPROGRESS && err != EALREADY && err != EAGAIN) return res; #endif b->events_to_wait_for|= MYSQL_WAIT_WRITE; if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; } else b->timeout_value= 0; if (b->suspend_resume_hook) (*b->suspend_resume_hook)(TRUE, b->suspend_resume_hook_user_data); my_context_yield(&b->async_context); if (b->suspend_resume_hook) (*b->suspend_resume_hook)(FALSE, b->suspend_resume_hook_user_data); if (b->events_occured & MYSQL_WAIT_TIMEOUT) return -1; s_err_size= sizeof(res); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*) &res, &s_err_size) != 0) return -1; if (res) { errno= res; return -1; } } return res; }