Module: Rserve::Protocol

Included in:
Connection, REXPFactory, Session, Talk
Defined in:
lib/rserve/protocol.rb,
lib/rserve/protocol/rexpfactory.rb

Overview

This module encapsulates methods and constants related to QAP1 protocol used by Rserv. Follows almost exactly the interface on RTalk class on Java version, except for use of undescores instead of CamelCase Implementation could differ if a cleaner/faster ruby version is available

Policy: No other class should know about the internal of protocol! See Rtalk class on Java version.

Defined Under Namespace

Classes: REXPFactory

Constant Summary collapse

CMD_RESP =

Defines from Rsrv.h

0x010000
RESP_OK =

all responses have this flag set

(CMD_RESP|0x0001)
RESP_ERR =

command failed, check stats code attached string may describe the error

(CMD_RESP|0x0002)
ERR_auth_failed =

auth.failed or auth.requested but no login came. in case of authentification failure due to name/pwd mismatch, server may send CMD_accessDenied instead

0x41
ERR_conn_broken =

connection closed or broken packet killed it */

0x42
ERR_inv_cmd =

unsupported/invalid command */

0x43
ERR_inv_par =

some parameters are invalid */

0x44
ERR_Rerror =

R-error occured, usually followed by connection shutdown */

0x45
ERR_IOerror =

I/O error */

0x46
ERR_notOpen =

attempt to perform fileRead/Write on closed file */

0x47
ERR_accessDenied =

this answer is also valid on CMD_login; otherwise it’s sent if the server deosn;t allow the user to issue the specified command. (e.g. some server admins may block file I/O operations for some users)

0x48
ERR_unsupportedCmd =

unsupported command */

0x49
ERR_unknownCmd =

unknown command - the difference between unsupported and unknown is that unsupported commands are known to the server but for some reasons (e.g. platform dependent) it’s not supported. unknown commands are simply not recognized by the server at all. */

0x4a
ERR_data_overflow =

incoming packet is too big. currently there is a limit as of the size of an incoming packet. */

0x4b
ERR_object_too_big =

the requested object is too big to be transported in that way. If received after CMD_eval then the evaluation itself was successful. optional parameter is the size of the object

0x4c
ERR_out_of_mem =

out of memory. the connection is usually closed after this error was sent

0x4d
ERR_ctrl_closed =

control pipe to the master process is closed or broken

0x4e
ERR_session_busy =

session is still busy */

0x50
ERR_detach_failed =

unable to detach session (cannot determine peer IP or problems creating a listening socket for resume) */

0x51
CMD_login =

“namenpwd” : - */

0x001
CMD_voidEval =

string : - */

0x002
CMD_eval =

string : encoded SEXP */

0x003
CMD_shutdown =
admin-pwd

: - */

0x004
CMD_openFile =

/* file I/O routines. server may answe */

0x010
CMD_createFile =

fn : - */

0x011
CMD_closeFile =

fn : - */

0x012
CMD_readFile =
  • : - */

0x013
CMD_writeFile =

server is free to choose any value - usually it uses the size of its static buffer */

0x014
CMD_removeFile =

data : - */

0x015
CMD_setSEXP =

/* object manipulation */

0x020
CMD_assignSEXP =

string(name), REXP : - */

0x021
CMD_detachSession =

/* session management (since 0.4-0) */

0x030
CMD_detachedVoidEval =

: session key */

0x031
CMD_attachSession =

string : session key; doesn’t */

0x032
CMD_ctrl =

control commands (since 0.6-0) - passed on to the master process */ Note: currently all control commands are asychronous, i.e. RESP_OK indicates that the command was enqueued in the master pipe, but there is no guarantee that it will be processed. Moreover non-forked connections (e.g. the default debug setup) don’t process any control commands until the current client connection is closed so the connection issuing the control command will never see its result.

0x40
CMD_ctrlEval =

– not a command - just a constant – */

0x42
CMD_ctrlSource =

string : - */

0x45
CMD_ctrlShutdown =

string : - */

0x44
CMD_setBufferSize =

/* ‘internal’ commands (since 0.1-9) */

0x081
CMD_setEncoding =
int sendBufSize

