ruby-staci 2.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +14 -0
  3. data/COPYING +30 -0
  4. data/COPYING_old +64 -0
  5. data/ChangeLog +3826 -0
  6. data/Makefile +92 -0
  7. data/NEWS +1194 -0
  8. data/README.md +66 -0
  9. data/dist-files +113 -0
  10. data/docs/bind-array-to-in_cond.md +38 -0
  11. data/docs/conflicts-local-connections-and-processes.md +98 -0
  12. data/docs/hanging-after-inactivity.md +63 -0
  13. data/docs/install-binary-package.md +44 -0
  14. data/docs/install-full-client.md +111 -0
  15. data/docs/install-instant-client.md +194 -0
  16. data/docs/install-on-osx.md +133 -0
  17. data/docs/ldap-auth-and-function-interposition.md +123 -0
  18. data/docs/number-type-mapping.md +79 -0
  19. data/docs/osx-install-dev-tools.png +0 -0
  20. data/docs/platform-specific-issues.md +164 -0
  21. data/docs/report-installation-issue.md +50 -0
  22. data/docs/timeout-parameters.md +94 -0
  23. data/ext/oci8/.document +18 -0
  24. data/ext/oci8/MANIFEST +18 -0
  25. data/ext/oci8/apiwrap.c.tmpl +178 -0
  26. data/ext/oci8/apiwrap.h.tmpl +61 -0
  27. data/ext/oci8/apiwrap.rb +96 -0
  28. data/ext/oci8/apiwrap.yml +1322 -0
  29. data/ext/oci8/attr.c +57 -0
  30. data/ext/oci8/bind.c +838 -0
  31. data/ext/oci8/connection_pool.c +216 -0
  32. data/ext/oci8/encoding.c +196 -0
  33. data/ext/oci8/env.c +139 -0
  34. data/ext/oci8/error.c +385 -0
  35. data/ext/oci8/extconf.rb +219 -0
  36. data/ext/oci8/hook_funcs.c +407 -0
  37. data/ext/oci8/lob.c +1278 -0
  38. data/ext/oci8/metadata.c +279 -0
  39. data/ext/oci8/object.c +919 -0
  40. data/ext/oci8/oci8.c +1058 -0
  41. data/ext/oci8/oci8.h +556 -0
  42. data/ext/oci8/oci8lib.c +704 -0
  43. data/ext/oci8/ocidatetime.c +506 -0
  44. data/ext/oci8/ocihandle.c +852 -0
  45. data/ext/oci8/ocinumber.c +1922 -0
  46. data/ext/oci8/oraconf.rb +1145 -0
  47. data/ext/oci8/oradate.c +670 -0
  48. data/ext/oci8/oranumber_util.c +352 -0
  49. data/ext/oci8/oranumber_util.h +24 -0
  50. data/ext/oci8/plthook.h +66 -0
  51. data/ext/oci8/plthook_elf.c +702 -0
  52. data/ext/oci8/plthook_osx.c +505 -0
  53. data/ext/oci8/plthook_win32.c +391 -0
  54. data/ext/oci8/post-config.rb +5 -0
  55. data/ext/oci8/stmt.c +448 -0
  56. data/ext/oci8/thread_util.c +81 -0
  57. data/ext/oci8/thread_util.h +18 -0
  58. data/ext/oci8/util.c +71 -0
  59. data/ext/oci8/win32.c +117 -0
  60. data/lib/.document +1 -0
  61. data/lib/dbd/STACI.rb +591 -0
  62. data/lib/oci8/.document +8 -0
  63. data/lib/oci8/bindtype.rb +333 -0
  64. data/lib/oci8/check_load_error.rb +146 -0
  65. data/lib/oci8/compat.rb +117 -0
  66. data/lib/oci8/connection_pool.rb +179 -0
  67. data/lib/oci8/cursor.rb +605 -0
  68. data/lib/oci8/datetime.rb +605 -0
  69. data/lib/oci8/encoding-init.rb +45 -0
  70. data/lib/oci8/encoding.yml +537 -0
  71. data/lib/oci8/metadata.rb +2148 -0
  72. data/lib/oci8/object.rb +641 -0
  73. data/lib/oci8/oci8.rb +756 -0
  74. data/lib/oci8/ocihandle.rb +591 -0
  75. data/lib/oci8/oracle_version.rb +153 -0
  76. data/lib/oci8/properties.rb +196 -0
  77. data/lib/oci8/version.rb +3 -0
  78. data/lib/ruby-staci.rb +1 -0
  79. data/lib/staci.rb +190 -0
  80. data/metaconfig +142 -0
  81. data/pre-distclean.rb +7 -0
  82. data/ruby-aci.gemspec +83 -0
  83. data/setup.rb +1342 -0
  84. data/test/README.md +37 -0
  85. data/test/config.rb +201 -0
  86. data/test/setup_test_object.sql +199 -0
  87. data/test/setup_test_package.sql +59 -0
  88. data/test/test_all.rb +56 -0
  89. data/test/test_appinfo.rb +62 -0
  90. data/test/test_array_dml.rb +333 -0
  91. data/test/test_bind_array.rb +70 -0
  92. data/test/test_bind_boolean.rb +99 -0
  93. data/test/test_bind_integer.rb +47 -0
  94. data/test/test_bind_raw.rb +45 -0
  95. data/test/test_bind_string.rb +105 -0
  96. data/test/test_bind_time.rb +177 -0
  97. data/test/test_break.rb +124 -0
  98. data/test/test_clob.rb +86 -0
  99. data/test/test_connection_pool.rb +124 -0
  100. data/test/test_connstr.rb +220 -0
  101. data/test/test_datetime.rb +585 -0
  102. data/test/test_dbi.rb +365 -0
  103. data/test/test_dbi_clob.rb +53 -0
  104. data/test/test_encoding.rb +103 -0
  105. data/test/test_error.rb +87 -0
  106. data/test/test_metadata.rb +2674 -0
  107. data/test/test_object.rb +546 -0
  108. data/test/test_oci8.rb +624 -0
  109. data/test/test_oracle_version.rb +68 -0
  110. data/test/test_oradate.rb +255 -0
  111. data/test/test_oranumber.rb +786 -0
  112. data/test/test_package_type.rb +981 -0
  113. data/test/test_properties.rb +17 -0
  114. data/test/test_rowid.rb +32 -0
  115. metadata +158 -0
