vincentchu-handlersocket 0.0.1

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 (135) hide show
  1. data/ext/HandlerSocket-Plugin-for-MySQL/AUTHORS +22 -0
  2. data/ext/HandlerSocket-Plugin-for-MySQL/COPYING +30 -0
  3. data/ext/HandlerSocket-Plugin-for-MySQL/ChangeLog +12 -0
  4. data/ext/HandlerSocket-Plugin-for-MySQL/Makefile.am +87 -0
  5. data/ext/HandlerSocket-Plugin-for-MySQL/README +78 -0
  6. data/ext/HandlerSocket-Plugin-for-MySQL/autogen.sh +117 -0
  7. data/ext/HandlerSocket-Plugin-for-MySQL/client/Makefile.am +24 -0
  8. data/ext/HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp +88 -0
  9. data/ext/HandlerSocket-Plugin-for-MySQL/client/hslongrun.cpp +1041 -0
  10. data/ext/HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl +224 -0
  11. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.cpp +1532 -0
  12. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.pl +228 -0
  13. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh +4 -0
  14. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh +4 -0
  15. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh +7 -0
  16. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh +3 -0
  17. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh +3 -0
  18. data/ext/HandlerSocket-Plugin-for-MySQL/configure.ac +144 -0
  19. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt +72 -0
  20. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt +99 -0
  21. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt +92 -0
  22. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt +135 -0
  23. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt +205 -0
  24. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt +51 -0
  25. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt +88 -0
  26. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt +127 -0
  27. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt +180 -0
  28. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt +27 -0
  29. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am +10 -0
  30. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template +31 -0
  31. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp +1190 -0
  32. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp +142 -0
  33. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp +222 -0
  34. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.spec.template +29 -0
  35. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.cpp +149 -0
  36. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.hpp +58 -0
  37. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.cpp +951 -0
  38. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.hpp +35 -0
  39. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/mysql_incl.hpp +50 -0
  40. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/COPYRIGHT.txt +27 -0
  41. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.am +12 -0
  42. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.plain +27 -0
  43. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/allocator.hpp +64 -0
  44. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_addrinfo.hpp +49 -0
  45. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_file.hpp +64 -0
  46. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_ptrcontainer.hpp +67 -0
  47. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.cpp +67 -0
  48. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.hpp +32 -0
  49. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.cpp +127 -0
  50. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.hpp +66 -0
  51. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.cpp +36 -0
  52. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.hpp +22 -0
  53. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.cpp +441 -0
  54. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.hpp +62 -0
  55. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/libhsclient.spec.template +39 -0
  56. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/mutex.hpp +51 -0
  57. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.cpp +186 -0
  58. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.hpp +51 -0
  59. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_buffer.hpp +118 -0
  60. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_ref.hpp +63 -0
  61. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.cpp +182 -0
  62. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.hpp +53 -0
  63. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/thread.hpp +84 -0
  64. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/util.hpp +25 -0
  65. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-hs.log +130 -0
  66. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-my.log +125 -0
  67. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/COPYRIGHT.txt +27 -0
  68. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Changes +6 -0
  69. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/HandlerSocket.xs +632 -0
  70. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/MANIFEST +8 -0
  71. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL +18 -0
  72. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL.installed +20 -0
  73. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/README +30 -0
  74. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm +68 -0
  75. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm +362 -0
  76. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template +127 -0
  77. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/ppport.h +6375 -0
  78. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/t/Net-HandlerSocket.t +15 -0
  79. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/Makefile +79 -0
  80. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/binary_my.cnf +4 -0
  81. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/compat.sh +29 -0
  82. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/hstest.pm +66 -0
  83. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/Makefile +4 -0
  84. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/run.sh +27 -0
  85. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.expected +100 -0
  86. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.pl +38 -0
  87. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.expected +100 -0
  88. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.pl +49 -0
  89. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.expected +771 -0
  90. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.pl +61 -0
  91. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.expected +0 -0
  92. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.pl +63 -0
  93. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.expected +771 -0
  94. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.pl +59 -0
  95. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.expected +644 -0
  96. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.pl +90 -0
  97. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.expected +304 -0
  98. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.pl +98 -0
  99. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.expected +2 -0
  100. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.pl +48 -0
  101. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.expected +12 -0
  102. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.pl +67 -0
  103. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.expected +771 -0
  104. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.pl +93 -0
  105. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.expected +37 -0
  106. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.pl +112 -0
  107. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.expected +273 -0
  108. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.pl +134 -0
  109. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.expected +92 -0
  110. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.pl +92 -0
  111. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.expected +144 -0
  112. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.pl +80 -0
  113. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.expected +764 -0
  114. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.pl +114 -0
  115. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.expected +66 -0
  116. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.pl +88 -0
  117. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.expected +0 -0
  118. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.pl +125 -0
  119. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.expected +22 -0
  120. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.pl +63 -0
  121. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.expected +14894 -0
  122. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.pl +190 -0
  123. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.expected +2 -0
  124. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.pl +33 -0
  125. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.expected +11 -0
  126. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.pl +58 -0
  127. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.expected +9 -0
  128. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.pl +61 -0
  129. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.expected +101 -0
  130. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.pl +53 -0
  131. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/README +33 -0
  132. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/extconf.rb +27 -0
  133. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.cpp +437 -0
  134. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.h +32 -0
  135. metadata +200 -0
