1 /*
2  *  C++ Interface to Rserve
3  *  Copyright (C) 2004-8 Simon Urbanek, All rights reserved.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; version 2.1 of the License
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU Leser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Although this code is licensed under LGPL v2.1, we strongly encourage
19  *  everyone modifying this software to contribute back any improvements and
20  *  bugfixes to the project for the benefit all other users. Thank you.
21  *
22  *  $Id$
23  */
24 
25 /* external defines:
26    SWAPEND  - needs to be defined for platforms with inverse endianess related to Intel
27    MAIN     - should be defined in just one file that will contain the fn definitions and variables
28               (this is inherited from Rsrv.h and sisocks.h)
29 */
30 
31 #ifndef __RCONNECTION_H__
32 #define __RCONNECTION_H__
33 
34 #if defined __GNUC__ && !defined unix && !defined Win32 && !defined WIN32
35 #define unix
36 #endif
37 
38 #include <iostream>
39 
40 #include <stdio.h>
41 #include "sisocks.h"
42 #include "Rsrv.h"
43 
44 typedef unsigned int Rsize_t;
45 
46 //=== Rconnection error codes
47 
48 #define CERR_connect_failed    -1
49 #define CERR_handshake_failed  -2
50 #define CERR_invalid_id        -3
51 #define CERR_protocol_not_supp -4
52 #define CERR_not_connected     -5
53 #define CERR_peer_closed       -7
54 #define CERR_malformed_packet  -8
55 #define CERR_send_error        -9
56 #define CERR_out_of_mem       -10
57 #define CERR_not_supported    -11
58 #define CERR_io_error         -12
59 
60 // this one is custom - authentication method required by
61 // the server is not supported in this client
62 #define CERR_auth_unsupported -20
63 
64 
65 #define A_required 0x001
66 #define A_crypt    0x002
67 #define A_plain    0x004
68 
69 //===================================== Rmessage ---- QAP1 storage
70 
71 class Rmessage {
72  public:
73     struct phdr head;
74     char *data;
75     Rsize_t len;
76     int complete;
77 
78     // the following is avaliable only for parsed messages (max 16 pars)
79     int pars;
80     unsigned int *par[16];
81 
82     Rmessage();
83     Rmessage(int cmd); // 0 data
84     Rmessage(int cmd, const char *txt); // DT_STRING data
85     Rmessage(int cmd, int i); // DT_INT data (1 entry)
86     Rmessage(int cmd, const void *buf, int len, int raw_data=0); // raw data or DT_BYTESTREAM
87     virtual ~Rmessage();
88 
command()89     int command() { return complete?head.cmd:-1; }
length()90     Rsize_t length() { return complete?head.len:-1; }
is_complete()91     int is_complete() { return complete; }
92 
93     int read(int s);
94     void parse();
95     int send(int s);
96 };
97 
98 //===================================== Rexp --- basis for all SEXPs
99 
100 class Rexp {
101 public:
102     Rmessage *msg;
103     unsigned int *pos;
104     Rsize_t len;
105     Rexp *attr;
106     int type;
107     /* memory manegement for data/len:
108         - content is in a message and this Rexp is the master of that message:
109           master=0; msg=<source message>;
110         - content is in a message, but this Rexp is not the master
111           master=<master Rexp>; msg=0
112         - content is all self-allocated with no message associated
113           master=this; msg=0 */
114     char *data, *next;
115 
116 protected:
117     // the next two are only cached if requested, no direct access allowed
118     int attribs;
119     const char **attrnames;
120 
121     Rexp *master; // if this is set then this Rexp allocated the memory for us, so we are not supposed to free anything; if this is set to "this" then the content is self-allocated, including any data
122     int rcount;  // reference count - only for a master - it counts how many children still exist
123 
124 public:
125     Rexp(Rmessage *msg);
126     Rexp(unsigned int *pos, Rmessage *msg=0);
127     Rexp(int type, const char *data=0, int len=0, Rexp *attr=0);
128 
129     virtual ~Rexp();
130 
131     void set_master(Rexp *m);
132     char *parse(unsigned int *pos);
133 
storageSize()134     virtual Rsize_t storageSize() { return len+((len>0x7fffff)?8:4); }
135 
136     virtual void store(char *buf);
137     Rexp *attribute(const char *name);
138     const char **attributeNames();
139 
length()140     virtual Rsize_t length() { return len; }
141 
142     friend std::ostream& operator<< (std::ostream& os, const Rexp& exp) {
143         return ((Rexp&)exp).os_print(os);
144     }
145 
146     friend std::ostream& operator<< (std::ostream& os, const Rexp* exp) {
147         return ((Rexp*)exp)->os_print(os);
148     }
149 
os_print(std::ostream & os)150     virtual std::ostream& os_print(std::ostream& os) {
151         return os << "Rexp[type=" << type << ",len=" << len <<"]";
152     }
153 };
154 
155 //===================================== Rint --- XT_INT/XT_ARRAY_INT
156 
157 class Rinteger : public Rexp {
158 public:
Rinteger(Rmessage * msg)159     Rinteger(Rmessage *msg) : Rexp(msg) { fix_content(); }
Rinteger(unsigned int * ipos,Rmessage * imsg)160     Rinteger(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { fix_content(); }
Rinteger(int * array,int count)161     Rinteger(int *array, int count) : Rexp(XT_ARRAY_INT, (char*)array, count*sizeof(int)) { fix_content(); }
162 
intArray()163     int *intArray() { return (int*) data; }
intAt(int pos)164     int intAt(int pos) { return (pos>=0 && (unsigned)pos<len/4)?((int*)data)[pos]:0; }
length()165     virtual Rsize_t length() { return len/4; }
166 
os_print(std::ostream & os)167     virtual std::ostream& os_print (std::ostream& os) {
168         return os << "Rinteger[" << (len/4) <<"]";
169     }
170 
171 private:
172     void fix_content();
173 };
174 
175 //===================================== Rdouble --- XT_DOUBLE/XT_ARRAY_DOUBLE
176 
177 class Rdouble : public Rexp {
178 public:
Rdouble(Rmessage * msg)179     Rdouble(Rmessage *msg) : Rexp(msg) { fix_content(); }
Rdouble(unsigned int * ipos,Rmessage * imsg)180     Rdouble(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { fix_content(); }
Rdouble(double * array,int count)181     Rdouble(double *array, int count) : Rexp(XT_ARRAY_DOUBLE, (char*)array, count*sizeof(double)) { fix_content(); }
182 
doubleArray()183     double *doubleArray() { return (double*) data; }
doubleAt(int pos)184     double doubleAt(int pos) { return (pos>=0 && (unsigned)pos<len/8)?((double*)data)[pos]:0; }
length()185     virtual Rsize_t length() { return len/8; }
186 
os_print(std::ostream & os)187     virtual std::ostream& os_print (std::ostream& os) {
188         return os << "Rdouble[" << (len/8) <<"]";
189     }
190 
191 private:
192     void fix_content();
193 };
194 
195 //===================================== Rsymbol --- XT_SYM
196 
197 class Rsymbol : public Rexp {
198 protected:
199     const char *name;
200 
201 public:
Rsymbol(Rmessage * msg)202     Rsymbol(Rmessage *msg) : Rexp(msg)
203     { name=""; fix_content(); }
204 
Rsymbol(unsigned int * ipos,Rmessage * imsg)205     Rsymbol(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg)
206     { name=""; fix_content(); }
207 
symbolName()208     const char *symbolName() { return name; }
209 
os_print(std::ostream & os)210     virtual std::ostream& os_print (std::ostream& os) {
211         return os << "Rsymbol[" << symbolName() <<"]";
212     }
213 
214 private:
215     void fix_content();
216 };
217 
218 //===================================== Rstrings --- XT_ARRAY_STR
219 // NOTE: XT_ARRAY_STR is new in 0103 and ths class is just a
220 //       very crude implementation. It replaces Rstring because
221 //       XT_STR has been deprecated.
222 // FIXME: it should be a subclass of Rvector!
223 class Rstrings : public Rexp {
224     char **cont;
225     unsigned int nel;
226 public:
Rstrings(Rmessage * msg)227    Rstrings(Rmessage *msg) : Rexp(msg) { decode(); }
Rstrings(unsigned int * ipos,Rmessage * imsg)228    Rstrings(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) { decode(); }
229     /*Rstring(const char *str) : Rexp(XT_STR, str, strlen(str)+1) {}*/
230 
strings()231     char **strings() { return cont; }
stringAt(unsigned int i)232     char *stringAt(unsigned int i) { return (i >= nel) ? 0 : cont[i]; }
string()233     char *string() { return stringAt(0); }
length()234     virtual Rsize_t length() { return nel; }
235 
count()236     unsigned int count() { return nel; }
237     int indexOfString(const char *str);
238 
os_print(std::ostream & os)239     virtual std::ostream& os_print (std::ostream& os) {
240         return os << "char*[" << nel <<"]\"" << string() <<"\"..";
241     }
242  private:
decode()243     void decode() {
244       char *c = (char*) data;
245       unsigned int i = 0;
246       nel = 0;
247       while (i < len) { if (!c[i]) nel++; i++; }
248       if (nel) {
249 	i = 0;
250 	cont = (char**) malloc(sizeof(char*)*nel);
251 	while (i < nel) {
252 	  cont[i] = strdup(c);
253 	  while (*c) c++;
254 	  c++; i++;
255 	}
256       } else
257 	cont = 0;
258     }
259 };
260 
261 //===================================== Rstring --- XT_STR
262 
263 class Rstring : public Rexp {
264 public:
Rstring(Rmessage * msg)265     Rstring(Rmessage *msg) : Rexp(msg) {}
Rstring(unsigned int * ipos,Rmessage * imsg)266     Rstring(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg) {}
Rstring(const char * str)267     Rstring(const char *str) : Rexp(XT_STR, str, strlen(str)+1) {}
268 
string()269     char *string() { return (char*) data; }
270 
os_print(std::ostream & os)271     virtual std::ostream& os_print (std::ostream& os) {
272         return os << "\"" << string() <<"\"";
273     }
274 };
275 
276 
277 
278 //===================================== Rlist --- XT_LIST (CONS lists)
279 
280 class Rlist : public Rexp {
281 public:
282     Rexp *head, *tag;
283     Rlist *tail;
284 
Rlist(Rmessage * msg)285     Rlist(Rmessage *msg) : Rexp(msg)
286     { head=tag=0; tail=0; fix_content(); }
287 
Rlist(unsigned int * ipos,Rmessage * imsg)288     Rlist(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg)
289     { head=tag=0; tail=0; fix_content(); }
290 
291     /* this is a sort of special constructor that allows to create a Rlist
292        based solely on its content. This is necessary since 0.5 because
293        each LISTSXP is no longer represented by its own encoded SEXP
294        but they are packed in one content list instead */
Rlist(int type,Rexp * head,Rexp * tag,char * next,Rmessage * imsg)295     Rlist(int type, Rexp *head, Rexp *tag, char *next, Rmessage *imsg) : Rexp(type, 0, 0, 0) { this->head = head; this->tag = tag; tail = 0; this->next = next; this->msg = imsg; master = 0; }
296 
297     virtual ~Rlist();
298 
entryByTagName(const char * tagName)299     Rexp *entryByTagName(const char *tagName)  {
300       if (tag && (tag->type==XT_SYM || tag->type==XT_SYMNAME) && !strcmp(((Rsymbol*)tag)->symbolName(),tagName)) return head;
301         if (tail) return tail->entryByTagName(tagName);
302         return 0;
303     }
304 
os_print(std::ostream & os)305     virtual std::ostream& os_print (std::ostream& os) {
306         os << "Rlist[tag=";
307         if (tag) os << *tag; else os << "<none>";
308         os << ",head=";
309         if (head) os << *head; else os << "<none>";
310         if (tail) os << ",tail=" << *tail;
311         return os << "]";
312     }
313 
314 private:
315     void fix_content();
316 };
317 
318 //===================================== Rvector --- XT_VECTOR (general lists)
319 
320 class Rvector : public Rexp {
321 protected:
322     Rexp **cont;
323     int count;
324 
325     // cached
326     char **strs;
327 public:
Rvector(Rmessage * msg)328     Rvector(Rmessage *msg) : Rexp(msg)
329     { cont=0; count=0; strs=0; fix_content(); }
330 
Rvector(unsigned int * ipos,Rmessage * imsg)331     Rvector(unsigned int *ipos, Rmessage *imsg) : Rexp(ipos, imsg)
332     { cont=0; count=0; strs=0; fix_content(); }
333 
334     virtual ~Rvector();
335 
336     char **strings();
337     int indexOf(Rexp *exp);
338     int indexOfString(const char *str);
length()339     virtual Rsize_t length() { return (Rsize_t) count; }
340 
stringAt(int i)341     char *stringAt(int i) {
342         if (i < 0 || i >= count || !cont[i] || cont[i]->type != XT_STR) return 0;
343         return ((Rstring*)cont[i])->string();
344     }
345 
elementAt(int i)346     Rexp *elementAt(int i) {
347 	return (i < 0 || i >= count || !cont[i]) ? 0 : cont[i];
348     }
349 
350     Rexp* byName(const char *name);
351 
os_print(std::ostream & os)352     virtual std::ostream& os_print (std::ostream& os) {
353         os << "Rvector[count=" << count << ":";
354         int i=0;
355         while (i<count) {
356             if (cont[i]) os << *cont[i]; else os << "NULL";
357             i++;
358             if (i<count) os << ",";
359         }
360         return os << "]";
361     }
362 private:
363     int capacity;
364     void fix_content();
365 };
366 
367 //===================================== Rconnection ---- Rserve interface class
368 
369 class Rconnection;
370 
371 class Rsession {
372 protected:
373     char *host_;
374     int port_;
375     char key_[32];
376 
377 public:
Rsession(const char * host,int port,const char key[32])378     Rsession(const char *host, int port, const char key[32]) {
379 	host_ = host ? strdup(host) : 0;
380 	port_ = port;
381 	memcpy(key_, key, 32);
382     }
383 
~Rsession()384     ~Rsession() {
385 	if (host_) free(host_);
386     }
387 
host()388     const char *host() { return host_; }
port()389     int port() { return port_; }
key()390     const char *key() { return key_; }
391 };
392 
393 class Rconnection {
394 protected:
395     char *host;
396     int  port;
397     SOCKET s;
398     int  family;
399     int auth;
400     char salt[2];
401     char *session_key;
402 
403 public:
404     /** host - either host name or unix socket path
405         port - either TCP port or -1 if unix sockets should be used */
406     Rconnection(const char *host="127.0.0.1", int port=default_Rsrv_port);
407     Rconnection(Rsession *session);
408 
409     virtual ~Rconnection();
410 
411     int connect();
412     int disconnect();
413 
414     /**--- low-level functions (should not be used directly) --- */
415 
416     int request(Rmessage *msg, int cmd, int len=0, void *par=0);
417     int request(Rmessage *targetMsg, Rmessage *contents);
418 
419     /** --- high-level functions --- */
420 
421     int assign(const char *symbol, Rexp *exp);
422     int voidEval(const char *cmd);
423     Rexp *eval(const char *cmd, int *status=0, int opt=0);
424     int login(const char *user, const char *pwd);
425     int shutdown(const char *key);
426 
427     /*      ( I/O functions )     */
428     int openFile(const char *fn);
429     int createFile(const char *fn);
430     int readFile(char *buf, unsigned int len);
431     int writeFile(const char *buf, unsigned int len);
432     int closeFile();
433     int removeFile(const char *fn);
434 
435     /* session methods - results of detach [if not NULL] must be deleted by the caller when no longer needed! */
436     Rsession *detachedEval(const char *cmd, int *status = 0);
437     Rsession *detach(int *status = 0);
438     // sessions are resumed using resume() method of the Rsession object
439 
440 #ifdef CMD_ctrl
441     /* server control functions (need Rserve 0.6-0 or higher) */
442     int serverEval(const char *cmd);
443     int serverSource(const char *fn);
444     int serverShutdown();
445 #endif
446 };
447 
448 #endif
449