@@ -0,0 +1,407 @@
1
+ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * hook.c
4
+ *
5
+ * Copyright (C) 2015-2018 Kubo Takehiro <kubo@jiubao.org>
6
+ */
7
+ #if defined(_WIN32) || defined(__CYGWIN__)
8
+ #define WINDOWS
9
+ #include <winsock2.h>
10
+ #endif
11
+ #include "oci8.h"
12
+ #include "plthook.h"
13
+ #ifdef __CYGWIN__
14
+ #undef boolean /* boolean defined in oratypes.h coflicts with that in windows.h */
15
+ #define stricmp strcasecmp
16
+ #define strnicmp strncasecmp
17
+ #endif
18
+ #ifdef WINDOWS
19
+ #include <windows.h>
20
+ #include <mstcpip.h>
21
+ #include <tlhelp32.h>
22
+ #else
23
+ #include <unistd.h>
24
+ #include <sys/socket.h>
25
+ #include <netinet/in.h>
26
+ #include <netinet/tcp.h>
27
+ #include <dlfcn.h>
28
+ #endif
29
+
30
+ #ifdef WINDOWS
31
+ static CRITICAL_SECTION lock;
32
+ #define LOCK(lock) EnterCriticalSection(lock)
33
+ #define UNLOCK(lock) LeaveCriticalSection(lock)
34
+ typedef int socklen_t;
35
+ #else
36
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
37
+ #define LOCK(lock) pthread_mutex_lock(lock)
38
+ #define UNLOCK(lock) pthread_mutex_unlock(lock)
39
+ #define SOCKET int
40
+ #define INVALID_SOCKET (-1)
41
+ #define WSAAPI
42
+ #endif
43
+
44
+ #if defined(__APPLE__) && defined(TCP_KEEPALIVE) /* macOS */
45
+ #define USE_TCP_KEEPALIVE
46
+ #define SUPPORT_TCP_KEEPALIVE_TIME
47
+ #elif defined(__sun) && defined(TCP_KEEPALIVE_THRESHOLD) /* Solaris */
48
+ #define USE_TCP_KEEPALIVE_THRESHOLD
49
+ #define SUPPORT_TCP_KEEPALIVE_TIME
50
+ #elif defined(TCP_KEEPIDLE) /* Linux, etc */
51
+ #define USE_TCP_KEEPIDLE
52
+ #define SUPPORT_TCP_KEEPALIVE_TIME
53
+ #elif defined(WINDOWS)
54
+ #define SUPPORT_TCP_KEEPALIVE_TIME
55
+ #endif
56
+
57
+ int oci8_cancel_read_at_exit = 0;
58
+
59
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
60
+ int oci8_tcp_keepalive_time = 0;
61
+ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen);
62
+ #else
63
+ int oci8_tcp_keepalive_time = -1;
64
+ #endif
65
+
66
+ static char hook_errmsg[512];
67
+
68
+ typedef struct {
69
+ const char *func_name;
70
+ void *func_addr;
71
+ void *old_func_addr;
72
+ } hook_func_entry_t;
73
+
74
+ typedef struct socket_entry {
75
+ struct socket_entry *next;
76
+ struct socket_entry *prev;
77
+ SOCKET sock;
78
+ } socket_entry_t;
79
+
80
+ static socket_entry_t sockets_in_use = {
81
+ &sockets_in_use, &sockets_in_use, INVALID_SOCKET,
82
+ };
83
+
84
+ static void socket_entry_set(socket_entry_t *entry, SOCKET sock)
85
+ {
86
+ LOCK(&lock);
87
+ entry->next = sockets_in_use.next;
88
+ entry->prev = &sockets_in_use;
89
+ sockets_in_use.next->prev = entry;
90
+ sockets_in_use.next = entry;
91
+ entry->sock = sock;
92
+ UNLOCK(&lock);
93
+ }
94
+
95
+ static void socket_entry_clear(socket_entry_t *entry)
96
+ {
97
+ LOCK(&lock);
98
+ entry->next->prev = entry->prev;
99
+ entry->prev->next = entry->next;
100
+ UNLOCK(&lock);
101
+ }
102
+
103
+ static int replace_functions(void *addr, const char *file, hook_func_entry_t *functions)
104
+ {
105
+ plthook_t *ph;
106
+ int i;
107
+ int rv = 0;
108
+
109
+ if (plthook_open_by_address(&ph, addr) != 0) {
110
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
111
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
112
+ return -1;
113
+ }
114
+
115
+ /* install hooks */
116
+ for (i = 0; functions[i].func_name != NULL ; i++) {
117
+ hook_func_entry_t *function = &functions[i];
118
+ rv = plthook_replace(ph, function->func_name, function->func_addr, &function->old_func_addr);
119
+ if (rv != 0) {
120
+ strncpy(hook_errmsg, plthook_error(), sizeof(hook_errmsg) - 1);
121
+ hook_errmsg[sizeof(hook_errmsg) - 1] = '\0';
122
+ while (--i >= 0) {
123
+ /*restore hooked fuction address */
124
+ plthook_replace(ph, functions[i].func_name, functions[i].old_func_addr, NULL);
125
+ }
126
+ snprintf(hook_errmsg, sizeof(hook_errmsg), "Could not replace function %s in %s", function->func_name, file);
127
+ break;
128
+ }
129
+ }
130
+ plthook_close(ph);
131
+ return rv;
132
+ }
133
+
134
+ #ifdef WINDOWS
135
+
136
+ #ifndef _MSC_VER
137
+ /* setsockopt() in ws2_32.dll */
138
+ #define setsockopt rboci_setsockopt
139
+ typedef int (WSAAPI *setsockopt_t)(SOCKET, int, int, const void *, int);
140
+ static setsockopt_t setsockopt;
141
+ #endif
142
+
143
+ /* system-wide keepalive interval */
144
+ static DWORD keepalive_interval;
145
+
146
+ static int locK_is_initialized;
147
+
148
+ static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
149
+
150
+ static hook_func_entry_t tcp_functions[] = {
151
+ {"WSARecv", (void*)hook_WSARecv, NULL},
152
+ {"setsockopt", (void*)hook_setsockopt, NULL},
153
+ {NULL, NULL, NULL},
154
+ };
155
+
156
+ /* WSARecv() is used for TCP connections */
157
+ static int WSAAPI hook_WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
158
+ {
159
+ socket_entry_t entry;
160
+ int enable_cancel = oci8_cancel_read_at_exit;
161
+ int rv;
162
+
163
+ if (enable_cancel > 0) {
164
+ socket_entry_set(&entry, s);
165
+ }
166
+ rv = WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
167
+ if (enable_cancel > 0) {
168
+ socket_entry_clear(&entry);
169
+ }
170
+ return rv;
171
+ }
172
+
173
+ void oci8_install_hook_functions()
174
+ {
175
+ static int hook_functions_installed = 0;
176
+ HKEY hKey;
177
+ DWORD type;
178
+ DWORD data;
179
+ DWORD cbData = sizeof(data);
180
+ const char *reg_key = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
181
+ HANDLE hSnapshot;
182
+ MODULEENTRY32 me;
183
+ BOOL module_found = FALSE;
184
+
185
+ if (hook_functions_installed) {
186
+ return;
187
+ }
188
+
189
+ InitializeCriticalSectionAndSpinCount(&lock, 5000);
190
+ locK_is_initialized = 1;
191
+
192
+ #ifndef _MSC_VER
193
+ /* Get setsockopt in ws2_32.dll.
194
+ * setsockopt used by mingw compiler isn't same with that in ws2_32.dll.
195
+ */
196
+ setsockopt = (setsockopt_t)GetProcAddress(GetModuleHandleA("WS2_32.DLL"), "setsockopt");
197
+ if (setsockopt == NULL){
198
+ rb_raise(rb_eRuntimeError, "setsockopt isn't found in WS2_32.DLL");
199
+ }
200
+ #endif
201
+
202
+ /* Get system-wide keepalive interval parameter.
203
+ * https://technet.microsoft.com/en-us/library/cc957548.aspx
204
+ */
205
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, reg_key, 0, KEY_QUERY_VALUE, &hKey) != 0) {
206
+ rb_raise(rb_eRuntimeError, "failed to open the registry key HKLM\\%s", reg_key);
207
+ }
208
+ keepalive_interval = 1000; /* default value when the following entry isn't found. */
209
+ if (RegQueryValueEx(hKey, "KeepAliveInterval", NULL, &type, (LPBYTE)&data, &cbData) == 0) {
210
+ if (type == REG_DWORD) {
211
+ keepalive_interval = data;
212
+ }
213
+ }
214
+ RegCloseKey(hKey);
215
+
216
+ hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId());
217
+ me.dwSize = sizeof(me);
218
+ if (Module32First(hSnapshot, &me)) {
219
+ do {
220
+ const char *p = NULL;
221
+ if (strnicmp(me.szModule, "orantcp", 7) == 0) { // ORACLE_HOME-based client
222
+ p = me.szModule + 7;
223
+ } else if (strnicmp(me.szModule, "oraociei", 8) == 0) { // instant client basic
224
+ p = me.szModule + 8;
225
+ } else if (strnicmp(me.szModule, "oraociicus", 10) == 0) { // instant client basic lite
226
+ p = me.szModule + 10;
227
+ }
228
+ if (p != NULL && ('1' <= *p && *p <= '9') && ('0' <= *(p + 1) && *(p + 1) <= '9')
229
+ && stricmp(p + 2, ".dll") == 0) {
230
+ if (GetProcAddress((HMODULE)me.modBaseAddr, "nttini") != NULL) {
231
+ module_found = TRUE;
232
+ if (replace_functions(me.modBaseAddr, me.szExePath, tcp_functions) != 0) {
233
+ CloseHandle(hSnapshot);
234
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
235
+ }
236
+ }
237
+ }
238
+ } while (Module32Next(hSnapshot, &me));
239
+ }
240
+ CloseHandle(hSnapshot);
241
+ if (!module_found) {
242
+ rb_raise(rb_eRuntimeError, "No DLL is found to hook.");
243
+ }
244
+ hook_functions_installed = 1;
245
+ }
246
+
247
+ static void shutdown_socket(socket_entry_t *entry)
248
+ {
249
+ /* This is dangerous. But I don't know how to cancel WSARecv().
250
+ * This technique is usable only at the process termination.
251
+ * Otherwise, Oracle client library may close sockets used by
252
+ * others.
253
+ */
254
+ closesocket(entry->sock);
255
+ }
256
+
257
+ #else
258
+ static ssize_t hook_read(int fd, void *buf, size_t count);
259
+
260
+ #ifdef __APPLE__
261
+ #define SO_EXT "dylib"
262
+ #else
263
+ #define SO_EXT "so"
264
+ #endif
265
+
266
+ static hook_func_entry_t functions[] = {
267
+ {"read", (void*)hook_read, NULL},
268
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
269
+ {"setsockopt", (void*)hook_setsockopt, NULL},
270
+ #endif
271
+ {NULL, NULL, NULL},
272
+ };
273
+
274
+ static ssize_t hook_read(int fd, void *buf, size_t count)
275
+ {
276
+ socket_entry_t entry;
277
+ int enable_cancel = oci8_cancel_read_at_exit;
278
+ ssize_t rv;
279
+
280
+ if (enable_cancel > 0) {
281
+ socket_entry_set(&entry, fd);
282
+ }
283
+ rv = read(fd, buf, count);
284
+ if (enable_cancel > 0) {
285
+ socket_entry_clear(&entry);
286
+ }
287
+ return rv;
288
+ }
289
+
290
+ static void *ocifunc_addr(void *dlsym_handle, const char **file)
291
+ {
292
+ void *addr = dlsym(dlsym_handle, "ACIEnvCreate");
293
+ Dl_info dli;
294
+
295
+ if (addr == NULL) {
296
+ return NULL;
297
+ }
298
+ if (dladdr(addr, &dli) == 0) {
299
+ return NULL;
300
+ }
301
+ if (strstr(dli.dli_fname, "/libclntsh." SO_EXT) == NULL) {
302
+ return NULL;
303
+ }
304
+ *file = dli.dli_fname;
305
+ return addr;
306
+ }
307
+
308
+ #ifdef __linux__
309
+ #include <link.h>
310
+ static void *ocifunc_addr_linux(const char **file)
311
+ {
312
+ struct link_map *lm;
313
+ for (lm = _r_debug.r_map; lm != NULL; lm = lm->l_next) {
314
+ if (strstr(lm->l_name, "/libclntsh." SO_EXT) != NULL) {
315
+ *file = lm->l_name;
316
+ return (void*)lm->l_addr;
317
+ }
318
+ }
319
+ return NULL;
320
+ }
321
+ #endif
322
+
323
+ void oci8_install_hook_functions(void)
324
+ {
325
+ static int hook_functions_installed = 0;
326
+ void *addr;
327
+ const char *file;
328
+
329
+ if (hook_functions_installed) {
330
+ return;
331
+ }
332
+ addr = ocifunc_addr(RTLD_DEFAULT, &file);
333
+ if (addr == NULL) {
334
+ /* OCI symbols may be hooked by LD_PRELOAD. */
335
+ addr = ocifunc_addr(RTLD_NEXT, &file);
336
+ }
337
+ #ifdef __linux__
338
+ if (addr == NULL) {
339
+ addr = ocifunc_addr_linux(&file);
340
+ }
341
+ #endif
342
+ if (addr == NULL) {
343
+ rb_raise(rb_eRuntimeError, "No shared library is found to hook.");
344
+ }
345
+ if (replace_functions(addr, file, functions) != 0) {
346
+ rb_raise(rb_eRuntimeError, "Hook error: %s", hook_errmsg);
347
+ }
348
+ hook_functions_installed = 1;
349
+ }
350
+
351
+ static void shutdown_socket(socket_entry_t *entry)
352
+ {
353
+ shutdown(entry->sock, SHUT_RDWR);
354
+ }
355
+ #endif
356
+
357
+ #ifdef SUPPORT_TCP_KEEPALIVE_TIME
358
+ static int WSAAPI hook_setsockopt(SOCKET sockfd, int level, int optname, const void *optval, socklen_t optlen)
359
+ {
360
+ int rv = setsockopt(sockfd, level, optname, optval, optlen);
361
+
362
+ if (rv == 0 && level == SOL_SOCKET && optname == SO_KEEPALIVE
363
+ && optlen == sizeof(int) && *(const int*)optval != 0) {
364
+ /* If Oracle client libraries enables keepalive by (ENABLE=BROKEN),
365
+ * set per-connection keepalive socket options to overwrite
366
+ * system-wide setting.
367
+ */
368
+ if (oci8_tcp_keepalive_time > 0) {
369
+ #if defined(USE_TCP_KEEPALIVE) /* macOS */
370
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, &oci8_tcp_keepalive_time, sizeof(int));
371
+ #elif defined(USE_TCP_KEEPALIVE_THRESHOLD) /* Solaris */
372
+ unsigned int millisec = oci8_tcp_keepalive_time * 1000;
373
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &millisec, sizeof(millisec));
374
+ #elif defined(USE_TCP_KEEPIDLE) /* Linux, etc */
375
+ setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &oci8_tcp_keepalive_time, sizeof(int));
376
+ #elif defined(WINDOWS)
377
+ struct tcp_keepalive vals;
378
+ DWORD dummy;
379
+
380
+ vals.onoff = 1;
381
+ vals.keepalivetime = oci8_tcp_keepalive_time * 1000;
382
+ vals.keepaliveinterval = keepalive_interval;
383
+ WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0,
384
+ &dummy, NULL, NULL);
385
+ #endif
386
+ }
387
+ }
388
+ return rv;
389
+ }
390
+ #endif
391
+
392
+ void oci8_shutdown_sockets(void)
393
+ {
394
+ socket_entry_t *entry;
395
+
396
+ #ifdef WINDOWS
397
+ if (!locK_is_initialized) {
398
+ return;
399
+ }
400
+ #endif
401
+
402
+ LOCK(&lock);
403
+ for (entry = sockets_in_use.next; entry != &sockets_in_use; entry = entry->next) {
404
+ shutdown_socket(entry);
405
+ }
406
+ UNLOCK(&lock);
407
+ }