/* * PROGRAM: Interprocess Interface server * MODULE: ipserver.c * DESCRIPTION: interprocess interface server * * 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): ______________________________________. */ #include "firebird.h" #include "../jrd/ib_stdio.h" #include #include #include #include "../ipserver/ipc.h" #include "../jrd/license.h" #include "../jrd/gds.h" #include "../jrd/gds_proto.h" #include "../ipserver/alli_proto.h" #include "../jrd/thd_proto.h" #include "../ipserver/ipsrv_proto.h" #include "../ipserver/ips.h" #include "../jrd/isc_proto.h" #include "../jrd/sch_proto.h" #include "../jrd/ibsetjmp.h" #include "../jrd/why_proto.h" #include "../common/config/config.h" #include "../jrd/gdsassert.h" static void allocate_statement(ICC); static void attach_database(ICC, P_OP); static void cancel_events(ICC); static USHORT check_statement_type(IPSERVER_ISR); static void compile(ICC); static void ddl(ICC); static void drop_database(ICC); static void end_blob(ICC, P_OP); static void end_database(ICC); static void end_request(ICC); static void end_statement(ICC); static void end_transaction(ICC, P_OP); static void event_ast(IVNT, USHORT, UCHAR *); static void execute_immediate(ICC, P_OP); static void execute_statement(ICC, P_OP); static void fetch(ICC); static UCHAR *get_buffer(IPS, USHORT, USHORT); static void get_segment(ICC); static void get_slice(ICC); static void info(ICC, P_OP); static void insert(ICC); static void ipi_end_thread(ICC); static void ipi_server(ICC); static IPM make_map(USHORT); static ITR make_transaction(IDB, FRBRD *); static void open_blob(ICC, P_OP); static void prepare_statement(ICC); static void put_segment(ICC); static void put_slice(ICC); static void que_events(ICC); static void receive_msg(ICC); static void reconnect(ICC); static void release_blob(IBL); static void release_event(IVNT); static void release_request(IRQ); static void release_sql_request(IPSERVER_ISR); static void release_transaction(ITR); static void seek_blob(ICC); static BOOL send_and_wait(ICC); static void send_msg(ICC); static void send_no_wait(ICC); static void send_response(ICC, ISC_STATUS *); static void set_cursor(ICC); static void service_attach(ICC); static void service_end(ICC); static void service_start(ICC); static void shutdown_attachments(ICC); static void start(ICC); static void start_and_send(ICC); static void start_transaction(ICC); static void transact_request(ICC); static BOOL transfer_buffers(ICC, ips_comm_area *); static void unwind(ICC); static BOOL wait_no_send(ICC); static HWND IPSVR_window = NULL; static UCHAR sql_info[] = { isc_info_sql_batch_fetch }; /* Macro to check a given handle for validity. While generally * we can depend on the client-side remote library to do this * for us, there were bugs due to not checking on our side. * Also, since these handles are passed though to * the why-value routines and checked there, strictly speaking * we only have to check ones that we dereference before * passing along. For safety's side, we check them all. */ /* h = handle to check * t = type of handle to expect * c = error code to return */ #define CHECK_HANDLE(h,t,c) if ( !(h) || (((BLK) (h))->blk_type !=( t))) \ { \ status_vector[0] = isc_arg_gds;\ status_vector[1] = (c);\ status_vector[2] = isc_arg_end;\ send_response( icc, status_vector); \ return; \ } #define NOT_NULL(p,s) if ( !(p) && (s)) \ { \ status_vector[0] = isc_arg_gds;\ status_vector[1] = isc_virmemexh;\ status_vector[2] = isc_arg_end;\ send_response( icc, status_vector); \ return; \ } #define GET_COMM_OBJECT { comm = (ips_comm_area*)icc->icc_mapped_addr;\ comm_ptr = (TEXT*)comm->ips_data;} #define IPS_SERVER(c,n,a,s) { c->ips_buffers[n].ips_sv_size = s;\ c->ips_buffers[n].ips_sv_addr = a;\ c->ips_buffers[n].ips_sv_copied = 0;} #define GDS_ATTACH_DATABASE isc_attach_database #define GDS_BLOB_INFO isc_blob_info #define GDS_CANCEL_BLOB isc_cancel_blob #define GDS_CANCEL_EVENTS isc_cancel_events #define GDS_CLOSE_BLOB isc_close_blob #define GDS_COMMIT isc_commit_transaction #define GDS_COMMIT_RETAINING isc_commit_retaining #define GDS_COMPILE isc_compile_request #define GDS_CREATE_BLOB isc_create_blob #define GDS_CREATE_BLOB2 isc_create_blob2 #define GDS_CREATE_DATABASE isc_create_database #define GDS_DATABASE_INFO isc_database_info #define GDS_DDL isc_ddl #define GDS_DETACH isc_detach_database #define GDS_DROP_DATABASE isc_drop_database #define GDS_GET_SEGMENT isc_get_segment #define GDS_GET_SLICE isc_get_slice #define GDS_OPEN_BLOB isc_open_blob #define GDS_OPEN_BLOB2 isc_open_blob2 #define GDS_PREPARE isc_prepare_transaction #define GDS_PREPARE2 isc_prepare_transaction2 #define GDS_PUT_SEGMENT isc_put_segment #define GDS_PUT_SLICE isc_put_slice #define GDS_QUE_EVENTS isc_que_events #define GDS_RECONNECT isc_reconnect_transaction #ifdef SCROLLABLE_CURSORS #define GDS_RECEIVE isc_receive2 #else #define GDS_RECEIVE isc_receive #endif #define GDS_RELEASE_REQUEST isc_release_request #define GDS_REQUEST_INFO isc_request_info #define GDS_ROLLBACK isc_rollback_transaction #define GDS_ROLLBACK_RETAINING isc_rollback_retaining #define GDS_SEEK_BLOB isc_seek_blob #define GDS_SEND isc_send #define GDS_SERVICE_ATTACH isc_service_attach #define GDS_SERVICE_DETACH isc_service_detach #define GDS_SERVICE_QUERY isc_service_query #define GDS_SERVICE_START isc_service_start #define GDS_START_AND_SEND isc_start_and_send #define GDS_START isc_start_request #define GDS_START_MULTIPLE isc_start_multiple #define GDS_START_TRANSACTION isc_start_transaction #define GDS_TRANSACT_REQUEST isc_transact_request #define GDS_TRANSACTION_INFO isc_transaction_info #define GDS_UNWIND isc_unwind_request #define GDS_DSQL_ALLOCATE isc_dsql_allocate_statement #define GDS_DSQL_EXECUTE isc_dsql_execute2_m #define GDS_DSQL_EXECUTE_IMMED isc_dsql_exec_immed3_m #define GDS_DSQL_FETCH isc_dsql_fetch_m #define GDS_DSQL_FREE isc_dsql_free_statement #define GDS_DSQL_INSERT isc_dsql_insert_m #define GDS_DSQL_PREPARE isc_dsql_prepare_m #define GDS_DSQL_SET_CURSOR isc_dsql_set_cursor_name #define GDS_DSQL_SQL_INFO isc_dsql_sql_info // // TMN: // // Static data ahead. // // But the multithread-wizard said: // - Let there be light. Move static data into specific instances. // Let these instances be one per thread, and there will be rejoicing // among your followers again... Currently we don't use thread-specific // data here, but putting it in a struct is a step. // struct ipserver_private_data_t { IPM first_ipm; IPM ipms; MUTX_T ipics; USHORT pages_per_user; USHORT users_per_map; // TMN: num_maps was never used, why I patched it with comments. // If anyone can shed some light as to why this was added in the // first place it would be appreciated. // USHORT num_maps; }; static ipserver_private_data_t ipserver_private_data = { 0, // first_ipm 0, // ipms { 0 }, // ipics - DON'T REMOVE THE BRACES! IPS_DEF_PAGES_PER_CLI, // pages_per_user IPS_DEF_NUM_CLI // users_per_map }; #ifdef DEBUG_IP_TRACE static const char* op_strings[] = { "op_attach", "op_create", "op_detach", "op_compile", "op_start", "op_start_and_send", "op_send", "op_receive", "op_unwind", "op_release", "op_transaction", "op_commit", "op_rollback", "op_reconnect", "op_create_blob", "op_open_blob", "op_get_segment", "op_put_segment", "op_cancel_blob", "op_close_blob", "op_info_database", "op_info_request", "op_info_transaction", "op_info_blob", "op_prepare2", "op_commit_retaining", "op_rollback_retaining", "op_open_blob2", "op_create_blob2", "op_ddl", "op_que_events", "op_cancel_events", "op_put_slice", "op_get_slice", "op_seek_blob", "op_allocate_stmt", "op_execute", "op_exec_immediate", "op_fetch", "op_free_stmt", "op_prepare_stmt", "op_set_cursor", "op_info_sql", "op_insert", "op_execute2", "op_exec_immediate2", "op_service_attach", "op_service_detach", "op_service_info", "op_service_start", "op_transact_request", "op_drop_database", "op_ping", "op_disconnect" }; #endif #if defined(SUPERSERVER) && defined(WIN_NT) extern "C" { static void atexit_close_handles() { IPM pFirstIpm = ipserver_private_data.first_ipm; for (IPM pIpm = pFirstIpm; pIpm; pIpm = pIpm->ipm_next) { if (pIpm->ipm_address) { UnmapViewOfFile(pIpm->ipm_address); pIpm->ipm_address = 0; } if (pIpm->ipm_handle) { CloseHandle(pIpm->ipm_handle); pIpm->ipm_handle = 0; } } } } #endif // SUPERSERVER && WIN_NT USHORT IPS_init(HWND hwnd, USHORT usrs_pr_mp, USHORT pgs_pr_usr, USHORT mx_mps) { /************************************** * * I P S _ i n i t * ************************************** * * Functional description * Create a critical section structure and init * the mapped file stuff. Returns 1 if successful * and 0 otherwise. * **************************************/ /* init the limits */ if (usrs_pr_mp && usrs_pr_mp >= IPS_MIN_NUM_CLI && usrs_pr_mp <= IPS_MAX_NUM_CLI) { ipserver_private_data.users_per_map = usrs_pr_mp; } if (pgs_pr_usr && pgs_pr_usr >= IPS_MIN_PAGES_PER_CLI && pgs_pr_usr <= IPS_MAX_PAGES_PER_CLI) { ipserver_private_data.pages_per_user = pgs_pr_usr; } // TMN: Disabled code. See definition of the struct above for comments. // if (mx_mps && mx_mps >= IPS_MIN_NUM_MAPS && mx_mps <= IPS_MAX_NUM_MAPS) { // ipserver_private_data.num_maps = mx_mps; // } /* init mapped chain and critical regions */ ipserver_private_data.ipms = NULL; THD_mutex_init(&ipserver_private_data.ipics); IPSVR_window = hwnd; /* create the first map (failure means it's already there */ IPM ipm = make_map(0); if (ipm && (ipm != (IPM) - 1)) { fb_assert(!ipserver_private_data.first_ipm); ipserver_private_data.first_ipm = ipm; #if defined(SUPERSERVER) && defined(WIN_NT) // TMN: 2003-03-11: Close the handles at server shutdown // Possibly this is also needed for CS, but since I can't test that // I decided to only do it for SS. atexit(&atexit_close_handles); #endif return (USHORT) 1; } return (USHORT)(ULONG) ipm; } ULONG IPS_start_thread(ULONG client_pid) { /************************************** * * I P S _ s t a r t _ t h r e a d * ************************************** * * Functional description * Start an interprocess thread. This allocates * the next available chunk of the mapped file and * tells the client where it is. * **************************************/ ICC icc; USHORT mapped_area, mapped_position; TEXT name_buffer[128]; IPM ipm; USHORT i, j; UCHAR *p; HANDLE server_proc; ips_comm_area *comm; /* go through list of maps */ THD_mutex_lock(&ipserver_private_data.ipics); j = 0; for (ipm = ipserver_private_data.ipms; ipm; ipm = ipm->ipm_next) { /* find an available unused comm area */ for (i = 0; i < ipserver_private_data.users_per_map; i++) { if (!ipm->ipm_ids[i]) { break; } } if (i < ipserver_private_data.users_per_map) { ipm->ipm_count++; ipm->ipm_ids[i]++; j = ipm->ipm_number; break; } j++; } /* if the mapped file structure has not yet been initialized, make one now */ if (!ipm) { /* allocate new map file and first slot */ ipm = make_map(j); /* check for errors in creation of mapped file */ if (!ipm || ipm == (IPM) - 1) { THD_mutex_unlock(&ipserver_private_data.ipics); return (ULONG) - 1; } i = 0; ipm->ipm_ids[0]++; ipm->ipm_count++; } mapped_area = j; mapped_position = i; /* allocate a communications control structure and fill it in */ icc = (ICC) ALLOC(type_icc); if (!icc) { THD_mutex_unlock(&ipserver_private_data.ipics); return (ULONG) - 1; } p = (UCHAR *) ipm->ipm_address; p += IPS_MAPPED_FOR_CLI(ipserver_private_data.pages_per_user, mapped_position); memset(p, (char) 0, IPS_MAPPED_PER_CLI(ipserver_private_data.pages_per_user)); icc->icc_mapped_addr = reinterpret_cast(p); icc->icc_ipm = ipm; icc->icc_slot = mapped_position; icc->icc_flags = 0; icc->icc_client_id = (DWORD) client_pid; icc->icc_client_proc = OpenProcess(PROCESS_ALL_ACCESS, TRUE, icc->icc_client_id); comm = (ips_comm_area *) icc->icc_mapped_addr; comm->ips_client_id = icc->icc_client_id; comm->ips_client_proc = icc->icc_client_proc; comm->ips_server_id = GetCurrentProcessId(); /* make sure client knows what this server speaks */ comm->ips_server_protocol = 1L; comm->ips_client_protocol = 0L; /* Duplicate the server process handle for client synchronization */ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &server_proc, PROCESS_ALL_ACCESS, FALSE, 0)) { CHAR szBuf[80]; DWORD dw = GetLastError(); sprintf(szBuf, "%s:%s failed: GetLastError returned %lu\n", "ipserver.c", "DuplicateHandle(server_proc)", dw); gds__log(szBuf); } if (!DuplicateHandle(server_proc, server_proc, comm->ips_client_proc, &comm->ips_server_proc, SYNCHRONIZE, FALSE, 0)) { CHAR szBuf[80]; DWORD dw = GetLastError(); sprintf(szBuf, "%s:%s failed: GetLastError returned %lu\n", "ipserver.c", "DuplicateHandle(ips_server_proc)", dw); gds__log(szBuf); comm->ips_server_proc = 0; } CloseHandle(server_proc); /* create the semaphores and put the handles into the icc */ sprintf(name_buffer, IPI_CLIENT_SEM_NAME, Config::getIpcName(), mapped_area, mapped_position); icc->icc_client_sem = CreateSemaphore(ISC_get_security_desc(), 0L, 1L, name_buffer); sprintf(name_buffer, IPI_SERVER_SEM_NAME, Config::getIpcName(), mapped_area, mapped_position); icc->icc_server_sem = CreateSemaphore(ISC_get_security_desc(), 0L, 1L, name_buffer); /* make sure semaphores are "empty" */ while (WaitForSingleObject(icc->icc_client_sem, (DWORD) 1) == WAIT_OBJECT_0); while (WaitForSingleObject(icc->icc_server_sem, (DWORD) 1) == WAIT_OBJECT_0); /* initialize wait for multiple objects array */ icc->icc_waits[0] = icc->icc_server_sem; icc->icc_waits[1] = icc->icc_client_proc; /* finally, start the thread for this client */ gds__thread_start(reinterpret_cast < FPTR_INT_VOID_PTR > (ipi_server), icc, THREAD_medium, 0, 0); /* return combined mapped area and number */ #ifdef DEBUG_IP_TRACE gds__log("ipserver icc %8lX, comm %8lX", icc, comm); #endif THD_mutex_unlock(&ipserver_private_data.ipics); return IPS_PACK_PARAMS(ipserver_private_data.users_per_map, ipserver_private_data.pages_per_user, mapped_area, mapped_position); } static void ipi_end_thread( ICC icc) { /************************************** * * i p i _ e n d _ t h r e a d * ************************************** * * Functional description * End a thread's existence, close its handles, * free its slot and whatnot. * **************************************/ /* free up this thread's slot */ IPM ipm = icc->icc_ipm; THD_mutex_lock(&ipserver_private_data.ipics); ipm->ipm_ids[icc->icc_slot] = 0; ipm->ipm_count--; /* if last slot was emptied, unmap and free structure, except for the first map, which is always retained */ if (!ipm->ipm_count && ipm != ipserver_private_data.first_ipm) { if (ipm->ipm_address) { UnmapViewOfFile(ipm->ipm_address); ipm->ipm_address = 0; } if (ipm->ipm_handle) { CloseHandle(ipm->ipm_handle); ipm->ipm_handle = 0; } if (ipserver_private_data.ipms == ipm){ ipserver_private_data.ipms = ipm->ipm_next; } else { for (IPM pipm = ipserver_private_data.ipms; pipm->ipm_next; pipm = pipm->ipm_next) { if (pipm->ipm_next == ipm) { pipm->ipm_next = ipm->ipm_next; break; } } } ALLI_free((UCHAR *) ipm); } /* close handles for semaphores */ CloseHandle(icc->icc_client_sem); CloseHandle(icc->icc_server_sem); CloseHandle(icc->icc_client_proc); ALLI_release((BLK) icc); THD_mutex_unlock(&ipserver_private_data.ipics); } static void ipi_server( ICC icc) { /************************************** * * i p i _ s e r v e r * ************************************** * * Functional description * Main entrypoint of server. * **************************************/ ips_comm_area *comm; TEXT *comm_ptr; // start this thread gds__thread_enable(-1); /* error handler */ try { /* request processing loop */ while (!(icc->icc_flags & ICCF_SHUTDOWN)) { if (!wait_no_send(icc)) break; GET_COMM_OBJECT; comm->ips_ops_count++; #ifdef DEBUG_IP_TRACE { char line[200]; sprintf(line, "%8lX %8lX %8lX %d ipserver %s", (long) GetCurrentThreadId(), (long) icc, comm, comm->ips_operation, op_strings[comm->ips_operation]); gds__log(line); } #endif switch (comm->ips_operation) { case op_attach: case op_create: attach_database(icc, static_cast(comm->ips_operation)); break; case op_cancel_events: cancel_events(icc); break; case op_compile: compile(icc); break; case op_ddl: ddl(icc); break; case op_receive: receive_msg(icc); break; case op_seek_blob: seek_blob(icc); break; case op_send: send_msg(icc); break; case op_start: start(icc); break; case op_start_and_send: start_and_send(icc); break; case op_transact_request: transact_request(icc); break; case op_transaction: start_transaction(icc); break; case op_rollback: case op_commit: case op_commit_retaining: case op_rollback_retaining: case op_prepare2: end_transaction(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_detach: end_database(icc); break; case op_drop_database: drop_database(icc); break; case op_create_blob: case op_open_blob: case op_create_blob2: case op_open_blob2: open_blob(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_put_segment: put_segment(icc); break; case op_get_segment: get_segment(icc); break; case op_cancel_blob: case op_close_blob: end_blob(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_release: end_request(icc); break; case op_que_events: que_events(icc); break; case op_unwind: unwind(icc); break; case op_reconnect: reconnect(icc); break; case op_info_blob: case op_info_request: case op_info_database: case op_info_transaction: case op_info_sql: case op_service_info: info(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_get_slice: get_slice(icc); break; case op_put_slice: put_slice(icc); break; case op_allocate_stmt: allocate_statement(icc); break; case op_execute: case op_execute2: execute_statement(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_exec_immediate: case op_exec_immediate2: execute_immediate(icc, static_cast < P_OP > (comm->ips_operation)); break; case op_fetch: fetch(icc); break; case op_free_stmt: end_statement(icc); break; case op_insert: insert(icc); break; case op_prepare_stmt: prepare_statement(icc); break; case op_set_cursor: set_cursor(icc); break; case op_service_attach: service_attach(icc); break; case op_service_detach: service_end(icc); break; case op_service_start: service_start(icc); break; case op_disconnect: icc->icc_flags |= ICCF_SHUTDOWN; break; default: gds__log("Interprocess Server op code %d unknown\n", (int *)(ULONG) comm->ips_operation); icc->icc_flags |= ICCF_SHUTDOWN; break; } } /* left loop, so shut down */ shutdown_attachments(icc); ipi_end_thread(icc); } // try catch (const std::exception&) { gds__log("ipi_server: error during startup, shutting down"); } } static void allocate_statement( ICC icc) { /************************************** * * a l l o c a t e _ s t a t e m e n t * ************************************** * * Functional description * Allocate a statement handle. * **************************************/ IDB idb; IPSERVER_ISR statement; FRBRD* handle; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_dsql *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); handle = NULL; /* allocate the statement and create a structure */ result = GDS_DSQL_ALLOCATE(status_vector, &idb->idb_handle, &handle); if (!result) { statement = (IPSERVER_ISR) ALLOC(type_ipserver_isr); ips->ips_st_handle = (UCHAR *) statement; NOT_NULL(statement, TRUE); statement->isr_handle = handle; statement->isr_idb = idb; statement->isr_next = idb->idb_sql_requests; statement->isr_batch_flag = 0; statement->isr_max_recs = 0; statement->isr_packed = NULL; idb->idb_sql_requests = statement; } else { ips->ips_st_handle = NULL; } send_response(icc, status_vector); } static void attach_database( ICC icc, P_OP operation) { /************************************** * * a t t a c h _ d a t a b a s e * ************************************** * * Functional description * Process an attach or create packet. * **************************************/ USHORT file_length, dpb_length, expanded_length; UCHAR *file_name, file_buf[256], *dpb, dpb_buf[256]; UCHAR *expanded, expanded_buf[256]; FRBRD* handle; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; IDB idb; ips_object *ips; ips_string *ips_name; ips_string *ips_dpb; ips_string *ips_expanded; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; /* figure out file name buffer */ ips_name = &comm->ips_buffers[IPS_ATTACH_NAME]; file_length = (USHORT) ips_name->ips_cl_size; if (file_length <= sizeof(file_buf)) file_name = file_buf; else file_name = get_buffer(comm, file_length, IPS_ATTACH_NAME); NOT_NULL(file_name, TRUE); IPS_SERVER(comm, IPS_ATTACH_NAME, file_name, file_length); /* figure out dpb buffer */ ips_dpb = &comm->ips_buffers[IPS_ATTACH_DPB]; dpb_length = (USHORT) ips_dpb->ips_cl_size; if (dpb_length <= sizeof(dpb_buf)) dpb = dpb_buf; else dpb = get_buffer(comm, dpb_length, IPS_ATTACH_DPB); NOT_NULL(dpb, dpb_length); IPS_SERVER(comm, IPS_ATTACH_DPB, dpb, dpb_length); /* figure out expanded file name buffer */ ips_expanded = &comm->ips_buffers[IPS_ATTACH_EXPANDED]; expanded_length = (USHORT) ips_expanded->ips_cl_size; if (expanded_length <= sizeof(expanded_buf)) expanded = expanded_buf; else expanded = get_buffer(comm, expanded_length, IPS_ATTACH_EXPANDED); NOT_NULL(expanded, expanded_length); IPS_SERVER(comm, IPS_ATTACH_EXPANDED, expanded, expanded_length); if (!transfer_buffers(icc, comm)) return; /* get handle */ handle = NULL; if (operation == op_attach) result = GDS_ATTACH_DATABASE(status_vector, file_length, reinterpret_cast < char *>(file_name), GDS_REF(handle), dpb_length, reinterpret_cast < char *>(dpb)); else result = GDS_CREATE_DATABASE(status_vector, file_length, reinterpret_cast < char *>(file_name), GDS_REF(handle), dpb_length, reinterpret_cast < char *>(dpb), 0); /* allocate structure and return handle */ if (!result) { idb = (IDB) ALLOC(type_idb); ips->ips_handle = (UCHAR *) idb; NOT_NULL(idb, TRUE); idb->idb_flags = IDBF_DATABASE_ATTACHMENT; idb->idb_handle = handle; idb->idb_next = icc->icc_databases; icc->icc_databases = idb; } else ips->ips_handle = NULL; send_response(icc, status_vector); } static void cancel_events( ICC icc) { /************************************** * * c a n c e l _ e v e n t s * ************************************** * * Functional description * Cancel an outstanding event call. * **************************************/ ISC_STATUS_ARRAY status_vector; IDB idb; IVNT event; SLONG id; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; idb = (IDB) ips->ips_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); id = ips->ips_parameter; /* perform operation, return response and remove event */ GDS_CANCEL_EVENTS(status_vector, GDS_REF(idb->idb_handle), GDS_REF(id)); for (event = idb->idb_events; event; event = event->ivnt_next) { if (event->ivnt_ast && event->ivnt_id == id) { event->ivnt_ast = NULL; event->ivnt_id = 0; break; } } send_response(icc, status_vector); } static USHORT check_statement_type( IPSERVER_ISR statement) { /************************************** * * c h e c k _ s t a t e m e n t _ t y p e * ************************************** * * Functional description * Return the type of SQL statement. * **************************************/ UCHAR buffer[16], *info; USHORT l, type; ISC_STATUS_ARRAY local_status; ISC_STATUS result; USHORT ret; BOOLEAN done; /* init to no batch allowed */ ret = 0; done = FALSE; result = GDS_DSQL_SQL_INFO(local_status, &statement->isr_handle, sizeof(sql_info), reinterpret_cast < char *>(sql_info), sizeof(buffer), reinterpret_cast < char *>(buffer)); if (!result) { /* check the buffer for a batch fetch flag */ for (info = buffer; (*info != isc_info_end) && !done;) { l = (USHORT)isc_vax_integer(reinterpret_cast(info + 1), 2); type = (USHORT)isc_vax_integer(reinterpret_cast(info + 3), l); switch (*info) { case isc_info_sql_batch_fetch: ret = type; done = TRUE; break; case isc_info_error: case isc_info_truncated: done = TRUE; break; } info += 3 + l; } } return ret; } static void compile( ICC icc) { /************************************** * * c o m p i l e * ************************************** * * Functional description * Compile a request. * **************************************/ IDB idb; IRQ request; USHORT blr_length; UCHAR *blr; FRBRD* handle; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_compile_req *ips; ips_string *ips_blr; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_compile; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* set up blr buffer */ ips_blr = &comm->ips_buffers[IPS_COMPILE_REQ]; blr_length = (USHORT) ips_blr->ips_cl_size; blr = get_buffer(comm, blr_length, IPS_COMPILE_REQ); NOT_NULL(blr, blr_length); IPS_SERVER(comm, IPS_COMPILE_REQ, blr, blr_length); if (!transfer_buffers(icc, comm)) return; /* compile and get handle */ handle = NULL; result = GDS_COMPILE(status_vector, GDS_REF(idb->idb_handle), GDS_REF(handle), blr_length, reinterpret_cast < char *>(GDS_VAL(blr))); /* create data structure and return handle */ if (!result) { request = (IRQ) ALLOC(type_irq); ips->ips_rq_handle = (UCHAR *) request; NOT_NULL(request, TRUE); request->irq_handle = handle; request->irq_idb = idb; request->irq_next = idb->idb_requests; idb->idb_requests = request; } else ips->ips_rq_handle = NULL; send_response(icc, status_vector); } static void ddl( ICC icc) { /************************************** * * d d l * ************************************** * * Functional description * Pass thru a DDL call. * **************************************/ ISC_STATUS_ARRAY status_vector; ITR transaction; IDB idb; UCHAR *buffer; USHORT length; ips_ddl *ips; ips_string *ips_ddl_string; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_ddl; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); /* set up ddl buffer */ ips_ddl_string = &comm->ips_buffers[IPS_DDL_DDL]; length = (USHORT) ips_ddl_string->ips_cl_size; buffer = get_buffer(comm, length, IPS_DDL_DDL); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_DDL_DDL, buffer, length); if (!transfer_buffers(icc, comm)) return; /* perform operation and return response */ GDS_DDL(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), length, reinterpret_cast < char *>(GDS_VAL(buffer))); send_response(icc, status_vector); } static void drop_database( ICC icc) { /************************************** * * d r o p _ d a t a b a s e * ************************************** * * Functional description * End a request. * **************************************/ IDB idb, *ptr; ISC_STATUS_ARRAY status_vector; ISC_STATUS code; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; idb = (IDB) ips->ips_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* drop database, release resources and send response */ code = GDS_DROP_DATABASE(status_vector, &idb->idb_handle); send_response(icc, status_vector); if (!code || (code == isc_drdb_completed_with_errs)) { while (idb->idb_events) release_event(idb->idb_events); while (idb->idb_requests) release_request(idb->idb_requests); while (idb->idb_sql_requests) release_sql_request(idb->idb_sql_requests); while (idb->idb_transactions) release_transaction(idb->idb_transactions); for (ptr = &icc->icc_databases; *ptr; ptr = &(*ptr)->idb_next) { if (*ptr == idb) { *ptr = idb->idb_next; break; } } ALLI_release((BLK) idb); } } static void end_blob( ICC icc, P_OP operation) { /************************************** * * e n d _ b l o b * ************************************** * * Functional description * End a blob. * **************************************/ IBL blob; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; UCHAR *buffer; USHORT length; ips_object *ips; ips_string *ips_seg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; blob = (IBL) ips->ips_handle; CHECK_HANDLE(blob, type_ibl, isc_bad_segstr_handle); /* set up buffer for last segment, if any */ ips_seg = &comm->ips_buffers[IPS_CLOSE_BLOB_REM]; length = (USHORT) ips_seg->ips_cl_size; if (length) { buffer = get_buffer(comm, length, IPS_CLOSE_BLOB_REM); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_CLOSE_BLOB_REM, buffer, length); if (!transfer_buffers(icc, comm)) return; } /* perform operation, send response and free resources */ if (operation == op_close_blob) result = GDS_CLOSE_BLOB(status_vector, GDS_REF(blob->ibl_handle)); else result = GDS_CANCEL_BLOB(status_vector, GDS_REF(blob->ibl_handle)); send_response(icc, status_vector); if (!result) release_blob(blob); } static void end_database( ICC icc) { /************************************** * * e n d _ d a t a b a s e * ************************************** * * Functional description * End a request. * **************************************/ IDB idb, *ptr; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; idb = (IDB) ips->ips_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* detach database, send response and free resources */ result = GDS_DETACH(status_vector, GDS_REF(idb->idb_handle)); send_response(icc, status_vector); if (!result) { while (idb->idb_events) release_event(idb->idb_events); while (idb->idb_requests) release_request(idb->idb_requests); while (idb->idb_sql_requests) release_sql_request(idb->idb_sql_requests); while (idb->idb_transactions) release_transaction(idb->idb_transactions); for (ptr = &icc->icc_databases; *ptr; ptr = &(*ptr)->idb_next) { if (*ptr == idb) { *ptr = idb->idb_next; break; } } ALLI_release((BLK) idb); } } static void end_request( ICC icc) { /************************************** * * e n d _ r e q u e s t * ************************************** * * Functional description * End a request. * **************************************/ IRQ request; ISC_STATUS_ARRAY status_vector; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; request = (IRQ) ips->ips_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); /* process call, respond and free resources */ GDS_RELEASE_REQUEST(status_vector, GDS_REF(request->irq_handle)); send_response(icc, status_vector); release_request(request); } static void end_statement( ICC icc) { /************************************** * * e n d _ s t a t e m e n t * ************************************** * * Functional description * Free a dynamic statement. * **************************************/ IPSERVER_ISR statement; USHORT option; ISC_STATUS_ARRAY status_vector; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; statement = (IPSERVER_ISR) ips->ips_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); option = (USHORT) ips->ips_parameter; /* free statement, return response and free resources */ GDS_DSQL_FREE(status_vector, &statement->isr_handle, option); if (statement->isr_handle) { ips->ips_handle = (UCHAR *) statement; send_response(icc, status_vector); } else { ips->ips_handle = (UCHAR *) NULL; send_response(icc, status_vector); release_sql_request(statement); } } static void end_transaction( ICC icc, P_OP operation) { /************************************** * * e n d _ t r a n s a c t i o n * ************************************** * * Functional description * End a transaction. * **************************************/ ITR transaction; UCHAR *msg; USHORT msg_length; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_object *ips; ips_string *ips_prep; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; transaction = (ITR) ips->ips_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); /* set up buffer for prepare2 */ if (operation == op_prepare2) { ips_prep = &comm->ips_buffers[IPS_PREPARE_TRANS]; msg_length = (USHORT) ips_prep->ips_cl_size; msg = get_buffer(comm, msg_length, IPS_PREPARE_TRANS); NOT_NULL(msg, msg_length); IPS_SERVER(comm, IPS_PREPARE_TRANS, msg, msg_length); if (!transfer_buffers(icc, comm)) return; } /* perform operation as required */ switch (operation) { case op_commit: result = GDS_COMMIT(status_vector, GDS_REF(transaction->itr_handle)); if (!result) release_transaction(transaction); break; case op_rollback: result = GDS_ROLLBACK(status_vector, GDS_REF(transaction->itr_handle)); if (!result) release_transaction(transaction); break; case op_commit_retaining: result = GDS_COMMIT_RETAINING(status_vector, GDS_REF(transaction->itr_handle)); break; case op_rollback_retaining: result = GDS_ROLLBACK_RETAINING(status_vector, GDS_REF(transaction->itr_handle)); break; case op_prepare2: result = GDS_PREPARE2(status_vector, GDS_REF(transaction->itr_handle), msg_length, reinterpret_cast(GDS_VAL(msg))); if (!result) transaction->itr_flags |= ITR_limbo; break; } send_response(icc, status_vector); } static void event_ast( IVNT event, USHORT length, UCHAR * data) { /************************************** * * e v e n t _ a s t * ************************************** * * Functional description * Send off event stuff. * **************************************/ COPYDATASTRUCT cpdata; ULONG result; if (!event->ivnt_ast) return; cpdata.dwData = (DWORD) event->ivnt_id; cpdata.cbData = (DWORD) length; cpdata.lpData = (LPVOID) data; result = SendMessage(event->ivnt_window, WM_COPYDATA, (WPARAM) IPSVR_window, (LPARAM) & cpdata); event->ivnt_ast = NULL; } static void execute_immediate( ICC icc, P_OP operation) { /************************************** * * e x e c u t e _ i m m e d i a t e * ************************************** * * Functional description * Prepare and execute a statement. * **************************************/ IDB idb; ITR transaction; FRBRD* handle; USHORT length, dialect, in_blr_length, in_msg_type, in_msg_length, out_blr_length, out_msg_type, out_msg_length, parser_version; UCHAR *string, *in_blr, *in_msg, *out_blr, *out_msg; ISC_STATUS_ARRAY status_vector; ips_dsql *ips; ips_string *ips_blr; ips_string *ips_msg; ips_string *ips_sql; ips_string *ips_blr_out; ips_string *ips_msg_out; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; if (transaction) { CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); handle = transaction->itr_handle; } else handle = NULL; in_msg_type = ips->ips_msg_type; dialect = (USHORT) ips->ips_parameter; /* set up sql */ ips_sql = &comm->ips_buffers[IPS_DSQL_EXEC_IMMED_SQL]; length = (USHORT) ips_sql->ips_cl_size; string = get_buffer(comm, length, IPS_DSQL_EXEC_IMMED_SQL); NOT_NULL(string, length); IPS_SERVER(comm, IPS_DSQL_EXEC_IMMED_SQL, string, length); /* set up blr */ ips_blr = &comm->ips_buffers[IPS_DSQL_EXEC_IMMED_BLR]; in_blr_length = (USHORT) ips_blr->ips_cl_size; in_blr = get_buffer(comm, in_blr_length, IPS_DSQL_EXEC_IMMED_BLR); NOT_NULL(in_blr, in_blr_length); IPS_SERVER(comm, IPS_DSQL_EXEC_IMMED_BLR, in_blr, in_blr_length); /* set up message */ ips_msg = &comm->ips_buffers[IPS_DSQL_EXEC_IMMED_MSG]; in_msg_length = (USHORT) ips_msg->ips_cl_size; in_msg = get_buffer(comm, in_msg_length, IPS_DSQL_EXEC_IMMED_MSG); NOT_NULL(in_msg, in_msg_length); IPS_SERVER(comm, IPS_DSQL_EXEC_IMMED_MSG, in_msg, in_msg_length); /* set up output message and blr if necessary */ if (operation == op_exec_immediate2) { out_msg_type = ips->ips_msg_out; ips_blr_out = &comm->ips_buffers[IPS_DSQL_EXEC_IMMED2_BLR_OUT]; out_blr_length = (USHORT) ips_blr_out->ips_cl_size; out_blr = get_buffer(comm, out_blr_length, IPS_DSQL_EXEC_IMMED2_BLR_OUT); NOT_NULL(out_blr, out_blr_length); IPS_SERVER(comm, IPS_DSQL_EXEC_IMMED2_BLR_OUT, out_blr, out_blr_length); ips_msg_out = &comm->ips_buffers[IPS_DSQL_EXEC_IMMED2_MSG_OUT]; out_msg_length = (USHORT) ips_msg_out->ips_cl_size; out_msg = get_buffer(comm, out_msg_length, IPS_DSQL_EXEC_IMMED2_MSG_OUT); NOT_NULL(out_msg, out_msg_length); IPS_SERVER(comm, IPS_DSQL_EXEC_IMMED2_MSG_OUT, out_msg, out_msg_length); } else { out_blr_length = out_msg_type = out_msg_length = 0; out_blr = out_msg = NULL; } if (!transfer_buffers(icc, comm)) return; /* NT Local access: Client and server are always the same version */ /* Since the API to GDS_DSQL_EXECUTE_IMMED is public and can not be changed, there needs to * be a way to send the parser version to DSQL so that the parser can compare the keyword * version to the parser version. To accomplish this, the parser version is combined with * the client dialect and sent across that way. In dsql8_execute_immediate, the parser version * and client dialect are separated and passed on to their final desintations. The information * is combined as follows: * Dialect * 10 + parser_version * * and is extracted in dsql8_execute_immediate as follows: * parser_version = ((dialect *10)+parser_version)%10 * client_dialect = ((dialect *10)+parser_version)/10 * * For example, parser_version = 1 and client dialect = 1 * * combined = (1 * 10) + 1 == 11 * * parser = (combined) %10 == 1 * dialect = (combined) / 19 == 1 */ parser_version = 2; /* execute the statement, respond and clean up */ GDS_DSQL_EXECUTE_IMMED(status_vector, &idb->idb_handle, &handle, length, reinterpret_cast < char *>(string), (USHORT) ((dialect * 10) + parser_version), in_blr_length, reinterpret_cast < char *>(in_blr), in_msg_type, in_msg_length, reinterpret_cast < char *>(in_msg), out_blr_length, reinterpret_cast < char *>(out_blr), out_msg_type, out_msg_length, reinterpret_cast < char *>(out_msg)); if (transaction && !handle) { release_transaction(transaction); transaction = NULL; } else if (!transaction && handle) { transaction = make_transaction(idb, handle); NOT_NULL(transaction, TRUE); } ips->ips_tr_handle = (UCHAR *) transaction; send_response(icc, status_vector); } static void execute_statement( ICC icc, P_OP operation) { /************************************** * * e x e c u t e _ s t a t e m e n t * ************************************** * * Functional description * Execute a non-SELECT dynamic SQL statement. * **************************************/ ITR transaction; IPSERVER_ISR statement; FRBRD* handle; USHORT in_blr_length, in_msg_type, in_msg_length, out_blr_length, out_msg_type, out_msg_length; UCHAR *in_blr, *in_msg, *out_blr, *out_msg; ISC_STATUS_ARRAY status_vector; ips_dsql *ips; ips_string *ips_blr; ips_string *ips_msg; ips_string *ips_blr_out; ips_string *ips_msg_out; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; transaction = (ITR) ips->ips_tr_handle; if (transaction) { CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); handle = transaction->itr_handle; } else handle = NULL; statement = (IPSERVER_ISR) ips->ips_st_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); in_msg_type = ips->ips_msg_type; /* set up blr */ ips_blr = &comm->ips_buffers[IPS_DSQL_EXEC_BLR]; in_blr_length = (USHORT) ips_blr->ips_cl_size; in_blr = get_buffer(comm, in_blr_length, IPS_DSQL_EXEC_BLR); NOT_NULL(in_blr, in_blr_length); IPS_SERVER(comm, IPS_DSQL_EXEC_BLR, in_blr, in_blr_length); /* set up message */ ips_msg = &comm->ips_buffers[IPS_DSQL_EXEC_MSG]; in_msg_length = (USHORT) ips_msg->ips_cl_size; in_msg = get_buffer(comm, in_msg_length, IPS_DSQL_EXEC_MSG); NOT_NULL(in_msg, in_msg_length); IPS_SERVER(comm, IPS_DSQL_EXEC_MSG, in_msg, in_msg_length); /* set up output message and blr if necessary */ if (operation == op_execute2) { out_msg_type = ips->ips_msg_out; ips_blr_out = &comm->ips_buffers[IPS_DSQL_EXEC2_BLR_OUT]; out_blr_length = (USHORT) ips_blr_out->ips_cl_size; out_blr = get_buffer(comm, out_blr_length, IPS_DSQL_EXEC2_BLR_OUT); NOT_NULL(out_blr, out_blr_length); IPS_SERVER(comm, IPS_DSQL_EXEC2_BLR_OUT, out_blr, out_blr_length); ips_msg_out = &comm->ips_buffers[IPS_DSQL_EXEC2_MSG_OUT]; out_msg_length = (USHORT) ips_msg_out->ips_cl_size; out_msg = get_buffer(comm, out_msg_length, IPS_DSQL_EXEC2_MSG_OUT); NOT_NULL(out_msg, out_msg_length); IPS_SERVER(comm, IPS_DSQL_EXEC2_MSG_OUT, out_msg, out_msg_length); } else { out_blr_length = out_msg_type = out_msg_length = 0; out_blr = out_msg = NULL; } if (!transfer_buffers(icc, comm)) return; /* execute, get results and clean up */ GDS_DSQL_EXECUTE(status_vector, &handle, &statement->isr_handle, in_blr_length, reinterpret_cast < char *>(in_blr), in_msg_type, in_msg_length, reinterpret_cast < char *>(in_msg), out_blr_length, reinterpret_cast < char *>(out_blr), out_msg_type, out_msg_length, reinterpret_cast < char *>(out_msg)); if (transaction && !handle) { release_transaction(transaction); transaction = NULL; } else if (!transaction && handle) { transaction = make_transaction(statement->isr_idb, handle); NOT_NULL(transaction, TRUE); } ips->ips_tr_handle = (UCHAR *) transaction; send_response(icc, status_vector); } static void fetch( ICC icc) { /************************************** * * f e t c h * ************************************** * * Functional description * Fetch next record from a dynamic SQL cursor. * **************************************/ IPSERVER_ISR statement; USHORT records, total_length, blr_length, msg_type, msg_length; UCHAR *blr, *msg; ISC_STATUS s; ISC_STATUS_ARRAY status_vector; ips_dsql *ips; ips_string *ips_blr; ips_string *ips_msg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; statement = (IPSERVER_ISR) ips->ips_st_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); msg_type = ips->ips_msg_type; /* set up blr */ ips_blr = &comm->ips_buffers[IPS_DSQL_FETCH_BLR]; blr_length = (USHORT) ips_blr->ips_cl_size; blr = get_buffer(comm, blr_length, IPS_DSQL_FETCH_BLR); NOT_NULL(blr, blr_length); IPS_SERVER(comm, IPS_DSQL_FETCH_BLR, blr, blr_length); /* set up message */ ips_msg = &comm->ips_buffers[IPS_DSQL_FETCH_MSG]; total_length = (USHORT) ips_msg->ips_cl_size; msg_length = total_length / ips->ips_rec_count; msg = get_buffer(comm, total_length, IPS_DSQL_FETCH_MSG); NOT_NULL(msg, msg_length); IPS_SERVER(comm, IPS_DSQL_FETCH_MSG, msg, total_length); if (!transfer_buffers(icc, comm)) return; /* pack in records, keeping final result of operation for eof */ for (records = 0; records < ips->ips_rec_count; records++) { s = GDS_DSQL_FETCH(status_vector, &statement->isr_handle, blr_length, reinterpret_cast < char *>(blr), msg_type, msg_length, reinterpret_cast < char *>(msg)); /* point to next packed record */ msg += msg_length; if (s) break; } ips->ips_rec_count = records; ips->ips_parameter = s; send_response(icc, status_vector); } static UCHAR *get_buffer( IPS comm, USHORT length, USHORT n) { /************************************** * * g e t _ b u f f e r * ************************************** * * Functional description * Get a buffer "big enough". * **************************************/ if (comm->ips_buffers[n].ips_sv_alloced < length) { if (comm->ips_buffers[n].ips_sv_buffer) gds__free(comm->ips_buffers[n].ips_sv_buffer); comm->ips_buffers[n].ips_sv_alloced = length; comm->ips_buffers[n].ips_sv_buffer = (UCHAR*)gds__alloc((SLONG) length); } /* Make sure that the buffer returned is empty */ if (comm->ips_buffers[n].ips_sv_buffer) memset(comm->ips_buffers[n].ips_sv_buffer, 0, comm->ips_buffers[n].ips_sv_alloced); return comm->ips_buffers[n].ips_sv_buffer; } static void get_segment( ICC icc) { /************************************** * * g e t _ s e g m e n t * ************************************** * * Functional description * Get a single blob segment. * **************************************/ IBL blob; USHORT buffer_length, length; UCHAR *buffer; ISC_STATUS_ARRAY status_vector; ips_segment *ips; ips_string *ips_seg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_segment; blob = (IBL) ips->ips_bl_handle; CHECK_HANDLE(blob, type_ibl, isc_bad_segstr_handle); /* set up segment buffer */ ips_seg = &comm->ips_buffers[IPS_BLOB_SEGMENT]; buffer_length = (USHORT) ips_seg->ips_cl_size; buffer = get_buffer(comm, buffer_length, IPS_BLOB_SEGMENT); NOT_NULL(buffer, buffer_length); IPS_SERVER(comm, IPS_BLOB_SEGMENT, buffer, buffer_length); /* get the segment data - return it regardless of result * as that is what the client side expects * isc_segment can be returned in the status vector, * but that the data is still valid. */ length = 0; GDS_GET_SEGMENT(status_vector, GDS_REF(blob->ibl_handle), GDS_REF(length), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); if (!transfer_buffers(icc, comm)) return; ips->ips_length = length; send_response(icc, status_vector); } static void get_slice( ICC icc) { /************************************** * * g e t _ s l i c e * ************************************** * * Functional description * Get slice of array; * **************************************/ IDB idb; ITR transaction; ISC_STATUS_ARRAY status_vector; SSHORT sdl_length, param_length; ULONG slice_length, return_length, *params, parameters[32]; UCHAR *sdl, sdl_buf[256], *slice; struct bid array_id; ips_slice *ips; ips_string *ips_sdl; ips_string *ips_parms; ips_string *ips_data; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_slice; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); array_id.bid_relation_id = ips->ips_rel_id; array_id.bid_number = ips->ips_number; /* set up sdl */ ips_sdl = &comm->ips_buffers[IPS_SLICE_SDL]; sdl_length = (SSHORT) ips_sdl->ips_cl_size; if (sdl_length <= (SLONG) sizeof(sdl_buf)) sdl = sdl_buf; else sdl = get_buffer(comm, sdl_length, IPS_SLICE_SDL); NOT_NULL(sdl, sdl_length); IPS_SERVER(comm, IPS_SLICE_SDL, sdl, sdl_length); /* set up parameters */ ips_parms = &comm->ips_buffers[IPS_SLICE_PARAM]; param_length = (SSHORT) ips_parms->ips_cl_size; if (param_length <= (SLONG) sizeof(parameters)) params = parameters; else params = (ULONG *) get_buffer(comm, param_length, IPS_SLICE_PARAM); NOT_NULL(params, param_length); IPS_SERVER(comm, IPS_SLICE_PARAM, (UCHAR *) params, param_length); /* set up slice data buffer */ ips_data = &comm->ips_buffers[IPS_SLICE_BUFFER]; slice_length = ips_data->ips_cl_size; if (slice_length) { slice = (UCHAR*)gds__alloc(slice_length); NOT_NULL(slice, TRUE); memset(slice, 0, slice_length); } else slice = NULL; IPS_SERVER(comm, IPS_SLICE_BUFFER, slice, slice_length); if (!transfer_buffers(icc, comm)) { if (slice) { gds__free(slice); } return; } /* get and return slice */ GDS_GET_SLICE(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), (GDS_QUAD *) & array_id, sdl_length, reinterpret_cast < char *>(sdl), param_length, reinterpret_cast < long *>(params), slice_length, slice, reinterpret_cast < long *>(GDS_REF(return_length))); ips->ips_length = return_length; send_response(icc, status_vector); if (slice) { gds__free(slice); } } static void info( ICC icc, P_OP operation) { /************************************** * * i n f o * ************************************** * * Functional description * Issue information. * **************************************/ FRBRD* handle; ISC_STATUS_ARRAY status_vector; USHORT item_length, recv_item_length, buffer_length, incarnation; UCHAR *buffer, *items, *recv_items; UCHAR items_buf[128], recv_items_buf[128]; IDB idb; ITR transaction; IBL blob; IRQ request; IPSERVER_ISR statement; ips_object *ips; ips_string *ips_items; ips_string *ips_data; ips_string *ips_rcv_items; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; comm->ips_operation = op_info_blob; ips = &comm->ips_operations.ips_op_object; handle = (FRBRD *)ips->ips_handle; if (operation == op_info_request) incarnation = (USHORT) ips->ips_parameter; /* set up items buffer */ ips_items = &comm->ips_buffers[IPS_INFO_ITEMS]; item_length = (USHORT) ips_items->ips_cl_size; if (item_length <= sizeof(items_buf)) items = items_buf; else items = get_buffer(comm, item_length, IPS_INFO_ITEMS); NOT_NULL(items, item_length); IPS_SERVER(comm, IPS_INFO_ITEMS, items, item_length); /* set up data buffer */ ips_data = &comm->ips_buffers[IPS_INFO_DATA]; buffer_length = (USHORT) ips_data->ips_cl_size; buffer = get_buffer(comm, buffer_length, IPS_INFO_DATA); NOT_NULL(buffer, buffer_length); IPS_SERVER(comm, IPS_INFO_DATA, buffer, buffer_length); /* set up receive items buffer if necessary */ if (operation == op_service_info) { ips_rcv_items = &comm->ips_buffers[IPS_QUERY_RECV_ITEMS]; recv_item_length = (USHORT) ips_rcv_items->ips_cl_size; if (recv_item_length <= sizeof(recv_items_buf)) recv_items = recv_items_buf; else recv_items = get_buffer(comm, recv_item_length, IPS_QUERY_RECV_ITEMS); NOT_NULL(recv_items, recv_item_length); IPS_SERVER(comm, IPS_QUERY_RECV_ITEMS, recv_items, recv_item_length); } if (!transfer_buffers(icc, comm)) return; /* perform operation */ switch (operation) { case op_info_database: idb = (IDB) handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); GDS_DATABASE_INFO(status_vector, GDS_REF(idb->idb_handle), item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); break; case op_info_blob: blob = (IBL) handle; CHECK_HANDLE(blob, type_ibl, isc_bad_segstr_handle); GDS_BLOB_INFO(status_vector, GDS_REF(blob->ibl_handle), item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); break; case op_info_request: request = (IRQ) handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); GDS_REQUEST_INFO(status_vector, GDS_REF(request->irq_handle), incarnation, item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); break; case op_info_transaction: transaction = (ITR) handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); GDS_TRANSACTION_INFO(status_vector, GDS_REF(transaction->itr_handle), item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); break; case op_service_info: idb = (IDB) handle; CHECK_HANDLE(idb, type_idb, isc_bad_svc_handle); GDS_SERVICE_QUERY(status_vector, &idb->idb_handle, 0, /* reserved */ item_length, reinterpret_cast < char *>(items), recv_item_length, reinterpret_cast < char *>(recv_items), buffer_length, reinterpret_cast < char *>(buffer)); break; case op_info_sql: statement = (IPSERVER_ISR) handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); GDS_DSQL_SQL_INFO(status_vector, &statement->isr_handle, item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(buffer)); break; } /* return results */ send_response(icc, status_vector); } static void insert( ICC icc) { /************************************** * * i n s e r t * ************************************** * * Functional description * Insert next record into a dynamic SQL cursor. * **************************************/ IPSERVER_ISR statement; USHORT blr_length, msg_type, msg_length; UCHAR *blr, *msg; ISC_STATUS_ARRAY status_vector; ips_dsql *ips; ips_string *ips_blr; ips_string *ips_msg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; statement = (IPSERVER_ISR) ips->ips_st_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); msg_type = ips->ips_msg_type; /* set up blr */ ips_blr = &comm->ips_buffers[IPS_DSQL_INSERT_BLR]; blr_length = (USHORT) ips_blr->ips_cl_size; blr = get_buffer(comm, blr_length, IPS_DSQL_INSERT_BLR); NOT_NULL(blr, blr_length); IPS_SERVER(comm, IPS_DSQL_INSERT_BLR, blr, blr_length); /* set up message */ ips_msg = &comm->ips_buffers[IPS_DSQL_INSERT_MSG]; msg_length = (USHORT) ips_msg->ips_cl_size; msg = get_buffer(comm, msg_length, IPS_DSQL_INSERT_MSG); NOT_NULL(msg, msg_length); IPS_SERVER(comm, IPS_DSQL_INSERT_MSG, msg, msg_length); if (!transfer_buffers(icc, comm)) return; /* insert the record and return */ GDS_DSQL_INSERT(status_vector, &statement->isr_handle, blr_length, reinterpret_cast < char *>(blr), msg_type, msg_length, reinterpret_cast < char *>(msg)); send_response(icc, status_vector); } static IPM make_map(USHORT map_number) { /************************************** * * m a k e _ m a p * ************************************** * * Functional description * Create a mapped file. This * returns - * 0 - mapped file already exists * -1 - mapping or creation error * other - pointer to new structure * **************************************/ HANDLE map_handle; LPVOID map_address; // Here we better be 100% SURE this won't overflow! TEXT name_buffer[128]; /* create the mapped file name and try to open it */ sprintf(name_buffer, IPI_MAPPED_FILE_NAME, Config::getIpcName(), map_number); map_handle = CreateFileMapping((HANDLE) 0xFFFFFFFF, ISC_get_security_desc(), PAGE_READWRITE, 0L, IPS_MAPPED_SIZE(ipserver_private_data.users_per_map, ipserver_private_data.pages_per_user), name_buffer); if (map_handle && GetLastError() == ERROR_ALREADY_EXISTS) { return NULL; } if (!map_handle) { return (IPM) -1; } map_address = MapViewOfFile(map_handle, FILE_MAP_WRITE, 0L, 0L, IPS_MAPPED_SIZE(ipserver_private_data.users_per_map, ipserver_private_data.pages_per_user)); if (!map_address) { CloseHandle(map_handle); return (IPM) -1; } /* allocate a structure and initialize it */ IPM ipm = (IPM) ALLI_alloc(sizeof(struct ipm)); if (!ipm) { UnmapViewOfFile(map_address); CloseHandle(map_handle); return (IPM) -1; } ipm->ipm_handle = map_handle; ipm->ipm_address = map_address; ipm->ipm_number = map_number; ipm->ipm_count = 0; for (USHORT i = 0; i < ipserver_private_data.users_per_map; i++) { ipm->ipm_ids[i] = 0; } ipm->ipm_next = ipserver_private_data.ipms; ipserver_private_data.ipms = ipm; return ipm; } static ITR make_transaction( IDB idb, FRBRD * handle) { /************************************** * * m a k e _ t r a n s a c t i o n * ************************************** * * Functional description * Create a local transaction handle. * **************************************/ ITR transaction; transaction = (ITR) ALLOC(type_itr); if (transaction) { transaction->itr_idb = idb; transaction->itr_handle = handle; transaction->itr_next = idb->idb_transactions; idb->idb_transactions = transaction; } return transaction; } static void open_blob( ICC icc, P_OP op) { /************************************** * * o p e n _ b l o b * ************************************** * * Functional description * Open or create a new blob. * **************************************/ IDB idb; IBL blob; ITR transaction; FRBRD * handle; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; USHORT bpb_length; UCHAR *bpb, bpb_buf[128]; struct bid blob_id; ips_blob *ips; ips_string *ips_bpb; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_blob; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); handle = NULL; bpb_length = 0; /* set up bpb if needed */ if (op == op_open_blob2 || op == op_create_blob2) { ips_bpb = &comm->ips_buffers[IPS_BLOB_BPB]; bpb_length = (USHORT) ips_bpb->ips_cl_size; if (bpb_length <= sizeof(bpb_buf)) bpb = bpb_buf; else bpb = get_buffer(comm, bpb_length, IPS_BLOB_BPB); NOT_NULL(bpb, bpb_length); IPS_SERVER(comm, IPS_BLOB_BPB, bpb, bpb_length); } if (!transfer_buffers(icc, comm)) return; /* perform operation and return handle */ switch (op) { case op_open_blob: blob_id.bid_relation_id = ips->ips_rel_id; blob_id.bid_number = ips->ips_bid_number; result = GDS_OPEN_BLOB(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), GDS_REF(handle), (GDS_QUAD *) & blob_id); break; case op_create_blob: result = GDS_CREATE_BLOB(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), GDS_REF(handle), (GDS_QUAD *) & blob_id); ips->ips_rel_id = blob_id.bid_relation_id; ips->ips_bid_number = blob_id.bid_number; break; case op_open_blob2: blob_id.bid_relation_id = ips->ips_rel_id; blob_id.bid_number = ips->ips_bid_number; result = GDS_OPEN_BLOB2(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), GDS_REF(handle), (GDS_QUAD *) & blob_id, bpb_length, reinterpret_cast(bpb)); break; case op_create_blob2: result = GDS_CREATE_BLOB2(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), GDS_REF(handle), (GDS_QUAD *) & blob_id, bpb_length, reinterpret_cast < char *>(bpb)); ips->ips_rel_id = blob_id.bid_relation_id; ips->ips_bid_number = blob_id.bid_number; break; } if (!result) { blob = (IBL) ALLOC(type_ibl); ips->ips_bl_handle = (UCHAR *) blob; NOT_NULL(blob, TRUE); blob->ibl_handle = handle; blob->ibl_idb = idb; blob->ibl_itr = transaction; blob->ibl_next = transaction->itr_blobs; transaction->itr_blobs = blob; } else ips->ips_bl_handle = NULL; send_response(icc, status_vector); } static void prepare_statement( ICC icc) { /************************************** * * p r e p a r e _ s t a t e m e n t * ************************************** * * Functional description * Prepare a dynamic SQL statement for execution. * **************************************/ ITR transaction; IPSERVER_ISR statement; USHORT length, item_length, buffer_length, dialect, parser_version; UCHAR *string, *items, items_buf[128], *buffer; ISC_STATUS_ARRAY status_vector; FRBRD * handle; ips_dsql *ips; ips_string *ips_prep_string; ips_string *ips_prep_items; ips_string *ips_prep_buffer; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; transaction = (ITR) ips->ips_tr_handle; if (transaction) { CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); handle = transaction->itr_handle; } else handle = NULL; statement = (IPSERVER_ISR) ips->ips_st_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); dialect = (USHORT) ips->ips_parameter; /* set up string */ ips_prep_string = &comm->ips_buffers[IPS_DSQL_PREP_STRING]; length = (USHORT) ips_prep_string->ips_cl_size; string = get_buffer(comm, length, IPS_DSQL_PREP_STRING); NOT_NULL(string, length); IPS_SERVER(comm, IPS_DSQL_PREP_STRING, string, length); /* set up items */ ips_prep_items = &comm->ips_buffers[IPS_DSQL_PREP_ITEMS]; item_length = (USHORT) ips_prep_items->ips_cl_size; if (item_length <= sizeof(items_buf)) items = items_buf; else items = get_buffer(comm, item_length, IPS_DSQL_PREP_ITEMS); NOT_NULL(items, item_length); IPS_SERVER(comm, IPS_DSQL_PREP_ITEMS, items, item_length); /* set up buffer */ ips_prep_buffer = &comm->ips_buffers[IPS_DSQL_PREP_BUFFER]; buffer_length = (USHORT) ips_prep_buffer->ips_cl_size; buffer = get_buffer(comm, buffer_length, IPS_DSQL_PREP_BUFFER); NOT_NULL(buffer, buffer_length); IPS_SERVER(comm, IPS_DSQL_PREP_BUFFER, buffer, buffer_length); if (!transfer_buffers(icc, comm)) return; /* NT Local access: Client and server are always the same version */ /* Since the API to GDS_DSQL_PREPARE is public and can not be changed, there needs to * be a way to send the parser version to DSQL so that the parser can compare the keyword * version to the parser version. To accomplish this, the parser version is combined with * the client dialect and sent across that way. In dsql8_prepare_statement, the parser version * and client dialect are separated and passed on to their final desintations. The information * is combined as follows: * Dialect * 10 + parser_version * * and is extracted in dsql8_prepare_statement as follows: * parser_version = ((dialect *10)+parser_version)%10 * client_dialect = ((dialect *10)+parser_version)/10 * * For example, parser_version = 1 and client dialect = 1 * * combined = (1 * 10) + 1 == 11 * * parser = (combined) %10 == 1 * dialect = (combined) / 19 == 1 */ parser_version = 2; /* prepare statement and return data */ GDS_DSQL_PREPARE(status_vector, &handle, &statement->isr_handle, length, reinterpret_cast < char *>(string), (USHORT) ((dialect * 10) + parser_version), item_length, reinterpret_cast < char *>(items), buffer_length, reinterpret_cast < char *>(buffer)); statement->isr_batch_flag = check_statement_type(statement); ips->ips_parameter = statement->isr_batch_flag; send_response(icc, status_vector); } static void put_segment( ICC icc) { /************************************** * * p u t _ s e g m e n t * ************************************** * * Functional description * Write a single blob segment. * **************************************/ IBL blob; USHORT buffer_length; UCHAR *buffer; ISC_STATUS_ARRAY status_vector; ips_segment *ips; ips_string *ips_seg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_segment; blob = (IBL) ips->ips_bl_handle; CHECK_HANDLE(blob, type_ibl, isc_bad_segstr_handle); /* set up segment buffer */ ips_seg = &comm->ips_buffers[IPS_BLOB_SEGMENT]; buffer_length = (USHORT) ips_seg->ips_cl_size; buffer = get_buffer(comm, buffer_length, IPS_BLOB_SEGMENT); NOT_NULL(buffer, buffer_length); IPS_SERVER(comm, IPS_BLOB_SEGMENT, buffer, buffer_length); if (!transfer_buffers(icc, comm)) return; /* put the segment into the database */ GDS_PUT_SEGMENT(status_vector, GDS_REF(blob->ibl_handle), buffer_length, reinterpret_cast < char *>(GDS_VAL(buffer))); send_response(icc, status_vector); } static void put_slice( ICC icc) { /************************************** * * p u t _ s l i c e * ************************************** * * Functional description * Put slice of array; * **************************************/ IDB idb; ITR transaction; ISC_STATUS_ARRAY status_vector; USHORT sdl_length, param_length; ULONG slice_length, *params, parameters[32]; UCHAR *sdl, sdl_buf[256], *slice; struct bid array_id; ips_slice *ips; ips_string *ips_sdl; ips_string *ips_parms; ips_string *ips_data; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_slice; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); array_id.bid_relation_id = ips->ips_rel_id; array_id.bid_number = ips->ips_number; /* set up sdl */ ips_sdl = &comm->ips_buffers[IPS_SLICE_SDL]; sdl_length = (USHORT) ips_sdl->ips_cl_size; if (sdl_length <= sizeof(sdl_buf)) sdl = sdl_buf; else sdl = get_buffer(comm, sdl_length, IPS_SLICE_SDL); NOT_NULL(sdl, sdl_length); IPS_SERVER(comm, IPS_SLICE_SDL, sdl, sdl_length); /* set up parameters */ ips_parms = &comm->ips_buffers[IPS_SLICE_PARAM]; param_length = (USHORT) ips_parms->ips_cl_size; if (param_length <= sizeof(parameters)) params = parameters; else params = (ULONG *) get_buffer(comm, param_length, IPS_SLICE_PARAM); NOT_NULL(params, param_length); IPS_SERVER(comm, IPS_SLICE_PARAM, (UCHAR *) params, param_length); /* set up slice data buffer */ ips_data = &comm->ips_buffers[IPS_SLICE_BUFFER]; slice_length = ips_data->ips_cl_size; if (slice_length) { slice = (UCHAR*)gds__alloc(slice_length); NOT_NULL(slice, TRUE); memset(slice, 0, slice_length); } else slice = NULL; IPS_SERVER(comm, IPS_SLICE_BUFFER, slice, slice_length); if (!transfer_buffers(icc, comm)) { if (slice) { gds__free(slice); } return; } /* put the slice into the database */ GDS_PUT_SLICE(status_vector, GDS_REF(idb->idb_handle), GDS_REF(transaction->itr_handle), (GDS_QUAD *) & array_id, sdl_length, reinterpret_cast < char *>(sdl), param_length, reinterpret_cast < long *>(params), slice_length, GDS_VAL(slice)); ips->ips_rel_id = array_id.bid_relation_id; ips->ips_number = array_id.bid_number; send_response(icc, status_vector); if (slice) { gds__free(slice); } } static void que_events( ICC icc) { /************************************** * * q u e _ e v e n t s * ************************************** * * Functional description * Que events for asynchronous notification. * **************************************/ IDB idb; USHORT length; UCHAR *events; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; IVNT event; ips_que_events *ips; ips_string *ips_event; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_que_evnt; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* set up event string */ ips_event = &comm->ips_buffers[IPS_QUEUE_EVENT]; length = (USHORT) ips_event->ips_cl_size; events = get_buffer(comm, length, IPS_QUEUE_EVENT); NOT_NULL(events, length); IPS_SERVER(comm, IPS_QUEUE_EVENT, events, length); /* find or allocate event block */ for (event = idb->idb_events; event; event = event->ivnt_next) if (!event->ivnt_ast) break; if (!event) { event = (IVNT) ALLOC(type_ivnt); NOT_NULL(event, TRUE); event->ivnt_next = idb->idb_events; event->ivnt_idb = idb; idb->idb_events = event; } /* Get data, etc */ event->ivnt_window = ips->ips_event_hwnd; event->ivnt_id = ips->ips_event_id; event->ivnt_ast = (void (*)()) ips->ips_ast; event->ivnt_arg = (void *) ips->ips_arg; if (!transfer_buffers(icc, comm)) return; /* queue the event and return id */ result = GDS_QUE_EVENTS(status_vector, GDS_REF(idb->idb_handle), GDS_REF(event->ivnt_handle), length, reinterpret_cast(GDS_VAL(events)), reinterpret_cast < void (*)() > (event_ast), GDS_VAL(event)); if (!result) ips->ips_event_id = event->ivnt_handle; else event->ivnt_ast = NULL; send_response(icc, status_vector); } static void receive_msg( ICC icc) { /************************************** * * r e c e i v e _ m s g * ************************************** * * Functional description * Receive a message. * **************************************/ ISC_STATUS_ARRAY status_vector; IRQ request; USHORT length, number, level; #ifdef SCROLLABLE_CURSORS USHORT direction; ULONG offset; #endif UCHAR *buffer; ips_request *ips; ips_string *ips_message; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_request; request = (IRQ) ips->ips_rq_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); /* set up message */ ips_message = &comm->ips_buffers[IPS_RECEIVE_MESSAGE]; length = (USHORT) ips_message->ips_cl_size; buffer = get_buffer(comm, length, IPS_RECEIVE_MESSAGE); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_RECEIVE_MESSAGE, buffer, length); number = ips->ips_msg_type; level = ips->ips_req_level; #ifdef SCROLLABLE_CURSORS direction = ips->ips_direction; offset = ips->ips_offset; #endif /* receive message and send response */ GDS_RECEIVE(status_vector, GDS_REF(request->irq_handle), number, length, GDS_VAL(buffer), level #ifdef SCROLLABLE_CURSORS , direction, offset #endif ); send_response(icc, status_vector); } static void reconnect( ICC icc) { /************************************** * * r e c o n n e c t * ************************************** * * Functional description * Reconnect to a transaction in limbo. * **************************************/ IDB idb; ITR transaction; USHORT length; UCHAR *buffer; FRBRD * handle; ISC_STATUS_ARRAY status_vector; ips_reconnect *ips; ips_string *ips_recon; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_recon_trans; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* set up string */ ips_recon = &comm->ips_buffers[IPS_RECONNECT_ID]; length = (USHORT) ips_recon->ips_cl_size; buffer = get_buffer(comm, length, IPS_RECONNECT_ID); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_RECONNECT_ID, buffer, length); handle = NULL; if (!transfer_buffers(icc, comm)) return; /* reconnect transaction and return id */ if (!GDS_RECONNECT(status_vector, GDS_REF(idb->idb_handle), GDS_REF(handle), length, reinterpret_cast < char *>(GDS_VAL(buffer)))) { if (transaction = make_transaction(idb, handle)) { ips->ips_tr_handle = (UCHAR *) transaction; transaction->itr_flags |= ITR_limbo; } else { gds__handle_cleanup(status_vector, (FRBRD **) GDS_REF(handle)); NOT_NULL(transaction, TRUE); } } send_response(icc, status_vector); } static void release_blob( IBL blob) { /************************************** * * r e l e a s e _ b l o b * ************************************** * * Functional description * Release a blob block and friends. * **************************************/ IDB idb; ITR transaction; IBL *p; idb = blob->ibl_idb; transaction = blob->ibl_itr; for (p = &transaction->itr_blobs; *p; p = &(*p)->ibl_next) { if (*p == blob) { *p = blob->ibl_next; break; } } ALLI_release((BLK) blob); } static void release_event( IVNT event) { /************************************** * * r e l e a s e _ e v e n t s * ************************************** * * Functional description * Release a event block and friends. * **************************************/ IDB idb; IVNT *p; idb = event->ivnt_idb; for (p = &idb->idb_events; *p; p = &(*p)->ivnt_next) { if (*p == event) { *p = event->ivnt_next; break; } } ALLI_release((BLK) event); } static void release_request( IRQ request) { /************************************** * * r e l e a s e _ r e q u e s t * ************************************** * * Functional description * Release a request block and friends. * **************************************/ IDB idb; IRQ *p; idb = request->irq_idb; for (p = &idb->idb_requests; *p; p = &(*p)->irq_next) if (*p == request) { *p = request->irq_next; break; } ALLI_release((BLK) request); } static void release_sql_request( IPSERVER_ISR stmt) { /************************************** * * r e l e a s e _ s q l _ r e q u e s t * ************************************** * * Functional description * Release an SQL request block. * **************************************/ IDB idb; IPSERVER_ISR *p; idb = stmt->isr_idb; for (p = &idb->idb_sql_requests; *p; p = &(*p)->isr_next) if (*p == stmt) { *p = stmt->isr_next; break; } ALLI_release((BLK) stmt); } static void release_transaction( ITR transaction) { /************************************** * * r e l e a s e _ t r a n s a c t i o n * ************************************** * * Functional description * Release a transaction block and friends. * **************************************/ IDB idb; ITR *p; idb = transaction->itr_idb; while (transaction->itr_blobs) release_blob(transaction->itr_blobs); for (p = &idb->idb_transactions; *p; p = &(*p)->itr_next) if (*p == transaction) { *p = transaction->itr_next; break; } ALLI_release((BLK) transaction); } static void seek_blob( ICC icc) { /************************************** * * s e e k _ b l o b * ************************************** * * Functional description * Perform a blob seek. * **************************************/ IBL blob; SSHORT mode; SLONG offset, result; ISC_STATUS_ARRAY status_vector; ips_seek_blob *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_sk_blob; blob = (IBL) ips->ips_bl_handle; CHECK_HANDLE(blob, type_ibl, isc_bad_segstr_handle); offset = ips->ips_offset; mode = ips->ips_mode; /* seek blob and return result */ GDS_SEEK_BLOB(status_vector, GDS_REF(blob->ibl_handle), mode, offset, GDS_REF(result)); ips->ips_result = result; send_response(icc, status_vector); } static BOOL send_and_wait( ICC icc) { /************************************** * * s e n d _ a n d _ w a i t * ************************************** * * Functional description * This function responds to the client by releasing * the client's semaphore, and then waits for more * work by waiting on the server's semaphore. * **************************************/ DWORD result; /* already in shutdown mode */ if (icc->icc_flags & ICCF_SHUTDOWN) return FALSE; /* first, signal the client that the communications area in mapped memory is filed and ready */ if (!ReleaseSemaphore(icc->icc_client_sem, 1L, NULL)) { icc->icc_flags |= ICCF_SHUTDOWN; #ifdef DEBUG_IP_TRACE gds__log("ipserver send of send and wait failed %lX %ld", (long) icc, (long) GetLastError()); #endif return FALSE; } /* next, wait for the client to signal us back */ result = WaitForMultipleObjects((DWORD) 2, icc->icc_waits, FALSE, INFINITE); if (result != WAIT_OBJECT_0) { icc->icc_flags |= ICCF_SHUTDOWN; #ifdef DEBUG_IP_TRACE gds__log("ipserver wait of send and wait failed %lX %ld", (long) icc, (long) GetLastError()); #endif return FALSE; } else return TRUE; } static void send_msg( ICC icc) { /************************************** * * s e n d _ m s g * ************************************** * * Functional description * **************************************/ ISC_STATUS_ARRAY status_vector; IRQ request; UCHAR *buffer; USHORT length, number, level; ips_request *ips; ips_string *ips_message; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_request; request = (IRQ) ips->ips_rq_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); /* set up message */ ips_message = &comm->ips_buffers[IPS_SEND_MESSAGE]; length = (USHORT) ips_message->ips_cl_size; buffer = get_buffer(comm, length, IPS_SEND_MESSAGE); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_SEND_MESSAGE, buffer, length); number = ips->ips_msg_type; level = ips->ips_req_level; if (!transfer_buffers(icc, comm)) return; /* send message */ GDS_SEND(status_vector, GDS_REF(request->irq_handle), number, length, GDS_VAL(buffer), level); send_response(icc, status_vector); } static void send_no_wait( ICC icc) { /************************************** * * s e n d _ n o _ w a i t * ************************************** * * Functional description * This function sends the client the server's * last filled in communications area, indicating * that the server is done. No wait is done here. * **************************************/ /* already in shutdown mode */ if (icc->icc_flags & ICCF_SHUTDOWN) return; /* signal the client that the communications area in mapped memory is filed and ready */ if (!ReleaseSemaphore(icc->icc_client_sem, 1L, NULL)) { #ifdef DEBUG_IP_TRACE gds__log("ipserver send no wait failed %lX %ld", (long) icc, (long) GetLastError()); #endif icc->icc_flags |= ICCF_SHUTDOWN; } } static void send_response( ICC icc, ISC_STATUS * status_vector) { /************************************** * * s e n d _ r e s p o n s e * ************************************** * * Functional description * Send a response packet. * **************************************/ ISC_STATUS *comm_status; USHORT i, length; ULONG to_copy, size_left; TEXT *p, buffer[1024]; TEXT *acursor, *scursor, *abase; ips_comm_area *comm; TEXT *comm_ptr; ips_string *string; ULONG l, *lp; /* first, initialize the status vector in the comm area */ comm = (ips_comm_area *) icc->icc_mapped_addr; comm_ptr = (TEXT *) comm->ips_data; comm_status = reinterpret_cast < ISC_STATUS * >(comm->ips_status); abase = comm_ptr; /* if there's no error or warning, just put in a clean status vector */ if (!status_vector[1] && !status_vector[2]) { *comm_status++ = *status_vector++; *comm_status++ = *status_vector++; } else { /* transfer the status vector, putting strings in the comm area's data area */ while (*status_vector) { switch (*status_vector) { case isc_arg_interpreted: case isc_arg_string: /* for strings, put the length, followed by the string in the comm data area */ *comm_status++ = *status_vector++; p = (TEXT *) * status_vector++; if (p) length = strlen(p); else length = 0; lp = (ULONG *) comm_ptr; *lp = length; comm_ptr += sizeof(ULONG); for (i = 0; i < length; i++) *comm_ptr++ = *p++; l = length % sizeof(ULONG); if (l) comm_ptr += (sizeof(ULONG) - l); break; case isc_arg_cstring: *comm_status++ = isc_arg_string; status_vector++; length = (USHORT) * status_vector++; lp = (ULONG *) comm_ptr; *lp = length; comm_ptr += sizeof(ULONG); p = (TEXT *) * status_vector++; for (i = 0; i < length; i++) *comm_ptr++ = *p++; l = length % sizeof(ULONG); if (l) comm_ptr += (sizeof(ULONG) - l); break; case isc_arg_warning: case isc_arg_number: case isc_arg_gds: *comm_status++ = *status_vector++; *comm_status++ = *status_vector++; break; default: length = (USHORT) isc_interprete(buffer, &status_vector); if (!length) { *status_vector = 0; break; } *comm_status++ = isc_arg_interpreted; lp = (ULONG *) comm_ptr; *lp = length; comm_ptr += sizeof(ULONG); for (i = 0; i < length; i++) *comm_ptr++ = buffer[i]; l = length % sizeof(ULONG); if (l) comm_ptr += (sizeof(ULONG) - l); break; } } } *comm_status++ = isc_arg_end; /* point to the current first available byte and figure space available */ acursor = comm_ptr; size_left = (ULONG) (IPS_USEFUL_SPACE(ipserver_private_data.pages_per_user)) - (abase - reinterpret_cast < TEXT * >(comm->ips_data)); for (i = 0; i < MAX_IPS_STRINGS; i++) { string = &comm->ips_buffers[i]; /* see if this buffer needs sending */ if ((string->ips_flags & IPS_OUTPUT_BUFFER) && string->ips_sv_size) { string->ips_sv_copied = 0; scursor = reinterpret_cast < char *>(string->ips_sv_addr); /* keep packing it in */ while (string->ips_sv_copied < string->ips_sv_size) { /* put in the whole thing, or whatever will fit */ to_copy = string->ips_sv_size - string->ips_sv_copied; if (size_left <= to_copy) to_copy = size_left; string->ips_com_offset = acursor - abase; string->ips_com_size = to_copy; memcpy(acursor, scursor, (USHORT) to_copy); acursor += to_copy; scursor += to_copy; size_left -= to_copy; string->ips_sv_copied += to_copy; /* if all the space has been used up, send it and wait */ if (!size_left && string->ips_sv_copied < string->ips_sv_size) { comm->ips_sequence++; if (!send_and_wait(icc)) return; size_left = (ULONG) (IPS_USEFUL_SPACE(ipserver_private_data.pages_per_user)); acursor = reinterpret_cast < char *>(comm->ips_data); } } } } /* sending the last buffer, all done */ comm->ips_sequence++; send_no_wait(icc); } static void service_attach( ICC icc) { /************************************** * * s e r v i c e _ a t t a c h * ************************************** * * Functional description * Connect to an Interbase service. * **************************************/ USHORT service_length, spb_length; UCHAR service_name[256], *spb, spb_buf[256]; FRBRD * handle; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; IDB idb; ips_object *ips; ips_string *ips_name; ips_string *ips_spb; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; /* figure out service name buffer */ ips_name = &comm->ips_buffers[IPS_ATTACH_SVC_NAME]; service_length = (USHORT) ips_name->ips_cl_size; IPS_SERVER(comm, IPS_ATTACH_SVC_NAME, service_name, service_length); /* figure out spb buffer */ ips_spb = &comm->ips_buffers[IPS_ATTACH_SVC_SPB]; spb_length = (USHORT) ips_spb->ips_cl_size; if (spb_length <= sizeof(spb_buf)) spb = spb_buf; else spb = get_buffer(comm, spb_length, IPS_ATTACH_SVC_SPB); NOT_NULL(spb, spb_length); IPS_SERVER(comm, IPS_ATTACH_SVC_SPB, spb, spb_length); if (!transfer_buffers(icc, comm)) return; /* get handle */ handle = NULL; result = GDS_SERVICE_ATTACH(status_vector, service_length, reinterpret_cast < char *>(service_name), &handle, spb_length, reinterpret_cast < char *>(spb)); /* allocate structure and return handle */ if (!result) { idb = (IDB) ALLOC(type_idb); ips->ips_handle = (UCHAR *) idb; NOT_NULL(idb, TRUE); idb->idb_flags = IDBF_SERVICE_ATTACHMENT; idb->idb_handle = handle; idb->idb_next = icc->icc_databases; icc->icc_databases = idb; } else ips->ips_handle = NULL; send_response(icc, status_vector); } static void service_end( ICC icc) { /************************************** * * s e r v i c e _ e n d * ************************************** * * Functional description * Close down a service. * **************************************/ IDB idb, *ptr; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; idb = (IDB) ips->ips_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); /* detach request, return response and free resources */ result = GDS_SERVICE_DETACH(status_vector, &idb->idb_handle); send_response(icc, status_vector); if (!result) { for (ptr = &icc->icc_databases; *ptr; ptr = &(*ptr)->idb_next) if (*ptr == idb) { *ptr = idb->idb_next; break; } ALLI_release((BLK) idb); } } static void service_start( ICC icc) { /************************************** * * s e r v i c e _ s t a r t * ************************************** * * Functional description * Start a service. * **************************************/ IDB idb; ISC_STATUS_ARRAY status_vector; ISC_STATUS result; ips_object *ips; ips_comm_area *comm; ips_string *ips_spb; TEXT *comm_ptr; USHORT spb_length; UCHAR *spb, spb_buf[256]; HANDLE handle; ULONG *reserved = 0; /* set up communications area */ GET_COMM_OBJECT; comm->ips_operation = op_service_start; ips = &comm->ips_operations.ips_op_object; handle = (HANDLE) ips->ips_handle; /* figure out spb buffer */ ips_spb = &comm->ips_buffers[IPS_START_SVC_SPB]; spb_length = (USHORT) ips_spb->ips_cl_size; if (spb_length <= sizeof(spb_buf)) spb = spb_buf; else spb = get_buffer(comm, spb_length, IPS_START_SVC_SPB); NOT_NULL(spb, spb_length); IPS_SERVER(comm, IPS_START_SVC_SPB, spb, spb_length); if (!transfer_buffers(icc, comm)) return; idb = (IDB) handle; CHECK_HANDLE(idb, type_idb, isc_bad_svc_handle); result = GDS_SERVICE_START(status_vector, &idb->idb_handle, reinterpret_cast < long *>(reserved), spb_length, reinterpret_cast < char *>(spb)); send_response(icc, status_vector); } static void set_cursor( ICC icc) { /************************************** * * s e t _ c u r s o r * ************************************** * * Functional description * Set a cursor name for a dynamic request. * **************************************/ IPSERVER_ISR statement; USHORT length, type; UCHAR *cursor; ISC_STATUS_ARRAY status_vector; ips_dsql *ips; ips_string *ips_name; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_dsql; statement = (IPSERVER_ISR) ips->ips_st_handle; CHECK_HANDLE(statement, type_ipserver_isr, isc_bad_stmt_handle); type = (USHORT) ips->ips_parameter; /* set up cursor name */ ips_name = &comm->ips_buffers[IPS_DSQL_SET_CURSOR]; length = (USHORT) ips_name->ips_cl_size; cursor = get_buffer(comm, length, IPS_DSQL_SET_CURSOR); NOT_NULL(cursor, length); IPS_SERVER(comm, IPS_DSQL_SET_CURSOR, cursor, length); if (!transfer_buffers(icc, comm)) return; /* set cursor name */ GDS_DSQL_SET_CURSOR(status_vector, &statement->isr_handle, reinterpret_cast < char *>(cursor), type); send_response(icc, status_vector); } static void shutdown_attachments( ICC icc) { /************************************** * * s h u t d o w n _ a t t a c h m e n t s * ************************************** * * Functional description * About to exit, detach any remaining database * and service attachments. * **************************************/ IDB idb, nextidb; ISC_STATUS_ARRAY status_vector; ips_comm_area *comm; USHORT i; for (idb = icc->icc_databases; idb; idb = nextidb) { /* save next pointer here because the structure's getting freed */ nextidb = idb->idb_next; if (idb->idb_flags | IDBF_DATABASE_ATTACHMENT) { while (idb->idb_transactions) { if (!(idb->idb_transactions->itr_flags & ITR_limbo)) GDS_ROLLBACK(status_vector, GDS_REF(idb->idb_transactions->itr_handle)); else gds__handle_cleanup(status_vector, (FRBRD **) GDS_REF(idb-> idb_transactions-> itr_handle)); release_transaction(idb->idb_transactions); } GDS_DETACH(status_vector, GDS_REF(idb->idb_handle)); while (idb->idb_events) release_event(idb->idb_events); while (idb->idb_requests) release_request(idb->idb_requests); while (idb->idb_sql_requests) release_sql_request(idb->idb_sql_requests); } else { GDS_SERVICE_DETACH(status_vector, &idb->idb_handle); } ALLI_release((BLK) idb); } /* free any allocated server buffers */ comm = (ips_comm_area *) icc->icc_mapped_addr; for (i = 0; i < MAX_IPS_STRINGS; i++) if (comm->ips_buffers[i].ips_sv_buffer) gds__free(comm->ips_buffers[i].ips_sv_buffer); } static void start( ICC icc) { /************************************** * * s t a r t * ************************************** * * Functional description * **************************************/ ISC_STATUS_ARRAY status_vector; IRQ request; ITR transaction; USHORT level; ips_request *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_request; request = (IRQ) ips->ips_rq_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); level = ips->ips_req_level; /* start the request */ GDS_START(status_vector, GDS_REF(request->irq_handle), GDS_REF(transaction->itr_handle), level); send_response(icc, status_vector); } static void start_and_send( ICC icc) { /************************************** * * s t a r t _ a n d _ s e n d * ************************************** * * Functional description * **************************************/ ISC_STATUS_ARRAY status_vector; IRQ request; ITR transaction; UCHAR *buffer; USHORT length, number, level; ips_request *ips; ips_string *ips_message; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_request; request = (IRQ) ips->ips_rq_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); number = ips->ips_msg_type; level = ips->ips_req_level; /* set up message */ ips_message = &comm->ips_buffers[IPS_SEND_MESSAGE]; length = (USHORT) ips_message->ips_cl_size; buffer = get_buffer(comm, length, IPS_SEND_MESSAGE); NOT_NULL(buffer, length); IPS_SERVER(comm, IPS_SEND_MESSAGE, buffer, length); number = ips->ips_msg_type; level = ips->ips_req_level; if (!transfer_buffers(icc, comm)) return; /* start the request */ GDS_START_AND_SEND(status_vector, GDS_REF(request->irq_handle), GDS_REF(transaction->itr_handle), number, length, GDS_VAL(buffer), level); send_response(icc, status_vector); } static void start_transaction( ICC icc) { /************************************** * * s t a r t _ t r a n s a c t i o n * ************************************** * * Functional description * Start a transaction. * **************************************/ IDB idb; ITR transaction; USHORT count, c; UCHAR *buffer; FRBRD * handle; ULONG **v, *vector[3 * 16]; ISC_STATUS_ARRAY status_vector; ips_start_trans *ips; ips_comm_area *comm; TEXT *comm_ptr; ULONG length, l, *lp; /* set up communications area */ GET_COMM_OBJECT; lp = (ULONG *) comm_ptr; ips = &comm->ips_operations.ips_op_strt_trans; v = vector; count = ips->ips_db_count; buffer = get_buffer(comm, 1024, 0); NOT_NULL(buffer, TRUE); /* set up all the handles */ for (c = 0; c < count; c++) { idb = (IDB) * lp++; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); *v++ = reinterpret_cast < ULONG * >(&idb->idb_handle); length = *lp++; *v++ = reinterpret_cast < ULONG * >(length); *v++ = reinterpret_cast < ULONG * >(buffer); comm_ptr = (TEXT *) lp; for (l = 0; l < length; l++) *buffer++ = *comm_ptr++; lp = lp + ((length + (sizeof(ULONG) - 1)) / sizeof(ULONG)); } handle = NULL; /* start the transaction and return the handle */ GDS_START_MULTIPLE(status_vector, GDS_REF(handle), count, (UCHAR *) vector); transaction = make_transaction(idb, handle); ips->ips_tr_handle = (UCHAR *) transaction; NOT_NULL(transaction, TRUE); send_response(icc, status_vector); } static void transact_request( ICC icc) { /************************************** * * t r a n s a c t _ r e q u e s t * ************************************** * * Functional description * **************************************/ IDB idb; ITR transaction; USHORT blr_length, in_msg_length, out_msg_length; UCHAR *blr, *in_buffer, *out_buffer; ISC_STATUS_ARRAY status_vector; ips_transact_request *ips; ips_string *ips_blr; ips_string *ips_in_msg; ips_string *ips_out_msg; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_trans_req; idb = (IDB) ips->ips_db_handle; CHECK_HANDLE(idb, type_idb, isc_bad_db_handle); transaction = (ITR) ips->ips_tr_handle; CHECK_HANDLE(transaction, type_itr, isc_bad_trans_handle); /* set up blr */ ips_blr = &comm->ips_buffers[IPS_TRANS_REQ_BLR]; blr_length = (USHORT) ips_blr->ips_cl_size; blr = get_buffer(comm, blr_length, IPS_TRANS_REQ_BLR); NOT_NULL(blr, blr_length); IPS_SERVER(comm, IPS_TRANS_REQ_BLR, blr, blr_length); /* set up input message */ ips_in_msg = &comm->ips_buffers[IPS_TRANS_REQ_IN_MSG]; in_msg_length = (USHORT) ips_in_msg->ips_cl_size; in_buffer = get_buffer(comm, in_msg_length, IPS_TRANS_REQ_IN_MSG); NOT_NULL(in_buffer, in_msg_length); IPS_SERVER(comm, IPS_TRANS_REQ_IN_MSG, in_buffer, in_msg_length); /* set up blr */ ips_out_msg = &comm->ips_buffers[IPS_TRANS_REQ_OUT_MSG]; out_msg_length = (USHORT) ips_out_msg->ips_cl_size; out_buffer = get_buffer(comm, out_msg_length, IPS_TRANS_REQ_OUT_MSG); NOT_NULL(out_buffer, out_msg_length); IPS_SERVER(comm, IPS_TRANS_REQ_OUT_MSG, out_buffer, out_msg_length); if (!transfer_buffers(icc, comm)) return; /* transact request and return output */ GDS_TRANSACT_REQUEST(status_vector, &idb->idb_handle, &transaction->itr_handle, blr_length, reinterpret_cast < char *>(blr), in_msg_length, reinterpret_cast < char *>(in_buffer), out_msg_length, reinterpret_cast < char *>(out_buffer)); send_response(icc, status_vector); } static BOOL transfer_buffers( ICC icc, ips_comm_area * comm) { /************************************** * * t r a n s f e r _ b u f f e r s * ************************************** * * Functional description * **************************************/ TEXT *acursor, *scursor; ULONG to_copy; USHORT i; ips_string *string; /* for each buffer, see if the client is sending stuff, and if so, put the data in the server's buffers */ for (i = 0; i < MAX_IPS_STRINGS; i++) { string = &comm->ips_buffers[i]; /* see if this buffer needs extraction */ if ((string->ips_flags & IPS_INPUT_BUFFER) && string->ips_sv_size) { string->ips_sv_copied = 0; scursor = reinterpret_cast < char *>(string->ips_sv_addr); /* start extraction */ while (string->ips_sv_copied < string->ips_sv_size) { /* extract all or whatever's available */ to_copy = string->ips_sv_size - string->ips_sv_copied; if (string->ips_com_size <= to_copy) to_copy = string->ips_com_size; acursor = (TEXT *) comm->ips_data + string->ips_com_offset; memcpy(scursor, acursor, (USHORT) to_copy); scursor += to_copy; string->ips_sv_copied += to_copy; /* if there is more to copy, wait for it */ if (string->ips_sv_copied < string->ips_sv_size) { comm->ips_sequence++; if (!send_and_wait(icc)) return FALSE; } } } } return TRUE; } static void unwind( ICC icc) { /************************************** * * u n w i n d * ************************************** * * Functional description * Unwind a request. * **************************************/ IRQ request; USHORT level; ISC_STATUS_ARRAY status_vector; ips_object *ips; ips_comm_area *comm; TEXT *comm_ptr; /* set up communications area */ GET_COMM_OBJECT; ips = &comm->ips_operations.ips_op_object; request = (IRQ) ips->ips_handle; CHECK_HANDLE(request, type_irq, isc_bad_req_handle); level = (USHORT) ips->ips_parameter; /* unwind the request */ GDS_UNWIND(status_vector, GDS_REF(request->irq_handle), level); send_response(icc, status_vector); } static BOOL wait_no_send( ICC icc) { /************************************** * * w a i t _ n o _ s e n d * ************************************** * * Functional description * This function waits for the client's next * request by waiting on the server's semaphore. * **************************************/ DWORD result1; DWORD result2; DWORD error1; DWORD error2; USHORT ret; /* already in shutdown mode */ if (icc->icc_flags & ICCF_SHUTDOWN) return FALSE; /* wait for the server to signal us back */ ret = TRUE; while (ret) { /* wait for semaphore for a minute */ result1 = WaitForSingleObject(icc->icc_waits[0], 10000L); error1 = GetLastError(); /* check for success */ if (result1 == WAIT_OBJECT_0) break; /* a non-timeout result is an error */ if (result1 != WAIT_TIMEOUT) { #ifdef DEBUG_IP_TRACE gds__log("ipserver wait no send failed %lX %ld %ld", (long) icc, result1, error1); gds__log("ipserver ids %lX %lX", icc->icc_waits[0], icc->icc_waits[1]); #endif ret = 0; break; } /* see if the client is still alive */ result2 = WaitForSingleObject(icc->icc_waits[1], 1L); error2 = GetLastError(); /* if process is gone, or there's some error, bag it */ if (result2 != WAIT_TIMEOUT) { #ifdef DEBUG_IP_TRACE gds__log("ip server wait no send failed again %lX %ld %ld", (long) icc, result2, error2); #endif ret = 0; break; } } if (!ret) icc->icc_flags |= ICCF_SHUTDOWN; return ret; }