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