|
From: <ale...@us...> - 2010-10-12 08:15:58
|
Revision: 51654
http://firebird.svn.sourceforge.net/firebird/?rev=51654&view=rev
Author: alexpeshkoff
Date: 2010-10-12 08:15:48 +0000 (Tue, 12 Oct 2010)
Log Message:
-----------
Missed in previous commit files
Added Paths:
-----------
firebird/trunk/src/remote/os/
firebird/trunk/src/remote/os/win32/
firebird/trunk/src/remote/os/win32/wnet.cpp
firebird/trunk/src/remote/os/win32/wnet_proto.h
firebird/trunk/src/remote/os/win32/xnet.cpp
firebird/trunk/src/remote/os/win32/xnet.h
firebird/trunk/src/remote/os/win32/xnet_proto.h
firebird/trunk/src/remote/server/os/win32/
firebird/trunk/src/remote/server/os/win32/caution.ico
firebird/trunk/src/remote/server/os/win32/chop.cpp
firebird/trunk/src/remote/server/os/win32/chop_proto.h
firebird/trunk/src/remote/server/os/win32/cntl.cpp
firebird/trunk/src/remote/server/os/win32/cntl_proto.h
firebird/trunk/src/remote/server/os/win32/property.cpp
firebird/trunk/src/remote/server/os/win32/property.rc
firebird/trunk/src/remote/server/os/win32/property.rh
firebird/trunk/src/remote/server/os/win32/propty_proto.h
firebird/trunk/src/remote/server/os/win32/server.ico
firebird/trunk/src/remote/server/os/win32/srvr_w32.cpp
firebird/trunk/src/remote/server/os/win32/window.cpp
firebird/trunk/src/remote/server/os/win32/window.h
firebird/trunk/src/remote/server/os/win32/window.rc
firebird/trunk/src/remote/server/os/win32/window.rh
firebird/trunk/src/remote/server/os/win32/window_proto.h
Added: firebird/trunk/src/remote/os/win32/wnet.cpp
===================================================================
--- firebird/trunk/src/remote/os/win32/wnet.cpp (rev 0)
+++ firebird/trunk/src/remote/os/win32/wnet.cpp 2010-10-12 08:15:48 UTC (rev 51654)
@@ -0,0 +1,1609 @@
+/*
+ * PROGRAM: JRD Remote Interface/Server
+ * MODULE: wnet.cpp
+ * DESCRIPTION: Windows Net Communications module.
+ *
+ * The contents of this file are subject to the Interbase Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy
+ * of the License at http://www.Inprise.com/IPL.html
+ *
+ * Software distributed under the License is distributed on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code was created by Inprise Corporation
+ * and its predecessors. Portions created by Inprise Corporation are
+ * Copyright (C) Inprise Corporation.
+ *
+ * All Rights Reserved.
+ * Contributor(s): ______________________________________.
+ */
+
+#ifdef DEBUG
+// define WNET_trace to 0 (zero) for no packet debugging
+#define WNET_trace
+#endif
+
+#include "firebird.h"
+#include <stdio.h>
+#include <string.h>
+#include "../remote/remote.h"
+#include "../jrd/ibase.h"
+#include "../common/thd.h"
+
+#include "../utilities/install/install_nt.h"
+
+#include "../remote/proto_proto.h"
+#include "../remote/remot_proto.h"
+#include "../remote/os/win32/wnet_proto.h"
+#include "../yvalve/gds_proto.h"
+#include "../common/isc_proto.h"
+#include "../common/isc_f_proto.h"
+#include "../common/config/config.h"
+#include "../common/utils_proto.h"
+#include "../common/classes/ClumpletWriter.h"
+#include "../common/classes/init.h"
+
+#include <stdarg.h>
+
+using namespace Firebird;
+
+const int MAX_DATA = 2048;
+const int BUFFER_SIZE = MAX_DATA;
+
+const char* PIPE_PREFIX = "pipe"; // win32-specific
+const char* SERVER_PIPE_SUFFIX = "server";
+const char* EVENT_PIPE_SUFFIX = "event";
+Firebird::AtomicCounter event_counter;
+
+static Firebird::GlobalPtr<PortsCleanup> wnet_ports;
+static Firebird::GlobalPtr<Firebird::Mutex> init_mutex;
+static volatile bool wnet_initialized = false;
+static volatile bool wnet_shutdown = false;
+
+static bool accept_connection(rem_port*, const P_CNCT*);
+static rem_port* alloc_port(rem_port*);
+static rem_port* aux_connect(rem_port*, PACKET*);
+static rem_port* aux_request(rem_port*, PACKET*);
+static bool connect_client(rem_port*);
+static void disconnect(rem_port*);
+#ifdef NOT_USED_OR_REPLACED
+static void exit_handler(void*);
+#endif
+static void force_close(rem_port*);
+static rem_str* make_pipe_name(const TEXT*, const TEXT*, const TEXT*);
+static rem_port* receive(rem_port*, PACKET*);
+static int send_full(rem_port*, PACKET*);
+static int send_partial(rem_port*, PACKET*);
+static int xdrwnet_create(XDR*, rem_port*, UCHAR*, USHORT, xdr_op);
+static bool_t xdrwnet_endofrecord(XDR*);//, int);
+static int wnet_destroy(XDR*);
+static bool wnet_error(rem_port*, const TEXT*, ISC_STATUS, int);
+static void wnet_gen_error(rem_port*, const Firebird::Arg::StatusVector& v);
+static bool_t wnet_getbytes(XDR*, SCHAR*, u_int);
+static bool_t wnet_getlong(XDR*, SLONG*);
+static u_int wnet_getpostn(XDR*);
+static caddr_t wnet_inline(XDR*, u_int);
+static bool_t wnet_putlong(XDR*, const SLONG*);
+static bool_t wnet_putbytes(XDR*, const SCHAR*, u_int);
+static bool_t wnet_read(XDR*);
+static bool_t wnet_setpostn(XDR*, u_int);
+static bool_t wnet_write(XDR*); //, int);
+#ifdef DEBUG
+static void packet_print(const TEXT*, const UCHAR*, const int);
+#endif
+static bool packet_receive(rem_port*, UCHAR*, SSHORT, SSHORT*);
+static bool packet_send(rem_port*, const SCHAR*, SSHORT);
+static void wnet_make_file_name(TEXT*, DWORD);
+
+static int cleanup_ports(const int, const int, void*);
+
+static xdr_t::xdr_ops wnet_ops =
+{
+ wnet_getlong,
+ wnet_putlong,
+ wnet_getbytes,
+ wnet_putbytes,
+ wnet_getpostn,
+ wnet_setpostn,
+ wnet_inline,
+ wnet_destroy
+};
+
+
+rem_port* WNET_analyze(const Firebird::PathName& file_name,
+ ISC_STATUS* status_vector,
+ const TEXT* node_name,
+ bool uv_flag)
+{
+/**************************************
+ *
+ * W N E T _ a n a l y z e
+ *
+ **************************************
+ *
+ * Functional description
+ * Determine whether the file name has a "\\nodename".
+ * If so, establish an external connection to the node.
+ *
+ * If a connection is established, return a port block, otherwise
+ * return NULL.
+ *
+ **************************************/
+
+ // We need to establish a connection to a remote server. Allocate the necessary
+ // blocks and get ready to go.
+
+ Rdb* rdb = new Rdb;
+ PACKET* packet = &rdb->rdb_packet;
+
+ // Pick up some user identification information
+ Firebird::string buffer;
+ Firebird::ClumpletWriter user_id(Firebird::ClumpletReader::UnTagged, MAX_DPB_SIZE);
+
+ ISC_get_user(&buffer, 0, 0);
+ buffer.lower();
+ user_id.insertString(CNCT_user, buffer);
+
+ ISC_get_host(buffer);
+ buffer.lower();
+ user_id.insertString(CNCT_host, buffer);
+
+ if (uv_flag) {
+ user_id.insertTag(CNCT_user_verification);
+ }
+
+ // Establish connection to server
+
+ P_CNCT* const cnct = &packet->p_cnct;
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ // If we want user verification, we can't speak anything less than version 7
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try1[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION7, ptype_rpc, ptype_batch_send, 1),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION8, ptype_rpc, ptype_batch_send, 2),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION10, ptype_rpc, ptype_batch_send, 3),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION11, ptype_rpc, ptype_batch_send, 4),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION12, ptype_rpc, ptype_batch_send, 5),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_rpc, ptype_batch_send, 6)
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try1);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try1[i];
+ }
+
+ // If we can't talk to a server, punt. Let somebody else generate an error.
+
+ rem_port* port = WNET_connect(node_name, packet, status_vector, 0);
+ if (!port)
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server.
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+
+ if (packet->p_operation == op_reject && !uv_flag)
+ {
+ disconnect(port);
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ // try again with next set of known protocols
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try2[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION4, ptype_rpc, ptype_batch_send, 1),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION6, ptype_rpc, ptype_batch_send, 2),
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try2);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try2[i];
+ }
+
+ port = WNET_connect(node_name, packet, status_vector, 0);
+ if (!port)
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server.
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+ }
+
+ if (packet->p_operation == op_reject && !uv_flag)
+ {
+ disconnect(port);
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ // try again with next set of known protocols
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try3[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION3, ptype_rpc, ptype_batch_send, 1)
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try3);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try3[i];
+ }
+
+ port = WNET_connect(node_name, packet, status_vector, 0);
+ if (!port)
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server.
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+ }
+
+ if (packet->p_operation != op_accept)
+ {
+ *status_vector++ = isc_arg_gds;
+ *status_vector++ = isc_connect_reject;
+ *status_vector++ = 0;
+ delete rdb;
+ disconnect(port);
+ return NULL;
+ }
+
+ port->port_protocol = packet->p_acpt.p_acpt_version;
+
+ // once we've decided on a protocol, concatenate the version
+ // string to reflect it...
+
+ Firebird::string temp;
+ temp.printf("%s/P%d", port->port_version->str_data,
+ port->port_protocol & FB_PROTOCOL_MASK);
+ delete port->port_version;
+ port->port_version = REMOTE_make_string(temp.c_str());
+
+ if (packet->p_acpt.p_acpt_architecture == ARCHITECTURE)
+ port->port_flags |= PORT_symmetric;
+
+ if (packet->p_acpt.p_acpt_type == ptype_rpc)
+ port->port_flags |= PORT_rpc;
+
+ if (packet->p_acpt.p_acpt_type != ptype_out_of_band)
+ port->port_flags |= PORT_no_oob;
+
+ return port;
+}
+
+
+rem_port* WNET_connect(const TEXT* name,
+ PACKET* packet,
+ ISC_STATUS* status_vector,
+ USHORT flag)
+{
+/**************************************
+ *
+ * W N E T _ c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * Establish half of a communication link. If a connect packet is given,
+ * the connection is on behalf of a remote interface. Otherwise the
+ * connect is for a server process.
+ *
+ **************************************/
+ rem_port* const port = alloc_port(0);
+ port->port_status_vector = status_vector;
+ status_vector[0] = isc_arg_gds;
+ status_vector[1] = 0;
+ status_vector[2] = isc_arg_end;
+
+ delete port->port_connection;
+ port->port_connection = make_pipe_name(name, SERVER_PIPE_SUFFIX, 0);
+
+ // If we're a host, just make the connection
+
+ if (packet)
+ {
+ while (true)
+ {
+ port->port_pipe = CreateFile(port->port_connection->str_data,
+ GENERIC_WRITE | GENERIC_READ,
+ 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (port->port_pipe != INVALID_HANDLE_VALUE) {
+ break;
+ }
+ const ISC_STATUS status = GetLastError();
+ if (status != ERROR_PIPE_BUSY)
+ {
+ wnet_error(port, "CreateFile", isc_net_connect_err, status);
+ disconnect(port);
+ return NULL;
+ }
+ WaitNamedPipe(port->port_connection->str_data, 3000L);
+ }
+ send_full(port, packet);
+ return port;
+ }
+
+ // We're a server, so wait for a host to show up
+
+ wnet_ports->registerPort(port);
+ while (!wnet_shutdown)
+ {
+ port->port_pipe =
+ CreateNamedPipe(port->port_connection->str_data,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_WAIT | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ PIPE_UNLIMITED_INSTANCES,
+ MAX_DATA,
+ MAX_DATA,
+ 0,
+ ISC_get_security_desc());
+ if (port->port_pipe == INVALID_HANDLE_VALUE)
+ {
+ const DWORD dwError = GetLastError();
+ if (dwError == ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ disconnect(port);
+ wnet_shutdown = true;
+ break;
+ }
+
+ wnet_error(port, "CreateNamedPipe", isc_net_connect_listen_err, dwError);
+ disconnect(port);
+ return NULL;
+ }
+
+ if (!connect_client(port))
+ break;
+
+ if (flag & (SRVR_debug | SRVR_multi_client))
+ {
+ port->port_server_flags |= SRVR_server;
+ if (flag & SRVR_multi_client)
+ {
+ port->port_server_flags |= SRVR_multi_client;
+ }
+
+ return port;
+ }
+
+ TEXT name[MAXPATHLEN];
+ GetModuleFileName(NULL, name, sizeof(name));
+
+ Firebird::string cmdLine;
+ cmdLine.printf("%s -w -h %"HANDLEFORMAT"@%"ULONGFORMAT, name, port->port_pipe, GetCurrentProcessId());
+
+ STARTUPINFO start_crud;
+ PROCESS_INFORMATION pi;
+ start_crud.cb = sizeof(STARTUPINFO);
+ start_crud.lpReserved = NULL;
+ start_crud.lpReserved2 = NULL;
+ start_crud.cbReserved2 = 0;
+ start_crud.lpDesktop = NULL;
+ start_crud.lpTitle = NULL;
+ start_crud.dwFlags = STARTF_FORCEOFFFEEDBACK;
+
+ if (CreateProcess(NULL, cmdLine.begin(), NULL, NULL, FALSE,
+ (flag & SRVR_high_priority ?
+ HIGH_PRIORITY_CLASS | DETACHED_PROCESS :
+ NORMAL_PRIORITY_CLASS | DETACHED_PROCESS),
+ NULL, NULL, &start_crud, &pi))
+ {
+ // hvlad: child process will close our handle of client pipe
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ }
+ else
+ {
+ gds__log("WNET/inet_error: fork/CreateProcess errno = %d", GetLastError());
+ CloseHandle(port->port_pipe);
+ }
+
+ if (wnet_shutdown) {
+ disconnect(port);
+ }
+ }
+
+ if (wnet_shutdown)
+ {
+ Arg::Gds temp(isc_net_server_shutdown);
+ temp << Arg::Str("WNET");
+ temp.copyTo(status_vector);
+ }
+ return NULL;
+}
+
+
+rem_port* WNET_reconnect(HANDLE handle, ISC_STATUS* status_vector)
+{
+/**************************************
+ *
+ * W N E T _ r e c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * A communications link has been established by another
+ * process. We have inheritted the handle. Set up
+ * a port block.
+ *
+ **************************************/
+ rem_port* const port = alloc_port(0);
+ port->port_status_vector = status_vector;
+ status_vector[0] = isc_arg_gds;
+ status_vector[1] = 0;
+ status_vector[2] = isc_arg_end;
+
+ delete port->port_connection;
+ port->port_connection = make_pipe_name(NULL, SERVER_PIPE_SUFFIX, 0);
+
+ port->port_pipe = handle;
+ port->port_server_flags |= SRVR_server;
+
+ return port;
+}
+
+
+static bool accept_connection( rem_port* port, const P_CNCT* cnct)
+{
+/**************************************
+ *
+ * a c c e p t _ c o n n e c t i o n
+ *
+ **************************************
+ *
+ * Functional description
+ * Accept an incoming request for connection. This is purely a lower
+ * level handshaking function, and does not constitute the server
+ * response for protocol selection.
+ *
+ **************************************/
+ // Default account to "guest" (in theory all packets contain a name)
+
+ Firebird::string name("guest"), password;
+
+ // Pick up account and password, if given. The password is ignored
+
+ Firebird::ClumpletReader id(Firebird::ClumpletReader::UnTagged,
+ cnct->p_cnct_user_id.cstr_address, cnct->p_cnct_user_id.cstr_length);
+
+ for (id.rewind(); !id.isEof(); id.moveNext())
+ {
+ switch (id.getClumpTag())
+ {
+ case CNCT_user:
+ id.getString(name);
+ port->port_user_name = REMOTE_make_string(name.c_str());
+ break;
+
+ case CNCT_passwd:
+ id.getString(password);
+ break;
+ }
+ }
+
+ // NS: Put in connection address. I have no good idea where to get an
+ // address of the remote end of named pipe so let's live without it for now
+ port->port_protocol_str = REMOTE_make_string("WNET");
+
+ return true;
+}
+
+
+static rem_port* alloc_port( rem_port* parent)
+{
+/**************************************
+ *
+ * a l l o c _ p o r t
+ *
+ **************************************
+ *
+ * Functional description
+ * Allocate a port block, link it in to parent (if there is a parent),
+ * and initialize input and output XDR streams.
+ *
+ **************************************/
+
+ if (!wnet_initialized)
+ {
+ Firebird::MutexLockGuard guard(init_mutex);
+ if (!wnet_initialized)
+ {
+ wnet_initialized = true;
+ fb_shutdown_callback(0, cleanup_ports, fb_shut_postproviders, 0);
+ }
+ }
+
+ rem_port* port = new rem_port(rem_port::PIPE, BUFFER_SIZE * 2);
+
+ TEXT buffer[BUFFER_TINY];
+ ISC_get_host(buffer, sizeof(buffer));
+ port->port_host = REMOTE_make_string(buffer);
+ port->port_connection = REMOTE_make_string(buffer);
+ sprintf(buffer, "WNet (%s)", port->port_host->str_data);
+ port->port_version = REMOTE_make_string(buffer);
+
+ port->port_accept = accept_connection;
+ port->port_disconnect = disconnect;
+ port->port_force_close = force_close;
+ port->port_receive_packet = receive;
+ port->port_send_packet = send_full;
+ port->port_send_partial = send_partial;
+ port->port_connect = aux_connect;
+ port->port_request = aux_request;
+ port->port_buff_size = BUFFER_SIZE;
+
+ port->port_event = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+ xdrwnet_create(&port->port_send, port, &port->port_buffer[BUFFER_SIZE], BUFFER_SIZE, XDR_ENCODE);
+
+ xdrwnet_create(&port->port_receive, port, port->port_buffer, 0, XDR_DECODE);
+
+ if (parent)
+ {
+ delete port->port_connection;
+ port->port_connection = REMOTE_make_string(parent->port_connection->str_data);
+
+ port->linkParent(parent);
+ }
+
+ return port;
+}
+
+
+static rem_port* aux_connect( rem_port* port, PACKET* packet)
+{
+/**************************************
+ *
+ * a u x _ c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * Try to establish an alternative connection. Somebody has already
+ * done a successfull connect request ("packet" contains the response).
+ *
+ **************************************/
+ // If this is a server, we're got an auxiliary connection. Accept it
+
+ if (port->port_server_flags)
+ {
+ if (!connect_client(port))
+ return NULL;
+
+ port->port_flags |= PORT_async;
+ return port;
+ }
+
+ // The server will be sending its process id in the packet to
+ // create a unique pipe name.
+
+ P_RESP* response = &packet->p_resp;
+
+ TEXT str_pid[32];
+ const TEXT* p = 0;
+ if (response->p_resp_data.cstr_length)
+ {
+ // Avoid B.O.
+ size_t len = MIN(response->p_resp_data.cstr_length, sizeof(str_pid) - 1);
+ memcpy(str_pid, response->p_resp_data.cstr_address, len);
+ str_pid[len] = 0;
+ p = str_pid;
+ }
+
+ rem_port* const new_port = alloc_port(port->port_parent);
+ port->port_async = new_port;
+ new_port->port_flags = port->port_flags & PORT_no_oob;
+ new_port->port_flags |= PORT_async;
+ new_port->port_connection = make_pipe_name(port->port_connection->str_data, EVENT_PIPE_SUFFIX, p);
+
+ while (true)
+ {
+ new_port->port_pipe =
+ CreateFile(new_port->port_connection->str_data, GENERIC_READ, 0,
+ NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (new_port->port_pipe != INVALID_HANDLE_VALUE)
+ break;
+ const ISC_STATUS status = GetLastError();
+ if (status != ERROR_PIPE_BUSY)
+ {
+ wnet_error(new_port, "CreateFile", isc_net_event_connect_err, status);
+ return NULL;
+ }
+ WaitNamedPipe(new_port->port_connection->str_data, 3000L);
+ }
+
+ return new_port;
+}
+
+
+static rem_port* aux_request( rem_port* vport, PACKET* packet)
+{
+/**************************************
+ *
+ * a u x _ r e q u e s t
+ *
+ **************************************
+ *
+ * Functional description
+ * A remote interface has requested the server prepare an auxiliary
+ * connection; the server calls aux_request to set up the connection.
+ * Send the servers process id on the packet. If at a later time
+ * a multi client server is used, there may be a need to
+ * generate a unique id based on connection.
+ *
+ **************************************/
+
+ const DWORD server_pid = (vport->port_server_flags & SRVR_multi_client) ?
+ ++event_counter : GetCurrentProcessId();
+ rem_port* const new_port = alloc_port(vport->port_parent);
+ vport->port_async = new_port;
+ new_port->port_server_flags = vport->port_server_flags;
+ new_port->port_flags = vport->port_flags & PORT_no_oob;
+
+ TEXT str_pid[32];
+ wnet_make_file_name(str_pid, server_pid);
+ new_port->port_connection =
+ make_pipe_name(vport->port_connection->str_data, EVENT_PIPE_SUFFIX, str_pid);
+
+ new_port->port_pipe =
+ CreateNamedPipe(new_port->port_connection->str_data,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_WAIT | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ PIPE_UNLIMITED_INSTANCES,
+ MAX_DATA,
+ MAX_DATA,
+ 0,
+ ISC_get_security_desc());
+
+ if (new_port->port_pipe == INVALID_HANDLE_VALUE)
+ {
+ wnet_error(new_port, "CreateNamedPipe", isc_net_event_listen_err, ERRNO);
+ disconnect(new_port);
+ return NULL;
+ }
+
+ P_RESP* response = &packet->p_resp;
+ response->p_resp_data.cstr_length = (USHORT) strlen(str_pid);
+ memcpy(response->p_resp_data.cstr_address, str_pid, response->p_resp_data.cstr_length);
+
+ return new_port;
+}
+
+
+static bool connect_client(rem_port *port)
+{
+/**************************************
+ *
+ * c o n n e c t _ c l i e n t
+ *
+ **************************************
+ *
+ * Functional description
+ * Wait for new client connected.
+ *
+ **************************************/
+
+ OVERLAPPED ovrl = {0};
+ ovrl.hEvent = port->port_event;
+ if (!ConnectNamedPipe(port->port_pipe, &ovrl))
+ {
+ DWORD err = GetLastError();
+ switch (err)
+ {
+ case ERROR_PIPE_CONNECTED:
+ break;
+
+ case ERROR_IO_PENDING:
+ if (WaitForSingleObject(port->port_event, INFINITE) == WAIT_OBJECT_0)
+ {
+ if (!wnet_shutdown)
+ break;
+ }
+ else
+ err = GetLastError(); // fall thru
+
+ default:
+ if (!wnet_shutdown) {
+ wnet_error(port, "ConnectNamedPipe", isc_net_connect_err, err);
+ }
+ disconnect(port);
+ return false;
+ }
+ }
+ return true;
+}
+
+
+static void disconnect(rem_port* port)
+{
+/**************************************
+ *
+ * d i s c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * Break a remote connection.
+ *
+ **************************************/
+
+ if (port->port_async)
+ {
+ disconnect(port->port_async);
+ port->port_async = NULL;
+ }
+
+ // If this is a sub-port, unlink it from its parent
+ port->unlinkParent();
+
+ if (port->port_server_flags & SRVR_server)
+ {
+ FlushFileBuffers(port->port_pipe);
+ DisconnectNamedPipe(port->port_pipe);
+ }
+ if (port->port_event != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(port->port_event);
+ port->port_event = INVALID_HANDLE_VALUE;
+ }
+ if (port->port_pipe != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(port->port_pipe);
+ port->port_pipe = INVALID_HANDLE_VALUE;
+ }
+
+ wnet_ports->unRegisterPort(port);
+ port->release();
+}
+
+
+static void force_close(rem_port* port)
+{
+/**************************************
+ *
+ * f o r c e _ c l o s e
+ *
+ **************************************
+ *
+ * Functional description
+ * Forcibly close remote connection.
+ *
+ **************************************/
+
+ if (port->port_event != INVALID_HANDLE_VALUE)
+ {
+ port->port_state = rem_port::BROKEN;
+
+ const HANDLE handle = port->port_pipe;
+ port->port_pipe = INVALID_HANDLE_VALUE;
+ SetEvent(port->port_event);
+ CloseHandle(handle);
+ }
+}
+
+
+#ifdef NOT_USED_OR_REPLACED
+static void exit_handler(void* main_port)
+{
+/**************************************
+ *
+ * e x i t _ h a n d l e r
+ *
+ **************************************
+ *
+ * Functional description
+ * Shutdown all active connections
+ * to allow restart.
+ *
+ **************************************/
+ for (rem_port* vport = static_cast<rem_port*>(main_port); vport; vport = vport->port_next)
+ CloseHandle(vport->port_pipe);
+}
+#endif
+
+
+static rem_str* make_pipe_name(const TEXT* connect_name, const TEXT* suffix_name, const TEXT* str_pid)
+{
+/**************************************
+ *
+ * m a k e _ p i p e _ n a m e
+ *
+ **************************************
+ *
+ * Functional description
+ * Construct a name for the pipe connection.
+ * Figure out whether we need a remote node name,
+ * and construct the pipe name accordingly.
+ * If a server pid != 0, append it to pipe name as <>/<pid>
+ *
+ **************************************/
+ Firebird::string buffer("\\\\");
+
+ const TEXT* p = connect_name;
+
+ if (!p || *p++ != '\\' || *p++ != '\\')
+ p = ".";
+
+ while (*p && *p != '\\' && *p != '@')
+ buffer += *p++;
+
+ const TEXT* protocol = NULL;
+ switch (*p)
+ {
+ case 0:
+ protocol = Config::getRemoteServiceName();
+ break;
+ case '@':
+ protocol = p + 1;
+ break;
+ default:
+ while (*p)
+ {
+ if (*p++ == '\\')
+ protocol = p;
+ }
+ }
+
+ buffer += '\\';
+ buffer += PIPE_PREFIX;
+ buffer += '\\';
+ const char *pipe_name = Config::getRemotePipeName();
+ buffer += pipe_name;
+ buffer += '\\';
+ buffer += suffix_name;
+ buffer += '\\';
+ buffer += protocol;
+
+ if (str_pid)
+ {
+ buffer += '\\';
+ buffer += str_pid;
+ }
+
+ return REMOTE_make_string(buffer.c_str());
+}
+
+
+static rem_port* receive( rem_port* main_port, PACKET* packet)
+{
+/**************************************
+ *
+ * r e c e i v e
+ *
+ **************************************
+ *
+ * Functional description
+ * Receive a message from a port or clients of a port. If the process
+ * is a server and a connection request comes in, generate a new port
+ * block for the client.
+ *
+ **************************************/
+
+#ifdef DEV_BUILD
+ main_port->port_receive.x_client = !(main_port->port_flags & PORT_server);
+#endif
+
+ if (!xdr_protocol(&main_port->port_receive, packet))
+ packet->p_operation = op_exit;
+
+ return main_port;
+}
+
+
+static int send_full( rem_port* port, PACKET* packet)
+{
+/**************************************
+ *
+ * s e n d _ f u l l
+ *
+ **************************************
+ *
+ * Functional description
+ * Send a packet across a port to another process.
+ *
+ **************************************/
+
+#ifdef DEV_BUILD
+ port->port_send.x_client = !(port->port_flags & PORT_server);
+#endif
+
+ if (!xdr_protocol(&port->port_send, packet))
+ return FALSE;
+
+ return xdrwnet_endofrecord(&port->port_send); //, TRUE);
+}
+
+
+static int send_partial( rem_port* port, PACKET* packet)
+{
+/**************************************
+ *
+ * s e n d _ p a r t i a l
+ *
+ **************************************
+ *
+ * Functional description
+ * Send a packet across a port to another process.
+ *
+ **************************************/
+
+#ifdef DEV_BUILD
+ port->port_send.x_client = !(port->port_flags & PORT_server);
+#endif
+
+ return xdr_protocol(&port->port_send, packet);
+}
+
+
+static int xdrwnet_create(XDR* xdrs,
+ rem_port* port,
+ UCHAR* buffer, USHORT length, xdr_op x_op)
+{
+/**************************************
+ *
+ * x d r w n e t _ c r e a t e
+ *
+ **************************************
+ *
+ * Functional description
+ * Initialize an XDR stream for Apollo mailboxes.
+ *
+ **************************************/
+
+ xdrs->x_public = (caddr_t) port;
+ xdrs->x_base = xdrs->x_private = reinterpret_cast<SCHAR*>(buffer);
+ xdrs->x_handy = length;
+ xdrs->x_ops = &wnet_ops;
+ xdrs->x_op = x_op;
+
+ return TRUE;
+}
+
+
+static bool_t xdrwnet_endofrecord( XDR* xdrs) //, bool_t flushnow)
+{
+/**************************************
+ *
+ * x d r w n e t _ e n d o f r e c o r d
+ *
+ **************************************
+ *
+ * Functional description
+ * Write out the rest of a record.
+ *
+ **************************************/
+
+ return wnet_write(xdrs); //, flushnow);
+}
+
+
+static int wnet_destroy( XDR*)
+{
+/**************************************
+ *
+ * w n e t _ d e s t r o y
+ *
+ **************************************
+ *
+ * Functional description
+ * Destroy a stream. A no-op.
+ *
+ **************************************/
+
+ return 0;
+}
+
+
+static bool wnet_error(rem_port* port,
+ const TEXT* function, ISC_STATUS operation, int status)
+{
+/**************************************
+ *
+ * w n e t _ e r r o r
+ *
+ **************************************
+ *
+ * Functional description
+ * An I/O error has occurred. If a status vector is present,
+ * generate an error return. In any case, return NULL, which
+ * is used to indicate and error.
+ *
+ **************************************/
+ if (status)
+ {
+ if (port->port_state != rem_port::BROKEN) {
+ gds__log("WNET/wnet_error: %s errno = %d", function, status);
+ }
+
+ wnet_gen_error(port, Arg::Gds(operation) << SYS_ERR(status));
+ }
+ else
+ {
+ wnet_gen_error(port, Arg::Gds(operation));
+ }
+
+ return false;
+}
+
+
+static void wnet_gen_error (rem_port* port, const Firebird::Arg::StatusVector& v)
+{
+/**************************************
+ *
+ * w n e t _ g e n _ e r r o r
+ *
+ **************************************
+ *
+ * Functional description
+ * An error has occurred. Mark the port as broken.
+ * Format the status vector if there is one and
+ * save the status vector strings in a permanent place.
+ *
+ **************************************/
+ port->port_state = rem_port::BROKEN;
+
+ TEXT node_name[MAXPATHLEN];
+ if (port->port_connection)
+ {
+ fb_utils::copy_terminate(node_name, port->port_connection->str_data + 2, sizeof(node_name));
+ TEXT* const p = strchr(node_name, '\\');
+ if (p != NULL)
+ *p = '\0';
+ }
+ else
+ {
+ strcpy(node_name, "(unknown)");
+ }
+
+ Arg::Gds error(isc_network_error);
+ error << Arg::Str(node_name) << v;
+
+ ISC_STATUS* status_vector = NULL;
+ if (port->port_context != NULL) {
+ status_vector = port->port_context->get_status_vector();
+ }
+ if (status_vector == NULL) {
+ status_vector = port->port_status_vector;
+ }
+ if (status_vector != NULL)
+ {
+ error.copyTo(status_vector);
+ REMOTE_save_status_strings(status_vector);
+ }
+}
+
+
+static bool_t wnet_getbytes( XDR* xdrs, SCHAR* buff, u_int count)
+{
+/**************************************
+ *
+ * w n e t _ g e t b y t e s
+ *
+ **************************************
+ *
+ * Functional description
+ * Get a bunch of bytes from a memory stream if it fits.
+ *
+ **************************************/
+ SLONG bytecount = count;
+
+ // Use memcpy to optimize bulk transfers.
+
+ while (bytecount > (SLONG) sizeof(ISC_QUAD))
+ {
+ if (xdrs->x_handy >= bytecount)
+ {
+ memcpy(buff, xdrs->x_private, bytecount);
+ xdrs->x_private += bytecount;
+ xdrs->x_handy -= bytecount;
+ return TRUE;
+ }
+ if (xdrs->x_handy > 0)
+ {
+ memcpy(buff, xdrs->x_private, xdrs->x_handy);
+ xdrs->x_private += xdrs->x_handy;
+ buff += xdrs->x_handy;
+ bytecount -= xdrs->x_handy;
+ xdrs->x_handy = 0;
+ }
+ if (!wnet_read(xdrs))
+ return FALSE;
+ }
+
+ // Scalar values and bulk transfer remainder fall thru
+ // to be moved byte-by-byte to avoid memcpy setup costs.
+
+ if (!bytecount)
+ return TRUE;
+
+ if (xdrs->x_handy >= bytecount)
+ {
+ xdrs->x_handy -= bytecount;
+ do {
+ *buff++ = *xdrs->x_private++;
+ } while (--bytecount);
+ return TRUE;
+ }
+
+ while (--bytecount >= 0)
+ {
+ if (!xdrs->x_handy && !wnet_read(xdrs))
+ return FALSE;
+ *buff++ = *xdrs->x_private++;
+ --xdrs->x_handy;
+ }
+
+ return TRUE;
+}
+
+
+static bool_t wnet_getlong( XDR* xdrs, SLONG* lp)
+{
+/**************************************
+ *
+ * w n e t _ g e t l o n g
+ *
+ **************************************
+ *
+ * Functional description
+ * Fetch a longword into a memory stream if it fits.
+ *
+ **************************************/
+ SLONG l;
+
+ if (!(*xdrs->x_ops->x_getbytes) (xdrs, reinterpret_cast<char*>(&l), 4))
+ return FALSE;
+
+ *lp = ntohl(l);
+
+ return TRUE;
+}
+
+
+static u_int wnet_getpostn( XDR* xdrs)
+{
+/**************************************
+ *
+ * w n e t _ g e t p o s t n
+ *
+ **************************************
+ *
+ * Functional description
+ * Get the current position (which is also current length) from stream.
+ *
+ **************************************/
+
+ return (u_int) (xdrs->x_private - xdrs->x_base);
+}
+
+
+static caddr_t wnet_inline( XDR* xdrs, u_int bytecount)
+{
+/**************************************
+ *
+ * w n e t _ i n l i n e
+ *
+ **************************************
+ *
+ * Functional description
+ * Return a pointer to somewhere in the buffer.
+ *
+ **************************************/
+
+ if (bytecount > (u_int) xdrs->x_handy)
+ return FALSE;
+
+ return xdrs->x_base + bytecount;
+}
+
+
+static bool_t wnet_putbytes( XDR* xdrs, const SCHAR* buff, u_int count)
+{
+/**************************************
+ *
+ * w n e t _ p u t b y t e s
+ *
+ **************************************
+ *
+ * Functional description
+ * Put a bunch of bytes to a memory stream if it fits.
+ *
+ **************************************/
+ SLONG bytecount = count;
+
+ // Use memcpy to optimize bulk transfers.
+
+ while (bytecount > (SLONG) sizeof(ISC_QUAD))
+ {
+ if (xdrs->x_handy >= bytecount)
+ {
+ memcpy(xdrs->x_private, buff, bytecount);
+ xdrs->x_private += bytecount;
+ xdrs->x_handy -= bytecount;
+ return TRUE;
+ }
+ if (xdrs->x_handy > 0)
+ {
+ memcpy(xdrs->x_private, buff, xdrs->x_handy);
+ xdrs->x_private += xdrs->x_handy;
+ buff += xdrs->x_handy;
+ bytecount -= xdrs->x_handy;
+ xdrs->x_handy = 0;
+ }
+ if (!wnet_write(xdrs /*, 0*/))
+ return FALSE;
+ }
+
+ // Scalar values and bulk transfer remainder fall thru
+ // to be moved byte-by-byte to avoid memcpy setup costs.
+
+ if (!bytecount)
+ return TRUE;
+
+ if (xdrs->x_handy >= bytecount)
+ {
+ xdrs->x_handy -= bytecount;
+ do {
+ *xdrs->x_private++ = *buff++;
+ } while (--bytecount);
+ return TRUE;
+ }
+
+ while (--bytecount >= 0)
+ {
+ if (xdrs->x_handy <= 0 && !wnet_write(xdrs /*, 0*/))
+ return FALSE;
+ --xdrs->x_handy;
+ *xdrs->x_private++ = *buff++;
+ }
+
+ return TRUE;
+}
+
+
+static bool_t wnet_putlong( XDR* xdrs, const SLONG* lp)
+{
+/**************************************
+ *
+ * w n e t _ p u t l o n g
+ *
+ **************************************
+ *
+ * Functional description
+ * Fetch a longword into a memory stream if it fits.
+ *
+ **************************************/
+ const SLONG l = htonl(*lp);
+ return (*xdrs->x_ops->x_putbytes) (xdrs, reinterpret_cast<const char*>(&l), 4);
+}
+
+
+static bool_t wnet_read( XDR* xdrs)
+{
+/**************************************
+ *
+ * w n e t _ r e a d
+ *
+ **************************************
+ *
+ * Functional description
+ * Read a buffer full of data. If we receive a bad packet,
+ * send the moral equivalent of a NAK and retry. ACK all
+ * partial packets. Don't ACK the last packet -- the next
+ * message sent will handle this.
+ *
+ **************************************/
+ rem_port* port = (rem_port*) xdrs->x_public;
+ SCHAR* p = xdrs->x_base;
+ const SCHAR* const end = p + BUFFER_SIZE;
+
+ // If buffer is not completely empty, slide down what what's left
+
+ if (xdrs->x_handy > 0)
+ {
+ memmove(p, xdrs->x_private, xdrs->x_handy);
+ p += xdrs->x_handy;
+ }
+
+ while (true)
+ {
+ SSHORT length = end - p;
+ if (!packet_receive(port, reinterpret_cast<UCHAR*>(p), length, &length))
+ {
+ return FALSE;
+ }
+ if (length >= 0)
+ {
+ p += length;
+ break;
+ }
+ p -= length;
+ if (!packet_send(port, 0, 0))
+ return FALSE;
+ }
+
+ xdrs->x_handy = (int) (p - xdrs->x_base);
+ xdrs->x_private = xdrs->x_base;
+
+ return TRUE;
+}
+
+
+static bool_t wnet_setpostn( XDR* xdrs, u_int bytecount)
+{
+/**************************************
+ *
+ * w n e t _ s e t p o s t n
+ *
+ **************************************
+ *
+ * Functional description
+ * Set the current position (which is also current length) from stream.
+ *
+ **************************************/
+
+ if (bytecount > (u_int) xdrs->x_handy)
+ return FALSE;
+
+ xdrs->x_private = xdrs->x_base + bytecount;
+
+ return TRUE;
+}
+
+
+static bool_t wnet_write( XDR* xdrs /*, bool_t end_flag*/)
+{
+/**************************************
+ *
+ * w n e t _ w r i t e
+ *
+ **************************************
+ *
+ * Functional description
+ * Write a buffer fulll of data.
+ * Obsolete: If the end_flag isn't set, indicate
+ * that the buffer is a fragment, and reset the XDR for another buffer
+ * load.
+ *
+ **************************************/
+ // Encode the data portion of the packet
+
+ rem_port* vport = (rem_port*) xdrs->x_public;
+ const SCHAR* p = xdrs->x_base;
+ SSHORT length = xdrs->x_private - p;
+
+ // Send data in manageable hunks. If a packet is partial, indicate
+ // that with a negative length. A positive length marks the end.
+
+ while (length)
+ {
+ const SSHORT l = MIN(length, MAX_DATA);
+ length -= l;
+ if (!packet_send(vport, p, (SSHORT) (length ? -l : l)))
+ return FALSE;
+ p += l;
+ }
+
+ xdrs->x_private = xdrs->x_base;
+ xdrs->x_handy = BUFFER_SIZE;
+
+ return TRUE;
+}
+
+
+#ifdef DEBUG
+static void packet_print(const TEXT* string, const UCHAR* packet, const int length)
+{
+/**************************************
+ *
+ * p a c k e t _ p r i n t
+ *
+ **************************************
+ *
+ * Functional description
+ * Print a summary of packet.
+ *
+ **************************************/
+ int sum = 0;
+ int l = length;
+
+ if (l)
+ {
+ do {
+ sum += *packet++;
+ } while (--l);
+ }
+
+ printf("%s\t: length = %d, checksum = %d\n", string, length, sum);
+}
+#endif
+
+
+static bool packet_receive(rem_port* port, UCHAR* buffer, SSHORT buffer_length, SSHORT* length)
+{
+/**************************************
+ *
+ * p a c k e t _ r e c e i v e
+ *
+ **************************************
+ *
+ * Functional description
+ * Receive a packet and pass on it's goodness. If it's good,
+ * return true and the reported length of the packet, and update
+ * the receive sequence number. If it's bad, return false. If it's
+ * a duplicate message, just ignore it.
+ *
+ **************************************/
+ DWORD n = 0;
+ OVERLAPPED ovrl = {0};
+ ovrl.hEvent = port->port_event;
+
+ BOOL status = ReadFile(port->port_pipe, buffer, buffer_length, &n, &ovrl);
+ DWORD dwError = GetLastError();
+
+ if (!status && dwError == ERROR_IO_PENDING)
+ {
+ status = GetOverlappedResult(port->port_pipe, &ovrl, &n, TRUE);
+ dwError = GetLastError();
+ }
+ if (!status && dwError != ERROR_BROKEN_PIPE) {
+ return wnet_error(port, "ReadFile", isc_net_read_err, dwError);
+ }
+
+ if (!n)
+ {
+ if (port->port_flags & PORT_detached)
+ return false;
+
+ return wnet_error(port, "ReadFile end-of-file", isc_net_read_err, dwError);
+ }
+
+#if defined(DEBUG) && defined(WNET_trace)
+ packet_print("receive", buffer, n);
+#endif
+
+ *length = (SSHORT) n;
+
+ return true;
+}
+
+
+static bool packet_send( rem_port* port, const SCHAR* buffer, SSHORT buffer_length)
+{
+/**************************************
+ *
+ * p a c k e t _ s e n d
+ *
+ **************************************
+ *
+ * Functional description
+ * Send some data on it's way.
+ *
+ **************************************/
+ const SCHAR* data = buffer;
+ const DWORD length = buffer_length;
+ OVERLAPPED ovrl = {0};
+ ovrl.hEvent = port->port_event;
+
+ DWORD n;
+ BOOL status = WriteFile(port->port_pipe, data, length, &n, &ovrl);
+ DWORD dwError = GetLastError();
+
+ if (!status && dwError == ERROR_IO_PENDING)
+ {
+ status = GetOverlappedResult(port->port_pipe, &ovrl, &n, TRUE);
+ dwError = GetLastError();
+ }
+ if (!status)
+ return wnet_error(port, "WriteFile", isc_net_write_err, dwError);
+ if (n != length)
+ return wnet_error(port, "WriteFile truncated", isc_net_write_err, dwError);
+
+#if defined(DEBUG) && defined(WNET_trace)
+ packet_print("send", reinterpret_cast<const UCHAR*>(buffer), buffer_length);
+#endif
+
+ return true;
+}
+
+
+static void wnet_make_file_name( TEXT* name, DWORD number)
+{
+/**************************************
+ *
+ * w n e t _ m a k e _ f i l e _ n a m e
+ *
+ **************************************
+ *
+ * Functional description
+ * Create a file name out of a number making sure
+ * the Windows <8>.<3> limitations are handled.
+ *
+ **************************************/
+ TEXT temp[32];
+
+ sprintf(temp, "%lu", number);
+
+ size_t length = strlen(temp);
+ if (length < 8)
+ {
+ strcpy(name, temp);
+ return;
+ }
+
+ TEXT* p = name;
+ const TEXT* q = temp;
+
+ while (length)
+ {
+ size_t len = (length > 8) ? 8 : length;
+ length -= len;
+ do {
+ *p++ = *q++;
+ } while (--len != 0);
+
+ if (length)
+ *p++ = '\\';
+ }
+ *p++ = 0;
+}
+
+static int cleanup_ports(const int, const int, void*)
+{
+/**************************************
+ *
+ * c l e a n u p _ p o r t s
+ *
+ **************************************
+ *
+ * Functional description
+ * Shutdown all active connections
+ * to allow correct shutdown.
+ *
+ **************************************/
+ wnet_shutdown = true;
+
+ wnet_ports->closePorts();
+ return 0;
+}
Property changes on: firebird/trunk/src/remote/os/win32/wnet.cpp
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Added: firebird/trunk/src/remote/os/win32/wnet_proto.h
===================================================================
--- firebird/trunk/src/remote/os/win32/wnet_proto.h (rev 0)
+++ firebird/trunk/src/remote/os/win32/wnet_proto.h 2010-10-12 08:15:48 UTC (rev 51654)
@@ -0,0 +1,44 @@
+/*
+ * PROGRAM: JRD Remote Interface/Server
+ * MODULE: wnet_proto.h
+ * DESCRIPTION: Prototpe header file for wnet.cpp
+ *
+ * The contents of this file are subject to the Interbase Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy
+ * of the License at http://www.Inprise.com/IPL.html
+ *
+ * Software distributed under the License is distributed on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code was created by Inprise Corporation
+ * and its predecessors. Portions created by Inprise Corporation are
+ * Copyright (C) Inprise Corporation.
+ *
+ * All Rights Reserved.
+ * Contributor(s): ______________________________________.
+ */
+
+#ifndef REMOTE_WNET_PROTO_H
+#define REMOTE_WNET_PROTO_H
+
+#include "../common/classes/fb_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+rem_port* WNET_analyze(const Firebird::PathName&, ISC_STATUS*, const TEXT*, bool);
+rem_port* WNET_connect(const TEXT*, struct packet*, ISC_STATUS*, USHORT);
+rem_port* WNET_reconnect(HANDLE, ISC_STATUS*);
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif // REMOTE_WNET_PROTO_H
Property changes on: firebird/trunk/src/remote/os/win32/wnet_proto.h
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:eol-style
+ native
Added: firebird/trunk/src/remote/os/win32/xnet.cpp
===================================================================
--- firebird/trunk/src/remote/os/win32/xnet.cpp (rev 0)
+++ firebird/trunk/src/remote/os/win32/xnet.cpp 2010-10-12 08:15:48 UTC (rev 51654)
@@ -0,0 +1,2649 @@
+/*
+ * PROGRAM: JRD Remote Interface/Server
+ * MODULE: xnet.cpp
+ * DESCRIPTION: Interprocess Server Communications module.
+ *
+ * The contents of this file are subject to the Interbase Public
+ * License Version 1.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy
+ * of the License at http://www.Inprise.com/IPL.html
+ *
+ * Software distributed under the License is distributed on an
+ * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
+ * or implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code was created by Inprise Corporation
+ * and its predecessors. Portions created by Inprise Corporation are
+ * Copyright (C) Inprise Corporation.
+ *
+ * All Rights Reserved.
+ * Contributor(s): ______________________________________.
+ *
+ * 2003.05.01 Victor Seryodkin, Dmitry Yemanov: Completed XNET implementation
+ */
+
+#include "firebird.h"
+#include <stdio.h>
+#include "../remote/remote.h"
+#include "../jrd/ibase.h"
+#include "../common/thd.h"
+#include "../remote/xnet.h"
+#include "../utilities/install/install_nt.h"
+#include "../remote/proto_proto.h"
+#include "../remote/remot_proto.h"
+#include "../remote/xnet_proto.h"
+#include "../remote/server/serve_proto.h"
+#include "../remote/os/win32/window.h"
+#include "../yvalve/gds_proto.h"
+#include "../common/isc_proto.h"
+#include "../common/classes/init.h"
+#include "../common/classes/fb_string.h"
+#include "../common/config/config.h"
+#include "../common/classes/ClumpletWriter.h"
+#include "../common/utils_proto.h"
+#include <time.h>
+
+#ifdef WIN_NT
+#include <process.h>
+#include <windows.h>
+#else
+#pragma FB_COMPILER_MESSAGE("POSIX implementation is required")
+#endif // WIN_NT
+
+using namespace Firebird;
+
+static bool accept_connection(rem_port*, const P_CNCT*);
+static rem_port* alloc_port(rem_port*, UCHAR*, ULONG, UCHAR*, ULONG);
+static rem_port* aux_connect(rem_port*, PACKET*);
+static rem_port* aux_request(rem_port*, PACKET*);
+
+static void cleanup_comm(XCC);
+static void cleanup_mapping(XPM);
+static void cleanup_port(rem_port*);
+static rem_port* connect_client(PACKET*, ISC_STATUS*);
+static rem_port* connect_server(ISC_STATUS*, USHORT);
+static void disconnect(rem_port*);
+static void force_close(rem_port*);
+static void exit_handler(rem_port*);
+static int cleanup_ports(const int, const int, void* arg);
+
+static rem_port* receive(rem_port*, PACKET*);
+static int send_full(rem_port*, PACKET*);
+static int send_partial(rem_port*, PACKET*);
+
+static void peer_shutdown(rem_port* port);
+static rem_port* get_server_port(ULONG, XPM, ULONG, ULONG, ULONG, ISC_STATUS*);
+static void make_map(ULONG, ULONG, FILE_ID*, CADDR_T*);
+static XPM make_xpm(ULONG, ULONG);
+static bool server_init(ISC_STATUS*, USHORT);
+static XPM get_free_slot(ULONG*, ULONG*, ULONG*);
+static bool fork(ULONG, USHORT, ULONG*);
+
+static int xdrxnet_create(XDR*, rem_port*, UCHAR*, USHORT, xdr_op);
+
+static int xnet_destroy(XDR*);
+static bool_t xnet_getbytes(XDR*, SCHAR*, u_int);
+static bool_t xnet_getlong(XDR*, SLONG*);
+static u_int xnet_getpostn(XDR*);
+static caddr_t xnet_inline(XDR*, u_int);
+static bool_t xnet_putlong(XDR*, const SLONG*);
+static bool_t xnet_putbytes(XDR*, const SCHAR*, u_int);
+static bool_t xnet_setpostn(XDR*, u_int);
+static bool_t xnet_read(XDR* xdrs);
+static bool_t xnet_write(XDR* xdrs);
+
+static xdr_t::xdr_ops xnet_ops =
+{
+ xnet_getlong,
+ xnet_putlong,
+ xnet_getbytes,
+ xnet_putbytes,
+ xnet_getpostn,
+ xnet_setpostn,
+ xnet_inline,
+ xnet_destroy
+};
+
+static ULONG global_pages_per_slot = XPS_DEF_PAGES_PER_CLI;
+static ULONG global_slots_per_map = XPS_DEF_NUM_CLI;
+static XPM global_client_maps = NULL;
+
+#ifdef WIN_NT
+
+static HANDLE xnet_connect_mutex = 0;
+static HANDLE xnet_connect_map_h = 0;
+static CADDR_T xnet_connect_map = 0;
+
+static HANDLE xnet_connect_event = 0;
+static HANDLE xnet_response_event = 0;
+static DWORD current_process_id;
+
+// XNET endpoint is the IPC prefix name used to access the server.
+// It may have to be dynamically determined and has to be initialized
+// before the protocol can be used. It is initialized at the following points:
+// - XNET_reconnect (classic servant size)
+// - connect_client (client side)
+// - server_init (listener side)
+static char xnet_endpoint[BUFFER_TINY] = "";
+
+#endif // WIN_NT
+
+static volatile bool xnet_initialized = false;
+static volatile bool xnet_shutdown = false;
+static Firebird::GlobalPtr<Firebird::Mutex> xnet_mutex;
+static Firebird::GlobalPtr<PortsCleanup> xnet_ports;
+static ULONG xnet_next_free_map_num = 0;
+
+static bool connect_init(ISC_STATUS* status);
+static void connect_fini();
+static void release_all();
+
+inline void make_obj_name(char* buffer, size_t size, const char* format)
+{
+ fb_assert(strcmp(xnet_endpoint, "") != 0);
+
+ fb_utils::snprintf(buffer, size, format, xnet_endpoint);
+}
+
+inline void make_map_name(char* buffer, size_t size, const char* format, ULONG arg1, ULONG arg2)
+{
+ fb_assert(strcmp(xnet_endpoint, "") != 0);
+
+ fb_utils::snprintf(buffer, size, format, xnet_endpoint, arg1, arg2);
+}
+
+inline void make_event_name(char* buffer, size_t size, const char* format, ULONG arg1, ULONG arg2, ULONG arg3)
+{
+ fb_assert(strcmp(xnet_endpoint, "") != 0);
+
+ fb_utils::snprintf(buffer, size, format, xnet_endpoint, arg1, arg2, arg3);
+}
+
+
+static void xnet_error(rem_port*, ISC_STATUS, int);
+
+static void xnet_log_error(const char* err_msg, const ISC_STATUS* status = NULL)
+{
+ if (status && status[1])
+ {
+ Firebird::string str("XNET error: ");
+ str += err_msg;
+ iscLogStatus(str.c_str(), status);
+ }
+ else
+ gds__log("XNET error: %s", err_msg);
+}
+
+#ifdef DEV_BUILD
+#define ERR_STR2(str, lnum) (str #lnum)
+#define ERR_STR1(str, lnum) ERR_STR2(str " at line ", lnum)
+#define ERR_STR(str) ERR_STR1(str, __LINE__)
+#else
+#define ERR_STR(str) (str)
+#endif
+
+rem_port* XNET_analyze(const Firebird::PathName& file_name,
+ ISC_STATUS* status_vector,
+ bool uv_flag)
+{
+/**************************************
+ *
+ * X N E T _ a n a l y z e
+ *
+ **************************************
+ *
+ * Functional description
+ * Client performs attempt to establish connection
+ * based on the set of protocols.
+ * If a connection is established, return a port block,
+ * otherwise return NULL.
+ *
+ **************************************/
+
+ // We need to establish a connection to a remote server.
+ // Allocate the necessary blocks and get ready to go.
+
+ Rdb* rdb = new Rdb;
+ PACKET* packet = &rdb->rdb_packet;
+
+ // Pick up some user identification information
+
+ Firebird::string buffer;
+ Firebird::ClumpletWriter user_id(Firebird::ClumpletReader::UnTagged, MAX_DPB_SIZE);
+
+ ISC_get_user(&buffer, 0, 0);
+ buffer.lower();
+ user_id.insertString(CNCT_user, buffer);
+
+ ISC_get_host(buffer);
+ buffer.lower();
+ user_id.insertString(CNCT_host, buffer);
+
+ if (uv_flag) {
+ user_id.insertTag(CNCT_user_verification);
+ }
+
+ // Establish connection to server
+
+ P_CNCT* cnct = &packet->p_cnct;
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try1[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION7, ptype_rpc, ptype_batch_send, 1),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION8, ptype_rpc, ptype_batch_send, 2),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION10, ptype_rpc, ptype_batch_send, 3),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION11, ptype_rpc, ptype_batch_send, 4),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION12, ptype_rpc, ptype_batch_send, 5),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION13, ptype_rpc, ptype_batch_send, 6)
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try1);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try1[i];
+ }
+
+ // If we can't talk to a server, punt. Let somebody else generate an error.
+
+ rem_port* port = XNET_connect(packet, status_vector, 0);
+ if (!port)
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+
+ if (packet->p_operation == op_reject && !uv_flag)
+ {
+ disconnect(port);
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ // try again with next set of known protocols
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try2[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION4, ptype_rpc, ptype_batch_send, 1),
+ REMOTE_PROTOCOL(PROTOCOL_VERSION6, ptype_rpc, ptype_batch_send, 2),
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try2);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try2[i];
+ }
+
+ if (!(port = XNET_connect(packet, status_vector, 0)))
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+ }
+
+ if (packet->p_operation == op_reject && !uv_flag)
+ {
+ disconnect(port);
+ packet->p_operation = op_connect;
+ cnct->p_cnct_operation = op_attach;
+ cnct->p_cnct_cversion = CONNECT_VERSION2;
+ cnct->p_cnct_client = ARCHITECTURE;
+ cnct->p_cnct_file.cstr_length = (USHORT) file_name.length();
+ cnct->p_cnct_file.cstr_address = reinterpret_cast<const UCHAR*>(file_name.c_str());
+
+ // try again with next set of known protocols
+
+ cnct->p_cnct_user_id.cstr_length = (USHORT) user_id.getBufferLength();
+ cnct->p_cnct_user_id.cstr_address = user_id.getBuffer();
+
+ static const p_cnct::p_cnct_repeat protocols_to_try3[] =
+ {
+ REMOTE_PROTOCOL(PROTOCOL_VERSION3, ptype_rpc, ptype_batch_send, 1)
+ };
+ cnct->p_cnct_count = FB_NELEM(protocols_to_try3);
+
+ for (size_t i = 0; i < cnct->p_cnct_count; i++) {
+ cnct->p_cnct_versions[i] = protocols_to_try3[i];
+ }
+
+ if (!(port = XNET_connect(packet, status_vector, 0)))
+ {
+ delete rdb;
+ return NULL;
+ }
+
+ // Get response packet from server
+
+ rdb->rdb_port = port;
+ port->port_context = rdb;
+ port->receive(packet);
+ }
+
+ if (packet->p_operation != op_accept)
+ {
+ *status_vector++ = isc_arg_gds;
+ *status_vector++ = isc_connect_reject;
+ *status_vector++ = isc_arg_end;
+ disconnect(port);
+ delete rdb;
+ return NULL;
+ }
+
+ port->port_protocol = packet->p_acpt.p_acpt_version;
+
+ // Once we've decided on a protocol, concatenate the version
+ // string to reflect it...
+
+ Firebird::string temp;
+ temp.printf("%s/P%d", port->port_version->str_data,
+ port->port_protocol & FB_PROTOCOL_MASK);
+
+ delete port->port_version;
+ port->port_version = REMOTE_make_string(temp.c_str());
+
+ if (packet->p_acpt.p_acpt_architecture == ARCHITECTURE)
+ port->port_flags |= PORT_symmetric;
+
+ if (packet->p_acpt.p_acpt_type == ptype_rpc)
+ port->port_flags |= PORT_rpc;
+
+ if (packet->p_acpt.p_acpt_type != ptype_out_of_band)
+ port->port_flags |= PORT_no_oob;
+
+ return port;
+}
+
+
+rem_port* XNET_connect(PACKET* packet,
+ ISC_STATUS* status_vector,
+ USHORT flag)
+{
+/**************************************
+ *
+ * X N E T _ c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * Establish half of a communication link.
+ *
+ **************************************/
+ if (xnet_shutdown)
+ {
+ Arg::StatusVector temp;
+ temp << Arg::Gds(isc_net_server_shutdown) << Arg::Str("XNET");
+ temp.copyTo(status_vector);
+
+ return NULL;
+ }
+
+ if (packet)
+ {
+ return connect_client(packet, status_vector);
+ }
+
+ return connect_server(status_vector, flag);
+}
+
+
+rem_port* XNET_reconnect(ULONG client_pid, ISC_STATUS* status_vector)
+{
+/**************************************
+ *
+ * X N E T _ r e c o n n e c t
+ *
+ **************************************
+ *
+ * Functional description
+ * Classic server initialization code
+ *
+ **************************************/
+
+ rem_port* port = NULL;
+ XPM xpm = NULL;
+
+ // Initialize server-side IPC endpoint to a value we know we have permissions to listen at
+ if (strcmp(xnet_endpoint, "") == 0)
+ {
+ fb_utils::copy_terminate(xnet_endpoint, Config::getIpcName(), sizeof(xnet_endpoint));
+ fb_utils::prefix_kernel_object_name(xnet_endpoint, sizeof(xnet_endpoint));
+ }
+
+ global_slots_per_map = 1;
+ global_pages_per_slot = XPS_MAX_PAGES_PER_CLI;
+ xnet_response_event = 0;
+
+ // current_process_id used as map number
+ current_process_id = getpid();
+
+ try
+ {
+ TEXT name_buffer[BUFFER_TINY];
+ make_obj_name(name_buffer, sizeof(name_buffer), XNET_RESPONSE_EVENT);
+ xnet_response_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
+ if (!xnet_response_event) {
+ Firebird::system_error::raise(ERR_STR("OpenEvent"));
+ }
+
+ xpm = make_xpm(current_process_id, 0);
+
+ port = get_server_port(client_pid, xpm, current_process_id, 0, 0, status_vector);
+ }
+ catch (const Firebird::Exception& ex)
+ {
+ stuff_exception(status_vector, ex);
+ xnet_log_error("Unable to initialize child process", status_vector);
+
+ if (port)
+ {
+ cleanup_port(port);
+ port = NULL;
+ }
+ else if (xpm)
+ cleanup_mapping(xpm);
+ }
+
+ if (xnet_response_event)
+ {
+ SetEvent(xnet_response_event); // to prevent client blocking
+ CloseHandle(xnet_response_event);
+ }
+
+ return port;
+}
+
+
+static bool connect_init(ISC_STATUS* status)
+{
+/**************************************
+ *
+ * c o n n e c t _ i n i t
+ *
+ **************************************
+ *
+ * Functional description
+ * Initialization of client side resources used
+ * when client performs connect to server
+ *
+ **************************************/
+ TEXT name_buffer[BUFFER_TINY];
+
+ xnet_connect_mutex = 0;
+ xnet_connect_map_h = 0;
+ xnet_connect_map = 0;
+
+ xnet_connect_event = 0;
+ xnet_response_event = 0;
+
+ try
+ {
+ make_obj_name(name_buffer, sizeof(name_buffer), XNET_CONNECT_MUTEX);
+ xnet_connect_mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, name_buffer);
+ if (!xnet_connect_mutex)
+ {
+ if (ERRNO == ERROR_FILE_NOT_FOUND)
+ {
+ Arg::Gds temp(isc_unavailable);
+ temp.copyTo(status);
+
+ return false;
+ }
+
+ Firebird::system_error::raise(ERR_STR("OpenMutex"));
+ }
+
+ make_obj_name(name_buffer, sizeof(name_buffer), XNET_CONNECT_EVENT);
+ xnet_connect_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
+ if (!xnet_connect_event) {
+ Firebird::system_error::raise(ERR_STR("OpenEvent"));
+ }
+
+ make_obj_name(name_buffer, sizeof(name_buffer), XNET_RESPONSE_EVENT);
+ xnet_response_event = OpenEvent(EVENT_ALL_ACCESS, FALSE, name_buffer);
+ if (!xnet_response_event) {
+ Firebird::system_error::raise(ERR_STR("OpenEvent"));
+ }
+
+ make_obj_name(name_buffer, sizeof(name_buffer), XNET_CONNECT_MAP);
+ xnet_connect_map_h = OpenFileMapping(FILE_MAP_WRITE, TRUE, name_buffer);
+ if (!xnet_connect_map_h) {
+ Firebird::system_error::raise(ERR_STR("OpenFileMapping"));
+ }
+
+ xnet_connect_map = MapViewOfFile(xnet_connect_map_h, FILE_M...
[truncated message content] |