1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <Util.h>
6 #include <Ice/LocalException.h>
7 #include <Ice/Protocol.h>
8 #include <stdarg.h>
9
10 #ifdef HAVE_RUBY_ENCODING_H
11 # include <ruby/encoding.h>
12 #endif
13
14 using namespace std;
15 using namespace IceRuby;
16
17 namespace
18 {
19
20 template<typename T>
21 bool
setVersion(VALUE p,const T & version)22 setVersion(VALUE p, const T& version)
23 {
24 volatile VALUE major = callRuby(rb_int2inum, version.major);
25 volatile VALUE minor = callRuby(rb_int2inum, version.minor);
26 rb_ivar_set(p, rb_intern("@major"), major);
27 rb_ivar_set(p, rb_intern("@minor"), minor);
28
29 return true;
30 }
31
32 template<typename T>
33 bool
getVersion(VALUE p,T & v)34 getVersion(VALUE p, T& v)
35 {
36 volatile VALUE major = callRuby(rb_ivar_get, p, rb_intern("@major"));
37 volatile VALUE minor = callRuby(rb_ivar_get, p, rb_intern("@minor"));
38
39 long m;
40
41 m = getInteger(major);
42 if(m < 0 || m > 255)
43 {
44 throw RubyException(rb_eTypeError, "version major must be a value between 0 and 255");
45 return false;
46 }
47 v.major = m;
48
49 m = getInteger(minor);
50 if(m < 0 || m > 255)
51 {
52 throw RubyException(rb_eTypeError, "version minor must be a value between 0 and 255");
53 return false;
54 }
55 v.minor = m;
56
57 return true;
58 }
59
60 template<typename T>
61 VALUE
createVersion(const T & version,const char * type)62 createVersion(const T& version, const char* type)
63 {
64 volatile VALUE rbType = callRuby(rb_path2class, type);
65 assert(!NIL_P(rbType));
66
67 volatile VALUE obj = callRuby(rb_class_new_instance, 0, static_cast<VALUE*>(0), rbType);
68
69 if(!setVersion<T>(obj, version))
70 {
71 return Qnil;
72 }
73
74 return obj;
75 }
76
77 template<typename T>
78 VALUE
versionToString(VALUE p,const char * type)79 versionToString(VALUE p, const char* type)
80 {
81 volatile VALUE rbType = callRuby(rb_path2class, type);
82 assert(!NIL_P(rbType));
83 if(callRuby(rb_obj_is_instance_of, p, rbType) != Qtrue)
84 {
85 throw RubyException(rb_eTypeError, "argument is not an instance of %s", type);
86 }
87
88 T v;
89 if(!getVersion<T>(p, v))
90 {
91 return Qnil;
92 }
93
94 ICE_RUBY_TRY
95 {
96 string s = IceInternal::versionToString<T>(v);
97 return createString(s);
98 }
99 ICE_RUBY_CATCH
100 return Qnil;
101 }
102
103 template<typename T>
104 VALUE
stringToVersion(VALUE p,const char * type)105 stringToVersion(VALUE p, const char* type)
106 {
107 string str = getString(p);
108
109 ICE_RUBY_TRY
110 {
111 T v = IceInternal::stringToVersion<T>(str);
112 return createVersion<T>(v, type);
113 }
114 ICE_RUBY_CATCH
115 return Qnil;
116 }
117
118 char Ice_ProtocolVersion[] = "Ice::ProtocolVersion";
119 char Ice_EncodingVersion[] = "Ice::EncodingVersion";
120
121 }
122
123 extern "C"
124 VALUE
IceRuby_stringVersion(int,VALUE *,VALUE)125 IceRuby_stringVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
126 {
127 ICE_RUBY_TRY
128 {
129 string s = ICE_STRING_VERSION;
130 return createString(s);
131 }
132 ICE_RUBY_CATCH
133 return Qnil;
134 }
135
136 extern "C"
137 VALUE
IceRuby_intVersion(int,VALUE *,VALUE)138 IceRuby_intVersion(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
139 {
140 ICE_RUBY_TRY
141 {
142 return INT2FIX(ICE_INT_VERSION);
143 }
144 ICE_RUBY_CATCH
145 return Qnil;
146 }
147
148 extern "C"
149 VALUE
IceRuby_currentProtocol(int,VALUE *,VALUE)150 IceRuby_currentProtocol(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
151 {
152 ICE_RUBY_TRY
153 {
154 return createProtocolVersion(Ice::currentProtocol);
155 }
156 ICE_RUBY_CATCH
157 return Qnil;
158 }
159
160 extern "C"
161 VALUE
IceRuby_currentProtocolEncoding(int,VALUE *,VALUE)162 IceRuby_currentProtocolEncoding(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
163 {
164 ICE_RUBY_TRY
165 {
166 return createEncodingVersion(Ice::currentProtocolEncoding);
167 }
168 ICE_RUBY_CATCH
169 return Qnil;
170 }
171
172 extern "C"
173 VALUE
IceRuby_currentEncoding(int,VALUE *,VALUE)174 IceRuby_currentEncoding(int /*argc*/, VALUE* /*argv*/, VALUE /*self*/)
175 {
176 ICE_RUBY_TRY
177 {
178 return createEncodingVersion(Ice::currentEncoding);
179 }
180 ICE_RUBY_CATCH
181 return Qnil;
182 }
183
184 extern "C"
185 VALUE
IceRuby_protocolVersionToString(VALUE,VALUE v)186 IceRuby_protocolVersionToString(VALUE /*self*/, VALUE v)
187 {
188 return versionToString<Ice::ProtocolVersion>(v, Ice_ProtocolVersion);
189 }
190
191 extern "C"
192 VALUE
IceRuby_stringToProtocolVersion(VALUE,VALUE v)193 IceRuby_stringToProtocolVersion(VALUE /*self*/, VALUE v)
194 {
195 return stringToVersion<Ice::ProtocolVersion>(v, Ice_ProtocolVersion);
196 }
197
198 extern "C"
199 VALUE
IceRuby_encodingVersionToString(VALUE,VALUE v)200 IceRuby_encodingVersionToString(VALUE /*self*/, VALUE v)
201 {
202 return versionToString<Ice::EncodingVersion>(v, Ice_EncodingVersion);
203 }
204
205 extern "C"
206 VALUE
IceRuby_stringToEncodingVersion(VALUE,VALUE v)207 IceRuby_stringToEncodingVersion(VALUE /*self*/, VALUE v)
208 {
209 return stringToVersion<Ice::EncodingVersion>(v, Ice_EncodingVersion);
210 }
211
212 void
initUtil(VALUE iceModule)213 IceRuby::initUtil(VALUE iceModule)
214 {
215 rb_define_module_function(iceModule, "stringVersion", CAST_METHOD(IceRuby_stringVersion), -1);
216 rb_define_module_function(iceModule, "intVersion", CAST_METHOD(IceRuby_intVersion), -1);
217 rb_define_module_function(iceModule, "currentProtocol", CAST_METHOD(IceRuby_currentProtocol), -1);
218 rb_define_module_function(iceModule, "currentProtocolEncoding", CAST_METHOD(IceRuby_currentProtocolEncoding), -1);
219 rb_define_module_function(iceModule, "currentEncoding", CAST_METHOD(IceRuby_currentEncoding), -1);
220 rb_define_module_function(iceModule, "protocolVersionToString", CAST_METHOD(IceRuby_protocolVersionToString), 1);
221 rb_define_module_function(iceModule, "stringToProtocolVersion", CAST_METHOD(IceRuby_stringToProtocolVersion), 1);
222 rb_define_module_function(iceModule, "encodingVersionToString", CAST_METHOD(IceRuby_encodingVersionToString), 1);
223 rb_define_module_function(iceModule, "stringToEncodingVersion", CAST_METHOD(IceRuby_stringToEncodingVersion), 1);
224 }
225
RubyException()226 IceRuby::RubyException::RubyException()
227 {
228 ex = rb_gv_get("$!");
229 }
230
RubyException(VALUE exv)231 IceRuby::RubyException::RubyException(VALUE exv) :
232 ex(exv)
233 {
234 }
235
RubyException(VALUE exClass,const char * fmt,...)236 IceRuby::RubyException::RubyException(VALUE exClass, const char* fmt, ...)
237 {
238 va_list args;
239 char buf[BUFSIZ];
240
241 va_start(args, fmt);
242 vsnprintf(buf, BUFSIZ, fmt, args);
243 buf[BUFSIZ - 1] = '\0';
244 va_end(args);
245
246 ex = callRuby(rb_exc_new2, exClass, buf);
247 }
248
249 ostream&
operator <<(ostream & ostr) const250 IceRuby::RubyException::operator<<(ostream& ostr) const
251 {
252 volatile VALUE cls = rb_class_path(CLASS_OF(ex));
253 volatile VALUE msg = rb_obj_as_string(ex);
254 ostr << RSTRING_PTR(cls) << ": " << RSTRING_PTR(msg);
255 return ostr;
256 }
257
258 bool
isString(VALUE val)259 IceRuby::isString(VALUE val)
260 {
261 return TYPE(val) == T_STRING || callRuby(rb_respond_to, val, rb_intern("to_str")) != 0;
262 }
263
264 bool
isArray(VALUE val)265 IceRuby::isArray(VALUE val)
266 {
267 return TYPE(val) == T_ARRAY || callRuby(rb_respond_to, val, rb_intern("to_arr")) != 0;
268 }
269
270 bool
isHash(VALUE val)271 IceRuby::isHash(VALUE val)
272 {
273 return TYPE(val) == T_HASH || callRuby(rb_respond_to, val, rb_intern("to_hash")) != 0;
274 }
275
276 string
getString(VALUE val)277 IceRuby::getString(VALUE val)
278 {
279 volatile VALUE result = callRuby(rb_string_value, &val);
280 return string(RSTRING_PTR(result), RSTRING_LEN(result));
281 }
282
283 VALUE
createString(const string & str)284 IceRuby::createString(const string& str)
285 {
286 #ifdef HAVE_RUBY_ENCODING_H
287 return callRuby(rb_enc_str_new, str.c_str(), static_cast<long>(str.size()), rb_utf8_encoding());
288 #else
289 return callRuby(rb_str_new, str.c_str(), static_cast<long>(str.size()));
290 #endif
291 }
292
293 namespace
294 {
295
296 template <typename T>
297 struct RubyCallArgs
298 {
299 volatile VALUE val;
300 T ret;
301 };
302
303 //
304 // Wrapper function to call rb_num2long with rb_protect
305 //
306 VALUE
rb_num2long_wrapper(VALUE val)307 rb_num2long_wrapper(VALUE val)
308 {
309 RubyCallArgs<long>* data = (RubyCallArgs<long>*)val;
310 data->ret = rb_num2long(data->val);
311 return val;
312 }
313
314 //
315 // Wrapper function to call rb_num2ll with rb_protect
316 //
317 VALUE
rb_num2ll_wrapper(VALUE val)318 rb_num2ll_wrapper(VALUE val)
319 {
320 RubyCallArgs<Ice::Long>* data = (RubyCallArgs<Ice::Long>*)val;
321 data->ret = rb_num2ll(data->val);
322 return val;
323 }
324
325 }
326
327 long
getInteger(VALUE val)328 IceRuby::getInteger(VALUE val)
329 {
330 RubyCallArgs<long> arg= {val, -1};
331 int error = 0;
332 rb_protect(rb_num2long_wrapper, (VALUE)&arg, &error);
333 if(error)
334 {
335 throw RubyException(rb_eTypeError, "unable to convert value to an int");
336 }
337 return arg.ret;
338 }
339
340 Ice::Long
getLong(VALUE val)341 IceRuby::getLong(VALUE val)
342 {
343 RubyCallArgs<Ice::Long> arg= {val, -1};
344 int error = 0;
345 rb_protect(rb_num2ll_wrapper, (VALUE)&arg, &error);
346 if(error)
347 {
348 throw RubyException(rb_eTypeError, "unable to convert value to a long");
349 }
350 return arg.ret;
351 }
352
353 bool
arrayToStringSeq(VALUE val,vector<string> & seq)354 IceRuby::arrayToStringSeq(VALUE val, vector<string>& seq)
355 {
356 volatile VALUE arr = callRuby(rb_check_array_type, val);
357 if(NIL_P(arr))
358 {
359 return false;
360 }
361 for(long i = 0; i < RARRAY_LEN(arr); ++i)
362 {
363 string s = getString(RARRAY_AREF(arr, i));
364 seq.push_back(getString(RARRAY_AREF(arr, i)));
365 }
366 return true;
367 }
368
369 VALUE
stringSeqToArray(const vector<string> & seq)370 IceRuby::stringSeqToArray(const vector<string>& seq)
371 {
372 volatile VALUE result = createArray(seq.size());
373 long i = 0;
374 if(seq.size() > 0)
375 {
376 for(vector<string>::const_iterator p = seq.begin(); p != seq.end(); ++p, ++i)
377 {
378 RARRAY_ASET(result, i, createString(*p));
379 }
380 }
381 return result;
382 }
383
384 VALUE
createNumSeq(const vector<Ice::Byte> & v)385 IceRuby::createNumSeq(const vector<Ice::Byte>& v)
386 {
387 volatile VALUE result = createArray(v.size());
388 long i = 0;
389 if(v.size() > 0)
390 {
391 for(vector<Ice::Byte>::const_iterator p = v.begin(); p != v.end(); ++p, ++i)
392 {
393 RARRAY_ASET(result, i, INT2FIX(*p));
394 }
395 }
396 return result;
397 }
398
399 namespace
400 {
401
402 struct HashToContextIterator : public IceRuby::HashIterator
403 {
HashToContextIterator__anon243556910311::HashToContextIterator404 HashToContextIterator(Ice::Context& c) : ctx(c)
405 {
406 }
407
element__anon243556910311::HashToContextIterator408 virtual void element(VALUE key, VALUE value)
409 {
410 string kstr = IceRuby::getString(key);
411 string vstr = IceRuby::getString(value);
412 ctx[kstr] = vstr;
413 }
414
415 Ice::Context& ctx;
416 };
417
418 }
419
420 bool
hashToContext(VALUE val,Ice::Context & ctx)421 IceRuby::hashToContext(VALUE val, Ice::Context& ctx)
422 {
423 if(TYPE(val) != T_HASH)
424 {
425 val = callRuby(rb_convert_type, val, T_HASH, "Hash", "to_hash");
426 if(NIL_P(val))
427 {
428 return false;
429 }
430 }
431 HashToContextIterator iter(ctx);
432 hashIterate(val, iter);
433 return true;
434 }
435
436 VALUE
contextToHash(const Ice::Context & ctx)437 IceRuby::contextToHash(const Ice::Context& ctx)
438 {
439 volatile VALUE result = callRuby(rb_hash_new);
440 for(Ice::Context::const_iterator p = ctx.begin(); p != ctx.end(); ++p)
441 {
442 volatile VALUE key = createString(p->first);
443 volatile VALUE value = createString(p->second);
444 callRuby(rb_hash_aset, result, key, value);
445 }
446 return result;
447 }
448
449 extern "C"
450 VALUE
IceRuby_Util_hash_foreach_callback(VALUE val,VALUE arg)451 IceRuby_Util_hash_foreach_callback(VALUE val, VALUE arg)
452 {
453 VALUE key = rb_ary_entry(val, 0);
454 VALUE value = rb_ary_entry(val, 1);
455
456 //
457 // We can't allow any C++ exceptions to propagate out of this function.
458 //
459 ICE_RUBY_TRY
460 {
461 IceRuby::HashIterator* iter = reinterpret_cast<IceRuby::HashIterator*>(arg);
462 iter->element(key, value);
463 }
464 ICE_RUBY_CATCH
465 return val;
466 }
467
468 extern "C"
469 {
470 typedef VALUE (*ICE_RUBY_HASH_FOREACH_CALLBACK)(...);
471 }
472
473 void
hashIterate(VALUE h,HashIterator & iter)474 IceRuby::hashIterate(VALUE h, HashIterator& iter)
475 {
476 assert(TYPE(h) == T_HASH);
477 callRuby(rb_iterate, rb_each, h,
478 reinterpret_cast<ICE_RUBY_HASH_FOREACH_CALLBACK>(IceRuby_Util_hash_foreach_callback),
479 reinterpret_cast<VALUE>(&iter));
480 }
481
482 Ice::Identity
getIdentity(VALUE v)483 IceRuby::getIdentity(VALUE v)
484 {
485 volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
486 assert(!NIL_P(cls));
487
488 if(callRuby(rb_obj_is_kind_of, v, cls) == Qfalse)
489 {
490 throw RubyException(rb_eTypeError, "value is not an Ice::Identity");
491 }
492
493 volatile VALUE name = callRuby(rb_iv_get, v, "@name");
494 volatile VALUE category = callRuby(rb_iv_get, v, "@category");
495
496 if(!NIL_P(category) && !isString(category))
497 {
498 throw RubyException(rb_eTypeError, "identity category must be a string");
499 }
500
501 if(NIL_P(name) || !isString(name))
502 {
503 throw RubyException(rb_eTypeError, "identity name must be a string");
504 }
505
506 Ice::Identity result;
507 result.name = getString(name);
508 if(!NIL_P(category))
509 {
510 result.category = getString(category);
511 }
512 return result;
513 }
514
515 VALUE
createIdentity(const Ice::Identity & id)516 IceRuby::createIdentity(const Ice::Identity& id)
517 {
518 volatile VALUE cls = callRuby(rb_path2class, "Ice::Identity");
519 assert(!NIL_P(cls));
520
521 volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
522 volatile VALUE name = createString(id.name);
523 volatile VALUE category = createString(id.category);
524 callRuby(rb_iv_set, result, "@name", name);
525 callRuby(rb_iv_set, result, "@category", category);
526 return result;
527 }
528
529 VALUE
createProtocolVersion(const Ice::ProtocolVersion & v)530 IceRuby::createProtocolVersion(const Ice::ProtocolVersion& v)
531 {
532 return createVersion<Ice::ProtocolVersion>(v, Ice_ProtocolVersion);
533 }
534
535 VALUE
createEncodingVersion(const Ice::EncodingVersion & v)536 IceRuby::createEncodingVersion(const Ice::EncodingVersion& v)
537 {
538 return createVersion<Ice::EncodingVersion>(v, Ice_EncodingVersion);
539 }
540
541 bool
getEncodingVersion(VALUE p,Ice::EncodingVersion & v)542 IceRuby::getEncodingVersion(VALUE p, Ice::EncodingVersion& v)
543 {
544 volatile VALUE cls = callRuby(rb_path2class, Ice_EncodingVersion);
545 assert(!NIL_P(cls));
546
547 if(callRuby(rb_obj_is_kind_of, p, cls) == Qfalse)
548 {
549 throw RubyException(rb_eTypeError, "value is not an Ice::EncodingVersion");
550 }
551
552 if(!getVersion<Ice::EncodingVersion>(p, v))
553 {
554 return false;
555 }
556
557 return true;
558 }
559
560 VALUE
callProtected(RubyFunction func,VALUE arg)561 IceRuby::callProtected(RubyFunction func, VALUE arg)
562 {
563 int error = 0;
564 volatile VALUE result = rb_protect(func, arg, &error);
565 if(error)
566 {
567 throw RubyException();
568 }
569 return result;
570 }
571
572 static void
setExceptionMembers(const Ice::LocalException & ex,VALUE p)573 setExceptionMembers(const Ice::LocalException& ex, VALUE p)
574 {
575 //
576 // Transfer data members from Ice exception to Ruby exception.
577 //
578 try
579 {
580 ex.ice_throw();
581 }
582 catch(const Ice::InitializationException& e)
583 {
584 volatile VALUE v = createString(e.reason);
585 callRuby(rb_iv_set, p, "@reason", v);
586 }
587 catch(const Ice::PluginInitializationException& e)
588 {
589 volatile VALUE v = createString(e.reason);
590 callRuby(rb_iv_set, p, "@reason", v);
591 }
592 catch(const Ice::AlreadyRegisteredException& e)
593 {
594 volatile VALUE v;
595 v = createString(e.kindOfObject);
596 callRuby(rb_iv_set, p, "@kindOfObject", v);
597 v = createString(e.id);
598 callRuby(rb_iv_set, p, "@id", v);
599 }
600 catch(const Ice::NotRegisteredException& e)
601 {
602 volatile VALUE v;
603 v = createString(e.kindOfObject);
604 callRuby(rb_iv_set, p, "@kindOfObject", v);
605 v = createString(e.id);
606 callRuby(rb_iv_set, p, "@id", v);
607 }
608 catch(const Ice::TwowayOnlyException& e)
609 {
610 volatile VALUE v = createString(e.operation);
611 callRuby(rb_iv_set, p, "@operation", v);
612 }
613 catch(const Ice::UnknownException& e)
614 {
615 volatile VALUE v = createString(e.unknown);
616 callRuby(rb_iv_set, p, "@unknown", v);
617 }
618 catch(const Ice::ObjectAdapterDeactivatedException& e)
619 {
620 volatile VALUE v = createString(e.name);
621 callRuby(rb_iv_set, p, "@name", v);
622 }
623 catch(const Ice::ObjectAdapterIdInUseException& e)
624 {
625 volatile VALUE v = createString(e.id);
626 callRuby(rb_iv_set, p, "@id", v);
627 }
628 catch(const Ice::NoEndpointException& e)
629 {
630 volatile VALUE v = createString(e.proxy);
631 callRuby(rb_iv_set, p, "@proxy", v);
632 }
633 catch(const Ice::EndpointParseException& e)
634 {
635 volatile VALUE v = createString(e.str);
636 callRuby(rb_iv_set, p, "@str", v);
637 }
638 catch(const Ice::EndpointSelectionTypeParseException& e)
639 {
640 volatile VALUE v = createString(e.str);
641 callRuby(rb_iv_set, p, "@str", v);
642 }
643 catch(const Ice::VersionParseException& e)
644 {
645 volatile VALUE v = createString(e.str);
646 callRuby(rb_iv_set, p, "@str", v);
647 }
648 catch(const Ice::IdentityParseException& e)
649 {
650 volatile VALUE v = createString(e.str);
651 callRuby(rb_iv_set, p, "@str", v);
652 }
653 catch(const Ice::ProxyParseException& e)
654 {
655 volatile VALUE v = createString(e.str);
656 callRuby(rb_iv_set, p, "@str", v);
657 }
658 catch(const Ice::IllegalIdentityException& e)
659 {
660 volatile VALUE v = IceRuby::createIdentity(e.id);
661 callRuby(rb_iv_set, p, "@id", v);
662 }
663 catch(const Ice::IllegalServantException& e)
664 {
665 volatile VALUE v = createString(e.reason);
666 callRuby(rb_iv_set, p, "@reason", v);
667 }
668 catch(const Ice::RequestFailedException& e)
669 {
670 volatile VALUE v;
671 v = IceRuby::createIdentity(e.id);
672 callRuby(rb_iv_set, p, "@id", v);
673 v = createString(e.facet);
674 callRuby(rb_iv_set, p, "@facet", v);
675 v = createString(e.operation);
676 callRuby(rb_iv_set, p, "@operation", v);
677 }
678 catch(const Ice::FileException& e)
679 {
680 volatile VALUE v = INT2FIX(e.error);
681 callRuby(rb_iv_set, p, "@error", v);
682 v = createString(e.path);
683 callRuby(rb_iv_set, p, "@path", v);
684 }
685 catch(const Ice::SyscallException& e) // This must appear after all subclasses of SyscallException.
686 {
687 volatile VALUE v = INT2FIX(e.error);
688 callRuby(rb_iv_set, p, "@error", v);
689 }
690 catch(const Ice::DNSException& e)
691 {
692 volatile VALUE v;
693 v = INT2FIX(e.error);
694 callRuby(rb_iv_set, p, "@error", v);
695 v = createString(e.host);
696 callRuby(rb_iv_set, p, "@host", v);
697 }
698 catch(const Ice::BadMagicException& e)
699 {
700 volatile VALUE v = createNumSeq(e.badMagic);
701 callRuby(rb_iv_set, p, "@badMagic", v);
702 }
703 catch(const Ice::UnsupportedProtocolException& e)
704 {
705 VALUE m;
706 m = createProtocolVersion(e.bad);
707 callRuby(rb_iv_set, p, "@bad", m);
708 m = createProtocolVersion(e.supported);
709 callRuby(rb_iv_set, p, "@supported", m);
710 }
711 catch(const Ice::UnsupportedEncodingException& e)
712 {
713 VALUE m;
714 m = createEncodingVersion(e.bad);
715 callRuby(rb_iv_set, p, "@bad", m);
716 m = createEncodingVersion(e.supported);
717 callRuby(rb_iv_set, p, "@supported", m);
718 }
719 catch(const Ice::NoValueFactoryException& e)
720 {
721 volatile VALUE v;
722 v = createString(e.reason);
723 callRuby(rb_iv_set, p, "@reason", v);
724 v = createString(e.type);
725 callRuby(rb_iv_set, p, "@type", v);
726 }
727 catch(const Ice::UnexpectedObjectException& e)
728 {
729 volatile VALUE v;
730 v = createString(e.reason);
731 callRuby(rb_iv_set, p, "@reason", v);
732 v = createString(e.type);
733 callRuby(rb_iv_set, p, "@type", v);
734 v = createString(e.expectedType);
735 callRuby(rb_iv_set, p, "@expectedType", v);
736 }
737 catch(const Ice::ProtocolException& e) // This must appear after all subclasses of ProtocolException.
738 {
739 volatile VALUE v = createString(e.reason);
740 callRuby(rb_iv_set, p, "@reason", v);
741 }
742 catch(const Ice::ConnectionManuallyClosedException& e)
743 {
744 callRuby(rb_iv_set, p, "@graceful", e.graceful ? Qtrue : Qfalse);
745 }
746 catch(const Ice::FeatureNotSupportedException& e)
747 {
748 volatile VALUE v = createString(e.unsupportedFeature);
749 callRuby(rb_iv_set, p, "@unsupportedFeature", v);
750 }
751 catch(const Ice::SecurityException& e)
752 {
753 volatile VALUE v = createString(e.reason);
754 callRuby(rb_iv_set, p, "@reason", v);
755 }
756 catch(const Ice::LocalException&)
757 {
758 //
759 // Nothing to do.
760 //
761 }
762 }
763
764 VALUE
createArrayHelper(long sz)765 IceRuby::createArrayHelper(long sz)
766 {
767 volatile VALUE arr = callRuby(rb_ary_new2, sz);
768 if(sz > 0)
769 {
770 callRubyVoid(rb_ary_store, arr, sz - 1, Qnil);
771 }
772 return arr;
773 }
774
775 VALUE
convertLocalException(const Ice::LocalException & ex)776 IceRuby::convertLocalException(const Ice::LocalException& ex)
777 {
778 //
779 // We cannot throw a C++ exception or raise a Ruby exception. If an error
780 // occurs while we are converting the exception, we do our best to return
781 // an appropriate Ruby exception.
782 //
783 try
784 {
785 string name = ex.ice_id().substr(2);
786 volatile VALUE cls = callRuby(rb_path2class, name.c_str());
787 if(NIL_P(cls))
788 {
789 throw RubyException(rb_eRuntimeError, "exception class `%s' not found", name.c_str());
790 }
791 volatile VALUE result = callRuby(rb_class_new_instance, 0, reinterpret_cast<VALUE*>(0), cls);
792 setExceptionMembers(ex, result);
793 return result;
794 }
795 catch(const RubyException& e)
796 {
797 return e.ex;
798 }
799 catch(...)
800 {
801 string msg = "failure occurred while converting exception " + ex.ice_id();
802 return rb_exc_new2(rb_eRuntimeError, msg.c_str());
803 }
804 }
805