1 
2 // vim:ai:sw=2:ts=8
3 
4 /*
5  * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6  * See COPYRIGHT.txt for details.
7  */
8 
9 #include "EXTERN.h"
10 #include "perl.h"
11 #include "XSUB.h"
12 
13 #include "ppport.h"
14 
15 #include "hstcpcli.hpp"
16 
17 #define DBG(x)
18 
19 static SV *
arr_get_entry(AV * av,I32 avmax,I32 idx)20 arr_get_entry(AV *av, I32 avmax, I32 idx)
21 {
22   if (idx > avmax) {
23     DBG(fprintf(stderr, "arr_get_entry1 %d %d\n", avmax, idx));
24     return 0;
25   }
26   SV **const ev = av_fetch(av, idx, 0);
27   if (ev == 0) {
28     DBG(fprintf(stderr, "arr_get_entry2 %d %d\n", avmax, idx));
29     return 0;
30   }
31   return *ev;
32 }
33 
34 static int
35 arr_get_intval(AV *av, I32 avmax, I32 idx, int default_val = 0)
36 {
37   SV *const e = arr_get_entry(av, avmax, idx);
38   if (e == 0) {
39     return default_val;
40   }
41   return SvIV(e);
42 }
43 
44 static const char *
sv_get_strval(SV * sv)45 sv_get_strval(SV *sv)
46 {
47   if (sv == 0 || !SvPOK(sv)) {
48     DBG(fprintf(stderr, "sv_get_strval\n"));
49     return 0;
50   }
51   return SvPV_nolen(sv);
52 }
53 
54 static const char *
arr_get_strval(AV * av,I32 avmax,I32 idx)55 arr_get_strval(AV *av, I32 avmax, I32 idx)
56 {
57   SV *const e = arr_get_entry(av, avmax, idx);
58   return sv_get_strval(e);
59 }
60 
61 static AV *
sv_get_arrval(SV * sv)62 sv_get_arrval(SV *sv)
63 {
64   if (sv == 0 || !SvROK(sv)) {
65     DBG(fprintf(stderr, "sv_get_arrval1\n"));
66     return 0;
67   }
68   SV *const svtarget = SvRV(sv);
69   if (svtarget == 0 || SvTYPE(svtarget) != SVt_PVAV) {
70     DBG(fprintf(stderr, "sv_get_arrval2\n"));
71     return 0;
72   }
73   return (AV *)svtarget;
74 }
75 
76 static AV *
arr_get_arrval(AV * av,I32 avmax,I32 idx)77 arr_get_arrval(AV *av, I32 avmax, I32 idx)
78 {
79   SV *const e = arr_get_entry(av, avmax, idx);
80   if (e == 0) {
81     DBG(fprintf(stderr, "arr_get_arrval1\n"));
82     return 0;
83   }
84   return sv_get_arrval(e);
85 }
86 
87 static void
hv_to_strmap(HV * hv,std::map<std::string,std::string> & m_r)88 hv_to_strmap(HV *hv, std::map<std::string, std::string>& m_r)
89 {
90   if (hv == 0) {
91     return;
92   }
93   hv_iterinit(hv);
94   HE *hent = 0;
95   while ((hent = hv_iternext(hv)) != 0) {
96     I32 klen = 0;
97     char *const k = hv_iterkey(hent, &klen);
98     DBG(fprintf(stderr, "k=%s\n", k));
99     const std::string key(k, klen);
100     SV *const vsv = hv_iterval(hv, hent);
101     STRLEN vlen = 0;
102     char *const v = SvPV(vsv, vlen);
103     DBG(fprintf(stderr, "v=%s\n", v));
104     const std::string val(v, vlen);
105     m_r[key] = val;
106   }
107 }
108 
109 static void
strrefarr_push_back(std::vector<dena::string_ref> & a_r,SV * sv)110 strrefarr_push_back(std::vector<dena::string_ref>& a_r, SV *sv)
111 {
112   if (sv == 0 || SvTYPE(sv) == SVt_NULL) { /* !SvPOK()? */
113     DBG(fprintf(stderr, "strrefarr_push_back: null\n"));
114     return a_r.push_back(dena::string_ref());
115   }
116   STRLEN vlen = 0;
117   char *const v = SvPV(sv, vlen);
118   DBG(fprintf(stderr, "strrefarr_push_back: %s\n", v));
119   a_r.push_back(dena::string_ref(v, vlen));
120 }
121 
122 static void
av_to_strrefarr(AV * av,std::vector<dena::string_ref> & a_r)123 av_to_strrefarr(AV *av, std::vector<dena::string_ref>& a_r)
124 {
125   if (av == 0) {
126     return;
127   }
128   const I32 len = av_len(av) + 1;
129   for (I32 i = 0; i < len; ++i) {
130     SV **const ev = av_fetch(av, i, 0);
131     strrefarr_push_back(a_r, ev ? *ev : 0);
132   }
133 }
134 
135 static dena::string_ref
sv_get_string_ref(SV * sv)136 sv_get_string_ref(SV *sv)
137 {
138   if (sv == 0 || SvTYPE(sv) == SVt_NULL) { /* !SvPOK()? */
139     return dena::string_ref();
140   }
141   STRLEN vlen = 0;
142   char *const v = SvPV(sv, vlen);
143   return dena::string_ref(v, vlen);
144 }
145 
146 static IV
sv_get_iv(SV * sv)147 sv_get_iv(SV *sv)
148 {
149   if (sv == 0 || ( !SvIOK(sv) && !SvPOK(sv) ) ) {
150     return 0;
151   }
152   return SvIV(sv);
153 }
154 
155 static void
av_to_filters(AV * av,std::vector<dena::hstcpcli_filter> & f_r)156 av_to_filters(AV *av, std::vector<dena::hstcpcli_filter>& f_r)
157 {
158   DBG(fprintf(stderr, "av_to_filters: %p\n", av));
159   if (av == 0) {
160     return;
161   }
162   const I32 len = av_len(av) + 1;
163   DBG(fprintf(stderr, "av_to_filters: len=%d\n", (int)len));
164   for (I32 i = 0; i < len; ++i) {
165     AV *const earr = arr_get_arrval(av, len, i);
166     if (earr == 0) {
167       continue;
168     }
169     const I32 earrlen = av_len(earr) + 1;
170     dena::hstcpcli_filter fe;
171     fe.filter_type = sv_get_string_ref(arr_get_entry(earr, earrlen, 0));
172     fe.op = sv_get_string_ref(arr_get_entry(earr, earrlen, 1));
173     fe.ff_offset = sv_get_iv(arr_get_entry(earr, earrlen, 2));
174     fe.val = sv_get_string_ref(arr_get_entry(earr, earrlen, 3));
175     f_r.push_back(fe);
176     DBG(fprintf(stderr, "av_to_filters: %s %s %d %s\n",
177       fe.filter_action.begin(), fe.filter_op.begin(), (int)fe.ff_offset,
178       fe.value.begin()));
179   }
180 }
181 
182 static void
set_process_verbose_level(const std::map<std::string,std::string> & m)183 set_process_verbose_level(const std::map<std::string, std::string>& m)
184 {
185   std::map<std::string, std::string>::const_iterator iter = m.find("verbose");
186   if (iter != m.end()) {
187     dena::verbose_level = atoi(iter->second.c_str());
188   }
189 }
190 
191 static AV *
execute_internal(SV * obj,int id,const char * op,AV * keys,int limit,int skip,const char * modop,AV * modvals,AV * filters,int invalues_keypart,AV * invalues)192 execute_internal(SV *obj, int id, const char *op, AV *keys, int limit,
193   int skip, const char *modop, AV *modvals, AV *filters, int invalues_keypart,
194   AV *invalues)
195 {
196   AV *retval = (AV *)&PL_sv_undef;
197   dena::hstcpcli_i *const ptr =
198     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
199   do {
200     std::vector<dena::string_ref> keyarr, mvarr;
201     std::vector<dena::hstcpcli_filter> farr;
202     std::vector<dena::string_ref> ivs;
203     av_to_strrefarr(keys, keyarr);
204     dena::string_ref modop_ref;
205     if (modop != 0) {
206       modop_ref = dena::string_ref(modop, strlen(modop));
207       av_to_strrefarr(modvals, mvarr);
208     }
209     if (filters != 0) {
210       av_to_filters(filters, farr);
211     }
212     if (invalues_keypart >= 0 && invalues != 0) {
213       av_to_strrefarr(invalues, ivs);
214     }
215     ptr->request_buf_exec_generic(id, dena::string_ref(op, strlen(op)),
216       &keyarr[0], keyarr.size(), limit, skip, modop_ref, &mvarr[0],
217       mvarr.size(), &farr[0], farr.size(), invalues_keypart, &ivs[0],
218       ivs.size());
219     AV *const av = newAV();
220     retval = av;
221     if (ptr->request_send() != 0) {
222       break;
223     }
224     size_t nflds = 0;
225     ptr->response_recv(nflds);
226     const int e = ptr->get_error_code();
227     DBG(fprintf(stderr, "e=%d nflds=%zu\n", e, nflds));
228     av_push(av, newSViv(e));
229     if (e != 0) {
230       const std::string s = ptr->get_error();
231       av_push(av, newSVpvn(s.data(), s.size()));
232     } else {
233       const dena::string_ref *row = 0;
234       while ((row = ptr->get_next_row()) != 0) {
235 	DBG(fprintf(stderr, "row=%p\n", row));
236 	for (size_t i = 0; i < nflds; ++i) {
237 	  const dena::string_ref& v = row[i];
238 	  DBG(fprintf(stderr, "FLD %zu v=%s vbegin=%p\n", i,
239 	    std::string(v.begin(), v.size())
240 	      .c_str(), v.begin()));
241 	  if (v.begin() != 0) {
242 	    SV *const e = newSVpvn(
243 	      v.begin(), v.size());
244 	    av_push(av, e);
245 	  } else {
246 	    av_push(av, &PL_sv_undef);
247 	  }
248 	}
249       }
250     }
251     if (e >= 0) {
252       ptr->response_buf_remove();
253     }
254   } while (0);
255   return retval;
256 }
257 
258 struct execute_arg {
259   int id;
260   const char *op;
261   AV *keys;
262   int limit;
263   int skip;
264   const char *modop;
265   AV *modvals;
266   AV *filters;
267   int invalues_keypart;
268   AV *invalues;
execute_argexecute_arg269   execute_arg() : id(0), op(0), keys(0), limit(0), skip(0), modop(0),
270     modvals(0), filters(0), invalues_keypart(-1), invalues(0) { }
271 };
272 
273 static AV *
execute_multi_internal(SV * obj,const execute_arg * args,size_t num_args)274 execute_multi_internal(SV *obj, const execute_arg *args, size_t num_args)
275 {
276   dena::hstcpcli_i *const ptr =
277     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
278   /* appends multiple requests to the send buffer */
279   for (size_t i = 0; i < num_args; ++i) {
280     std::vector<dena::string_ref> keyarr, mvarr;
281     std::vector<dena::hstcpcli_filter> farr;
282     std::vector<dena::string_ref> ivs;
283     const execute_arg& arg = args[i];
284     av_to_strrefarr(arg.keys, keyarr);
285     dena::string_ref modop_ref;
286     if (arg.modop != 0) {
287       modop_ref = dena::string_ref(arg.modop, strlen(arg.modop));
288       av_to_strrefarr(arg.modvals, mvarr);
289     }
290     if (arg.filters != 0) {
291       av_to_filters(arg.filters, farr);
292     }
293     if (arg.invalues_keypart >= 0 && arg.invalues != 0) {
294       av_to_strrefarr(arg.invalues, ivs);
295     }
296     ptr->request_buf_exec_generic(arg.id,
297       dena::string_ref(arg.op, strlen(arg.op)), &keyarr[0], keyarr.size(),
298       arg.limit, arg.skip, modop_ref, &mvarr[0], mvarr.size(), &farr[0],
299       farr.size(), arg.invalues_keypart, &ivs[0], ivs.size());
300   }
301   AV *const retval = newAV();
302   /* sends the requests */
303   if (ptr->request_send() < 0) {
304     /* IO error */
305     AV *const av_respent = newAV();
306     av_push(retval, newRV_noinc((SV *)av_respent));
307     av_push(av_respent, newSViv(ptr->get_error_code()));
308     const std::string& s = ptr->get_error();
309     av_push(av_respent, newSVpvn(s.data(), s.size()));
310     return retval; /* retval : [ [ err_code, err_message ] ] */
311   }
312   /* receives responses */
313   for (size_t i = 0; i < num_args; ++i) {
314     AV *const av_respent = newAV();
315     av_push(retval, newRV_noinc((SV *)av_respent));
316     size_t nflds = 0;
317     const int e = ptr->response_recv(nflds);
318     av_push(av_respent, newSViv(e));
319     if (e != 0) {
320       const std::string& s = ptr->get_error();
321       av_push(av_respent, newSVpvn(s.data(), s.size()));
322     } else {
323       const dena::string_ref *row = 0;
324       while ((row = ptr->get_next_row()) != 0) {
325 	for (size_t i = 0; i < nflds; ++i) {
326 	  const dena::string_ref& v = row[i];
327 	  DBG(fprintf(stderr, "%zu %s\n", i,
328 	    std::string(v.begin(), v.size()).c_str()));
329 	  if (v.begin() != 0) {
330 	    av_push(av_respent, newSVpvn(v.begin(), v.size()));
331 	  } else {
332 	    /* null */
333 	    av_push(av_respent, &PL_sv_undef);
334 	  }
335 	}
336       }
337     }
338     if (e >= 0) {
339       ptr->response_buf_remove();
340     }
341     if (e < 0) {
342       return retval;
343     }
344   }
345   return retval;
346 }
347 
348 MODULE = Net::HandlerSocket    PACKAGE = Net::HandlerSocket
349 
350 SV *
351 new(klass, args)
352   char *klass
353   HV *args
354 CODE:
355   RETVAL = &PL_sv_undef;
356   dena::config conf;
357   hv_to_strmap(args, conf);
358   set_process_verbose_level(conf);
359   dena::socket_args sargs;
360   sargs.set(conf);
361   dena::hstcpcli_ptr p = dena::hstcpcli_i::create(sargs);
362   SV *const objref = newSViv(0);
363   SV *const obj = newSVrv(objref, klass);
364   dena::hstcpcli_i *const ptr = p.get();
365   sv_setiv(obj, reinterpret_cast<IV>(ptr));
366   p.release();
367   SvREADONLY_on(obj);
368   RETVAL = objref;
369 OUTPUT:
370   RETVAL
371 
372 void
373 DESTROY(obj)
374   SV *obj
375 CODE:
376   dena::hstcpcli_i *const ptr =
377     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
378   delete ptr;
379 
380 void
381 close(obj)
382   SV *obj
383 CODE:
384   dena::hstcpcli_i *const ptr =
385     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
386   ptr->close();
387 
388 int
389 reconnect(obj)
390   SV *obj
391 CODE:
392   RETVAL = 0;
393   dena::hstcpcli_i *const ptr =
394     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
395   RETVAL = ptr->reconnect();
396 OUTPUT:
397   RETVAL
398 
399 int
400 stable_point(obj)
401   SV *obj
402 CODE:
403   RETVAL = 0;
404   dena::hstcpcli_i *const ptr =
405     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
406   const bool rv = ptr->stable_point();
407   RETVAL = static_cast<int>(rv);
408 OUTPUT:
409   RETVAL
410 
411 int
412 get_error_code(obj)
413   SV *obj
414 CODE:
415   RETVAL = 0;
416   dena::hstcpcli_i *const ptr =
417     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
418   RETVAL = ptr->get_error_code();
419 OUTPUT:
420   RETVAL
421 
422 SV *
423 get_error(obj)
424   SV *obj
425 CODE:
426   RETVAL = &PL_sv_undef;
427   dena::hstcpcli_i *const ptr =
428     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
429   const std::string s = ptr->get_error();
430   RETVAL = newSVpvn(s.data(), s.size());
431 OUTPUT:
432   RETVAL
433 
434 int
435 auth(obj, key, typ = 0)
436   SV *obj
437   const char *key
438   const char *typ
439 CODE:
440   RETVAL = 0;
441   dena::hstcpcli_i *const ptr =
442     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
443   do {
444     ptr->request_buf_auth(key, typ);
445     if (ptr->request_send() != 0) {
446       break;
447     }
448     size_t nflds = 0;
449     ptr->response_recv(nflds);
450     const int e = ptr->get_error_code();
451     DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
452     if (e >= 0) {
453       ptr->response_buf_remove();
454     }
455     DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
456   } while (0);
457   RETVAL = ptr->get_error_code();
458 OUTPUT:
459   RETVAL
460 
461 
462 int
463 open_index(obj, id, db, table, index, fields, ffields = 0)
464   SV *obj
465   int id
466   const char *db
467   const char *table
468   const char *index
469   const char *fields
470   SV *ffields
471 CODE:
472   const char *const ffields_str = sv_get_strval(ffields);
473   RETVAL = 0;
474   dena::hstcpcli_i *const ptr =
475     reinterpret_cast<dena::hstcpcli_i *>(SvIV(SvRV(obj)));
476   do {
477     ptr->request_buf_open_index(id, db, table, index, fields, ffields_str);
478     if (ptr->request_send() != 0) {
479       break;
480     }
481     size_t nflds = 0;
482     ptr->response_recv(nflds);
483     const int e = ptr->get_error_code();
484     DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
485     if (e >= 0) {
486       ptr->response_buf_remove();
487     }
488     DBG(fprintf(stderr, "errcode=%d\n", ptr->get_error_code()));
489   } while (0);
490   RETVAL = ptr->get_error_code();
491 OUTPUT:
492   RETVAL
493 
494 AV *
495 execute_single(obj, id, op, keys, limit, skip, mop = 0, mvs = 0, fils = 0, ivkeypart = -1, ivs = 0)
496   SV *obj
497   int id
498   const char *op
499   AV *keys
500   int limit
501   int skip
502   SV *mop
503   SV *mvs
504   SV *fils
505   int ivkeypart
506   SV *ivs
507 CODE:
508   const char *const mop_str = sv_get_strval(mop);
509   AV *const mvs_av = sv_get_arrval(mvs);
510   AV *const fils_av = sv_get_arrval(fils);
511   AV *const ivs_av = sv_get_arrval(ivs);
512   RETVAL = execute_internal(obj, id, op, keys, limit, skip, mop_str, mvs_av,
513     fils_av, ivkeypart, ivs_av);
514   sv_2mortal((SV *)RETVAL);
515 OUTPUT:
516   RETVAL
517 
518 AV *
519 execute_multi(obj, cmds)
520   SV *obj
521   AV *cmds
522 CODE:
523   DBG(fprintf(stderr, "execute_multi0\n"));
524   const I32 cmdsmax = av_len(cmds);
525   execute_arg args[cmdsmax + 1]; /* GNU */
526   for (I32 i = 0; i <= cmdsmax; ++i) {
527     AV *const avtarget = arr_get_arrval(cmds, cmdsmax, i);
528     if (avtarget == 0) {
529       DBG(fprintf(stderr, "execute_multi1 %d\n", i));
530       continue;
531     }
532     const I32 argmax = av_len(avtarget);
533     if (argmax < 2) {
534       DBG(fprintf(stderr, "execute_multi2 %d\n", i));
535       continue;
536     }
537     execute_arg& ag = args[i];
538     ag.id = arr_get_intval(avtarget, argmax, 0);
539     ag.op = arr_get_strval(avtarget, argmax, 1);
540     ag.keys = arr_get_arrval(avtarget, argmax, 2);
541     ag.limit = arr_get_intval(avtarget, argmax, 3);
542     ag.skip = arr_get_intval(avtarget, argmax, 4);
543     ag.modop = arr_get_strval(avtarget, argmax, 5);
544     ag.modvals = arr_get_arrval(avtarget, argmax, 6);
545     ag.filters = arr_get_arrval(avtarget, argmax, 7);
546     ag.invalues_keypart = arr_get_intval(avtarget, argmax, 8, -1);
547     ag.invalues = arr_get_arrval(avtarget, argmax, 9);
548     DBG(fprintf(stderr, "execute_multi3 %d: %d %s %p %d %d %s %p %p %d %p\n",
549       i, ag.id, ag.op, ag.keys, ag.limit, ag.skip, ag.modop, ag.modvals,
550       ag.filters, ag.invalues_keypart, ag.invalues));
551   }
552   RETVAL = execute_multi_internal(obj, args, cmdsmax + 1);
553   sv_2mortal((SV *)RETVAL);
554 OUTPUT:
555   RETVAL
556 
557 AV *
558 execute_find(obj, id, op, keys, limit, skip, mop = 0, mvs = 0, fils = 0, ivkeypart = -1, ivs = 0)
559   SV *obj
560   int id
561   const char *op
562   AV *keys
563   int limit
564   int skip
565   SV *mop
566   SV *mvs
567   SV *fils
568   int ivkeypart
569   SV *ivs
570 CODE:
571   const char *const mop_str = sv_get_strval(mop);
572   AV *const mvs_av = sv_get_arrval(mvs);
573   AV *const fils_av = sv_get_arrval(fils);
574   AV *const ivs_av = sv_get_arrval(ivs);
575   RETVAL = execute_internal(obj, id, op, keys, limit, skip, mop_str, mvs_av,
576     fils_av, ivkeypart, ivs_av);
577   sv_2mortal((SV *)RETVAL);
578 OUTPUT:
579   RETVAL
580 
581 AV *
582 execute_update(obj, id, op, keys, limit, skip, modvals, fils = 0, ivkeypart = -1, ivs = 0)
583   SV *obj
584   int id
585   const char *op
586   AV *keys
587   int limit
588   int skip
589   AV *modvals
590   SV *fils
591   int ivkeypart
592   SV *ivs
593 CODE:
594   AV *const fils_av = sv_get_arrval(fils);
595   AV *const ivs_av = sv_get_arrval(ivs);
596   RETVAL = execute_internal(obj, id, op, keys, limit, skip, "U",
597     modvals, fils_av, ivkeypart, ivs_av);
598   sv_2mortal((SV *)RETVAL);
599 OUTPUT:
600   RETVAL
601 
602 AV *
603 execute_delete(obj, id, op, keys, limit, skip, fils = 0, ivkeypart = -1, ivs = 0)
604   SV *obj
605   int id
606   const char *op
607   AV *keys
608   int limit
609   int skip
610   SV *fils
611   int ivkeypart
612   SV *ivs
613 CODE:
614   AV *const fils_av = sv_get_arrval(fils);
615   AV *const ivs_av = sv_get_arrval(ivs);
616   RETVAL = execute_internal(obj, id, op, keys, limit, skip, "D", 0, fils_av,
617     ivkeypart, ivs_av);
618   sv_2mortal((SV *)RETVAL);
619 OUTPUT:
620   RETVAL
621 
622 AV *
623 execute_insert(obj, id, fvals)
624   SV *obj
625   int id
626   AV *fvals
627 CODE:
628   RETVAL = execute_internal(obj, id, "+", fvals, 0, 0, 0, 0, 0, -1, 0);
629   sv_2mortal((SV *)RETVAL);
630 OUTPUT:
631   RETVAL
632 
633