376 lines
12 KiB
C++
376 lines
12 KiB
C++
/*
|
|
Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "shared_memory_connection.h"
|
|
|
|
#include "violite.h" // Vio
|
|
#include "channel_info.h" // Channel_info
|
|
#include "connection_handler_manager.h" // Connection_handler_manager
|
|
#include "log.h" // sql_print_error
|
|
#include "sql_class.h" // THD
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Channel_info_shared_mem implementation
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
This class abstracts the info. about the windows shared memory mode
|
|
of communication with the server.
|
|
*/
|
|
class Channel_info_shared_mem : public Channel_info
|
|
{
|
|
HANDLE m_handle_client_file_map;
|
|
char* m_handle_client_map;
|
|
HANDLE m_event_server_wrote;
|
|
HANDLE m_event_server_read;
|
|
HANDLE m_event_client_wrote;
|
|
HANDLE m_event_client_read;
|
|
HANDLE m_event_conn_closed;
|
|
|
|
protected:
|
|
virtual Vio* create_and_init_vio() const
|
|
{
|
|
return vio_new_win32shared_memory(m_handle_client_file_map,
|
|
m_handle_client_map,
|
|
m_event_client_wrote,
|
|
m_event_client_read,
|
|
m_event_server_wrote,
|
|
m_event_server_read,
|
|
m_event_conn_closed);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
Constructor to instantiate Channel_info_shared_mem object
|
|
|
|
@param handle_client_file_map handle to client file map.
|
|
@param handle_client_map handle to client map.
|
|
@param event_server_wrote handle object for server write event.
|
|
@param event_server_read handle object for server read event.
|
|
@param event_client_wrote handle object for client write event.
|
|
@param event_client_read handle object for client read event.
|
|
@param event_conn_closed handle object for connection close event.
|
|
*/
|
|
Channel_info_shared_mem(HANDLE handle_client_file_map,
|
|
char* handle_client_map,
|
|
HANDLE event_server_wrote,
|
|
HANDLE event_server_read,
|
|
HANDLE event_client_wrote,
|
|
HANDLE event_client_read,
|
|
HANDLE event_conn_closed)
|
|
: m_handle_client_file_map(handle_client_file_map),
|
|
m_handle_client_map(handle_client_map),
|
|
m_event_server_wrote(event_server_wrote),
|
|
m_event_server_read(event_server_read),
|
|
m_event_client_wrote(event_client_wrote),
|
|
m_event_client_read(event_client_read),
|
|
m_event_conn_closed(event_conn_closed)
|
|
{ }
|
|
|
|
virtual THD* create_thd()
|
|
{
|
|
THD* thd= Channel_info::create_thd();
|
|
|
|
if (thd != NULL)
|
|
thd->security_context()->set_host_ptr(my_localhost, strlen(my_localhost));
|
|
return thd;
|
|
}
|
|
|
|
virtual void send_error_and_close_channel(uint errorcode,
|
|
int error,
|
|
bool senderror)
|
|
{
|
|
Channel_info::send_error_and_close_channel(errorcode, error, senderror);
|
|
|
|
// Channel_info::send_error_and_close_channel will have closed
|
|
// handles on senderror
|
|
if (!senderror)
|
|
{
|
|
if (m_handle_client_file_map)
|
|
CloseHandle(m_handle_client_file_map);
|
|
if (m_handle_client_map)
|
|
UnmapViewOfFile(m_handle_client_map);
|
|
if (m_event_server_wrote)
|
|
CloseHandle(m_event_server_wrote);
|
|
if (m_event_server_read)
|
|
CloseHandle(m_event_server_read);
|
|
if (m_event_client_wrote)
|
|
CloseHandle(m_event_client_wrote);
|
|
if (m_event_client_read)
|
|
CloseHandle(m_event_client_read);
|
|
if (m_event_conn_closed)
|
|
CloseHandle(m_event_conn_closed);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Shared_mem_listener implementation
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
void Shared_mem_listener::close_shared_mem()
|
|
{
|
|
if (m_temp_buffer)
|
|
my_free(m_temp_buffer);
|
|
|
|
my_security_attr_free(m_sa_event);
|
|
my_security_attr_free(m_sa_mapping);
|
|
if (m_connect_map)
|
|
UnmapViewOfFile(m_connect_map);
|
|
if (m_connect_named_mutex)
|
|
CloseHandle(m_connect_named_mutex);
|
|
if (m_connect_file_map)
|
|
CloseHandle(m_connect_file_map);
|
|
if (m_event_connect_answer)
|
|
CloseHandle(m_event_connect_answer);
|
|
if (m_event_connect_request)
|
|
CloseHandle(m_event_connect_request);
|
|
}
|
|
|
|
|
|
bool Shared_mem_listener::setup_listener()
|
|
{
|
|
const char *errmsg= NULL;
|
|
sql_print_information("Shared memory setting up listener");
|
|
/*
|
|
get enough space base-name + '_' + longest suffix we might ever send
|
|
*/
|
|
if (!(m_temp_buffer= (char *)my_malloc(key_memory_shared_memory_name,
|
|
m_shared_mem_name.length() + 32L, MYF(MY_FAE))))
|
|
goto error;
|
|
|
|
if (my_security_attr_create(&m_sa_event, &errmsg,
|
|
GENERIC_ALL, SYNCHRONIZE | EVENT_MODIFY_STATE))
|
|
goto error;
|
|
|
|
if (my_security_attr_create(&m_sa_mapping, &errmsg,
|
|
GENERIC_ALL, FILE_MAP_READ | FILE_MAP_WRITE))
|
|
goto error;
|
|
|
|
/*
|
|
The name of event and file-mapping events create agree next rule:
|
|
shared_memory_base_name+unique_part
|
|
Where:
|
|
shared_memory_base_name is unique value for each server
|
|
unique_part is unique value for each object (events and file-mapping)
|
|
*/
|
|
m_suffix_pos= strxmov(m_temp_buffer,m_shared_mem_name.c_str(),"_",NullS);
|
|
my_stpcpy(m_suffix_pos, "CONNECT_REQUEST");
|
|
if ((m_event_connect_request= CreateEvent(m_sa_event,
|
|
FALSE, FALSE, m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create request event";
|
|
goto error;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "CONNECT_ANSWER");
|
|
if ((m_event_connect_answer= CreateEvent(m_sa_event, FALSE,
|
|
FALSE, m_temp_buffer)) == 0)
|
|
{
|
|
errmsg="Could not create answer event";
|
|
goto error;
|
|
}
|
|
|
|
my_stpcpy(m_suffix_pos, "CONNECT_NAMED_MUTEX");
|
|
m_connect_named_mutex= CreateMutex(NULL, FALSE, m_temp_buffer);
|
|
if (m_connect_named_mutex == NULL)
|
|
{
|
|
errmsg="Unable to create connect named mutex.";
|
|
goto error;
|
|
}
|
|
if ( GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
errmsg="Another instance of application already running.";
|
|
goto error;
|
|
}
|
|
|
|
my_stpcpy(m_suffix_pos, "CONNECT_DATA");
|
|
if ((m_connect_file_map=
|
|
CreateFileMapping(INVALID_HANDLE_VALUE, m_sa_mapping, PAGE_READWRITE, 0,
|
|
sizeof(m_connect_number), m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create file mapping";
|
|
goto error;
|
|
}
|
|
if ((m_connect_map= (char *)MapViewOfFile(m_connect_file_map,
|
|
FILE_MAP_WRITE,0,0,
|
|
sizeof(DWORD))) == 0)
|
|
{
|
|
errmsg= "Could not create shared memory service";
|
|
goto error;
|
|
}
|
|
|
|
return false;
|
|
|
|
error:
|
|
if (errmsg)
|
|
{
|
|
sql_print_error("Can't create shared memory service: %s. : %s",
|
|
errmsg, strerror(errno));
|
|
}
|
|
|
|
close_shared_mem();
|
|
return true;
|
|
}
|
|
|
|
|
|
Channel_info* Shared_mem_listener::listen_for_connection_event()
|
|
{
|
|
/* Wait for a request from client */
|
|
WaitForSingleObject(m_event_connect_request, INFINITE);
|
|
|
|
/*
|
|
it can be after shutdown command
|
|
*/
|
|
if (abort_loop)
|
|
return NULL;
|
|
|
|
char connect_number_char[22];
|
|
char* p= int10_to_str(m_connect_number, connect_number_char, 10);
|
|
|
|
/*
|
|
The name of event and file-mapping events create agree next rule:
|
|
shared_memory_base_name+unique_part+number_of_connection
|
|
Where:
|
|
shared_memory_base_name is uniquel value for each server
|
|
unique_part is unique value for each object (events and file-mapping)
|
|
number_of_connection is connection-number between server and client
|
|
*/
|
|
m_suffix_pos= strxmov(m_temp_buffer, m_shared_mem_name.c_str(), "_",
|
|
connect_number_char, "_", NullS);
|
|
|
|
|
|
const char *errmsg= NULL;
|
|
ulong smem_buffer_length= shared_memory_buffer_length + 4;
|
|
|
|
my_stpcpy(m_suffix_pos, "DATA");
|
|
if ((m_handle_client_file_map=
|
|
CreateFileMapping(INVALID_HANDLE_VALUE, m_sa_mapping, PAGE_READWRITE,
|
|
0, smem_buffer_length, m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create file mapping";
|
|
goto errorconn;
|
|
}
|
|
if ((m_handle_client_map= (char*)MapViewOfFile(m_handle_client_file_map,
|
|
FILE_MAP_WRITE,0,0,
|
|
smem_buffer_length)) == 0)
|
|
{
|
|
errmsg= "Could not create memory map";
|
|
goto errorconn;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "CLIENT_WROTE");
|
|
if ((m_event_client_wrote= CreateEvent(m_sa_event, FALSE, FALSE,
|
|
m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create client write event";
|
|
goto errorconn;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "CLIENT_READ");
|
|
if ((m_event_client_read= CreateEvent(m_sa_event, FALSE, FALSE,
|
|
m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create client read event";
|
|
goto errorconn;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "SERVER_READ");
|
|
if ((m_event_server_read= CreateEvent(m_sa_event, FALSE, FALSE,
|
|
m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create server read event";
|
|
goto errorconn;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "SERVER_WROTE");
|
|
if ((m_event_server_wrote= CreateEvent(m_sa_event, FALSE, FALSE,
|
|
m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create server write event";
|
|
goto errorconn;
|
|
}
|
|
my_stpcpy(m_suffix_pos, "CONNECTION_CLOSED");
|
|
if ((m_event_conn_closed= CreateEvent(m_sa_event, TRUE, FALSE,
|
|
m_temp_buffer)) == 0)
|
|
{
|
|
errmsg= "Could not create closed connection event";
|
|
goto errorconn;
|
|
}
|
|
if (abort_loop)
|
|
goto errorconn;
|
|
|
|
Channel_info* channel_info= new (std::nothrow)
|
|
Channel_info_shared_mem(m_handle_client_file_map,
|
|
m_handle_client_map,
|
|
m_event_server_wrote,
|
|
m_event_server_read,
|
|
m_event_client_wrote,
|
|
m_event_client_read,
|
|
m_event_conn_closed);
|
|
if (channel_info != NULL)
|
|
{
|
|
int4store(m_connect_map, m_connect_number);
|
|
if (!SetEvent(m_event_connect_answer))
|
|
{
|
|
errmsg= "Could not send answer event";
|
|
delete channel_info;
|
|
goto errorconn;
|
|
}
|
|
|
|
if (!SetEvent(m_event_client_read))
|
|
{
|
|
errmsg= "Could not set client to read mode";
|
|
delete channel_info;
|
|
goto errorconn;
|
|
}
|
|
m_connect_number++;
|
|
return channel_info;
|
|
}
|
|
errorconn:
|
|
/* Could not form connection; Free used handlers/memort and retry */
|
|
if (errmsg)
|
|
{
|
|
sql_print_error("Can't create shared memory connection: %s. : %s",
|
|
errmsg, strerror(errno));
|
|
}
|
|
if (m_handle_client_file_map)
|
|
CloseHandle(m_handle_client_file_map);
|
|
if (m_handle_client_map)
|
|
UnmapViewOfFile(m_handle_client_map);
|
|
if (m_event_server_wrote)
|
|
CloseHandle(m_event_server_wrote);
|
|
if (m_event_server_read)
|
|
CloseHandle(m_event_server_read);
|
|
if (m_event_client_wrote)
|
|
CloseHandle(m_event_client_wrote);
|
|
if (m_event_client_read)
|
|
CloseHandle(m_event_client_read);
|
|
if (m_event_conn_closed)
|
|
CloseHandle(m_event_conn_closed);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void Shared_mem_listener::close_listener()
|
|
{
|
|
if (!SetEvent(m_event_connect_request))
|
|
{
|
|
DBUG_PRINT("error",
|
|
("Got error: %ld from SetEvent of mem_event_connect_request",
|
|
GetLastError()));
|
|
}
|
|
close_shared_mem();
|
|
}
|