"Fossies" - the Fresh Open Source Software Archive

Member "mariadb-connector-c-3.0.8-src/plugins/pvio/pvio_npipe.c" (18 Dec 2018, 9480 Bytes) of package /linux/misc/mariadb-connector-c-3.0.8-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "pvio_npipe.c": 3.0.6-src_vs_3.0.7-src.

    1 /************************************************************************************
    2     Copyright (C) 2015 Georg Richter and MariaDB Corporation AB
    3    
    4    This library is free software; you can redistribute it and/or
    5    modify it under the terms of the GNU Library General Public
    6    License as published by the Free Software Foundation; either
    7    version 2 of the License, or (at your option) any later version.
    8    
    9    This library is distributed in the hope that it will be useful,
   10    but WITHOUT ANY WARRANTY; without even the implied warranty of
   11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12    Library General Public License for more details.
   13    
   14    You should have received a copy of the GNU Library General Public
   15    License along with this library; if not see <http://www.gnu.org/licenses>
   16    or write to the Free Software Foundation, Inc., 
   17    51 Franklin St., Fifth Floor, Boston, MA 02110, USA
   18 
   19 *************************************************************************************/
   20 
   21 /* MariaDB virtual IO plugin for Windows named pipe communication */
   22 
   23 #ifdef _WIN32
   24 
   25 #include <ma_global.h>
   26 #include <ma_sys.h>
   27 #include <errmsg.h>
   28 #include <mysql.h>
   29 #include <mysql/client_plugin.h>
   30 #include <string.h>
   31 #include <ma_string.h>
   32 
   33 /* Function prototypes */
   34 my_bool pvio_npipe_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout);
   35 int pvio_npipe_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type);
   36 ssize_t pvio_npipe_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length);
   37 ssize_t pvio_npipe_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length);
   38 
   39 my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo);
   40 my_bool pvio_npipe_close(MARIADB_PVIO *pvio);
   41 int pvio_npipe_fast_send(MARIADB_PVIO *pvio);
   42 int pvio_npipe_keepalive(MARIADB_PVIO *pvio);
   43 my_bool pvio_npipe_get_handle(MARIADB_PVIO *pvio, void *handle);
   44 my_bool pvio_npipe_is_blocking(MARIADB_PVIO *pvio);
   45 int pvio_npipe_shutdown(MARIADB_PVIO *pvio);
   46 my_bool pvio_npipe_is_alive(MARIADB_PVIO *pvio);
   47 
   48 struct st_ma_pvio_methods pvio_npipe_methods= {
   49   pvio_npipe_set_timeout,
   50   pvio_npipe_get_timeout,
   51   pvio_npipe_read,
   52   NULL,
   53   pvio_npipe_write,
   54   NULL,
   55   NULL,
   56   NULL,
   57   pvio_npipe_connect,
   58   pvio_npipe_close,
   59   pvio_npipe_fast_send,
   60   pvio_npipe_keepalive,
   61   pvio_npipe_get_handle,
   62   pvio_npipe_is_blocking,
   63   pvio_npipe_is_alive,
   64   NULL,
   65   pvio_npipe_shutdown
   66 };
   67 
   68 #ifndef PLUGIN_DYNAMIC
   69 MARIADB_PVIO_PLUGIN pvio_npipe_client_plugin =
   70 #else
   71 MARIADB_PVIO_PLUGIN _mysql_client_plugin_declaration_ =
   72 #endif
   73 {
   74   MARIADB_CLIENT_PVIO_PLUGIN,
   75   MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION,
   76   "pvio_npipe",
   77   "Georg Richter",
   78   "MariaDB virtual IO plugin for named pipe connection",
   79   {1, 0, 0},
   80   "LGPL",
   81   NULL,
   82   NULL,
   83   NULL,
   84   NULL,
   85   &pvio_npipe_methods
   86 };
   87 
   88 struct st_pvio_npipe {
   89   HANDLE pipe;
   90   OVERLAPPED overlapped;
   91   MYSQL *mysql;
   92 };
   93 
   94 my_bool pvio_npipe_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
   95 {
   96   int timeout_ms;
   97 
   98   if (!pvio)
   99     return 1;
  100   if (timeout > INT_MAX/1000)
  101     timeout_ms= -1;
  102   else if (timeout <=0)
  103     timeout_ms= -1;
  104   else
  105     timeout_ms = timeout*100;
  106 
  107   pvio->timeout[type]= (timeout > 0) ? timeout * 1000 : -1;
  108   return 0;
  109 }
  110 
  111 int pvio_npipe_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type)
  112 {
  113   if (!pvio)
  114     return -1;
  115   return pvio->timeout[type] / 1000;
  116 }
  117 
  118 static BOOL complete_io(HANDLE file, OVERLAPPED *ov, BOOL ret, DWORD timeout, DWORD *size)
  119 {
  120   if (ret)
  121     timeout = 0; /* IO completed successfully, do not WaitForSingleObject */
  122   else
  123   {
  124     assert(timeout);
  125     if (GetLastError() != ERROR_IO_PENDING)
  126       return FALSE;
  127   }
  128 
  129   if (timeout)
  130   {
  131     HANDLE wait_handle= ov->hEvent;
  132     assert(wait_handle && (wait_handle != INVALID_HANDLE_VALUE));
  133 
  134     DWORD wait_ret= WaitForSingleObject(wait_handle, timeout);
  135     switch (wait_ret)
  136     {
  137       case WAIT_OBJECT_0:
  138         break;
  139       case WAIT_TIMEOUT:
  140         CancelIoEx(file, ov);
  141         SetLastError(ERROR_TIMEOUT);
  142         return FALSE;
  143       default:
  144         /* WAIT_ABANDONED or WAIT_FAILED unexpected. */
  145         assert(0);
  146         return FALSE;
  147     }
  148   }
  149 
  150   return GetOverlappedResult(file, ov, size, FALSE);
  151 }
  152 
  153 ssize_t pvio_npipe_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
  154 {
  155   BOOL ret;
  156   ssize_t r= -1;
  157   struct st_pvio_npipe *cpipe= NULL;
  158   DWORD size;
  159 
  160   if (!pvio || !pvio->data)
  161     return -1;
  162 
  163   cpipe= (struct st_pvio_npipe *)pvio->data;
  164 
  165   ret= ReadFile(cpipe->pipe, buffer, (DWORD)length, NULL, &cpipe->overlapped);
  166   ret= complete_io(cpipe->pipe, &cpipe->overlapped, ret, pvio->timeout[PVIO_READ_TIMEOUT], &size);
  167   r= ret? (ssize_t) size:-1;
  168 
  169   return r;
  170 }
  171 
  172 ssize_t pvio_npipe_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
  173 {
  174   ssize_t r= -1;
  175   struct st_pvio_npipe *cpipe= NULL;
  176   BOOL ret;
  177   DWORD size;
  178 
  179   if (!pvio || !pvio->data)
  180     return -1;
  181 
  182   cpipe= (struct st_pvio_npipe *)pvio->data;
  183 
  184   ret= WriteFile(cpipe->pipe, buffer, (DWORD)length, NULL , &cpipe->overlapped);
  185   ret= complete_io(cpipe->pipe, &cpipe->overlapped, ret, pvio->timeout[PVIO_WRITE_TIMEOUT], &size);
  186   r= ret ? (ssize_t)size : -1;
  187   return r;
  188 }
  189 
  190 
  191 int pvio_npipe_keepalive(MARIADB_PVIO *pvio)
  192 {
  193   /* keep alive is used for TCP/IP connections only */
  194   return 0;
  195 }
  196 
  197 int pvio_npipe_fast_send(MARIADB_PVIO *pvio)
  198 {
  199   /* not supported */
  200   return 0;
  201 }
  202 my_bool pvio_npipe_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
  203 {
  204   struct st_pvio_npipe *cpipe= NULL;
  205 
  206   if (!pvio || !cinfo)
  207     return 1;
  208 
  209   /* if connect timeout is set, we will overwrite read/write timeout */
  210   if (pvio->timeout[PVIO_CONNECT_TIMEOUT])
  211   {
  212     pvio->timeout[PVIO_READ_TIMEOUT]= pvio->timeout[PVIO_WRITE_TIMEOUT]= pvio->timeout[PVIO_CONNECT_TIMEOUT];
  213   }
  214 
  215   if (!(cpipe= (struct st_pvio_npipe *)LocalAlloc(LMEM_ZEROINIT, sizeof(struct st_pvio_npipe))))
  216   {
  217     PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, "HY000", 0, "");
  218     return 1;
  219   }
  220   memset(cpipe, 0, sizeof(struct st_pvio_npipe));
  221   pvio->data= (void *)cpipe;
  222   cpipe->pipe= INVALID_HANDLE_VALUE;
  223   pvio->mysql= cinfo->mysql;
  224   pvio->type= cinfo->type;
  225 
  226   if (cinfo->type == PVIO_TYPE_NAMEDPIPE)
  227   {
  228     char szPipeName[MAX_PATH];
  229     ULONGLONG deadline;
  230     LONGLONG wait_ms;
  231     DWORD backoff= 0; /* Avoid busy wait if ERROR_PIPE_BUSY.*/
  232     if ( ! cinfo->unix_socket || (cinfo->unix_socket)[0] == 0x00)
  233       cinfo->unix_socket = MARIADB_NAMEDPIPE;
  234     if (!cinfo->host || !strcmp(cinfo->host,LOCAL_HOST))
  235       cinfo->host=LOCAL_HOST_NAMEDPIPE;
  236 
  237     szPipeName[MAX_PATH - 1]= 0;
  238     snprintf(szPipeName, MAX_PATH - 1, "\\\\%s\\pipe\\%s", cinfo->host, cinfo->unix_socket);
  239 
  240     deadline = GetTickCount64() + pvio->timeout[PVIO_CONNECT_TIMEOUT];
  241     while (1)
  242     {
  243       if ((cpipe->pipe = CreateFile(szPipeName,
  244                                     GENERIC_READ |
  245                                     GENERIC_WRITE,
  246                                     0,               /* no sharing */
  247                                     NULL,            /* default security attributes */
  248                                     OPEN_EXISTING,
  249                                     FILE_FLAG_OVERLAPPED,
  250                                     NULL)) != INVALID_HANDLE_VALUE)
  251         break;
  252 
  253       if (GetLastError() != ERROR_PIPE_BUSY)
  254       {
  255         pvio->set_error(pvio->mysql, CR_NAMEDPIPEOPEN_ERROR, "HY000", 0,
  256                        cinfo->host, cinfo->unix_socket, GetLastError());
  257         goto end;
  258       }
  259 
  260       Sleep(backoff);
  261       if (!backoff)
  262         backoff = 1;
  263 
  264       wait_ms = deadline - GetTickCount64();
  265       if (wait_ms > INFINITE)
  266         wait_ms = INFINITE;
  267 
  268       if ((wait_ms <= 0) || !WaitNamedPipe(szPipeName, (DWORD)wait_ms))
  269       {
  270         pvio->set_error(pvio->mysql, CR_NAMEDPIPEWAIT_ERROR, "HY000", 0,
  271                        cinfo->host, cinfo->unix_socket, ERROR_TIMEOUT);
  272         goto end;
  273       }
  274     }
  275 
  276 
  277     if (!(cpipe->overlapped.hEvent= CreateEvent(NULL, FALSE, FALSE, NULL)))
  278     {
  279       pvio->set_error(pvio->mysql, CR_EVENT_CREATE_FAILED, "HY000", 0,
  280                      GetLastError());
  281       goto end;
  282     }
  283     return 0;
  284   }
  285 end:
  286   if (cpipe)
  287   {
  288     if (cpipe->pipe != INVALID_HANDLE_VALUE)
  289       CloseHandle(cpipe->pipe);
  290     LocalFree(cpipe);
  291     pvio->data= NULL;
  292   }
  293   return 1;
  294 }
  295 
  296 my_bool pvio_npipe_close(MARIADB_PVIO *pvio)
  297 {
  298   struct st_pvio_npipe *cpipe= NULL;
  299   int r= 0;
  300 
  301   if (!pvio)
  302     return 1;
  303 
  304   if (pvio->data)
  305   {
  306     cpipe= (struct st_pvio_npipe *)pvio->data;
  307     CloseHandle(cpipe->overlapped.hEvent);
  308     if (cpipe->pipe != INVALID_HANDLE_VALUE)
  309     {
  310       CloseHandle(cpipe->pipe);
  311       cpipe->pipe= INVALID_HANDLE_VALUE;
  312     }
  313     LocalFree(pvio->data);
  314     pvio->data= NULL;
  315   }
  316   return r;
  317 }
  318 
  319 my_bool pvio_npipe_get_handle(MARIADB_PVIO *pvio, void *handle)
  320 {
  321   if (pvio && pvio->data)
  322   {
  323     *(HANDLE *)handle= ((struct st_pvio_npipe *)pvio->data)->pipe;
  324     return 0;
  325   }
  326   return 1;
  327 } 
  328 
  329 my_bool pvio_npipe_is_blocking(MARIADB_PVIO *pvio)
  330 {
  331   return 1;
  332 }
  333 
  334 int pvio_npipe_shutdown(MARIADB_PVIO *pvio)
  335 {
  336   HANDLE h;
  337   if (pvio_npipe_get_handle(pvio, &h) == 0)
  338   {
  339     return(CancelIoEx(h, NULL) ? 0 : 1);
  340   }
  341   return 1;
  342 }
  343 
  344 my_bool pvio_npipe_is_alive(MARIADB_PVIO *pvio)
  345 {
  346   HANDLE handle;
  347   if (!pvio || !pvio->data)
  348     return FALSE;
  349     handle= ((struct st_pvio_npipe *)pvio->data)->pipe;
  350   /* Copy data from named pipe without removing it */
  351   if (PeekNamedPipe(handle, NULL, 0, NULL, NULL, NULL))
  352     return TRUE;
  353   return test(GetLastError() != ERROR_BROKEN_PIPE);
  354 }
  355 #endif