libdap++  Updated for version 3.14.0
XDRStreamMarshaller.cc
Go to the documentation of this file.
1 // XDRStreamMarshaller.cc
2 
3 // -*- mode: c++; c-basic-offset:4 -*-
4 
5 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
6 // Access Protocol.
7 
8 // Copyright (c) 2002,2003 OPeNDAP, Inc.
9 // Author: Patrick West <pwest@ucar.edu>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 // (c) COPYRIGHT URI/MIT 1994-1999
28 // Please read the full copyright statement in the file COPYRIGHT_URI.
29 //
30 // Authors:
31 // pwest Patrick West <pwest@ucar.edu>
32 
33 #include "config.h"
34 
35 #include "XDRStreamMarshaller.h"
36 
37 #include <iostream>
38 #include <sstream>
39 #include <iomanip>
40 
41 using namespace std;
42 
43 //#define DODS_DEBUG 1
44 
45 #include "Vector.h"
46 #include "util.h"
47 #include "debug.h"
48 
49 namespace libdap {
50 
51 char *XDRStreamMarshaller::d_buf = 0;
52 
53 #define XDR_DAP_BUFF_SIZE 256
54 
63 XDRStreamMarshaller::XDRStreamMarshaller(ostream &out) : d_out(out)
64 {
65  if (!d_buf)
66  d_buf = (char *) malloc(XDR_DAP_BUFF_SIZE);
67  if (!d_buf)
68  throw Error("Failed to allocate memory for data serialization.");
69 
70  xdrmem_create( &d_sink, d_buf, XDR_DAP_BUFF_SIZE, XDR_ENCODE);
71 
72 #if CHECKSUMS
73  if (checksum) {
74  _MD_CTX = EVP_MD_CTX_create();
75  }
76 #endif
77 }
78 
79 XDRStreamMarshaller::XDRStreamMarshaller() :
80  Marshaller(), d_out(cout)
81 {
82  throw InternalErr(__FILE__, __LINE__, "Default constructor not implemented.");
83 }
84 
85 XDRStreamMarshaller::XDRStreamMarshaller(const XDRStreamMarshaller &m) :
86  Marshaller(m), d_out(cout)
87 {
88  throw InternalErr(__FILE__, __LINE__, "Copy constructor not implemented.");
89 }
90 
91 XDRStreamMarshaller &
92 XDRStreamMarshaller::operator=(const XDRStreamMarshaller &)
93 {
94  throw InternalErr(__FILE__, __LINE__, "Copy operator not implemented.");
95 
96  return *this;
97 }
98 
100 {
101  xdr_destroy(&d_sink);
102 
103 #if CHECKSUMS
104  if (_MD_CTX)
105  EVP_MD_CTX_destroy(_MD_CTX);
106 #endif
107 }
108 
109 #if 0
110 
114 void XDRStreamMarshaller::reset_checksum()
115 {
116 #if CHECKSUMS
117  if (_MD_CTX == 0)
118  throw InternalErr( __FILE__, __LINE__, "reset_checksum() called by checksum is not enabled.");
119 
120  if (EVP_DigestInit_ex(_MD_CTX, EVP_sha1(), 0) == 0)
121  throw Error("Failed to initialize checksum object.");
122 
123  _checksum_ctx_valid = true;
124 #endif
125 }
126 
132 string XDRStreamMarshaller::get_checksum()
133 {
134 #if CHECKSUMS
135  if (_MD_CTX == 0)
136  throw InternalErr(__FILE__, __LINE__, "checksum_init() called by checksum is not enabled.");
137 
138  if (_checksum_ctx_valid) {
139  // '...Final()' 'erases' the context so the next call without a reset
140  // returns a bogus value.
141  _checksum_ctx_valid = false;
142 
143  vector<unsigned char> md(EVP_MAX_MD_SIZE);
144  unsigned int md_len;
145  if (EVP_DigestFinal_ex(_MD_CTX, &md[0], &md_len) == 0)
146  throw Error("Error computing the checksum (checksum computation).");
147 
148  ostringstream oss;
149  oss.setf(ios::hex, ios::basefield);
150  for (unsigned int i = 0; i < md_len; ++i) {
151  oss << setfill('0') << setw(2) << (unsigned int) md[i];
152  }
153 
154  _checksum = oss.str();
155  }
156 
157  return _checksum;
158 #else
159  return "";
160 #endif
161 }
162 
163 void XDRStreamMarshaller::checksum_update(const void *data, unsigned long len)
164 {
165 #if CHECKSUMS
166  if (_MD_CTX == 0)
167  throw InternalErr( __FILE__, __LINE__, "checksum_init() called by checksum is not enabled.");
168 
169  if (!_checksum_ctx_valid)
170  throw InternalErr( __FILE__, __LINE__, "Invalid checksum context (checksum update).");
171 
172  if (EVP_DigestUpdate(_MD_CTX, data, len) == 0) {
173  _checksum_ctx_valid = false;
174  throw Error("Error computing the checksum (checksum update).");
175  }
176 #endif
177 }
178 #endif
179 
181 {
182 #if CHECKSUM
183  if (_MD_CTX)
184  checksum_update(&val, sizeof(dods_byte));
185 #endif
186  DBG( std::cerr << "put_byte: " << val << std::endl );
187 
188  if (!xdr_setpos( &d_sink, 0 ))
189  throw Error("Network I/O Error. Could not send byte data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
190 
191  if (!xdr_char(&d_sink, (char *) &val))
192  throw Error("Network I/O Error. Could not send byte data.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
193 
194  unsigned int bytes_written = xdr_getpos( &d_sink );
195  if (!bytes_written)
196  throw Error("Network I/O Error. Could not send byte data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
197 
198  d_out.write(d_buf, bytes_written);
199 }
200 
202 {
203 #if 0
204  if (_MD_CTX)
205  checksum_update(&val, sizeof(dods_int16));
206 #endif
207  if (!xdr_setpos( &d_sink, 0 ))
208  throw Error("Network I/O Error. Could not send int 16 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
209 
210  if (!XDR_INT16(&d_sink, &val))
211  throw Error("Network I/O Error. Could not send int 16 data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
212 
213  unsigned int bytes_written = xdr_getpos( &d_sink );
214  if (!bytes_written)
215  throw Error("Network I/O Error. Could not send int 16 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
216 
217  d_out.write(d_buf, bytes_written);
218 }
219 
221 {
222 #if 0
223  if (_MD_CTX)
224  checksum_update(&val, sizeof(dods_int32));
225 #endif
226  if (!xdr_setpos( &d_sink, 0 ))
227  throw Error("Network I/O Error. Could not send int 32 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
228 
229  if (!XDR_INT32(&d_sink, &val))
230  throw Error("Network I/O Error. Culd not read int 32 data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
231 
232  unsigned int bytes_written = xdr_getpos( &d_sink );
233  if (!bytes_written)
234  throw Error("Network I/O Error. Could not send int 32 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
235 
236  d_out.write(d_buf, bytes_written);
237 }
238 
240 {
241 #if 0
242  if (_MD_CTX)
243  checksum_update(&val, sizeof(dods_float32));
244 #endif
245  if (!xdr_setpos( &d_sink, 0 ))
246  throw Error("Network I/O Error. Could not send float 32 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
247 
248  if (!xdr_float(&d_sink, &val))
249  throw Error("Network I/O Error. Could not send float 32 data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
250 
251  unsigned int bytes_written = xdr_getpos( &d_sink );
252  if (!bytes_written)
253  throw Error("Network I/O Error. Could not send float 32 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
254 
255  d_out.write(d_buf, bytes_written);
256 }
257 
259 {
260 #if 0
261  if (_MD_CTX)
262  checksum_update(&val, sizeof(dods_float64));
263 #endif
264  if (!xdr_setpos( &d_sink, 0 ))
265  throw Error("Network I/O Error. Could not send float 64 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
266 
267  if (!xdr_double(&d_sink, &val))
268  throw Error("Network I/O Error. Could not send float 64 data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
269 
270  unsigned int bytes_written = xdr_getpos( &d_sink );
271  if (!bytes_written)
272  throw Error("Network I/O Error. Could not send float 64 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
273 
274  d_out.write(d_buf, bytes_written);
275 }
276 
278 {
279 #if 0
280  if (_MD_CTX)
281  checksum_update(&val, sizeof(dods_uint16));
282 #endif
283  if (!xdr_setpos( &d_sink, 0 ))
284  throw Error("Network I/O Error. Could not send uint 16 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
285 
286  if (!XDR_UINT16(&d_sink, &val))
287  throw Error("Network I/O Error. Could not send uint 16 data. This may be due to a\nbug in libdap or a problem with the network connection.");
288 
289  unsigned int bytes_written = xdr_getpos( &d_sink );
290  if (!bytes_written)
291  throw Error("Network I/O Error. Could not send uint 16 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
292 
293  d_out.write(d_buf, bytes_written);
294 }
295 
297 {
298 #if 0
299  if (_MD_CTX)
300  checksum_update(&val, sizeof(dods_uint32));
301 #endif
302  if (!xdr_setpos( &d_sink, 0 ))
303  throw Error("Network I/O Error. Could not send uint 32 data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
304 
305  if (!XDR_UINT32(&d_sink, &val))
306  throw Error("Network I/O Error. Could not send uint 32 data. This may be due to a\nbug in libdap or a problem with the network connection.");
307 
308  unsigned int bytes_written = xdr_getpos( &d_sink );
309  if (!bytes_written)
310  throw Error("Network I/O Error. Could not send uint 32 data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
311 
312  d_out.write(d_buf, bytes_written);
313 }
314 
315 void XDRStreamMarshaller::put_str(const string &val)
316 {
317 #if 0
318  if (_MD_CTX)
319  checksum_update(val.c_str(), val.length());
320 #endif
321  int size = val.length() + 8;
322 #if 0
323  char *str_buf = (char *) malloc(size);
324 
325  if (!str_buf) {
326  throw Error("Failed to allocate memory for string data serialization.");
327  }
328 #endif
329 
330  XDR str_sink;
331  vector<char> str_buf(size);
332  //XDR *str_sink = new XDR;
333  try {
334  xdrmem_create(&str_sink, &str_buf[0], size, XDR_ENCODE);
335 
336  if (!xdr_setpos( &str_sink, 0 ))
337  throw Error(
338  "Network I/O Error. Could not send string data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
339 
340  const char *out_tmp = val.c_str();
341  if (!xdr_string(&str_sink, (char **) &out_tmp, size))
342  throw Error(
343  "Network I/O Error. Could not send string data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
344 
345  unsigned int bytes_written = xdr_getpos( &str_sink );
346  if (!bytes_written)
347  throw Error(
348  "Network I/O Error. Could not send string data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
349 
350  d_out.write(&str_buf[0], bytes_written);
351 
352  xdr_destroy(&str_sink);
353  }
354  catch (...) {
355  xdr_destroy(&str_sink);
356  throw;
357  }
358 }
359 
360 void XDRStreamMarshaller::put_url(const string &val)
361 {
362  put_str(val);
363 }
364 
365 void XDRStreamMarshaller::put_opaque(char *val, unsigned int len)
366 {
367 #if 0
368  if (_MD_CTX)
369  checksum_update(&val, len);
370 #endif
371  if (len > XDR_DAP_BUFF_SIZE)
372  throw Error("Network I/O Error. Could not send opaque data - length of opaque data larger than allowed");
373 
374  if (!xdr_setpos( &d_sink, 0 ))
375  throw Error("Network I/O Error. Could not send opaque data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
376 
377  if (!xdr_opaque(&d_sink, val, len))
378  throw Error("Network I/O Error. Could not send opaque data.\nThis may be due to a bug in libdap, on the server or a\nproblem with the network connection.");
379 
380  unsigned int bytes_written = xdr_getpos( &d_sink );
381  if (!bytes_written)
382  throw Error("Network I/O Error. Could not send opaque data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
383 
384  d_out.write(d_buf, bytes_written);
385 }
386 
388 {
389 #if 0
390  if (_MD_CTX)
391  checksum_update(&val, sizeof(int));
392 #endif
393  if (!xdr_setpos( &d_sink, 0 ))
394  throw Error("Network I/O Error. Could not send int data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
395 
396  if (!xdr_int(&d_sink, &val))
397  throw Error("Network I/O Error(1). Could not send int data.\nThis may be due to a bug in libdap or a\nproblem with the network connection.");
398 
399  unsigned int bytes_written = xdr_getpos( &d_sink );
400  if (!bytes_written)
401  throw Error("Network I/O Error. Could not send int data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
402 
403  d_out.write(d_buf, bytes_written);
404 }
405 
406 void XDRStreamMarshaller::put_vector(char *val, int num, Vector &)
407 {
408  if (!val) throw InternalErr(__FILE__, __LINE__, "Could not send byte vector data. Buffer pointer is not set.");
409 #if 0
410  if (_MD_CTX)
411  checksum_update(val, num);
412 #endif
413  // write the number of members of the array being written and then set the position to 0
414  put_int(num);
415 
416  // this is the word boundary for writing xdr bytes in a vector.
417  const unsigned int add_to = 8;
418 #if 0
419  char *byte_buf = (char *) malloc(num + add_to);
420  if (!byte_buf) throw Error("Failed to allocate memory for byte vector data serialization.");
421 #endif
422  vector<char> byte_buf(num + add_to);
423  XDR byte_sink;
424  try {
425  xdrmem_create(&byte_sink, &byte_buf[0], num + add_to, XDR_ENCODE);
426  if (!xdr_setpos( &byte_sink, 0 ))
427  throw Error(
428  "Network I/O Error. Could not send byte vector data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
429 
430  if (!xdr_bytes(&byte_sink, (char **) &val, (unsigned int *) &num, num + add_to))
431  throw Error(
432  "Network I/O Error(2). Could not send byte vector data.\nThis may be due to a bug in libdap or a\nproblem with the network connection.");
433 
434  unsigned int bytes_written = xdr_getpos( &byte_sink );
435  if (!bytes_written)
436  throw Error(
437  "Network I/O Error. Could not send byte vector data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
438 
439  d_out.write(&byte_buf[0], bytes_written);
440 
441  xdr_destroy(&byte_sink);
442  }
443  catch (...) {
444  xdr_destroy(&byte_sink);
445  throw;
446  }
447 }
448 
449 void
450 XDRStreamMarshaller::put_vector( char *val, int num, int width, Vector &vec )
451 {
452  put_vector(val, num, width, vec.var()->type());
453 }
454 
455 
456 void XDRStreamMarshaller::put_vector(char *val, unsigned int num, int width, Type type)
457 {
458  if (!val) throw InternalErr(__FILE__, __LINE__, "Buffer pointer is not set.");
459 #if CHECKSUM
460  if (_MD_CTX)
461  checksum_update(val, num * width);
462 #endif
463  // write the number of array members being written, then set the position back to 0
464  put_int(num);
465 
466  int use_width = width;
467  if (use_width < 4) use_width = 4;
468 
469  // the size is the number of elements num times the width of each
470  // element, then add 4 bytes for the number of elements
471  int size = (num * use_width) + 4;
472 
473  // allocate enough memory for the elements
474 #if 0
475  char *vec_buf = (char *) malloc(size);
476  if (!vec_buf)
477  throw Error("Failed to allocate memory for vector data serialization.");
478 #endif
479  vector<char> vec_buf(size);
480  XDR vec_sink;
481  try {
482  xdrmem_create(&vec_sink, &vec_buf[0], size, XDR_ENCODE);
483 
484  // set the position of the sink to 0, we're starting at the beginning
485  if (!xdr_setpos( &vec_sink, 0 ))
486  throw Error(
487  "Network I/O Error. Could not send vector data - unable to set stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
488 
489  // write the array to the buffer
490  if (!xdr_array(&vec_sink, (char **) &val, (unsigned int *) &num, size, width, XDRUtils::xdr_coder(type)))
491  throw Error(
492  "Network I/O Error(2). Could not send vector data.\nThis may be due to a bug in libdap or a\nproblem with the network connection.");
493 
494  // how much was written to the buffer
495  unsigned int bytes_written = xdr_getpos( &vec_sink );
496  if (!bytes_written)
497  throw Error(
498  "Network I/O Error. Could not send vector data - unable to get stream position.\nThis may be due to a bug in DODS, on the server or a\nproblem with the network connection.");
499 
500  // write that much out to the output stream
501  d_out.write(&vec_buf[0], bytes_written);
502 
503  xdr_destroy(&vec_sink);
504  }
505  catch (...) {
506  xdr_destroy(&vec_sink);
507  throw;
508  }
509 }
510 
511 void XDRStreamMarshaller::dump(ostream &strm) const
512 {
513  strm << DapIndent::LMarg << "XDRStreamMarshaller::dump - (" << (void *) this << ")" << endl;
514 }
515 
516 } // namespace libdap
517 
#define XDR_UINT32
Definition: config.h:968
uint8_t dods_byte
virtual void dump(ostream &strm) const
dump the contents of this object to the specified ostream
Holds a one-dimensional collection of DAP2 data types.
Definition: Vector.h:80
#define XDR_UINT16
Definition: config.h:965
virtual void put_int16(dods_int16 val)
Type
Identifies the data type.
Definition: Type.h:94
Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:306
virtual void put_uint16(dods_uint16 val)
#define XDR_INT32
Definition: config.h:962
virtual void put_float64(dods_float64 val)
uint16_t dods_uint16
const int XDR_DAP_BUFF_SIZE
A class for software fault reporting.
Definition: InternalErr.h:64
virtual void put_byte(dods_byte val)
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=0)
Definition: Vector.cc:387
#define DBG(x)
Definition: debug.h:58
double dods_float64
virtual void put_float32(dods_float32 val)
virtual void put_opaque(char *val, unsigned int len)
uint32_t dods_uint32
virtual void put_str(const string &val)
#define XDR_INT16
Definition: config.h:959
static ostream & LMarg(ostream &strm)
Definition: DapIndent.cc:80
int16_t dods_int16
abstract base class used to marshal/serialize dap data objects
Definition: Marshaller.h:53
virtual void put_vector(char *val, int num, Vector &vec)
static xdrproc_t xdr_coder(const Type &t)
Returns a function used to encode elements of an array.
Definition: XDRUtils.cc:145
A class for error processing.
Definition: Error.h:90
virtual void put_int32(dods_int32 val)
virtual void put_uint32(dods_uint32 val)
virtual void put_url(const string &val)
int32_t dods_int32