this commad allow clients to request bigger buffer sizes if large data is to be transported from Rserve to the client. (incoming buffer is resized automatically) */

0x082
CMD_SPECIAL_MASK =

/* special commands - the payload of packages with this mask does not contain defined parameters */

0xf0
CMD_serEval =

serialized eval - the packets are raw serialized data without data header */

0xf5
CMD_serAssign =

serialized assign - serialized list with [[1]]=name, [[2]]=value */

0xf6
CMD_serEEval =

serialized expression eval - like serEval with one additional evaluation round */

0xf7
DT_INT =

data types for the transport protocol (QAP1)do NOT confuse with XT_.. values.

1
DT_CHAR =

int */

2
DT_DOUBLE =

char */

3
DT_STRING =

double */

4
DT_BYTESTREAM =

0 terminted string */

5
DT_SEXP =

stream of bytes (unlike DT_STRING may contain 0) */

10
DT_ARRAY =

encoded SEXP */

11
DT_LARGE =

array of objects (i.e. first 4 bytes specify how many subsequent objects are part of the array; 0 is legitimate) */

64
ERROR_DESCRIPTIONS =

new in 0102: if this flag is set then the length of the object is coded as 56-bit integer enlarging the header by 4 bytes */

{
  ERR_auth_failed=>'auth.failed or auth.requested but no login came',
  ERR_conn_broken=>'connection closed or broken packet killed it',
  ERR_inv_cmd=>"unsupported/invalid command",
  ERR_inv_par=>"some parameters are invalid",
  ERR_Rerror=>"R-error",
  ERR_IOerror=>"I/O error",
  ERR_notOpen=>"attempt to perform fileRead/Write  on closed file",
  ERR_accessDenied=>"Access denied",
  ERR_unsupportedCmd=>"unsupported command",
  ERR_unknownCmd=>"unknown command",
  ERR_data_overflow=>"data overflow",
  ERR_object_too_big=>"requested object is too big",
  ERR_out_of_mem=>"out of memory",
  ERR_ctrl_closed=>"control pipe to the master process is closed or broken",
  ERR_session_busy=>"session still busy",
  ERR_detach_failed=>"unable to detach seesion"
}
MAX_LONG_SIGNED =

I have to use to support different archs

2**31
MAX_LONG_UNSIGNED =
2**32

Instance Method Summary collapse

Instance Method Details

#doubleToRawLongBits(double) ⇒ Object



223
224
225
# File 'lib/rserve/protocol.rb', line 223

def doubleToRawLongBits(double)
  [double].pack("d").unpack("Q")[0]
end

#get_int(buf, o) ⇒ Object

converts bit-wise stored int in Intel-endian form into ruby int

make sure that the buffer is big enough

Parameters:

  • buf

    buffer containg the representation

  • o

    offset where to start (4 bytes will be used)

Returns:

  • the int value. no bounds checking is done so you need to



172
173
174
# File 'lib/rserve/protocol.rb', line 172

def get_int(buf, o)
  buf[o,4].pack("C*").unpack("l")[0]
end

#get_int_original(buf, o) ⇒ Object

:nodoc:



175
176
177
178
# File 'lib/rserve/protocol.rb', line 175

def get_int_original(buf,o) # :nodoc:
  v=((buf[o]&255)|((buf[o+1]&255)<<8)|((buf[o+2]&255)<<16)|((buf[o+3]&255)<<24))
  v >= MAX_LONG_SIGNED ? v-MAX_LONG_UNSIGNED : v
end

#get_len(buf, o) ⇒ Object

converts bit-wise stored length from a header. “long” format is supported up to 32-bit

Parameters:

  • buf

    buffer

  • o

    offset of the header (length is at o+1)

Returns:

  • length */



184
185
186
187
188
189
190
191
192
193
# File 'lib/rserve/protocol.rb', line 184

def get_len(buf, o)
  # // "long" format; still - we support 32-bit only
  if  ((buf[o]&64)>0)
    #p "buf:#{buf} --- o: #{o} -- [#{buf[o+4]}]"
    raise "Buffer without enough values" if buf[o+4].nil?
    (buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)|((buf[o+4]&255)<<24)
  else
    (buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)
  end
