1 | #include <sys/errno.h> |
1 | #include <errno.h> |
2 | #include <unistd.h> |
2 | #include <unistd.h> |
3 | #include <fcntl.h> |
3 | #include <fcntl.h> |
|
|
4 | |
|
|
5 | /* mariadb/mysql uses all these reserved macro names, and probably more :( */ |
|
|
6 | #undef read |
|
|
7 | #undef write |
|
|
8 | #undef close |
4 | |
9 | |
5 | #include <mysql.h> |
10 | #include <mysql.h> |
6 | |
11 | |
7 | #include "EXTERN.h" |
12 | #include "EXTERN.h" |
8 | #include "perl.h" |
13 | #include "perl.h" |
9 | #include "XSUB.h" |
14 | #include "XSUB.h" |
10 | |
15 | |
|
|
16 | #if HAVE_EV |
|
|
17 | # include "EVAPI.h" |
|
|
18 | # include "CoroAPI.h" |
|
|
19 | #endif |
|
|
20 | |
11 | #define IN_DESTRUCT PL_dirty |
21 | #define IN_DESTRUCT PL_dirty |
12 | |
22 | |
13 | typedef U16 uint16; |
23 | typedef U16 uint16; |
14 | |
24 | |
15 | /* cached function gv's */ |
25 | /* cached function gv's */ |
16 | static CV *readable, *writable; |
26 | static CV *readable, *writable; |
|
|
27 | static int use_ev; |
17 | |
28 | |
|
|
29 | #if MARIADB_VERSION_ID >= 100300 |
|
|
30 | |
|
|
31 | typedef unsigned char uchar; /* bug? */ |
|
|
32 | #include <ma_pvio.h> |
|
|
33 | |
|
|
34 | #define PVIO 1 |
|
|
35 | #define VIOPTR MARIADB_PVIO * |
|
|
36 | #define VIOM(vio) (vio)->methods |
|
|
37 | #define vioblocking blocking |
|
|
38 | #define vioclose close |
|
|
39 | #define VIODATA(vio) (vio)->data |
|
|
40 | /* ma_pvio_get_socket would be it, but it's only declared, not defined */ |
|
|
41 | #define VIOSD(vio) mysql_get_socket ((vio)->mysql) |
|
|
42 | #define VIO_READ_BUFFER_SIZE PVIO_READ_AHEAD_CACHE_SIZE |
|
|
43 | #define my_to_vio(sock) (sock)->net.pvio |
|
|
44 | |
|
|
45 | #define OURDATAPTR ((ourdata *)vio->methods) |
|
|
46 | |
|
|
47 | typedef uchar *xgptr; |
|
|
48 | typedef const uchar *cxgptr; |
|
|
49 | typedef size_t xsize_t; |
|
|
50 | typedef ssize_t xssize_t; |
|
|
51 | typedef my_bool xmy_bool; |
|
|
52 | |
|
|
53 | #else |
|
|
54 | |
18 | #include "violite.h" |
55 | #include "violite.h" |
19 | |
56 | |
20 | #define DESC_OFFSET 22 |
57 | #define PVIO 0 |
|
|
58 | #define VIOPTR Vio * |
|
|
59 | #define VIOM(vio) vio |
|
|
60 | #define VIODATA(vio) (vio)->desc |
|
|
61 | #define VIOSD(vio) (vio)->sd |
|
|
62 | #define my_to_vio(sock) (sock)->net.vio |
|
|
63 | |
|
|
64 | typedef int xmy_bool; |
|
|
65 | |
|
|
66 | #endif |
21 | |
67 | |
22 | #define CoMy_MAGIC 0x436f4d79 |
68 | #define CoMy_MAGIC 0x436f4d79 |
23 | |
69 | |
24 | typedef struct { |
70 | typedef struct { |
|
|
71 | #if PVIO |
|
|
72 | /* must be first member */ |
|
|
73 | struct st_ma_pvio_methods methods; |
|
|
74 | #else |
|
|
75 | #if DESC_IS_PTR |
|
|
76 | char desc[30]; |
|
|
77 | const char *old_desc; |
|
|
78 | #endif |
|
|
79 | #endif |
25 | int magic; |
80 | int magic; |
26 | SV *corohandle_sv, *corohandle; |
81 | SV *corohandle_sv, *corohandle; |
27 | int bufofs, bufcnt; |
82 | int bufofs, bufcnt; |
|
|
83 | #if HAVE_EV |
|
|
84 | ev_io rw, ww; |
|
|
85 | #endif |
28 | char buf[VIO_READ_BUFFER_SIZE]; |
86 | char buf[VIO_READ_BUFFER_SIZE]; |
|
|
87 | #if PVIO |
|
|
88 | struct st_ma_pvio_methods *oldmethods; |
|
|
89 | #else |
|
|
90 | xssize_t (*old_read)(VIOPTR, uchar *, size_t); |
|
|
91 | xssize_t (*old_write)(VIOPTR, const uchar *, size_t); |
|
|
92 | xmy_bool (*old_close)(VIOPTR); |
|
|
93 | #endif |
29 | } ourdata; |
94 | } ourdata; |
30 | |
95 | |
|
|
96 | #ifndef OURDATAPTR |
|
|
97 | #if DESC_IS_PTR |
|
|
98 | # define OURDATAPTR (*(ourdata **)&((vio)->desc)) |
|
|
99 | #else |
|
|
100 | # define DESC_OFFSET 22 |
31 | #define OURDATAPTR (*((ourdata **)((vio)->desc + DESC_OFFSET))) |
101 | # define OURDATAPTR (*((ourdata **)((vio)->desc + DESC_OFFSET))) |
|
|
102 | #endif |
|
|
103 | #endif |
32 | |
104 | |
33 | static int |
105 | static xssize_t |
34 | our_read (Vio *vio, xgptr p, int len) |
106 | our_read (VIOPTR vio, xgptr p, xsize_t len) |
35 | { |
107 | { |
36 | ourdata *our = OURDATAPTR; |
108 | ourdata *our = OURDATAPTR; |
37 | |
109 | |
38 | if (!our->bufcnt) |
110 | if (!our->bufcnt) |
39 | { |
111 | { |
40 | int rd; |
112 | int rd; |
41 | my_bool dummy; |
113 | my_bool dummy; |
42 | |
114 | |
43 | vio->vioblocking (vio, 0, &dummy); |
115 | VIOM (vio)->vioblocking (vio, 0, &dummy); |
44 | |
116 | |
45 | for (;;) |
117 | for (;;) |
46 | { |
118 | { |
47 | rd = recv (vio->sd, our->buf, sizeof (our->buf), 0); |
119 | rd = recv (VIOSD (vio), our->buf, sizeof (our->buf), 0); |
48 | |
120 | |
49 | if (rd >= 0 || errno != EAGAIN) |
121 | if (rd >= 0 || errno != EAGAIN) |
50 | break; |
122 | break; |
51 | |
123 | |
|
|
124 | #if HAVE_EV |
|
|
125 | if (use_ev) |
52 | { |
126 | { |
|
|
127 | our->rw.data = (void *)sv_2mortal (SvREFCNT_inc (CORO_CURRENT)); |
|
|
128 | ev_io_start (EV_DEFAULT_UC, &(our->rw)); |
|
|
129 | CORO_SCHEDULE; |
|
|
130 | ev_io_stop (EV_DEFAULT_UC, &(our->rw)); /* avoids races */ |
|
|
131 | } |
|
|
132 | else |
|
|
133 | #endif |
|
|
134 | { |
53 | dSP; |
135 | dSP; |
54 | PUSHMARK (SP); |
136 | PUSHMARK (SP); |
55 | XPUSHs (our->corohandle); |
137 | XPUSHs (our->corohandle); |
56 | PUTBACK; |
138 | PUTBACK; |
57 | call_sv ((SV *)readable, G_VOID | G_DISCARD); |
139 | call_sv ((SV *)readable, G_VOID | G_DISCARD); |
58 | } |
140 | } |
59 | } |
141 | } |
60 | |
142 | |
61 | if (rd <= 0) |
143 | if (rd <= 0) |
62 | return rd; |
144 | return rd; |
63 | |
145 | |
… | |
… | |
73 | our->bufcnt -= len; |
155 | our->bufcnt -= len; |
74 | |
156 | |
75 | return len; |
157 | return len; |
76 | } |
158 | } |
77 | |
159 | |
78 | static int |
160 | static xssize_t |
79 | our_write (Vio *vio, const xgptr p, int len) |
161 | our_write (VIOPTR vio, cxgptr p, xsize_t len) |
80 | { |
162 | { |
81 | char *ptr = (char *)p; |
163 | char *ptr = (char *)p; |
82 | my_bool dummy; |
164 | my_bool dummy; |
83 | |
165 | |
84 | vio->vioblocking (vio, 0, &dummy); |
166 | VIOM (vio)->vioblocking (vio, 0, &dummy); |
85 | |
167 | |
86 | while (len > 0) |
168 | while (len > 0) |
87 | { |
169 | { |
88 | int wr = send (vio->sd, ptr, len, 0); |
170 | int wr = send (VIOSD (vio), ptr, len, 0); |
89 | |
171 | |
90 | if (wr > 0) |
172 | if (wr > 0) |
91 | { |
173 | { |
92 | ptr += wr; |
174 | ptr += wr; |
93 | len -= wr; |
175 | len -= wr; |
94 | } |
176 | } |
95 | else if (errno == EAGAIN) |
177 | else if (errno == EAGAIN) |
96 | { |
178 | { |
|
|
179 | ourdata *our = OURDATAPTR; |
|
|
180 | |
|
|
181 | #if HAVE_EV |
|
|
182 | if (use_ev) |
|
|
183 | { |
|
|
184 | our->ww.data = (void *)sv_2mortal (SvREFCNT_inc (CORO_CURRENT)); |
|
|
185 | ev_io_start (EV_DEFAULT_UC, &(our->ww)); |
|
|
186 | CORO_SCHEDULE; |
|
|
187 | ev_io_stop (EV_DEFAULT_UC, &(our->ww)); /* avoids races */ |
|
|
188 | } |
|
|
189 | else |
|
|
190 | #endif |
|
|
191 | { |
97 | dSP; |
192 | dSP; |
98 | PUSHMARK (SP); |
193 | PUSHMARK (SP); |
99 | XPUSHs (OURDATAPTR->corohandle); |
194 | XPUSHs (our->corohandle); |
100 | PUTBACK; |
195 | PUTBACK; |
101 | call_sv ((SV *)writable, G_VOID | G_DISCARD); |
196 | call_sv ((SV *)writable, G_VOID | G_DISCARD); |
|
|
197 | } |
102 | } |
198 | } |
103 | else if (ptr == (char *)p) |
199 | else if (ptr == (char *)p) |
104 | return -1; |
200 | return -1; |
105 | else |
201 | else |
106 | break; |
202 | break; |
107 | } |
203 | } |
108 | |
204 | |
109 | return ptr - (char *)p; |
205 | return ptr - (char *)p; |
110 | } |
206 | } |
111 | |
207 | |
112 | static int |
208 | static xmy_bool |
113 | our_close (Vio *vio) |
209 | our_close (VIOPTR vio) |
114 | { |
210 | { |
|
|
211 | ourdata *our = OURDATAPTR; |
|
|
212 | |
115 | if (vio->read != our_read) |
213 | if (VIOM (vio)->read != our_read) |
116 | croak ("vio.read has unexpected content during unpatch - wtf?"); |
214 | croak ("vio.read has unexpected content during unpatch - wtf?"); |
117 | |
215 | |
118 | if (vio->write != our_write) |
216 | if (VIOM (vio)->write != our_write) |
119 | croak ("vio.write has unexpected content during unpatch - wtf?"); |
217 | croak ("vio.write has unexpected content during unpatch - wtf?"); |
120 | |
218 | |
121 | if (vio->vioclose != our_close) |
219 | if (VIOM (vio)->vioclose != our_close) |
122 | croak ("vio.vioclose has unexpected content during unpatch - wtf?"); |
220 | croak ("vio.vioclose has unexpected content during unpatch - wtf?"); |
123 | |
221 | |
|
|
222 | #if HAVE_EV |
|
|
223 | if (use_ev) |
|
|
224 | { |
|
|
225 | ev_io_stop (EV_DEFAULT_UC, &(our->rw)); |
|
|
226 | ev_io_stop (EV_DEFAULT_UC, &(our->ww)); |
|
|
227 | } |
|
|
228 | #endif |
|
|
229 | |
124 | SvREFCNT_dec (OURDATAPTR->corohandle); |
230 | SvREFCNT_dec (our->corohandle); |
125 | SvREFCNT_dec (OURDATAPTR->corohandle_sv); |
231 | SvREFCNT_dec (our->corohandle_sv); |
126 | |
232 | |
127 | Safefree (OURDATAPTR); |
233 | #if DESC_IS_PTR |
|
|
234 | vio->desc = our->old_desc; |
|
|
235 | #endif |
128 | |
236 | |
129 | vio->read = vio_read; |
237 | #if PVIO |
130 | vio->write = vio_write; |
238 | vio->methods = our->oldmethods; |
|
|
239 | #else |
131 | vio->vioclose = vio_close; |
240 | VIOM (vio)->vioclose = our->old_close; |
|
|
241 | VIOM (vio)->write = our->old_write; |
|
|
242 | VIOM (vio)->read = our->old_read; |
|
|
243 | #endif |
132 | |
244 | |
|
|
245 | Safefree (our); |
|
|
246 | |
133 | vio->vioclose (vio); |
247 | VIOM (vio)->vioclose (vio); |
134 | } |
248 | } |
|
|
249 | |
|
|
250 | #if HAVE_EV |
|
|
251 | static void |
|
|
252 | iocb (EV_P_ ev_io *w, int revents) |
|
|
253 | { |
|
|
254 | ev_io_stop (EV_A, w); |
|
|
255 | CORO_READY ((SV *)w->data); |
|
|
256 | } |
|
|
257 | #endif |
135 | |
258 | |
136 | MODULE = Coro::Mysql PACKAGE = Coro::Mysql |
259 | MODULE = Coro::Mysql PACKAGE = Coro::Mysql |
137 | |
260 | |
138 | BOOT: |
261 | BOOT: |
139 | { |
262 | { |
… | |
… | |
142 | } |
265 | } |
143 | |
266 | |
144 | PROTOTYPES: ENABLE |
267 | PROTOTYPES: ENABLE |
145 | |
268 | |
146 | void |
269 | void |
|
|
270 | _use_ev () |
|
|
271 | PPCODE: |
|
|
272 | { |
|
|
273 | static int onceonly; |
|
|
274 | |
|
|
275 | if (!onceonly) |
|
|
276 | { |
|
|
277 | onceonly = 1; |
|
|
278 | #if HAVE_EV |
|
|
279 | I_EV_API ("Coro::Mysql"); |
|
|
280 | I_CORO_API ("Coro::Mysql"); |
|
|
281 | use_ev = 1; |
|
|
282 | #endif |
|
|
283 | } |
|
|
284 | |
|
|
285 | XPUSHs (use_ev ? &PL_sv_yes : &PL_sv_no); |
|
|
286 | } |
|
|
287 | |
|
|
288 | void |
147 | _patch (IV sock, int fd, SV *corohandle_sv, SV *corohandle) |
289 | _patch (IV sock, int fd, unsigned long client_version, SV *corohandle_sv, SV *corohandle) |
148 | CODE: |
290 | CODE: |
149 | { |
291 | { |
150 | MYSQL *my = (MYSQL *)sock; |
292 | MYSQL *my = (MYSQL *)sock; |
151 | Vio *vio = my->net.vio; |
293 | VIOPTR vio = my_to_vio (my); |
152 | ourdata *our; |
294 | ourdata *our; |
|
|
295 | |
|
|
296 | /* matching versions are required but not sufficient */ |
|
|
297 | if (client_version != mysql_get_client_version ()) |
|
|
298 | croak ("DBD::mysql linked against different libmysqlclient library than Coro::Mysql (%lu vs. %lu).", |
|
|
299 | client_version, mysql_get_client_version ()); |
153 | |
300 | |
154 | if (fd != my->net.fd) |
301 | if (fd != my->net.fd) |
155 | croak ("DBD::mysql fd and libmysql disagree - library mismatch, unsupported transport or API changes?"); |
302 | croak ("DBD::mysql fd and libmysql disagree - library mismatch, unsupported transport or API changes?"); |
156 | |
303 | |
157 | if (fd != vio->sd) |
304 | if (fd != VIOSD (vio)) |
158 | croak ("DBD::mysql fd and vio-sd disagree - library mismatch, unsupported transport or API changes?"); |
305 | croak ("DBD::mysql fd and vio-sd disagree - library mismatch, unsupported transport or API changes?"); |
159 | |
306 | #if MYSQL_VERSION_ID < 100010 && !defined(MARIADB_BASE_VERSION) |
160 | if (vio->vioclose != vio_close) |
307 | if (VIOM (vio)->vioclose != vio_close) |
|
|
308 | croak ("vio.vioclose has unexpected content - library mismatch, unsupported transport or API changes?"); |
|
|
309 | |
|
|
310 | if (VIOM (vio)->write != vio_write) |
161 | croak ("vio.write has unexpected content - library mismatch, unsupported transport or API changes?"); |
311 | croak ("vio.write has unexpected content - library mismatch, unsupported transport or API changes?"); |
162 | |
312 | |
163 | if (vio->write != vio_write) |
|
|
164 | croak ("vio.write has unexpected content - library mismatch, unsupported transport or API changes?"); |
|
|
165 | |
|
|
166 | if (vio->read != vio_read |
313 | if (VIOM (vio)->read != vio_read |
167 | && vio->read != vio_read_buff) |
314 | && VIOM (vio)->read != vio_read_buff) |
168 | croak ("vio.read has unexpected content - library mismatch, unsupported transport or API changes?"); |
315 | croak ("vio.read has unexpected content - library mismatch, unsupported transport or API changes?"); |
|
|
316 | #endif |
|
|
317 | #if PVIO |
|
|
318 | if (vio->type != PVIO_TYPE_UNIXSOCKET && vio->type != PVIO_TYPE_SOCKET) |
|
|
319 | croak ("connection type mismatch: Coro::Mysql only supports 'unixsocket' and 'socket' types at this time"); |
|
|
320 | #endif |
169 | |
321 | |
170 | Newz (0, our, 1, ourdata); |
322 | Newz (0, our, 1, ourdata); |
171 | our->magic = CoMy_MAGIC; |
323 | our->magic = CoMy_MAGIC; |
172 | our->corohandle_sv = newSVsv (corohandle_sv); |
324 | our->corohandle_sv = newSVsv (corohandle_sv); |
173 | our->corohandle = newSVsv (corohandle); |
325 | our->corohandle = newSVsv (corohandle); |
174 | |
326 | #if HAVE_EV |
|
|
327 | if (use_ev) |
|
|
328 | { |
|
|
329 | ev_io_init (&(our->rw), iocb, VIOSD (vio), EV_READ); |
|
|
330 | ev_io_init (&(our->ww), iocb, VIOSD (vio), EV_WRITE); |
|
|
331 | } |
|
|
332 | #endif |
|
|
333 | #if PVIO |
|
|
334 | /* with pvio, we replace methods by our own struct, |
|
|
335 | * both becauase the original might be read-only, |
|
|
336 | * and because we have no private data member, so the |
|
|
337 | * methods pointer includes our data as well |
|
|
338 | */ |
|
|
339 | our->methods = *vio->methods; |
|
|
340 | our->oldmethods = vio->methods; |
|
|
341 | vio->methods = &our->methods; |
|
|
342 | #else |
|
|
343 | OURDATAPTR = our; |
|
|
344 | #if DESC_IS_PTR |
|
|
345 | our->old_desc = vio->desc; |
|
|
346 | strncpy (our->desc, vio->desc, sizeof (our->desc)); |
|
|
347 | our->desc [sizeof (our->desc) - 1] = 0; |
|
|
348 | #else |
175 | vio->desc [DESC_OFFSET - 1] = 0; |
349 | vio->desc [DESC_OFFSET - 1] = 0; |
176 | OURDATAPTR = our; |
350 | #endif |
|
|
351 | our->old_close = VIOM (vio)->vioclose; |
|
|
352 | our->old_write = VIOM (vio)->write; |
|
|
353 | our->old_read = VIOM (vio)->read; |
|
|
354 | #endif |
177 | |
355 | |
|
|
356 | /* with pvio, this patches our own struct */ |
178 | vio->vioclose = our_close; |
357 | VIOM (vio)->vioclose = our_close; |
179 | vio->write = our_write; |
358 | VIOM (vio)->write = our_write; |
180 | vio->read = our_read; |
359 | VIOM (vio)->read = our_read; |
181 | } |
360 | } |
182 | |
361 | |