"Fossies" - the Fresh Open Source Software Archive

Member "mariadb-connector-c-3.0.9-src/plugins/pvio/pvio_shmem.c" (8 Feb 2019, 12916 Bytes) of package /linux/misc/mariadb-connector-c-3.0.9-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_shmem.c": 3.0.5-src_vs_3.0.6-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 /* MariaDB virtual IO plugin for Windows shared memory communication */
   21 
   22 #ifdef _WIN32
   23 
   24 #include <ma_global.h>
   25 #include <ma_sys.h>
   26 #include <errmsg.h>
   27 #include <mysql.h>
   28 #include <mysql/client_plugin.h>
   29 #include <string.h>
   30 #include <ma_string.h>
   31 
   32 #define PVIO_SHM_BUFFER_SIZE 16000 + 4
   33 
   34 my_bool pvio_shm_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout);
   35 int pvio_shm_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type);
   36 ssize_t pvio_shm_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length);
   37 ssize_t pvio_shm_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length);
   38 int pvio_shm_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout);
   39 int pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool value, my_bool *old_value);
   40 my_bool pvio_shm_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo);
   41 my_bool pvio_shm_close(MARIADB_PVIO *pvio);
   42 int pvio_shm_shutdown(MARIADB_PVIO *pvio);
   43 my_bool pvio_shm_is_alive(MARIADB_PVIO *pvio);
   44 my_bool pvio_shm_get_handle(MARIADB_PVIO *pvio, void *handle);
   45 
   46 struct st_ma_pvio_methods pvio_shm_methods= {
   47   pvio_shm_set_timeout,
   48   pvio_shm_get_timeout,
   49   pvio_shm_read,
   50   NULL,
   51   pvio_shm_write,
   52   NULL,
   53   pvio_shm_wait_io_or_timeout,
   54   pvio_shm_blocking,
   55   pvio_shm_connect,
   56   pvio_shm_close,
   57   NULL,
   58   NULL,
   59   pvio_shm_get_handle,
   60   NULL,
   61   pvio_shm_is_alive,
   62   NULL,
   63   pvio_shm_shutdown
   64 };
   65 
   66 #ifndef PLUGIN_DYNAMIC
   67 MARIADB_PVIO_PLUGIN pvio_shmem_client_plugin=
   68 #else
   69 MARIADB_PVIO_PLUGIN _mysql_client_plugin_declaration_=
   70 #endif
   71 {
   72   MARIADB_CLIENT_PVIO_PLUGIN,
   73   MARIADB_CLIENT_PVIO_PLUGIN_INTERFACE_VERSION,
   74   "pvio_shmem",
   75   "Georg Richter",
   76   "MariaDB virtual IO plugin for Windows shared memory communication",
   77   {1, 0, 0},
   78   "LGPPL",
   79   NULL,
   80   NULL,
   81   NULL,
   82   NULL,
   83   &pvio_shm_methods,
   84  
   85 };
   86 
   87 enum enum_shm_events
   88 {
   89   PVIO_SHM_SERVER_WROTE= 0,
   90   PVIO_SHM_SERVER_READ,
   91   PVIO_SHM_CLIENT_WROTE,
   92   PVIO_SHM_CLIENT_READ,
   93   PVIO_SHM_CONNECTION_CLOSED
   94 };
   95 
   96 typedef struct {
   97   HANDLE event[5];
   98   HANDLE file_map;
   99   LPVOID *map;
  100   char *read_pos;
  101   size_t buffer_size;
  102 } PVIO_SHM;
  103 
  104 char *StrEvent[]= {"SERVER_WROTE", "SERVER_READ", "CLIENT_WROTE", "CLIENT_READ", "CONNECTION_CLOSED"};
  105 
  106 struct st_pvio_shm {
  107   char *shm_name;
  108 };
  109 
  110 my_bool pvio_shm_set_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type, int timeout)
  111 {
  112   if (!pvio)
  113     return 1;
  114   pvio->timeout[type]= (timeout > 0) ? timeout * 1000 : INFINITE;
  115   return 0;
  116 }
  117 
  118 int pvio_shm_get_timeout(MARIADB_PVIO *pvio, enum enum_pvio_timeout type)
  119 {
  120   if (!pvio)
  121     return -1;
  122   return pvio->timeout[type] / 1000;
  123 }
  124 
  125 ssize_t pvio_shm_read(MARIADB_PVIO *pvio, uchar *buffer, size_t length)
  126 {
  127   PVIO_SHM *pvio_shm= (PVIO_SHM *)pvio->data;
  128   size_t copy_size= length;
  129   HANDLE events[2];
  130   
  131   if (!pvio_shm)
  132     return -1;
  133 
  134   /* we need to wait for write and close events */
  135   if (!pvio_shm->buffer_size)
  136   {
  137     events[0]= pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED];
  138     events[1]= pvio_shm->event[PVIO_SHM_SERVER_WROTE];
  139 
  140     switch(WaitForMultipleObjects(2, events, 0, pvio->timeout[PVIO_READ_TIMEOUT]))
  141     {
  142     case WAIT_OBJECT_0: /* server closed connection */
  143       SetLastError(ERROR_GRACEFUL_DISCONNECT);
  144       return -1;
  145     case WAIT_OBJECT_0 +1: /* server_wrote event */
  146       break;
  147     case WAIT_TIMEOUT:
  148       SetLastError(ETIMEDOUT);
  149     default:
  150       return -1;
  151     }
  152     /* server sent data */
  153     pvio_shm->read_pos= (char *)pvio_shm->map;
  154     pvio_shm->buffer_size= uint4korr(pvio_shm->read_pos);
  155     pvio_shm->read_pos+= 4;
  156   }
  157 
  158   if (pvio_shm->buffer_size < copy_size)
  159     copy_size= pvio_shm->buffer_size;
  160   
  161   if (copy_size)
  162   {
  163     memcpy(buffer, (uchar *)pvio_shm->read_pos, pvio_shm->buffer_size);
  164     pvio_shm->read_pos+= copy_size;
  165     pvio_shm->buffer_size-= copy_size;
  166   }
  167 
  168   /* we need to read again */
  169   if (!pvio_shm->buffer_size)
  170     if (!SetEvent(pvio_shm->event[PVIO_SHM_CLIENT_READ]))
  171       return -1;
  172 
  173   return (ssize_t)copy_size;
  174 }
  175 
  176 ssize_t pvio_shm_write(MARIADB_PVIO *pvio, const uchar *buffer, size_t length)
  177 {
  178   HANDLE events[2];
  179   PVIO_SHM *pvio_shm= (PVIO_SHM *)pvio->data;
  180   size_t bytes_to_write= length;
  181   uchar *buffer_pos= (uchar *)buffer;
  182   
  183   if (!pvio_shm)
  184     return -1;
  185 
  186   events[0]= pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED];
  187   events[1]= pvio_shm->event[PVIO_SHM_SERVER_READ];
  188 
  189   while (bytes_to_write)
  190   {
  191     size_t pkt_length;
  192     switch (WaitForMultipleObjects(2, events, 0, pvio->timeout[PVIO_WRITE_TIMEOUT])) {
  193     case WAIT_OBJECT_0: /* connection closed */
  194       SetLastError(ERROR_GRACEFUL_DISCONNECT);
  195       return -1;
  196     case WAIT_OBJECT_0 + 1: /* server_read */
  197       break;
  198     case WAIT_TIMEOUT:
  199       SetLastError(ETIMEDOUT);
  200     default:
  201       return -1;
  202     }
  203     pkt_length= MIN(PVIO_SHM_BUFFER_SIZE, length);
  204     int4store(pvio_shm->map, pkt_length);
  205     memcpy((uchar *)pvio_shm->map + 4, buffer_pos, length);
  206     buffer_pos+= length;
  207     bytes_to_write-= length;
  208 
  209     if (!SetEvent(pvio_shm->event[PVIO_SHM_CLIENT_WROTE]))
  210       return -1;
  211   }
  212   return (ssize_t)length;
  213 }
  214 
  215 
  216 int pvio_shm_wait_io_or_timeout(MARIADB_PVIO *pvio, my_bool is_read, int timeout)
  217 {
  218   return 0;
  219 }
  220 
  221 int pvio_shm_blocking(MARIADB_PVIO *pvio, my_bool block, my_bool *previous_mode)
  222 {
  223   /* not supported */
  224   return 0;
  225 }
  226 
  227 int pvio_shm_keepalive(MARIADB_PVIO *pvio)
  228 {
  229   /* not supported */
  230   return 0;
  231 }
  232 
  233 int pvio_shm_fast_send(MARIADB_PVIO *pvio)
  234 {
  235   /* not supported */
  236   return 0;
  237 }
  238 
  239 my_bool pvio_shm_connect(MARIADB_PVIO *pvio, MA_PVIO_CINFO *cinfo)
  240 {
  241   const char *base_memory_name;
  242   char *prefixes[]= {"", "Global\\", NULL};
  243   char *shm_name, *shm_suffix, *shm_prefix;
  244   uchar i= 0;
  245   int len;
  246   int cid;
  247   DWORD dwDesiredAccess= EVENT_MODIFY_STATE | SYNCHRONIZE;
  248   HANDLE hdlConnectRequest= NULL,
  249          hdlConnectRequestAnswer= NULL,
  250          file_map= NULL;
  251   LPVOID map= NULL;
  252   PVIO_SHM *pvio_shm= (PVIO_SHM*)LocalAlloc(LMEM_ZEROINIT, sizeof(PVIO_SHM)); 
  253 
  254   if (!pvio_shm)
  255   {
  256     PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, "HY000", 0, "");
  257     return 0;
  258   }
  259 
  260   /* MariaDB server constructs the event name as follows:
  261      "Global\\base_memory_name" or
  262      "\\base_memory_name"
  263    */
  264  
  265 
  266   base_memory_name= (cinfo->host) ? cinfo->host : SHM_DEFAULT_NAME;
  267 
  268   if (!(shm_name= (char *)LocalAlloc(LMEM_ZEROINIT, strlen(base_memory_name) + 40)))
  269   {
  270     PVIO_SET_ERROR(cinfo->mysql, CR_OUT_OF_MEMORY, "HY000", 0, "");
  271     goto error;
  272   }
  273 
  274   /* iterate through prefixes */
  275   while (prefixes[i])
  276   {
  277     len= sprintf(shm_name, "%s%s_", prefixes[i], base_memory_name);
  278     shm_suffix= shm_name + len;
  279     strcpy(shm_suffix, "CONNECT_REQUEST");
  280     if ((hdlConnectRequest= OpenEvent(dwDesiredAccess, 0, shm_name)))
  281     {
  282       /* save prefix to prevent further loop */
  283       shm_prefix= prefixes[i];
  284       break;
  285     }
  286     i++;
  287   }
  288   if (!hdlConnectRequest)
  289   {
  290     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Opening CONNECT_REQUEST event failed", GetLastError());
  291     goto error;
  292   }
  293 
  294   strcpy(shm_suffix, "CONNECT_ANSWER");
  295   if (!(hdlConnectRequestAnswer= OpenEvent(dwDesiredAccess, 0, shm_name)))
  296   {
  297     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Opening CONNECT_ANSWER event failed", GetLastError());
  298     goto error;
  299   }
  300   
  301   /* get connection id, so we can build the filename used for connection */
  302   strcpy(shm_suffix, "CONNECT_DATA");
  303   if (!(file_map= OpenFileMapping(FILE_MAP_WRITE, 0, shm_name)))
  304   {
  305     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "OpenFileMapping failed", GetLastError());
  306     goto error;
  307   }
  308 
  309   /* try to get first 4 bytes, which represents connection_id */
  310   if (!(map= MapViewOfFile(file_map, FILE_MAP_WRITE, 0, 0, sizeof(cid))))
  311   {
  312     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Reading connection_id failed", GetLastError());
  313     goto error;
  314   }
  315 
  316   /* notify server */
  317   if (!SetEvent(hdlConnectRequest))
  318   {
  319     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Failed sending connection request", GetLastError());
  320     goto error;
  321   }
  322 
  323   /* Wait for server answer */
  324   switch(WaitForSingleObject(hdlConnectRequestAnswer, pvio->timeout[PVIO_CONNECT_TIMEOUT])) {
  325   case WAIT_ABANDONED:
  326     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Mutex was not released in time", GetLastError());
  327     goto error;
  328     break;
  329   case WAIT_FAILED:
  330     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Operation wait failed", GetLastError());
  331     goto error;
  332     break;
  333   case WAIT_TIMEOUT:
  334     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Operation timed out", GetLastError());
  335     goto error;
  336     break;
  337   case WAIT_OBJECT_0:
  338     break;
  339   default:
  340     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Wait for server failed", GetLastError());
  341     break;
  342   }
  343 
  344   cid= uint4korr(map);
  345 
  346   len= sprintf(shm_name, "%s%s_%d_", shm_prefix, base_memory_name, cid);
  347   shm_suffix= shm_name + len;
  348   
  349   strcpy(shm_suffix, "DATA");
  350   pvio_shm->file_map= OpenFileMapping(FILE_MAP_WRITE, 0, shm_name);
  351   if (pvio_shm->file_map == NULL)
  352   {
  353     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "OpenFileMapping failed", GetLastError());
  354     goto error;
  355   }
  356   if (!(pvio_shm->map= MapViewOfFile(pvio_shm->file_map, FILE_MAP_WRITE, 0, 0, PVIO_SHM_BUFFER_SIZE)))
  357   {
  358     PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "MapViewOfFile failed", GetLastError());
  359     goto error;
  360   }
  361 
  362   for (i=0; i < 5; i++)
  363   {
  364     strcpy(shm_suffix, StrEvent[i]);
  365     if (!(pvio_shm->event[i]= OpenEvent(dwDesiredAccess, 0, shm_name)))
  366     {
  367       PVIO_SET_ERROR(cinfo->mysql, CR_SHARED_MEMORY_CONNECT_ERROR, "HY000", 0, "Couldn't create event", GetLastError());
  368       goto error;
  369     }
  370   }
  371   /* we will first read from server */
  372   SetEvent(pvio_shm->event[PVIO_SHM_SERVER_READ]);
  373 
  374 error:
  375   if (hdlConnectRequest)
  376     CloseHandle(hdlConnectRequest);
  377   if (hdlConnectRequestAnswer)
  378     CloseHandle(hdlConnectRequestAnswer);
  379   if (shm_name)
  380     LocalFree(shm_name);
  381   if (map)
  382     UnmapViewOfFile(map);
  383   if (file_map)
  384     CloseHandle(file_map);
  385   if (pvio_shm)
  386   {
  387     /* check if all events are set */
  388     if (pvio_shm->event[4])
  389     {
  390       pvio->data= (void *)pvio_shm;
  391       pvio->mysql= cinfo->mysql;
  392       pvio->type= cinfo->type;
  393       pvio_shm->read_pos= (char *)pvio_shm->map;
  394       pvio->mysql->net.pvio= pvio;
  395       return 0;
  396     }
  397     for (i=0;i < 5; i++)
  398       if (pvio_shm->event[i])
  399         CloseHandle(pvio_shm->event[i]);
  400     if (pvio_shm->map)
  401       UnmapViewOfFile(pvio_shm->map);
  402     if (pvio_shm->file_map)
  403       CloseHandle(pvio_shm->file_map);
  404     LocalFree(pvio_shm);
  405   }
  406   return 1;
  407 
  408 }
  409 
  410 my_bool pvio_shm_close(MARIADB_PVIO *pvio)
  411 {
  412   PVIO_SHM *pvio_shm= (PVIO_SHM *)pvio->data;
  413   int i;
  414 
  415   if (!pvio_shm)
  416     return 1;
  417 
  418   /* notify server */
  419   SetEvent(pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED]);
  420 
  421   UnmapViewOfFile(pvio_shm->map);
  422   CloseHandle(pvio_shm->file_map);
  423 
  424   for (i=0; i < 5; i++)
  425     CloseHandle(pvio_shm->event[i]);
  426 
  427   LocalFree(pvio_shm);
  428   pvio->data= NULL;
  429   return 0;
  430 }
  431 
  432 my_bool pvio_shm_get_socket(MARIADB_PVIO *pvio, void *handle)
  433 {
  434   return 1;
  435 } 
  436 
  437 my_bool pvio_shm_is_blocking(MARIADB_PVIO *pvio)
  438 {
  439   return 1;
  440 }
  441 
  442 int pvio_shm_shutdown(MARIADB_PVIO *pvio)
  443 {
  444   PVIO_SHM *pvio_shm= (PVIO_SHM *)pvio->data;
  445   if (pvio_shm)
  446     return (SetEvent(pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED]) ? 0 : 1);
  447   return 1;
  448 }
  449 
  450 my_bool pvio_shm_is_alive(MARIADB_PVIO *pvio)
  451 {
  452   PVIO_SHM *pvio_shm;
  453   if (!pvio || !pvio->data)
  454     return FALSE;
  455   pvio_shm= (PVIO_SHM *)pvio->data;
  456   return WaitForSingleObject(pvio_shm->event[PVIO_SHM_CONNECTION_CLOSED], 0)!=WAIT_OBJECT_0;
  457 }
  458 
  459 my_bool pvio_shm_get_handle(MARIADB_PVIO *pvio, void *handle)
  460 {
  461 
  462   *(HANDLE **)handle= 0;
  463   if (!pvio || !pvio->data)
  464     return FALSE;
  465   *(HANDLE **)handle= ((PVIO_SHM*)pvio->data)->event;
  466   return TRUE;
  467 }
  468 #endif
  469