@@ -0,0 +1,58 @@
1
+
2
+ // vim:sw=2:ai
3
+
4
+ /*
5
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6
+ * See COPYRIGHT.txt for details.
7
+ */
8
+
9
+ #ifndef DENA_HSTCPSVR_HPP
10
+ #define DENA_HSTCPSVR_HPP
11
+
12
+ #include <memory>
13
+ #include <string>
14
+ #include <map>
15
+
16
+ #include "mutex.hpp"
17
+ #include "auto_file.hpp"
18
+ #include "database.hpp"
19
+ #include "config.hpp"
20
+ #include "socket.hpp"
21
+
22
+ namespace dena {
23
+
24
+ struct hstcpsvr_shared_c {
25
+ config conf;
26
+ long num_threads;
27
+ long nb_conn_per_thread;
28
+ bool for_write_flag;
29
+ bool require_auth;
30
+ std::string plain_secret;
31
+ int readsize;
32
+ socket_args sockargs;
33
+ auto_file listen_fd;
34
+ database_ptr dbptr;
35
+ volatile unsigned int *thread_num_conns; /* 0 .. num_threads-1 */
36
+ hstcpsvr_shared_c() : num_threads(0), nb_conn_per_thread(100),
37
+ for_write_flag(false), require_auth(false), readsize(0),
38
+ thread_num_conns(0) { }
39
+ };
40
+
41
+ struct hstcpsvr_shared_v : public mutex {
42
+ int shutdown;
43
+ hstcpsvr_shared_v() : shutdown(0) { }
44
+ };
45
+
46
+ struct hstcpsvr_i;
47
+ typedef std::auto_ptr<hstcpsvr_i> hstcpsvr_ptr;
48
+
49
+ struct hstcpsvr_i {
50
+ virtual ~hstcpsvr_i() { }
51
+ virtual std::string start_listen() = 0;
52
+ static hstcpsvr_ptr create(const config& conf);
53
+ };
54
+
55
+ };
56
+
57
+ #endif
58
+
@@ -0,0 +1,951 @@
1
+
2
+ // vim:sw=2:ai
3
+
4
+ /*
5
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6
+ * See COPYRIGHT.txt for details.
7
+ */
8
+
9
+ #include <netinet/in.h>
10
+ #include <errno.h>
11
+ #include <poll.h>
12
+ #include <unistd.h>
13
+ #include <fcntl.h>
14
+ #include <stdexcept>
15
+ #include <signal.h>
16
+ #include <list>
17
+ #if __linux__
18
+ #include <sys/epoll.h>
19
+ #endif
20
+
21
+ #include "hstcpsvr_worker.hpp"
22
+ #include "string_buffer.hpp"
23
+ #include "auto_ptrcontainer.hpp"
24
+ #include "string_util.hpp"
25
+ #include "escape.hpp"
26
+
27
+ #define DBG_FD(x)
28
+ #define DBG_TR(x)
29
+ #define DBG_EP(x)
30
+ #define DBG_MULTI(x)
31
+
32
+ /* TODO */
33
+ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(MSG_NOSIGNAL)
34
+ #define MSG_NOSIGNAL 0
35
+ #endif
36
+
37
+ namespace dena {
38
+
39
+ struct dbconnstate {
40
+ string_buffer readbuf;
41
+ string_buffer writebuf;
42
+ std::vector<prep_stmt> prep_stmts;
43
+ size_t resp_begin_pos;
44
+ size_t find_nl_pos;
45
+ void reset() {
46
+ readbuf.clear();
47
+ writebuf.clear();
48
+ prep_stmts.clear();
49
+ resp_begin_pos = 0;
50
+ find_nl_pos = 0;
51
+ }
52
+ dbconnstate() : resp_begin_pos(0), find_nl_pos(0) { }
53
+ };
54
+
55
+ struct hstcpsvr_conn;
56
+ typedef auto_ptrcontainer< std::list<hstcpsvr_conn *> > hstcpsvr_conns_type;
57
+
58
+ struct hstcpsvr_conn : public dbcallback_i {
59
+ public:
60
+ auto_file fd;
61
+ sockaddr_storage addr;
62
+ socklen_t addr_len;
63
+ dbconnstate cstate;
64
+ std::string err;
65
+ size_t readsize;
66
+ bool nonblocking;
67
+ bool read_finished;
68
+ bool write_finished;
69
+ time_t nb_last_io;
70
+ hstcpsvr_conns_type::iterator conns_iter;
71
+ bool authorized;
72
+ public:
73
+ bool closed() const;
74
+ bool ok_to_close() const;
75
+ void reset();
76
+ int accept(const hstcpsvr_shared_c& cshared);
77
+ bool write_more(bool *more_r = 0);
78
+ bool read_more(bool *more_r = 0);
79
+ public:
80
+ virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v);
81
+ virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const;
82
+ virtual void dbcb_resp_short(uint32_t code, const char *msg);
83
+ virtual void dbcb_resp_short_num(uint32_t code, uint32_t value);
84
+ virtual void dbcb_resp_short_num64(uint32_t code, uint64_t value);
85
+ virtual void dbcb_resp_begin(size_t num_flds);
86
+ virtual void dbcb_resp_entry(const char *fld, size_t fldlen);
87
+ virtual void dbcb_resp_end();
88
+ virtual void dbcb_resp_cancel();
89
+ public:
90
+ hstcpsvr_conn() : addr_len(sizeof(addr)), readsize(4096),
91
+ nonblocking(false), read_finished(false), write_finished(false),
92
+ nb_last_io(0), authorized(false) { }
93
+ };
94
+
95
+ bool
96
+ hstcpsvr_conn::closed() const
97
+ {
98
+ return fd.get() < 0;
99
+ }
100
+
101
+ bool
102
+ hstcpsvr_conn::ok_to_close() const
103
+ {
104
+ return write_finished || (read_finished && cstate.writebuf.size() == 0);
105
+ }
106
+
107
+ void
108
+ hstcpsvr_conn::reset()
109
+ {
110
+ addr = sockaddr_storage();
111
+ addr_len = sizeof(addr);
112
+ cstate.reset();
113
+ fd.reset();
114
+ read_finished = false;
115
+ write_finished = false;
116
+ }
117
+
118
+ int
119
+ hstcpsvr_conn::accept(const hstcpsvr_shared_c& cshared)
120
+ {
121
+ reset();
122
+ return socket_accept(cshared.listen_fd.get(), fd, cshared.sockargs, addr,
123
+ addr_len, err);
124
+ }
125
+
126
+ bool
127
+ hstcpsvr_conn::write_more(bool *more_r)
128
+ {
129
+ if (write_finished || cstate.writebuf.size() == 0) {
130
+ return false;
131
+ }
132
+ const size_t wlen = cstate.writebuf.size();
133
+ ssize_t len = send(fd.get(), cstate.writebuf.begin(), wlen, MSG_NOSIGNAL);
134
+ if (len <= 0) {
135
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
136
+ cstate.writebuf.clear();
137
+ write_finished = true;
138
+ }
139
+ return false;
140
+ }
141
+ cstate.writebuf.erase_front(len);
142
+ /* FIXME: reallocate memory if too large */
143
+ if (more_r) {
144
+ *more_r = (static_cast<size_t>(len) == wlen);
145
+ }
146
+ return true;
147
+ }
148
+
149
+ bool
150
+ hstcpsvr_conn::read_more(bool *more_r)
151
+ {
152
+ if (read_finished) {
153
+ return false;
154
+ }
155
+ const size_t block_size = readsize > 4096 ? readsize : 4096;
156
+ char *wp = cstate.readbuf.make_space(block_size);
157
+ const ssize_t len = read(fd.get(), wp, block_size);
158
+ if (len <= 0) {
159
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
160
+ read_finished = true;
161
+ }
162
+ return false;
163
+ }
164
+ cstate.readbuf.space_wrote(len);
165
+ if (more_r) {
166
+ *more_r = (static_cast<size_t>(len) == block_size);
167
+ }
168
+ return true;
169
+ }
170
+
171
+ void
172
+ hstcpsvr_conn::dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v)
173
+ {
174
+ if (cstate.prep_stmts.size() <= pst_id) {
175
+ cstate.prep_stmts.resize(pst_id + 1);
176
+ }
177
+ cstate.prep_stmts[pst_id] = v;
178
+ }
179
+
180
+ const prep_stmt *
181
+ hstcpsvr_conn::dbcb_get_prep_stmt(size_t pst_id) const
182
+ {
183
+ if (cstate.prep_stmts.size() <= pst_id) {
184
+ return 0;
185
+ }
186
+ return &cstate.prep_stmts[pst_id];
187
+ }
188
+
189
+ void
190
+ hstcpsvr_conn::dbcb_resp_short(uint32_t code, const char *msg)
191
+ {
192
+ write_ui32(cstate.writebuf, code);
193
+ const size_t msglen = strlen(msg);
194
+ if (msglen != 0) {
195
+ cstate.writebuf.append_literal("\t1\t");
196
+ cstate.writebuf.append(msg, msg + msglen);
197
+ } else {
198
+ cstate.writebuf.append_literal("\t1");
199
+ }
200
+ cstate.writebuf.append_literal("\n");
201
+ }
202
+
203
+ void
204
+ hstcpsvr_conn::dbcb_resp_short_num(uint32_t code, uint32_t value)
205
+ {
206
+ write_ui32(cstate.writebuf, code);
207
+ cstate.writebuf.append_literal("\t1\t");
208
+ write_ui32(cstate.writebuf, value);
209
+ cstate.writebuf.append_literal("\n");
210
+ }
211
+
212
+ void
213
+ hstcpsvr_conn::dbcb_resp_short_num64(uint32_t code, uint64_t value)
214
+ {
215
+ write_ui32(cstate.writebuf, code);
216
+ cstate.writebuf.append_literal("\t1\t");
217
+ write_ui64(cstate.writebuf, value);
218
+ cstate.writebuf.append_literal("\n");
219
+ }
220
+
221
+ void
222
+ hstcpsvr_conn::dbcb_resp_begin(size_t num_flds)
223
+ {
224
+ cstate.resp_begin_pos = cstate.writebuf.size();
225
+ cstate.writebuf.append_literal("0\t");
226
+ write_ui32(cstate.writebuf, num_flds);
227
+ }
228
+
229
+ void
230
+ hstcpsvr_conn::dbcb_resp_entry(const char *fld, size_t fldlen)
231
+ {
232
+ if (fld != 0) {
233
+ cstate.writebuf.append_literal("\t");
234
+ escape_string(cstate.writebuf, fld, fld + fldlen);
235
+ } else {
236
+ static const char t[] = "\t\0";
237
+ cstate.writebuf.append(t, t + 2);
238
+ }
239
+ }
240
+
241
+ void
242
+ hstcpsvr_conn::dbcb_resp_end()
243
+ {
244
+ cstate.writebuf.append_literal("\n");
245
+ cstate.resp_begin_pos = 0;
246
+ }
247
+
248
+ void
249
+ hstcpsvr_conn::dbcb_resp_cancel()
250
+ {
251
+ cstate.writebuf.resize(cstate.resp_begin_pos);
252
+ cstate.resp_begin_pos = 0;
253
+ }
254
+
255
+ struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable {
256
+ hstcpsvr_worker(const hstcpsvr_worker_arg& arg);
257
+ virtual void run();
258
+ private:
259
+ const hstcpsvr_shared_c& cshared;
260
+ volatile hstcpsvr_shared_v& vshared;
261
+ long worker_id;
262
+ dbcontext_ptr dbctx;
263
+ hstcpsvr_conns_type conns; /* conns refs dbctx */
264
+ time_t last_check_time;
265
+ std::vector<pollfd> pfds;
266
+ #ifdef __linux__
267
+ std::vector<epoll_event> events_vec;
268
+ auto_file epoll_fd;
269
+ #endif
270
+ bool accept_enabled;
271
+ int accept_balance;
272
+ std::vector<string_ref> invalues_work;
273
+ std::vector<record_filter> filters_work;
274
+ private:
275
+ int run_one_nb();
276
+ int run_one_ep();
277
+ void execute_lines(hstcpsvr_conn& conn);
278
+ void execute_line(char *start, char *finish, hstcpsvr_conn& conn);
279
+ void do_open_index(char *start, char *finish, hstcpsvr_conn& conn);
280
+ void do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
281
+ char *finish, hstcpsvr_conn& conn);
282
+ void do_authorization(char *start, char *finish, hstcpsvr_conn& conn);
283
+ };
284
+
285
+ hstcpsvr_worker::hstcpsvr_worker(const hstcpsvr_worker_arg& arg)
286
+ : cshared(*arg.cshared), vshared(*arg.vshared), worker_id(arg.worker_id),
287
+ dbctx(cshared.dbptr->create_context(cshared.for_write_flag)),
288
+ last_check_time(time(0)), accept_enabled(true), accept_balance(0)
289
+ {
290
+ #ifdef __linux__
291
+ if (cshared.sockargs.use_epoll) {
292
+ epoll_fd.reset(epoll_create(10));
293
+ if (epoll_fd.get() < 0) {
294
+ fatal_abort("epoll_create");
295
+ }
296
+ epoll_event ev = { };
297
+ ev.events = EPOLLIN;
298
+ ev.data.ptr = 0;
299
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
300
+ != 0) {
301
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
302
+ }
303
+ events_vec.resize(10240);
304
+ }
305
+ #endif
306
+ accept_balance = cshared.conf.get_int("accept_balance", 0);
307
+ }
308
+
309
+ namespace {
310
+
311
+ struct thr_init {
312
+ thr_init(const dbcontext_ptr& dc, volatile int& shutdown_flag) : dbctx(dc) {
313
+ dbctx->init_thread(this, shutdown_flag);
314
+ }
315
+ ~thr_init() {
316
+ dbctx->term_thread();
317
+ }
318
+ const dbcontext_ptr& dbctx;
319
+ };
320
+
321
+ }; // namespace
322
+
323
+ void
324
+ hstcpsvr_worker::run()
325
+ {
326
+ thr_init initobj(dbctx, vshared.shutdown);
327
+
328
+ #ifdef __linux__
329
+ if (cshared.sockargs.use_epoll) {
330
+ while (!vshared.shutdown && dbctx->check_alive()) {
331
+ run_one_ep();
332
+ }
333
+ } else if (cshared.sockargs.nonblocking) {
334
+ while (!vshared.shutdown && dbctx->check_alive()) {
335
+ run_one_nb();
336
+ }
337
+ } else {
338
+ /* UNUSED */
339
+ fatal_abort("run_one");
340
+ }
341
+ #else
342
+ while (!vshared.shutdown && dbctx->check_alive()) {
343
+ run_one_nb();
344
+ }
345
+ #endif
346
+ }
347
+
348
+ int
349
+ hstcpsvr_worker::run_one_nb()
350
+ {
351
+ size_t nfds = 0;
352
+ /* CLIENT SOCKETS */
353
+ for (hstcpsvr_conns_type::const_iterator i = conns.begin();
354
+ i != conns.end(); ++i) {
355
+ if (pfds.size() <= nfds) {
356
+ pfds.resize(nfds + 1);
357
+ }
358
+ pollfd& pfd = pfds[nfds++];
359
+ pfd.fd = (*i)->fd.get();
360
+ short ev = 0;
361
+ if ((*i)->cstate.writebuf.size() != 0) {
362
+ ev = POLLOUT;
363
+ } else {
364
+ ev = POLLIN;
365
+ }
366
+ pfd.events = pfd.revents = ev;
367
+ }
368
+ /* LISTENER */
369
+ {
370
+ const size_t cpt = cshared.nb_conn_per_thread;
371
+ const short ev = (cpt > nfds) ? POLLIN : 0;
372
+ if (pfds.size() <= nfds) {
373
+ pfds.resize(nfds + 1);
374
+ }
375
+ pollfd& pfd = pfds[nfds++];
376
+ pfd.fd = cshared.listen_fd.get();
377
+ pfd.events = pfd.revents = ev;
378
+ }
379
+ /* POLL */
380
+ const int npollev = poll(&pfds[0], nfds, 1 * 1000);
381
+ dbctx->set_statistics(conns.size(), npollev);
382
+ const time_t now = time(0);
383
+ size_t j = 0;
384
+ const short mask_in = ~POLLOUT;
385
+ const short mask_out = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
386
+ /* READ */
387
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
388
+ ++i, ++j) {
389
+ pollfd& pfd = pfds[j];
390
+ if ((pfd.revents & mask_in) == 0) {
391
+ continue;
392
+ }
393
+ hstcpsvr_conn& conn = **i;
394
+ if (conn.read_more()) {
395
+ if (conn.cstate.readbuf.size() > 0) {
396
+ const char ch = conn.cstate.readbuf.begin()[0];
397
+ if (ch == 'Q') {
398
+ vshared.shutdown = 1;
399
+ } else if (ch == '/') {
400
+ conn.cstate.readbuf.clear();
401
+ conn.cstate.find_nl_pos = 0;
402
+ conn.cstate.writebuf.clear();
403
+ conn.read_finished = true;
404
+ conn.write_finished = true;
405
+ }
406
+ }
407
+ conn.nb_last_io = now;
408
+ }
409
+ }
410
+ /* EXECUTE */
411
+ j = 0;
412
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
413
+ ++i, ++j) {
414
+ pollfd& pfd = pfds[j];
415
+ if ((pfd.revents & mask_in) == 0 || (*i)->cstate.readbuf.size() == 0) {
416
+ continue;
417
+ }
418
+ execute_lines(**i);
419
+ }
420
+ /* COMMIT */
421
+ dbctx->unlock_tables_if();
422
+ const bool commit_error = dbctx->get_commit_error();
423
+ dbctx->clear_error();
424
+ /* WRITE/CLOSE */
425
+ j = 0;
426
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
427
+ ++j) {
428
+ pollfd& pfd = pfds[j];
429
+ hstcpsvr_conn& conn = **i;
430
+ hstcpsvr_conns_type::iterator icur = i;
431
+ ++i;
432
+ if (commit_error) {
433
+ conn.reset();
434
+ continue;
435
+ }
436
+ if ((pfd.revents & (mask_out | mask_in)) != 0) {
437
+ if (conn.write_more()) {
438
+ conn.nb_last_io = now;
439
+ }
440
+ }
441
+ if (cshared.sockargs.timeout != 0 &&
442
+ conn.nb_last_io + cshared.sockargs.timeout < now) {
443
+ conn.reset();
444
+ }
445
+ if (conn.closed() || conn.ok_to_close()) {
446
+ conns.erase_ptr(icur);
447
+ }
448
+ }
449
+ /* ACCEPT */
450
+ {
451
+ pollfd& pfd = pfds[nfds - 1];
452
+ if ((pfd.revents & mask_in) != 0) {
453
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
454
+ c->nonblocking = true;
455
+ c->readsize = cshared.readsize;
456
+ c->accept(cshared);
457
+ if (c->fd.get() >= 0) {
458
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
459
+ fatal_abort("F_SETFL O_NONBLOCK");
460
+ }
461
+ c->nb_last_io = now;
462
+ conns.push_back_ptr(c);
463
+ } else {
464
+ /* errno == 11 (EAGAIN) is not a fatal error. */
465
+ DENA_VERBOSE(100, fprintf(stderr,
466
+ "accept failed: errno=%d (not fatal)\n", errno));
467
+ }
468
+ }
469
+ }
470
+ DENA_VERBOSE(30, fprintf(stderr, "nb: %p nfds=%zu cns=%zu\n", this, nfds,
471
+ conns.size()));
472
+ if (conns.empty()) {
473
+ dbctx->close_tables_if();
474
+ }
475
+ dbctx->set_statistics(conns.size(), 0);
476
+ return 0;
477
+ }
478
+
479
+ #ifdef __linux__
480
+ int
481
+ hstcpsvr_worker::run_one_ep()
482
+ {
483
+ epoll_event *const events = &events_vec[0];
484
+ const size_t num_events = events_vec.size();
485
+ const time_t now = time(0);
486
+ size_t in_count = 0, out_count = 0, accept_count = 0;
487
+ int nfds = epoll_wait(epoll_fd.get(), events, num_events, 1000);
488
+ /* READ/ACCEPT */
489
+ dbctx->set_statistics(conns.size(), nfds);
490
+ for (int i = 0; i < nfds; ++i) {
491
+ epoll_event& ev = events[i];
492
+ if ((ev.events & EPOLLIN) == 0) {
493
+ continue;
494
+ }
495
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
496
+ if (conn == 0) {
497
+ /* listener */
498
+ ++accept_count;
499
+ DBG_EP(fprintf(stderr, "IN listener\n"));
500
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
501
+ c->nonblocking = true;
502
+ c->readsize = cshared.readsize;
503
+ c->accept(cshared);
504
+ if (c->fd.get() >= 0) {
505
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
506
+ fatal_abort("F_SETFL O_NONBLOCK");
507
+ }
508
+ epoll_event cev = { };
509
+ cev.events = EPOLLIN | EPOLLOUT | EPOLLET;
510
+ cev.data.ptr = c.get();
511
+ c->nb_last_io = now;
512
+ const int fd = c->fd.get();
513
+ conns.push_back_ptr(c);
514
+ conns.back()->conns_iter = --conns.end();
515
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, fd, &cev) != 0) {
516
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
517
+ }
518
+ } else {
519
+ DENA_VERBOSE(100, fprintf(stderr,
520
+ "accept failed: errno=%d (not fatal)\n", errno));
521
+ }
522
+ } else {
523
+ /* client connection */
524
+ ++in_count;
525
+ DBG_EP(fprintf(stderr, "IN client\n"));
526
+ bool more_data = false;
527
+ while (conn->read_more(&more_data)) {
528
+ DBG_EP(fprintf(stderr, "IN client read_more\n"));
529
+ conn->nb_last_io = now;
530
+ if (!more_data) {
531
+ break;
532
+ }
533
+ }
534
+ }
535
+ }
536
+ /* EXECUTE */
537
+ for (int i = 0; i < nfds; ++i) {
538
+ epoll_event& ev = events[i];
539
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
540
+ if ((ev.events & EPOLLIN) == 0 || conn == 0 ||
541
+ conn->cstate.readbuf.size() == 0) {
542
+ continue;
543
+ }
544
+ const char ch = conn->cstate.readbuf.begin()[0];
545
+ if (ch == 'Q') {
546
+ vshared.shutdown = 1;
547
+ } else if (ch == '/') {
548
+ conn->cstate.readbuf.clear();
549
+ conn->cstate.find_nl_pos = 0;
550
+ conn->cstate.writebuf.clear();
551
+ conn->read_finished = true;
552
+ conn->write_finished = true;
553
+ } else {
554
+ execute_lines(*conn);
555
+ }
556
+ }
557
+ /* COMMIT */
558
+ dbctx->unlock_tables_if();
559
+ const bool commit_error = dbctx->get_commit_error();
560
+ dbctx->clear_error();
561
+ /* WRITE */
562
+ for (int i = 0; i < nfds; ++i) {
563
+ epoll_event& ev = events[i];
564
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
565
+ if (commit_error && conn != 0) {
566
+ conn->reset();
567
+ continue;
568
+ }
569
+ if ((ev.events & EPOLLOUT) == 0) {
570
+ continue;
571
+ }
572
+ ++out_count;
573
+ if (conn == 0) {
574
+ /* listener */
575
+ DBG_EP(fprintf(stderr, "OUT listener\n"));
576
+ } else {
577
+ /* client connection */
578
+ DBG_EP(fprintf(stderr, "OUT client\n"));
579
+ bool more_data = false;
580
+ while (conn->write_more(&more_data)) {
581
+ DBG_EP(fprintf(stderr, "OUT client write_more\n"));
582
+ conn->nb_last_io = now;
583
+ if (!more_data) {
584
+ break;
585
+ }
586
+ }
587
+ }
588
+ }
589
+ /* CLOSE */
590
+ for (int i = 0; i < nfds; ++i) {
591
+ epoll_event& ev = events[i];
592
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
593
+ if (conn != 0 && conn->ok_to_close()) {
594
+ DBG_EP(fprintf(stderr, "CLOSE close\n"));
595
+ conns.erase_ptr(conn->conns_iter);
596
+ }
597
+ }
598
+ /* TIMEOUT & cleanup */
599
+ if (last_check_time + 10 < now) {
600
+ for (hstcpsvr_conns_type::iterator i = conns.begin();
601
+ i != conns.end(); ) {
602
+ hstcpsvr_conns_type::iterator icur = i;
603
+ ++i;
604
+ if (cshared.sockargs.timeout != 0 &&
605
+ (*icur)->nb_last_io + cshared.sockargs.timeout < now) {
606
+ conns.erase_ptr((*icur)->conns_iter);
607
+ }
608
+ }
609
+ last_check_time = now;
610
+ DENA_VERBOSE(20, fprintf(stderr, "ep: %p nfds=%d cns=%zu\n", this, nfds,
611
+ conns.size()));
612
+ }
613
+ DENA_VERBOSE(30, fprintf(stderr, "%p in=%zu out=%zu ac=%zu, cns=%zu\n",
614
+ this, in_count, out_count, accept_count, conns.size()));
615
+ if (conns.empty()) {
616
+ dbctx->close_tables_if();
617
+ }
618
+ /* STATISTICS */
619
+ const size_t num_conns = conns.size();
620
+ dbctx->set_statistics(num_conns, 0);
621
+ /* ENABLE/DISABLE ACCEPT */
622
+ if (accept_balance != 0) {
623
+ cshared.thread_num_conns[worker_id] = num_conns;
624
+ size_t total_num_conns = 0;
625
+ for (long i = 0; i < cshared.num_threads; ++i) {
626
+ total_num_conns += cshared.thread_num_conns[i];
627
+ }
628
+ bool e_acc = false;
629
+ if (num_conns < 10 ||
630
+ total_num_conns * 2 > num_conns * cshared.num_threads) {
631
+ e_acc = true;
632
+ }
633
+ epoll_event ev = { };
634
+ ev.events = EPOLLIN;
635
+ ev.data.ptr = 0;
636
+ if (e_acc == accept_enabled) {
637
+ } else if (e_acc) {
638
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
639
+ != 0) {
640
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
641
+ }
642
+ } else {
643
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_DEL, cshared.listen_fd.get(), &ev)
644
+ != 0) {
645
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
646
+ }
647
+ }
648
+ accept_enabled = e_acc;
649
+ }
650
+ return 0;
651
+ }
652
+ #endif
653
+
654
+ void
655
+ hstcpsvr_worker::execute_lines(hstcpsvr_conn& conn)
656
+ {
657
+ DBG_MULTI(int cnt = 0);
658
+ dbconnstate& cstate = conn.cstate;
659
+ char *buf_end = cstate.readbuf.end();
660
+ char *line_begin = cstate.readbuf.begin();
661
+ char *find_pos = line_begin + cstate.find_nl_pos;
662
+ while (true) {
663
+ char *const nl = memchr_char(find_pos, '\n', buf_end - find_pos);
664
+ if (nl == 0) {
665
+ break;
666
+ }
667
+ char *const lf = (line_begin != nl && nl[-1] == '\r') ? nl - 1 : nl;
668
+ DBG_MULTI(cnt++);
669
+ execute_line(line_begin, lf, conn);
670
+ find_pos = line_begin = nl + 1;
671
+ }
672
+ cstate.readbuf.erase_front(line_begin - cstate.readbuf.begin());
673
+ cstate.find_nl_pos = cstate.readbuf.size();
674
+ DBG_MULTI(fprintf(stderr, "cnt=%d\n", cnt));
675
+ }
676
+
677
+ void
678
+ hstcpsvr_worker::execute_line(char *start, char *finish, hstcpsvr_conn& conn)
679
+ {
680
+ /* safe to modify, safe to dereference 'finish' */
681
+ char *const cmd_begin = start;
682
+ read_token(start, finish);
683
+ char *const cmd_end = start;
684
+ skip_one(start, finish);
685
+ if (cmd_begin == cmd_end) {
686
+ return conn.dbcb_resp_short(2, "cmd");
687
+ }
688
+ if (cmd_begin + 1 == cmd_end) {
689
+ if (cmd_begin[0] == 'P') {
690
+ if (cshared.require_auth && !conn.authorized) {
691
+ return conn.dbcb_resp_short(3, "unauth");
692
+ }
693
+ return do_open_index(start, finish, conn);
694
+ }
695
+ if (cmd_begin[0] == 'A') {
696
+ return do_authorization(start, finish, conn);
697
+ }
698
+ }
699
+ if (cmd_begin[0] >= '0' && cmd_begin[0] <= '9') {
700
+ if (cshared.require_auth && !conn.authorized) {
701
+ return conn.dbcb_resp_short(3, "unauth");
702
+ }
703
+ return do_exec_on_index(cmd_begin, cmd_end, start, finish, conn);
704
+ }
705
+ return conn.dbcb_resp_short(2, "cmd");
706
+ }
707
+
708
+ void
709
+ hstcpsvr_worker::do_open_index(char *start, char *finish, hstcpsvr_conn& conn)
710
+ {
711
+ const size_t pst_id = read_ui32(start, finish);
712
+ skip_one(start, finish);
713
+ /* dbname */
714
+ char *const dbname_begin = start;
715
+ read_token(start, finish);
716
+ char *const dbname_end = start;
717
+ skip_one(start, finish);
718
+ /* tblname */
719
+ char *const tblname_begin = start;
720
+ read_token(start, finish);
721
+ char *const tblname_end = start;
722
+ skip_one(start, finish);
723
+ /* idxname */
724
+ char *const idxname_begin = start;
725
+ read_token(start, finish);
726
+ char *const idxname_end = start;
727
+ skip_one(start, finish);
728
+ /* retfields */
729
+ char *const retflds_begin = start;
730
+ read_token(start, finish);
731
+ char *const retflds_end = start;
732
+ skip_one(start, finish);
733
+ /* filfields */
734
+ char *const filflds_begin = start;
735
+ read_token(start, finish);
736
+ char *const filflds_end = start;
737
+ dbname_end[0] = 0;
738
+ tblname_end[0] = 0;
739
+ idxname_end[0] = 0;
740
+ retflds_end[0] = 0;
741
+ filflds_end[0] = 0;
742
+ cmd_open_args args;
743
+ args.pst_id = pst_id;
744
+ args.dbn = dbname_begin;
745
+ args.tbl = tblname_begin;
746
+ args.idx = idxname_begin;
747
+ args.retflds = retflds_begin;
748
+ args.filflds = filflds_begin;
749
+ return dbctx->cmd_open(conn, args);
750
+ }
751
+
752
+ void
753
+ hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
754
+ char *finish, hstcpsvr_conn& conn)
755
+ {
756
+ cmd_exec_args args;
757
+ const size_t pst_id = read_ui32(cmd_begin, cmd_end);
758
+ if (pst_id >= conn.cstate.prep_stmts.size()) {
759
+ return conn.dbcb_resp_short(2, "stmtnum");
760
+ }
761
+ args.pst = &conn.cstate.prep_stmts[pst_id];
762
+ char *const op_begin = start;
763
+ read_token(start, finish);
764
+ char *const op_end = start;
765
+ args.op = string_ref(op_begin, op_end);
766
+ skip_one(start, finish);
767
+ const uint32_t fldnum = read_ui32(start, finish);
768
+ string_ref *const flds = DENA_ALLOCA_ALLOCATE(string_ref, fldnum);
769
+ auto_alloca_free<string_ref> flds_autofree(flds);
770
+ args.kvals = flds;
771
+ args.kvalslen = fldnum;
772
+ for (size_t i = 0; i < fldnum; ++i) {
773
+ skip_one(start, finish);
774
+ char *const f_begin = start;
775
+ read_token(start, finish);
776
+ char *const f_end = start;
777
+ if (is_null_expression(f_begin, f_end)) {
778
+ /* null */
779
+ flds[i] = string_ref();
780
+ } else {
781
+ /* non-null */
782
+ char *wp = f_begin;
783
+ unescape_string(wp, f_begin, f_end);
784
+ flds[i] = string_ref(f_begin, wp - f_begin);
785
+ }
786
+ }
787
+ skip_one(start, finish);
788
+ args.limit = read_ui32(start, finish);
789
+ skip_one(start, finish);
790
+ args.skip = read_ui32(start, finish);
791
+ if (start == finish) {
792
+ /* simple query */
793
+ return dbctx->cmd_exec(conn, args);
794
+ }
795
+ /* has more options */
796
+ skip_one(start, finish);
797
+ /* in-clause */
798
+ if (start[0] == '@') {
799
+ read_token(start, finish); /* '@' */
800
+ skip_one(start, finish);
801
+ args.invalues_keypart = read_ui32(start, finish);
802
+ skip_one(start, finish);
803
+ args.invalueslen = read_ui32(start, finish);
804
+ if (args.invalueslen <= 0) {
805
+ return conn.dbcb_resp_short(2, "invalueslen");
806
+ }
807
+ if (invalues_work.size() < args.invalueslen) {
808
+ invalues_work.resize(args.invalueslen);
809
+ }
810
+ args.invalues = &invalues_work[0];
811
+ for (uint32_t i = 0; i < args.invalueslen; ++i) {
812
+ skip_one(start, finish);
813
+ char *const invalue_begin = start;
814
+ read_token(start, finish);
815
+ char *const invalue_end = start;
816
+ char *wp = invalue_begin;
817
+ unescape_string(wp, invalue_begin, invalue_end);
818
+ invalues_work[i] = string_ref(invalue_begin, wp - invalue_begin);
819
+ }
820
+ skip_one(start, finish);
821
+ }
822
+ if (start == finish) {
823
+ /* no more options */
824
+ return dbctx->cmd_exec(conn, args);
825
+ }
826
+ /* filters */
827
+ size_t filters_count = 0;
828
+ while (start != finish && (start[0] == 'W' || start[0] == 'F')) {
829
+ char *const filter_type_begin = start;
830
+ read_token(start, finish);
831
+ char *const filter_type_end = start;
832
+ skip_one(start, finish);
833
+ char *const filter_op_begin = start;
834
+ read_token(start, finish);
835
+ char *const filter_op_end = start;
836
+ skip_one(start, finish);
837
+ const uint32_t ff_offset = read_ui32(start, finish);
838
+ skip_one(start, finish);
839
+ char *const filter_val_begin = start;
840
+ read_token(start, finish);
841
+ char *const filter_val_end = start;
842
+ skip_one(start, finish);
843
+ if (filters_work.size() <= filters_count) {
844
+ filters_work.resize(filters_count + 1);
845
+ }
846
+ record_filter& fi = filters_work[filters_count];
847
+ if (filter_type_end != filter_type_begin + 1) {
848
+ return conn.dbcb_resp_short(2, "filtertype");
849
+ }
850
+ fi.filter_type = (filter_type_begin[0] == 'W')
851
+ ? record_filter_type_break : record_filter_type_skip;
852
+ const uint32_t num_filflds = args.pst->get_filter_fields().size();
853
+ if (ff_offset >= num_filflds) {
854
+ return conn.dbcb_resp_short(2, "filterfld");
855
+ }
856
+ fi.op = string_ref(filter_op_begin, filter_op_end);
857
+ fi.ff_offset = ff_offset;
858
+ if (is_null_expression(filter_val_begin, filter_val_end)) {
859
+ /* null */
860
+ fi.val = string_ref();
861
+ } else {
862
+ /* non-null */
863
+ char *wp = filter_val_begin;
864
+ unescape_string(wp, filter_val_begin, filter_val_end);
865
+ fi.val = string_ref(filter_val_begin, wp - filter_val_begin);
866
+ }
867
+ ++filters_count;
868
+ }
869
+ if (filters_count > 0) {
870
+ if (filters_work.size() <= filters_count) {
871
+ filters_work.resize(filters_count + 1);
872
+ }
873
+ filters_work[filters_count].op = string_ref(); /* sentinel */
874
+ args.filters = &filters_work[0];
875
+ } else {
876
+ args.filters = 0;
877
+ }
878
+ if (start == finish) {
879
+ /* no modops */
880
+ return dbctx->cmd_exec(conn, args);
881
+ }
882
+ /* has modops */
883
+ char *const mod_op_begin = start;
884
+ read_token(start, finish);
885
+ char *const mod_op_end = start;
886
+ args.mod_op = string_ref(mod_op_begin, mod_op_end);
887
+ const size_t num_uvals = args.pst->get_ret_fields().size();
888
+ string_ref *const uflds = DENA_ALLOCA_ALLOCATE(string_ref, num_uvals);
889
+ auto_alloca_free<string_ref> uflds_autofree(uflds);
890
+ for (size_t i = 0; i < num_uvals; ++i) {
891
+ skip_one(start, finish);
892
+ char *const f_begin = start;
893
+ read_token(start, finish);
894
+ char *const f_end = start;
895
+ if (is_null_expression(f_begin, f_end)) {
896
+ /* null */
897
+ uflds[i] = string_ref();
898
+ } else {
899
+ /* non-null */
900
+ char *wp = f_begin;
901
+ unescape_string(wp, f_begin, f_end);
902
+ uflds[i] = string_ref(f_begin, wp - f_begin);
903
+ }
904
+ }
905
+ args.uvals = uflds;
906
+ return dbctx->cmd_exec(conn, args);
907
+ }
908
+
909
+ void
910
+ hstcpsvr_worker::do_authorization(char *start, char *finish,
911
+ hstcpsvr_conn& conn)
912
+ {
913
+ /* auth type */
914
+ char *const authtype_begin = start;
915
+ read_token(start, finish);
916
+ char *const authtype_end = start;
917
+ const size_t authtype_len = authtype_end - authtype_begin;
918
+ skip_one(start, finish);
919
+ /* key */
920
+ char *const key_begin = start;
921
+ read_token(start, finish);
922
+ char *const key_end = start;
923
+ const size_t key_len = key_end - key_begin;
924
+ authtype_end[0] = 0;
925
+ key_end[0] = 0;
926
+ char *wp = key_begin;
927
+ unescape_string(wp, key_begin, key_end);
928
+ if (authtype_len != 1 || authtype_begin[0] != '1') {
929
+ return conn.dbcb_resp_short(3, "authtype");
930
+ }
931
+ if (cshared.plain_secret.size() == key_len &&
932
+ memcmp(cshared.plain_secret.data(), key_begin, key_len) == 0) {
933
+ conn.authorized = true;
934
+ } else {
935
+ conn.authorized = false;
936
+ }
937
+ if (!conn.authorized) {
938
+ return conn.dbcb_resp_short(3, "unauth");
939
+ } else {
940
+ return conn.dbcb_resp_short(0, "");
941
+ }
942
+ }
943
+
944
+ hstcpsvr_worker_ptr
945
+ hstcpsvr_worker_i::create(const hstcpsvr_worker_arg& arg)
946
+ {
947
+ return hstcpsvr_worker_ptr(new hstcpsvr_worker(arg));
948
+ }
949
+
950
+ };
951
+