end

#get_long(buf, o) ⇒ Object

converts bit-wise Intel-endian format into long

Parameters:

  • buf

    buffer

  • o

    offset (8 bytes will be used)

Returns:

  • long value */



199
200
201
# File 'lib/rserve/protocol.rb', line 199

def get_long(buf, o)
  buf[o,8].pack("CCCCCCCC").unpack("Q")[0]
end

#get_long_original(buf, o) ⇒ Object

:nodoc:



202
203
204
205
206
207
# File 'lib/rserve/protocol.rb', line 202

def get_long_original(buf,o)   #:nodoc:
  low=(get_int(buf,o))&0xffffffff;
  hi=(get_int(buf,o+4))&0xffffffff;
  hi<<=32; hi|=low;
  hi
end

#longBitsToDouble(bits) ⇒ Object



209
210
211
# File 'lib/rserve/protocol.rb', line 209

def longBitsToDouble(bits)
  (bits==LONG_NA) ? Rserve::REXP::Double::NA : [bits].pack("Q").unpack("d")[0]
end

#longBitsToDouble_old(bits) ⇒ Object

Complete version of longBitsToDouble, as Java documentation established



214
215
216
217
218
219
220
221
# File 'lib/rserve/protocol.rb', line 214

def longBitsToDouble_old(bits) # :nodoc:
  s = ((bits >> 63) == 0) ? 1 : -1;
  e = ((bits >> 52) & 0x7ff)
  m = (e == 0) ?
  (bits & 0xfffffffffffff) << 1 :
  (bits & 0xfffffffffffff) | 0x10000000000000;
  s*m*2**(e-1075)
end

#new_hdr(ty, len) ⇒ Object

creates a new header according to the type and length of the parameter

Parameters:

  • ty

    type/cmd/resp byte

  • len

    length



159
160
161
162
163
# File 'lib/rserve/protocol.rb', line 159

def new_hdr(ty, len)
  hdr=Array.new(  (len>0xfffff0)?8:4)
  set_hdr(ty,len,hdr,0);
  hdr
end

#set_hdr(ty, len, buf, o) ⇒ Object

writes cmd/resp/type byte + 3/7 bytes len into a byte buffer at specified offset.

Parameters:

  • ty

    type/cmd/resp byte

  • len

    length

  • buf

    buffer

  • o

    offset

Returns:

  • offset in buf just after the header. Please note that since Rserve 0.3 the header can be either 4 or 8 bytes long, depending on the len parameter.



143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/rserve/protocol.rb', line 143

def set_hdr(ty, len, buf, o)
  buf[o]=((ty&255)|((len>0xfffff0) ? DT_LARGE : 0)); o+=1;
  buf[o]=(len&255); o+=1;
  buf[o]=((len&0xff00)>>8); o+=1;
  buf[o]=((len&0xff0000)>>16); o+=1;
  if (len>0xfffff0)  # for large data we need to set the next 4 bytes as well
    buf[o]=((len&0xff000000)>>24); o+=1;
    buf[o]=0; o+=1; # since len is int, we get 32-bits only
    buf[o]=0; o+=1;
    buf[o]=0; o+=1;
  end
  o
end

#set_int(v, buf, o) ⇒ Object

writes bit-wise int to a byte buffer at specified position in Intel-endian form Internal: byte buffer will be the result of unpack(“CCCC”) an integer.

Parameters:

  • v

    value to be written

  • buf

    buffer

  • o

    offset in the buffer to start at. An int takes always 4 bytes */



130
131
132
133
134
135
# File 'lib/rserve/protocol.rb', line 130

def  set_int(v, buf, o)
  buf[o]=(v&255);o+=1
  buf[o]=((v&0xff00)>>8); o+=1
  buf[o]=((v&0xff0000)>>16); o+=1
  buf[o]=((v&0xff000000)>>24);
end

#set_long(l, buf, o) ⇒ Object



226
227
228
229
# File 'lib/rserve/protocol.rb', line 226

def set_long(l, buf, o)
  set_int((l&0xffffffff), buf, o)
  set_int((l>>32),buf,o+4)
end