1 // Copyright (C) 2016-2020 John Donoghue <john.donoghue@ieee.org>
2 //
3 // This program is free software; you can redistribute it and/or modify it under
4 // the terms of the GNU General Public License as published by the Free Software
5 // Foundation; either version 3 of the License, or (at your option) any later
6 // version.
7 //
8 // This program is distributed in the hope that it will be useful, but WITHOUT
9 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 // details.
12 //
13 // You should have received a copy of the GNU General Public License along with
14 // this program; if not, see <http://www.gnu.org/licenses/>.
15 
16 // Octave Includes
17 #include <octave/oct.h>
18 #include <octave/defun-dld.h>
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23 
24 #include "socket_class.h"
25 
26 #include <zmq.h>
27 
28 // PKG_ADD: autoload ("zmq_getsockopt", "zeromq.oct");
29 DEFUN_DLD (zmq_getsockopt, args, nargout,
30         "-*- texinfo -*-\n\
31 @deftypefn {Loadable Function} @var{value} =  zmq_getsockopt (@var{sock}, @var{optionid})\n \
32 \n\
33 Get the current value of an option.\n \
34 \n \
35 @var{sock} - the socket to connect.\n \
36 \n \
37 @var{optionid} - the setsockopt option to set.\n \
38 \n \
39 @var{value} - the value set for the option, or [].\n \
40 \n \
41 Valid @var{optionid}s are:\n \
42 @table @asis\n \
43 @item @code{ZMQ_RCVMORE}\n \
44 Flag for whether a message has been split into multiple messages. The return value will be either 0 or 1.\n \
45 @item @code{ZMQ_TYPE}\n \
46 Socket type for zeromq socket created with zmq_socket.\n \
47 Valid types are the same as the socket type value specified with zmq_socket. \n \
48 @item @code{ZMQ_EVENTS}\n \
49 Get the event state of zeromq socket.\n \
50 The returned value is a bit mask that may contain the following set values:\n \
51 @itemize\n \
52 @item @code{ZMQ_POLLIN} set when at least one message is available to read and zmq_recv will not block.\n \
53 @item @code{ZMQ_POLLOUT} set when at least one message can be written without zmq_send blocking.\n \
54 @end itemize\n \
55 @item @code{ZMQ_IDENTITY}\n \
56 Get the socket identity value\n \
57 @item @code{ZMQ_LAST_ENDPOINT}\n \
58 Get the last endpoint the socket was connected to\n \
59 @item @code{ZMQ_CONNECT_TIMEOUT}\n \
60 Get the connect timeout value\n \
61 @item @code{ZMQ_SOCKS_PROXY}\n \
62 Get the SOCKS5 proxy value (string)\n \
63 @item @code{ZMQ_CURVE_SERVER}\n \
64 Get whether socket is a curve server (1) or not (0)\n \
65 @item @code{ZMQ_CURVE_PRIVATEKEY}\n \
66 Get a the curve socket private key (string)\n \
67 @item @code{ZMQ_CURVE_PUBLICKEY}\n \
68 Get a the curve socket public key (string)\n \
69 @item @code{ZMQ_CURVE_SERVERKEY}\n \
70 Get a the curve socket public key (string)\n \
71 @item @code{ZMQ_PLAIN_SERVER}\n \
72 Get whether socket server will use plain authentication (1) or not (0)\n \
73 @item @code{ZMQ_PLAIN_USERNAME}\n \
74 Get the plain socket username (string)\n \
75 @item @code{ZMQ_PLAIN_PASSWORD}\n \
76 Get the plain socket password (string)\n \
77 @item @code{ZMQ_GSSAPI_SERVER}\n \
78 Get whether socket server will use gssapi authentication (1) or not (0)\n \
79 @item @code{ZMQ_GSSAPI_PLAINTEXT}\n \
80 Get whether socket will encrypt gssapi authentication (1) or not (0)\n \
81 @item @code{ZMQ_GSSAPI_PRINCIPAL}\n \
82 Get the name of the gssapi principal (string)\n \
83 @item @code{ZMQ_GSSAPI_SERVICE_PRINCIPAL}\n \
84 Get the name of the gssapi service principal (string)\n \
85 @item @code{ZMQ_MECHANISM}\n \
86 Get the security mechanism (ZMQ_NULL, ZMQ_PLAIN, ZMQ_CURVE, ZMQ_GSSAPI)\n \
87 @end table\n \
88 \n \
89 @seealso{zmq_socket, zmq_setsockopt}\n \
90 @end deftypefn")
91 {
92   init_types ();
93 
94 
95   if (args.length () != 2 ||
96       args(0).type_id () != octave_zeromq_socket::static_type_id ())
97     {
98       print_usage ();
99       return octave_value ();
100     }
101 
102   if (args (1).OV_ISINTEGER () && !args (1).OV_ISFLOAT ())
103     {
104       print_usage ();
105       return octave_value ();
106     }
107 
108   octave_zeromq_socket * sock = NULL;
109 
110   const octave_base_value& rep = args (0).get_rep ();
111 
112   sock = &((octave_zeromq_socket &)rep);
113 
114   int opt = args (1).int_value ();
115 
116   std::string strvalue;
117 
118   octave_value ret;
119   switch(opt)
120   {
121   case ZMQ_RCVMORE:
122     {
123 #if ZMQ_VERSION < ZMQ_MAKE_VERSION(3,0,0)
124       int64_t flag = 0;
125 #else
126       int flag = 0;
127 #endif
128       size_t sz = sizeof (flag);
129       if (! sock->getsockopt (opt, &flag, &sz))
130         error ("zeromq: failed getsockopt");
131 
132       ret = octave_value (flag);
133     }
134     break;
135 #if ZMQ_VERSION < ZMQ_MAKE_VERSION(3,0,0)
136  case ZMQ_HWM:
137     {
138       uint64_t value = 0;
139       size_t sz = sizeof (value);
140       if (! sock->getsockopt (opt, &value, &sz))
141         error ("zeromq: failed getsockopt");
142 
143       ret = octave_value (value);
144     }
145     break;
146 #endif
147 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
148  case ZMQ_SNDHWM:
149     {
150       int value = 0;
151       size_t sz = sizeof (value);
152       if ( !sock->getsockopt (opt, &value, &sz))
153         error ("zeromq: failed getsockopt");
154 
155       ret = octave_value (value);
156     }
157     break;
158 #endif
159 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0)
160  case ZMQ_RCVHWM:
161     {
162       int value = 0;
163       size_t sz = sizeof (value);
164       if (! sock->getsockopt (opt, &value, &sz))
165         error ("zeromq: failed getsockopt");
166 
167       ret = octave_value (value);
168     }
169     break;
170 #endif
171 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(2,1,0)
172  case ZMQ_TYPE:
173     {
174       ret = octave_value (sock->socktype ());
175     }
176     break;
177 #endif
178   case ZMQ_EVENTS:
179     {
180 #if ZMQ_VERSION < ZMQ_MAKE_VERSION(3,0,0)
181       uint32_t value = 0;
182 #else
183       int value = 0;
184 #endif
185       size_t sz = sizeof (value);
186       if (! sock->getsockopt (opt, &value, &sz))
187         error ("zeromq: ZMQ_EVENTS failed getsockopt");
188 
189       ret = octave_value (value);
190     }
191     break;
192  case ZMQ_IDENTITY:
193     {
194       uint8_t value[256];
195       size_t sz = sizeof (value);
196 
197       if (! sock->getsockopt (opt, value, &sz))
198         error ("zeromq: failed getsockopt");
199 
200       if (sz > 0)
201         {
202           uint8NDArray data( dim_vector (1,sz) );
203           for (size_t i=0;i<sz;i++)
204             {
205               data(i) = value[i];
206             }
207 
208           ret = data;
209         }
210       else
211         ret = uint8NDArray (dim_vector (1,0));
212     }
213     break;
214 
215 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,2,0)
216   case ZMQ_LAST_ENDPOINT:
217     {
218       char value[1024];
219       size_t sz = sizeof (value);
220 
221       if (! sock->getsockopt (opt, value, &sz))
222         error ("zeromq: failed getsockopt");
223 
224       if (sz > 0)
225         {
226           strvalue = std::string(value, sz-1);
227         }
228       else
229         strvalue = "";
230 
231       ret = octave_value(strvalue);
232     }
233     break;
234 #endif
235 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4,2,0)
236   case ZMQ_CONNECT_TIMEOUT:
237     {
238       int value;
239       size_t sz = sizeof (value);
240 
241       if (! sock->getsockopt (opt, &value, &sz))
242         error ("zeromq: failed getsockopt");
243 
244       ret = octave_value (value);
245     }
246     break;
247 #endif
248 #ifdef ZMQ_SOCKS_PROXY
249   case ZMQ_SOCKS_PROXY:
250     {
251       char value[1024];
252       size_t sz = sizeof(value);
253 
254       if (! sock->getsockopt (opt, value, &sz))
255         error ("zeromq: failed getsockopt");
256 
257       if (sz > 0)
258         {
259           strvalue = std::string(value, sz-1);
260         }
261       else
262         strvalue = "";
263 
264       ret = octave_value(strvalue);
265     }
266     break;
267 #endif
268 #ifdef ZMQ_CURVE_SERVER
269   case ZMQ_CURVE_SERVER:
270     {
271       int value;
272       size_t sz = sizeof (value);
273 
274       if (! sock->getsockopt (opt, &value, &sz))
275         error ("zeromq: failed getsockopt");
276 
277       ret = octave_value (value);
278     }
279     break;
280 #endif
281 
282 #ifdef ZMQ_CURVE_PUBLICKEY
283   case ZMQ_CURVE_PUBLICKEY:
284     {
285       char value[1024];
286       size_t sz = 41;
287 
288       if (! sock->getsockopt (opt, value, &sz))
289         error ("zeromq: failed getsockopt");
290 
291       if (sz > 0)
292         {
293           strvalue = std::string(value, sz-1);
294         }
295       else
296         strvalue = "";
297 
298       ret = octave_value(strvalue);
299     }
300     break;
301 #endif
302 #ifdef ZMQ_CURVE_SERVERKEY
303   case ZMQ_CURVE_SERVERKEY:
304     {
305       char value[1024];
306       size_t sz = 41;
307 
308       if (! sock->getsockopt (opt, value, &sz))
309         error ("zeromq: failed getsockopt");
310 
311       if (sz > 0)
312         {
313           strvalue = std::string(value, sz-1);
314         }
315       else
316         strvalue = "";
317 
318       ret = octave_value(strvalue);
319     }
320     break;
321 #endif
322 #ifdef ZMQ_CURVE_SECRETKEY
323   case ZMQ_CURVE_SECRETKEY:
324     {
325       char value[1024];
326       size_t sz = 41;
327 
328       if (! sock->getsockopt (opt, value, &sz))
329         error ("zeromq: failed getsockopt");
330 
331       if (sz > 0)
332         {
333           strvalue = std::string(value, sz-1);
334         }
335       else
336         strvalue = "";
337 
338       ret = octave_value(strvalue);
339     }
340     break;
341 #endif
342 #ifdef ZMQ_PLAIN_SERVER
343   case ZMQ_PLAIN_SERVER:
344     {
345       int value;
346       size_t sz = sizeof (value);
347 
348       if (! sock->getsockopt (opt, &value, &sz))
349         error ("zeromq: failed getsockopt");
350 
351       ret = octave_value (value);
352     }
353     break;
354 #endif
355 
356 #ifdef ZMQ_PLAIN_USERNAME
357   case ZMQ_PLAIN_USERNAME:
358     {
359       char value[1024];
360       size_t sz = sizeof (value);
361 
362       if (! sock->getsockopt (opt, value, &sz))
363         error ("zeromq: failed getsockopt");
364 
365       if (sz > 0)
366         {
367           strvalue = std::string(value, sz-1);
368         }
369       else
370         strvalue = "";
371 
372       ret = octave_value(strvalue);
373     }
374     break;
375 #endif
376 #ifdef ZMQ_PLAIN_PASSWORD
377   case ZMQ_PLAIN_PASSWORD:
378     {
379       char value[1024];
380       size_t sz = sizeof (value);
381 
382       if (! sock->getsockopt (opt, value, &sz))
383         error ("zeromq: failed getsockopt");
384 
385       if (sz > 0)
386         {
387           strvalue = std::string(value, sz-1);
388         }
389       else
390         strvalue = "";
391 
392       ret = octave_value(strvalue);
393     }
394     break;
395 #endif
396 #ifdef ZMQ_GSSAPI_SERVER
397   case ZMQ_GSSAPI_SERVER:
398     {
399       int value;
400       size_t sz = sizeof (value);
401 
402       if (! sock->getsockopt (opt, &value, &sz))
403         error ("zeromq: failed getsockopt");
404 
405       ret = octave_value (value);
406     }
407     break;
408 #endif
409 
410 #ifdef ZMQ_GSSAPI_PLAINTEXT
411   case ZMQ_GSSAPI_PLAINTEXT:
412     {
413       int value;
414       size_t sz = sizeof (value);
415 
416       if (! sock->getsockopt (opt, &value, &sz))
417         error ("zeromq: failed getsockopt");
418 
419       ret = octave_value (value);
420     }
421     break;
422 #endif
423 #ifdef ZMQ_GSSAPI_PRINCIPAL
424   case ZMQ_GSSAPI_PRINCIPAL:
425     {
426       char value[1024];
427       size_t sz = sizeof (value);
428 
429       if (! sock->getsockopt (opt, value, &sz))
430         error ("zeromq: failed getsockopt");
431 
432       if (sz > 0)
433         {
434           strvalue = std::string(value, sz-1);
435         }
436       else
437         strvalue = "";
438 
439       ret = octave_value(strvalue);
440     }
441     break;
442 #endif
443 
444 #ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL
445   case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
446     {
447       char value[1024];
448       size_t sz = sizeof (value);
449 
450       if (! sock->getsockopt (opt, value, &sz))
451         error ("zeromq: failed getsockopt");
452 
453       if (sz > 0)
454         {
455           strvalue = std::string(value, sz-1);
456         }
457       else
458         strvalue = "";
459 
460       ret = octave_value(strvalue);
461     }
462     break;
463 #endif
464 
465 #ifdef ZMQ_MECHANISM
466   case ZMQ_MECHANISM:
467     {
468       int value;
469       size_t sz = sizeof (value);
470 
471       if (! sock->getsockopt (opt, &value, &sz))
472         error ("zeromq: failed getsockopt");
473 
474       ret = octave_value (value);
475     }
476     break;
477 #endif
478 
479   default:
480     error ("zeromq: invalid getsockopt value %d", opt);
481     break;
482   }
483 
484   return ret;
485 }
486 
487 #if 0
488 %!error <Invalid call to zmq_getsockopt> zmq_getsockopt
489 %!error <Invalid call to zmq_getsockopt> zmq_getsockopt(10)
490 
491 %!test
492 %! s = zmq_socket(ZMQ_SUB);
493 %! assert(zmq_getsockopt(s, ZMQ_TYPE), ZMQ_SUB);
494 %! zmq_setsockopt(s, ZMQ_IDENTITY, uint8([104 101 108 108 111]));
495 %! assert(zmq_getsockopt(s, ZMQ_IDENTITY), uint8([104 101 108 108 111]));
496 %! zmq_close(s);
497 
498 #endif
499