libdap++  Updated for version 3.11.7
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "XDRStreamMarshaller.h"
34 
35 #include <iostream>
36 #include <sstream>
37 #include <iomanip>
38 
39 using namespace std;
40 
41 //#define DODS_DEBUG 1
42 
43 #include "Vector.h"
44 #include "util.h"
45 #include "debug.h"
46 
47 namespace libdap {
48 
49 char *XDRStreamMarshaller::_buf = 0;
50 
51 #define XDR_DAP_BUFF_SIZE 256
52 
61 XDRStreamMarshaller::XDRStreamMarshaller(ostream &out, bool checksum, bool write_data) :
62  _sink(0), _out(out), _md5(0), _write_data(write_data), _checksum_ctx_valid(false)
63 {
64  if (!_buf)
65  _buf = (char *) malloc(XDR_DAP_BUFF_SIZE);
66  if (!_buf)
67  throw Error("Failed to allocate memory for data serialization.");
68 
69  _sink = new XDR;
70  xdrmem_create(_sink, _buf, XDR_DAP_BUFF_SIZE, XDR_ENCODE);
71 
72  if (checksum) {
73  _md5 = reinterpret_cast<MD5_CTX*>(new char[sizeof(MD5_CTX)]);
74  }
75 }
76 
77 XDRStreamMarshaller::XDRStreamMarshaller() :
78  Marshaller(), _sink(0), _out(cout)
79 {
80  throw InternalErr(__FILE__, __LINE__, "Default constructor not implemented.");
81 }
82 
83 XDRStreamMarshaller::XDRStreamMarshaller(const XDRStreamMarshaller &m) :
84  Marshaller(m), _sink(0), _out(cout)
85 {
86  throw InternalErr(__FILE__, __LINE__, "Copy constructor not implemented.");
87 }
88 
89 XDRStreamMarshaller &
90 XDRStreamMarshaller::operator=(const XDRStreamMarshaller &)
91 {
92  throw InternalErr(__FILE__, __LINE__, "Copy operator not implemented.");
93 
94  return *this;
95 }
96 
98 {
99  if (_sink)
100  xdr_destroy(_sink); //delete_xdrstdio(_sink);
101 
102  // xdr_destroy knows nothing about the memory we allocated
103  delete _sink;
104  _sink = 0;
105 }
106 
112 {
113  if (_md5 == 0)
114  throw InternalErr( __FILE__, __LINE__, "checksum_init() called by checksum is not enabled.");
115 
116  if (MD5_Init(_md5) == 0)
117  throw Error("Error initializing the checksum buffer.");
118 
119  _checksum_ctx_valid = true;
120 }
121 
128 {
129  if (_md5 == 0)
130  throw InternalErr( __FILE__, __LINE__, "checksum_init() called by checksum is not enabled.");
131 
132  if (!_checksum_ctx_valid)
133  throw InternalErr( __FILE__, __LINE__, "Invalid checksum context.");
134 
135  // Setting this here ensures that we call get_checksum() only once for
136  // a context. The 'Final()' 'erases' the context so the next checksum is
137  // bogus.
138  _checksum_ctx_valid = false;
139 
140  vector<unsigned char> md(MD5_DIGEST_LENGTH);
141  if (MD5_Final(&md[0], _md5) == 0)
142  throw Error("Error computing the checksum.");
143 
144  ostringstream oss;
145  oss.setf ( ios::hex, ios::basefield );
146  for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
147  oss << setfill('0') << setw(2) << (unsigned int)md[i];
148  }
149 
150  return oss.str();
151 }
152 
153 void XDRStreamMarshaller::checksum_update(const void *data, unsigned long len)
154 {
155  if (_md5 == 0)
156  throw InternalErr( __FILE__, __LINE__, "checksum_init() called by checksum is not enabled.");
157 
158  if (!_checksum_ctx_valid)
159  throw InternalErr( __FILE__, __LINE__, "Invalid checksum context.");
160 
161  if (MD5_Update(_md5, data, len) == 0) {
162  _checksum_ctx_valid = false;
163  throw Error("Error computing the checksum.");
164  }
165 }
166 
168 {
169  if (_md5)
170  checksum_update(&val, sizeof(dods_byte));
171 
172  if (_write_data) {
173  DBG( std::cerr << "put_byte: " << val << std::endl );
174 
175  if (!xdr_setpos( _sink, 0 ))
176  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.");
177 
178  if (!xdr_char(_sink, (char *) &val))
179  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.");
180 
181  unsigned int bytes_written = xdr_getpos( _sink );
182  if (!bytes_written)
183  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.");
184 
185  _out.write(_buf, bytes_written);
186  }
187 }
188 
190 {
191  if (_md5)
192  checksum_update(&val, sizeof(dods_int16));
193 
194  if (_write_data) {
195  if (!xdr_setpos( _sink, 0 ))
196  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.");
197 
198  if (!XDR_INT16(_sink, &val))
199  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.");
200 
201  unsigned int bytes_written = xdr_getpos( _sink );
202  if (!bytes_written)
203  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.");
204 
205  _out.write(_buf, bytes_written);
206  }
207 }
208 
210 {
211  if (_md5)
212  checksum_update(&val, sizeof(dods_int32));
213 
214  if (_write_data) {
215  if (!xdr_setpos( _sink, 0 ))
216  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.");
217 
218  if (!XDR_INT32(_sink, &val))
219  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.");
220 
221  unsigned int bytes_written = xdr_getpos( _sink );
222  if (!bytes_written)
223  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.");
224 
225  _out.write(_buf, bytes_written);
226  }
227 }
228 
230 {
231  if (_md5)
232  checksum_update(&val, sizeof(dods_float32));
233 
234  if (_write_data) {
235  if (!xdr_setpos( _sink, 0 ))
236  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.");
237 
238  if (!xdr_float(_sink, &val))
239  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.");
240 
241  unsigned int bytes_written = xdr_getpos( _sink );
242  if (!bytes_written)
243  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.");
244 
245  _out.write(_buf, bytes_written);
246  }
247 }
248 
250 {
251  if (_md5)
252  checksum_update(&val, sizeof(dods_float64));
253 
254  if (_write_data) {
255  if (!xdr_setpos( _sink, 0 ))
256  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.");
257 
258  if (!xdr_double(_sink, &val))
259  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.");
260 
261  unsigned int bytes_written = xdr_getpos( _sink );
262  if (!bytes_written)
263  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.");
264 
265  _out.write(_buf, bytes_written);
266  }
267 }
268 
270 {
271  if (_md5)
272  checksum_update(&val, sizeof(dods_uint16));
273 
274  if (_write_data) {
275  if (!xdr_setpos( _sink, 0 ))
276  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.");
277 
278  if (!XDR_UINT16(_sink, &val))
279  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.");
280 
281  unsigned int bytes_written = xdr_getpos( _sink );
282  if (!bytes_written)
283  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.");
284 
285  _out.write(_buf, bytes_written);
286  }
287 }
288 
290 {
291  if (_md5)
292  checksum_update(&val, sizeof(dods_uint32));
293 
294  if (_write_data) {
295  if (!xdr_setpos( _sink, 0 ))
296  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.");
297 
298  if (!XDR_UINT32(_sink, &val))
299  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.");
300 
301  unsigned int bytes_written = xdr_getpos( _sink );
302  if (!bytes_written)
303  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.");
304 
305  _out.write(_buf, bytes_written);
306  }
307 }
308 
309 void XDRStreamMarshaller::put_str(const string &val)
310 {
311  if (_md5)
312  checksum_update(val.c_str(), val.length());
313 
314  if (_write_data) {
315  int size = val.length() + 8;
316  // Replace this malloc with a vector<char>.
317  // ...and maybe elsewhere in this class... jhrg 3/9/12
318  char *str_buf = (char *) malloc(size);
319 
320  if (!str_buf) {
321  throw Error("Failed to allocate memory for string data serialization.");
322  }
323 
324  XDR *str_sink = new XDR;
325  xdrmem_create(str_sink, str_buf, size, XDR_ENCODE);
326 
327  if (!xdr_setpos( str_sink, 0 )) {
328  delete_xdrstdio(str_sink);
329  free(str_buf);
330  throw Error("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.");
331  }
332 
333  const char *out_tmp = val.c_str();
334  if (!xdr_string(str_sink, (char **) &out_tmp, size)) {
335  delete_xdrstdio(str_sink);
336  free(str_buf);
337  throw Error("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.");
338  }
339 
340  unsigned int bytes_written = xdr_getpos( str_sink );
341  if (!bytes_written) {
342  delete_xdrstdio(str_sink);
343  free(str_buf);
344  throw Error("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.");
345  }
346 
347  _out.write(str_buf, bytes_written);
348 
349  delete_xdrstdio(str_sink);
350  free(str_buf);
351  }
352 }
353 
354 void XDRStreamMarshaller::put_url(const string &val)
355 {
356  put_str(val);
357 }
358 
359 void XDRStreamMarshaller::put_opaque(char *val, unsigned int len)
360 {
361  if (_md5)
362  checksum_update(&val, len);
363 
364  if (_write_data) {
365  if (len > XDR_DAP_BUFF_SIZE)
366  throw Error("Network I/O Error. Could not send opaque data - length of opaque data larger than allowed");
367 
368  if (!xdr_setpos( _sink, 0 ))
369  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.");
370 
371  if (!xdr_opaque(_sink, val, len))
372  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.");
373 
374  unsigned int bytes_written = xdr_getpos( _sink );
375  if (!bytes_written)
376  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.");
377 
378  _out.write(_buf, bytes_written);
379  }
380 }
381 
383 {
384 #if 0
385  if (_md5)
386  checksum_update(&val, sizeof(int));
387 #endif
388  if (_write_data) {
389  if (!xdr_setpos( _sink, 0 ))
390  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.");
391 
392  if (!xdr_int(_sink, &val))
393  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.");
394 
395  unsigned int bytes_written = xdr_getpos( _sink );
396  if (!bytes_written)
397  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.");
398 
399  _out.write(_buf, bytes_written);
400  }
401 }
402 
403 void XDRStreamMarshaller::put_vector(char *val, int num, Vector &)
404 {
405  if (!val)
406  throw InternalErr(__FILE__, __LINE__, "Could not send byte vector data. Buffer pointer is not set.");
407 
408  if (_md5)
409  checksum_update(val, num);
410 
411  if (_write_data) {
412  // write the number of members of the array being written and then set the position to 0
413  put_int(num);
414 
415  // this is the word boundary for writing xdr bytes in a vector.
416  unsigned int add_to = 8;
417 
418  char *byte_buf = (char *) malloc(num + add_to);
419  if (!byte_buf) {
420  throw Error("Failed to allocate memory for byte vector data serialization.");
421  }
422 
423  XDR *byte_sink = new XDR;
424  xdrmem_create(byte_sink, byte_buf, num + add_to, XDR_ENCODE);
425 
426  if (!xdr_setpos( byte_sink, 0 )) {
427  delete_xdrstdio(byte_sink);
428  free(byte_buf);
429  throw Error("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.");
430  }
431 
432  if (!xdr_bytes(byte_sink, (char **) &val, (unsigned int *) &num, num + add_to)) {
433  delete_xdrstdio(byte_sink);
434  free(byte_buf);
435  throw Error("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.");
436  }
437 
438  unsigned int bytes_written = xdr_getpos( byte_sink );
439  if (!bytes_written) {
440  delete_xdrstdio(byte_sink);
441  free(byte_buf);
442  throw Error("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.");
443  }
444 
445  _out.write(byte_buf, bytes_written);
446 
447  delete_xdrstdio(byte_sink);
448  free(byte_buf);
449  }
450 }
451 
452 void XDRStreamMarshaller::put_vector(char *val, int num, int width, Vector &vec)
453 {
454  if (!val)
455  throw InternalErr(__FILE__, __LINE__, "Buffer pointer is not set.");
456 
457  if (_md5)
458  checksum_update(val, num * width);
459 
460  if (_write_data) {
461  // write the number of array members being written, then set the position back to 0
462  put_int(num);
463 
464  int use_width = width;
465  if (use_width < 4)
466  use_width = 4;
467 
468  // the size is the number of elements num times the width of each
469  // element, then add 4 bytes for the number of elements
470  int size = (num * use_width) + 4;
471 
472  // allocate enough memory for the elements
473  char *vec_buf = (char *) malloc(size);
474  if (!vec_buf) {
475  free(vec_buf);
476  throw Error("Failed to allocate memory for vector data serialization.");
477  }
478 
479  XDR *vec_sink = new XDR;
480  xdrmem_create(vec_sink, vec_buf, size, XDR_ENCODE);
481 
482  // set the position of the sink to 0, we're starting at the beginning
483  if (!xdr_setpos( vec_sink, 0 )) {
484  delete_xdrstdio(vec_sink);
485  free(vec_buf);
486  throw Error("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.");
487  }
488 
489  BaseType *var = vec.var();
490 
491  // write the array to the buffer
492  if (!xdr_array(vec_sink, (char **) &val, (unsigned int *) &num, size, width, XDRUtils::xdr_coder(var->type()))) {
493  delete_xdrstdio(vec_sink);
494  free(vec_buf);
495  throw Error("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.");
496  }
497 
498  // how much was written to the buffer
499  unsigned int bytes_written = xdr_getpos( vec_sink );
500  if (!bytes_written) {
501  delete_xdrstdio(vec_sink);
502  free(vec_buf);
503  throw Error("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.");
504  }
505 
506  // write that much out to the output stream
507  _out.write(vec_buf, bytes_written);
508 
509  delete_xdrstdio(vec_sink);
510  free(vec_buf);
511  }
512 }
513 
514 void XDRStreamMarshaller::dump(ostream &strm) const
515 {
516  strm << DapIndent::LMarg << "XDRStreamMarshaller::dump - (" << (void *) this << ")" << endl;
517 }
518 
519 } // namespace libdap
520