1 | #include <errno.h> |
1 | #include <errno.h> |
2 | #include <unistd.h> |
2 | #include <unistd.h> |
3 | #include <fcntl.h> |
3 | #include <fcntl.h> |
4 | |
4 | |
|
|
5 | /* mariadb/mysql uses all these reserved macro names, and probably more :( */ |
|
|
6 | #undef read |
|
|
7 | #undef write |
|
|
8 | #undef close |
|
|
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" |
… | |
… | |
19 | |
24 | |
20 | /* cached function gv's */ |
25 | /* cached function gv's */ |
21 | static CV *readable, *writable; |
26 | static CV *readable, *writable; |
22 | static int use_ev; |
27 | static int use_ev; |
23 | |
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 | |
24 | #include "violite.h" |
55 | #include "violite.h" |
|
|
56 | |
|
|
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 |
25 | |
67 | |
26 | #define CoMy_MAGIC 0x436f4d79 |
68 | #define CoMy_MAGIC 0x436f4d79 |
27 | |
69 | |
28 | typedef struct { |
70 | typedef struct { |
|
|
71 | #if PVIO |
|
|
72 | /* must be first member */ |
|
|
73 | struct st_ma_pvio_methods methods; |
|
|
74 | #else |
29 | #if DESC_IS_PTR |
75 | #if DESC_IS_PTR |
30 | char desc[30]; |
76 | char desc[30]; |
31 | const char *old_desc; |
77 | const char *old_desc; |
32 | #endif |
78 | #endif |
|
|
79 | #endif |
33 | int magic; |
80 | int magic; |
34 | SV *corohandle_sv, *corohandle; |
81 | SV *corohandle_sv, *corohandle; |
35 | int bufofs, bufcnt; |
82 | int bufofs, bufcnt; |
36 | #if HAVE_EV |
83 | #if HAVE_EV |
37 | ev_io rw, ww; |
84 | ev_io rw, ww; |
38 | #endif |
85 | #endif |
39 | 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 |
40 | size_t (*old_read)(Vio*, uchar *, size_t); |
90 | xssize_t (*old_read)(VIOPTR, uchar *, size_t); |
41 | size_t (*old_write)(Vio*, const uchar *, size_t); |
91 | xssize_t (*old_write)(VIOPTR, const uchar *, size_t); |
42 | int (*old_vioclose)(Vio*); |
92 | xmy_bool (*old_close)(VIOPTR); |
|
|
93 | #endif |
43 | } ourdata; |
94 | } ourdata; |
44 | |
95 | |
|
|
96 | #ifndef OURDATAPTR |
45 | #if DESC_IS_PTR |
97 | #if DESC_IS_PTR |
46 | # define OURDATAPTR (*(ourdata **)&((vio)->desc)) |
98 | # define OURDATAPTR (*(ourdata **)&((vio)->desc)) |
47 | #else |
99 | #else |
48 | # define DESC_OFFSET 22 |
100 | # define DESC_OFFSET 22 |
49 | # define OURDATAPTR (*((ourdata **)((vio)->desc + DESC_OFFSET))) |
101 | # define OURDATAPTR (*((ourdata **)((vio)->desc + DESC_OFFSET))) |
50 | #endif |
102 | #endif |
|
|
103 | #endif |
51 | |
104 | |
52 | static xlen |
105 | static xssize_t |
53 | our_read (Vio *vio, xgptr p, xlen len) |
106 | our_read (VIOPTR vio, xgptr p, xsize_t len) |
54 | { |
107 | { |
55 | ourdata *our = OURDATAPTR; |
108 | ourdata *our = OURDATAPTR; |
56 | |
109 | |
57 | if (!our->bufcnt) |
110 | if (!our->bufcnt) |
58 | { |
111 | { |
59 | int rd; |
112 | int rd; |
60 | my_bool dummy; |
113 | my_bool dummy; |
61 | |
114 | |
62 | vio->vioblocking (vio, 0, &dummy); |
115 | VIOM (vio)->vioblocking (vio, 0, &dummy); |
63 | |
116 | |
64 | for (;;) |
117 | for (;;) |
65 | { |
118 | { |
66 | rd = recv (vio->sd, our->buf, sizeof (our->buf), 0); |
119 | rd = recv (VIOSD (vio), our->buf, sizeof (our->buf), 0); |
67 | |
120 | |
68 | if (rd >= 0 || errno != EAGAIN) |
121 | if (rd >= 0 || errno != EAGAIN) |
69 | break; |
122 | break; |
70 | |
123 | |
71 | #if HAVE_EV |
124 | #if HAVE_EV |
… | |
… | |
102 | our->bufcnt -= len; |
155 | our->bufcnt -= len; |
103 | |
156 | |
104 | return len; |
157 | return len; |
105 | } |
158 | } |
106 | |
159 | |
107 | static xlen |
160 | static xssize_t |
108 | our_write (Vio *vio, cxgptr p, xlen len) |
161 | our_write (VIOPTR vio, cxgptr p, xsize_t len) |
109 | { |
162 | { |
110 | char *ptr = (char *)p; |
163 | char *ptr = (char *)p; |
111 | my_bool dummy; |
164 | my_bool dummy; |
112 | |
165 | |
113 | vio->vioblocking (vio, 0, &dummy); |
166 | VIOM (vio)->vioblocking (vio, 0, &dummy); |
114 | |
167 | |
115 | while (len > 0) |
168 | while (len > 0) |
116 | { |
169 | { |
117 | int wr = send (vio->sd, ptr, len, 0); |
170 | int wr = send (VIOSD (vio), ptr, len, 0); |
118 | |
171 | |
119 | if (wr > 0) |
172 | if (wr > 0) |
120 | { |
173 | { |
121 | ptr += wr; |
174 | ptr += wr; |
122 | len -= wr; |
175 | len -= wr; |
… | |
… | |
150 | } |
203 | } |
151 | |
204 | |
152 | return ptr - (char *)p; |
205 | return ptr - (char *)p; |
153 | } |
206 | } |
154 | |
207 | |
155 | static int |
208 | static xmy_bool |
156 | our_close (Vio *vio) |
209 | our_close (VIOPTR vio) |
157 | { |
210 | { |
158 | ourdata *our = OURDATAPTR; |
211 | ourdata *our = OURDATAPTR; |
159 | |
212 | |
160 | if (vio->read != our_read) |
213 | if (VIOM (vio)->read != our_read) |
161 | croak ("vio.read has unexpected content during unpatch - wtf?"); |
214 | croak ("vio.read has unexpected content during unpatch - wtf?"); |
162 | |
215 | |
163 | if (vio->write != our_write) |
216 | if (VIOM (vio)->write != our_write) |
164 | croak ("vio.write has unexpected content during unpatch - wtf?"); |
217 | croak ("vio.write has unexpected content during unpatch - wtf?"); |
165 | |
218 | |
166 | if (vio->vioclose != our_close) |
219 | if (VIOM (vio)->vioclose != our_close) |
167 | croak ("vio.vioclose has unexpected content during unpatch - wtf?"); |
220 | croak ("vio.vioclose has unexpected content during unpatch - wtf?"); |
168 | |
221 | |
169 | #if HAVE_EV |
222 | #if HAVE_EV |
170 | if (use_ev) |
223 | if (use_ev) |
171 | { |
224 | { |
… | |
… | |
179 | |
232 | |
180 | #if DESC_IS_PTR |
233 | #if DESC_IS_PTR |
181 | vio->desc = our->old_desc; |
234 | vio->desc = our->old_desc; |
182 | #endif |
235 | #endif |
183 | |
236 | |
|
|
237 | #if PVIO |
|
|
238 | vio->methods = our->oldmethods; |
|
|
239 | #else |
184 | vio->vioclose = our->old_vioclose; |
240 | VIOM (vio)->vioclose = our->old_close; |
185 | vio->write = our->old_write; |
241 | VIOM (vio)->write = our->old_write; |
186 | vio->read = our->old_read; |
242 | VIOM (vio)->read = our->old_read; |
|
|
243 | #endif |
187 | |
244 | |
188 | Safefree (our); |
245 | Safefree (our); |
189 | |
246 | |
190 | vio->vioclose (vio); |
247 | VIOM (vio)->vioclose (vio); |
191 | } |
248 | } |
192 | |
249 | |
193 | #if HAVE_EV |
250 | #if HAVE_EV |
194 | static void |
251 | static void |
195 | iocb (EV_P_ ev_io *w, int revents) |
252 | iocb (EV_P_ ev_io *w, int revents) |
… | |
… | |
231 | void |
288 | void |
232 | _patch (IV sock, int fd, unsigned long client_version, SV *corohandle_sv, SV *corohandle) |
289 | _patch (IV sock, int fd, unsigned long client_version, SV *corohandle_sv, SV *corohandle) |
233 | CODE: |
290 | CODE: |
234 | { |
291 | { |
235 | MYSQL *my = (MYSQL *)sock; |
292 | MYSQL *my = (MYSQL *)sock; |
236 | Vio *vio = my->net.vio; |
293 | VIOPTR vio = my_to_vio (my); |
237 | ourdata *our; |
294 | ourdata *our; |
238 | |
295 | |
239 | /* matching versions are required but not sufficient */ |
296 | /* matching versions are required but not sufficient */ |
240 | if (client_version != mysql_get_client_version ()) |
297 | if (client_version != mysql_get_client_version ()) |
241 | croak ("DBD::mysql linked against different libmysqlclient library than Coro::Mysql (%lu vs. %lu).", |
298 | croak ("DBD::mysql linked against different libmysqlclient library than Coro::Mysql (%lu vs. %lu).", |
242 | client_version, mysql_get_client_version ()); |
299 | client_version, mysql_get_client_version ()); |
243 | |
300 | |
244 | if (fd != my->net.fd) |
301 | if (fd != my->net.fd) |
245 | 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?"); |
246 | |
303 | |
247 | if (fd != vio->sd) |
304 | if (fd != VIOSD (vio)) |
248 | 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?"); |
249 | #if MYSQL_VERSION_ID < 100010 && !defined(MARIADB_BASE_VERSION) |
306 | #if MYSQL_VERSION_ID < 100010 && !defined(MARIADB_BASE_VERSION) |
250 | if (vio->vioclose != vio_close) |
307 | if (VIOM (vio)->vioclose != vio_close) |
251 | croak ("vio.vioclose has unexpected content - library mismatch, unsupported transport or API changes?"); |
308 | croak ("vio.vioclose has unexpected content - library mismatch, unsupported transport or API changes?"); |
252 | |
309 | |
253 | if (vio->write != vio_write) |
310 | if (VIOM (vio)->write != vio_write) |
254 | 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?"); |
255 | |
312 | |
256 | if (vio->read != vio_read |
313 | if (VIOM (vio)->read != vio_read |
257 | && vio->read != vio_read_buff) |
314 | && VIOM (vio)->read != vio_read_buff) |
258 | 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"); |
259 | #endif |
320 | #endif |
260 | |
321 | |
261 | Newz (0, our, 1, ourdata); |
322 | Newz (0, our, 1, ourdata); |
262 | our->magic = CoMy_MAGIC; |
323 | our->magic = CoMy_MAGIC; |
263 | our->corohandle_sv = newSVsv (corohandle_sv); |
324 | our->corohandle_sv = newSVsv (corohandle_sv); |
264 | our->corohandle = newSVsv (corohandle); |
325 | our->corohandle = newSVsv (corohandle); |
265 | #if HAVE_EV |
326 | #if HAVE_EV |
266 | if (use_ev) |
327 | if (use_ev) |
267 | { |
328 | { |
268 | ev_io_init (&(our->rw), iocb, vio->sd, EV_READ); |
329 | ev_io_init (&(our->rw), iocb, VIOSD (vio), EV_READ); |
269 | ev_io_init (&(our->ww), iocb, vio->sd, EV_WRITE); |
330 | ev_io_init (&(our->ww), iocb, VIOSD (vio), EV_WRITE); |
270 | } |
331 | } |
271 | #endif |
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; |
272 | #if DESC_IS_PTR |
344 | #if DESC_IS_PTR |
273 | our->old_desc = vio->desc; |
345 | our->old_desc = vio->desc; |
274 | strncpy (our->desc, vio->desc, sizeof (our->desc)); |
346 | strncpy (our->desc, vio->desc, sizeof (our->desc)); |
275 | our->desc [sizeof (our->desc) - 1] = 0; |
347 | our->desc [sizeof (our->desc) - 1] = 0; |
276 | #else |
348 | #else |
277 | vio->desc [DESC_OFFSET - 1] = 0; |
349 | vio->desc [DESC_OFFSET - 1] = 0; |
278 | #endif |
350 | #endif |
279 | OURDATAPTR = our; |
|
|
280 | |
|
|
281 | our->old_vioclose = vio->vioclose; |
351 | our->old_close = VIOM (vio)->vioclose; |
282 | our->old_write = vio->write; |
352 | our->old_write = VIOM (vio)->write; |
283 | our->old_read = vio->read; |
353 | our->old_read = VIOM (vio)->read; |
|
|
354 | #endif |
284 | |
355 | |
|
|
356 | /* with pvio, this patches our own struct */ |
285 | vio->vioclose = our_close; |
357 | VIOM (vio)->vioclose = our_close; |
286 | vio->write = our_write; |
358 | VIOM (vio)->write = our_write; |
287 | vio->read = our_read; |
359 | VIOM (vio)->read = our_read; |
288 | } |
360 | } |
289 | |
361 | |