1 // Regression test Bug 2234
3 // The bug actually manifested itself in class AnInterceptor::receive_request()
4 // where any OUT parameters of variable length items (as they are held as
5 // addresses of NULL pointers)
7 // The bug is caused by the arguments() call which should be
8 // creating a read-only COPY of the parameters to the call. These are held as
9 // a sequence of ANYs, whith the code for the insertion into which is created
10 // by the TAO_IDL compiler when their user types are compiled.
11 // It is also manifested by the result() call in the same way.
14 #include "ace/Get_Opt.h"
15 #include "ace/IOStream.h"
16 #include "tao/PI/PI.h"
17 #include "tao/PI_Server/PI_Server.h"
18 #include "tao/ORBInitializer_Registry.h"
19 #include "tao/PortableServer/Root_POA.h"
20 #include "tao/LocalObject.h"
22 const ACE_TCHAR
*ior_output_file
= ACE_TEXT ("test.ior");
25 parse_args (int argc
, ACE_TCHAR
*argv
[])
27 ACE_Get_Opt
get_opts (argc
, argv
, ACE_TEXT("o:"));
30 while ((c
= get_opts ()) != -1)
34 ior_output_file
= get_opts
.opt_arg ();
39 ACE_ERROR_RETURN ((LM_ERROR
,
46 // Indicates successful parsing of the command line
52 // The test case code for the server always sends back to the client:
54 // c(inout)= c(inout) + 1
56 // Strings are single numerical digits, longs are the numbers themselves
57 // and sequences are always single long values.
58 // Parameter 'a' must be received from the client as 1, and 'c' as 3.
60 class FooImpl
: public POA_Test::Foo
66 //-----------------------------------------------------------
74 ACE_DEBUG( (LM_INFO
, ". in TestLong\n"));
75 if (static_cast<CORBA::Long
>(1) != a
)
77 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n"));
78 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
80 if (static_cast<CORBA::Long
>(3) != c
)
82 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n"));
83 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
86 b
= static_cast<CORBA::Long
>( a
<< 1);
88 c
+= static_cast<CORBA::Long
>( 1);
89 return static_cast<CORBA::Long
>( 7);
92 //-----------------------------------------------------------
100 ACE_DEBUG( (LM_INFO
, ". in TestString\n"));
103 //FUZZ: disable check_for_NULL
104 ACE_DEBUG( (LM_INFO
, "* Incorrect NULL string given for parameter a\n"));
105 //FUZZ: enable check_for_NULL
106 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
108 if (1 != ACE_OS::strlen( a
))
110 ACE_DEBUG( (LM_INFO
, "* Incorrect string length for parameter a\n"));
111 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
115 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n"));
116 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
120 //FUZZ: disable check_for_NULL
121 ACE_DEBUG( (LM_INFO
, "* Incorrect NULL string given for parameter c\n"));
122 //FUZZ: enable check_for_NULL
123 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
125 if (1 != ACE_OS::strlen( c
))
127 ACE_DEBUG( (LM_INFO
, "* Incorrect string length for parameter c\n"));
128 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
132 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n"));
133 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
136 b
= CORBA::string_dup("0"); // Create a one character output buffer
139 return CORBA::string_dup("7");
142 //-----------------------------------------------------------
144 Test::MyNonVarStruct
TestNonVarStruct(
145 const Test::MyNonVarStruct
&a
,
146 Test::MyNonVarStruct_out b
,
147 Test::MyNonVarStruct
&c
153 ACE_DEBUG( (LM_INFO
, ". in TestNonVarStruct\n"));
154 if (static_cast<CORBA::Long
>(1) != a
.val
)
156 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n"));
157 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
159 if (static_cast<CORBA::Long
>(3) != c
.val
)
161 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n"));
162 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
165 newret
.val
= static_cast<CORBA::Long
>( 7);
167 Test::MyNonVarStruct
*newval_p
;
168 ACE_NEW_RETURN( newval_p
, Test::MyNonVarStruct
, newret
);
169 Test::MyNonVarStruct_var
172 newval
->val
= a
.val
<< 1;
179 //-----------------------------------------------------------
181 Test::MyVarStruct
*TestVarStruct(
182 const Test::MyVarStruct
&a
,
183 Test::MyVarStruct_out b
,
187 ACE_DEBUG( (LM_INFO
, ". in TestVarStruct\n"));
190 //FUZZ: disable check_for_NULL
191 ACE_DEBUG( (LM_INFO
, "* Incorrect NULL string given for parameter a\n"));
192 //FUZZ: enable check_for_NULL
193 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
195 if (1 != ACE_OS::strlen( a
.val
.in() ))
197 ACE_DEBUG( (LM_INFO
, "* Incorrect string length for parameter a\n"));
198 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
200 if ('1' != *a
.val
.in())
202 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n"));
203 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
207 //FUZZ: disable check_for_NULL
208 ACE_DEBUG( (LM_INFO
, "* Incorrect NULL string given for parameter c\n"));
209 //FUZZ: enable check_for_NULL
210 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
212 if (1 != ACE_OS::strlen( c
.val
.in() ))
214 ACE_DEBUG( (LM_INFO
, "* Incorrect string length for parameter c\n"));
215 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
217 if ('3' != *c
.val
.in())
219 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n"));
220 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
224 ca
[0]= ('0' + ((*a
.val
.in() -'0') << 1));
226 Test::MyVarStruct_var
229 ACE_NEW_RETURN( newval_p
, Test::MyVarStruct(), 0);
230 Test::MyVarStruct_var
232 ACE_NEW_RETURN( newret_p
, Test::MyVarStruct(), 0);
233 Test::MyVarStruct_var
236 newval
->val
= CORBA::string_dup( ca
);
240 newret
->val
= CORBA::string_dup( "7");
243 return newret
._retn();
246 //-----------------------------------------------------------
248 Test::MyNonVarUnion
TestNonVarUnion(
249 const Test::MyNonVarUnion
&a
,
250 Test::MyNonVarUnion_out b
,
251 Test::MyNonVarUnion
&c
)
256 ACE_DEBUG( (LM_INFO
, ". in TestNonVarUnion\n"));
257 if (static_cast<CORBA::Short
>(1) != a
._d())
259 ACE_DEBUG( (LM_INFO
, "* Incorrect type of parameter a\n"));
260 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
262 if (static_cast<CORBA::Long
>(1) != a
.valLong())
264 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n") );
265 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
267 if (static_cast<CORBA::Short
>(1) != c
._d())
269 ACE_DEBUG( (LM_INFO
, "* Incorrect type of parameter c\n") );
270 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
272 if (static_cast<CORBA::Long
>(3) != c
.valLong())
274 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n") );
275 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
278 Test::MyNonVarUnion
*newval_p
;
279 ACE_NEW_RETURN( newval_p
, Test::MyNonVarUnion(), newret
);
280 Test::MyNonVarUnion_var
283 newval
->valLong( a
.valLong() << 1 );
284 c
.valLong( c
.valLong() + 1 );
286 newret
.valLong( static_cast<CORBA::Long
>(7));
292 //-----------------------------------------------------------
294 Test::MyVarUnion
*TestVarUnion(
295 const Test::MyVarUnion
&a
,
296 Test::MyVarUnion_out b
,
300 ACE_DEBUG( (LM_INFO
, ". in TestVarUnion\n") );
301 if (static_cast<CORBA::Short
>(1) != a
._d())
303 ACE_DEBUG( (LM_INFO
, "* Incorrect type of parameter a\n") );
304 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
306 if (static_cast<CORBA::Long
>(1) != a
.valLong())
308 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n") );
309 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
311 if (static_cast<CORBA::Short
>(1) != c
._d())
313 ACE_DEBUG( (LM_INFO
, "* Incorrect type of parameter c\n") );
314 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
316 if (static_cast<CORBA::Long
>(3) != c
.valLong())
318 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n") );
319 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
322 Test::MyVarUnion
*newval_p
;
323 ACE_NEW_RETURN( newval_p
, Test::MyVarUnion(), 0 );
327 newval
->valLong( a
.valLong() << 1 );
328 c
.valLong( c
.valLong() + 1 );
332 ACE_NEW_RETURN( newret_p
, Test::MyVarUnion(), 0);
335 newret
->valLong( static_cast<CORBA::Short
>(7) );
338 return newret
._retn();
341 //-----------------------------------------------------------
343 Test::MySeqOfLong
*TestSeqOfLong (
344 const Test::MySeqOfLong
&a
,
345 Test::MySeqOfLong_out b
,
349 ACE_DEBUG( (LM_INFO
, ". in TestSeqOfLong\n") );
350 if (1u != a
.length())
352 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter a\n") );
353 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
355 if (static_cast<CORBA::Long
>(1) != a
[0])
357 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n") );
358 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
360 if (1u != c
.length())
362 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter c\n") );
363 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
365 if (static_cast<CORBA::Long
>(3) != c
[0])
367 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n") );
368 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
371 Test::MySeqOfLong
*newval_p
;
372 ACE_NEW_RETURN( newval_p
, Test::MySeqOfLong(1), 0 );
373 Test::MySeqOfLong_var
377 newval
[0]= a
[0] << 1;
380 Test::MySeqOfLong
*newret_p
;
381 ACE_NEW_RETURN( newret_p
, Test::MySeqOfLong(1), 0 );
382 Test::MySeqOfLong_var
385 newret
[0]= static_cast<CORBA::Long
>( 7 );
388 return newret
._retn();
391 //-----------------------------------------------------------
399 ACE_DEBUG( (LM_INFO
, ". in TestAny\n") );
404 if (static_cast<CORBA::Long
>(1) != aL
)
406 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a\n") );
407 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
412 ACE_DEBUG( (LM_INFO
, "* Incorrect any type for parameter a\n") );
413 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
417 if (static_cast<CORBA::Long
>(3) != cL
)
419 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c\n") );
420 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
425 ACE_DEBUG( (LM_INFO
, "* Incorrect any type for parameter c\n") );
426 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
429 CORBA::Any
*newval_p
;
430 ACE_NEW_RETURN( newval_p
, CORBA::Any(), 0 );
437 CORBA::Any
*newret_p
;
438 ACE_NEW_RETURN( newret_p
, CORBA::Any(), 0 );
441 newret
<<= static_cast<CORBA::Long
>( 7 );
444 return newret
._retn();
447 //-----------------------------------------------------------
449 Test::MyArray_slice
*TestArray(
450 const Test::MyArray a
,
454 ACE_DEBUG( (LM_INFO
, ". in TestArray\n") );
455 if (a
[0].length () != 1)
457 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter a[0]\n") );
458 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
462 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a[0]\n") );
463 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
465 if (a
[1].length () != 1)
467 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter a[1]\n") );
468 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
472 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter a[1]\n") );
473 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
476 if (c
[0].length () != 1)
478 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter c[0]\n") );
479 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
483 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c[0]\n") );
484 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
486 if (c
[1].length () != 1)
488 ACE_DEBUG( (LM_INFO
, "* Incorrect length of parameter c[1]\n") );
489 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
493 ACE_DEBUG( (LM_INFO
, "* Incorrect input value of parameter c[1]\n") );
494 throw CORBA::BAD_PARAM(0, CORBA::COMPLETED_NO
);
497 b
= Test::MyArray_alloc ();
498 CORBA::ULong
idx (0);
505 Test::MyArray_var ret
= new Test::MyArray
;
515 //-----------------------------------------------------------
517 CORBA::Object_ptr
TestObject(
523 b
= CORBA::Object::_duplicate (a
);
524 return CORBA::Object::_duplicate (c
);
527 //-----------------------------------------------------------
532 ACE_DEBUG( (LM_INFO
, ". in ShutdownServer\n") );
537 // Here is our Regression test class that actually tests the problem with
538 // the interceptor's arguments.
540 class AnInterceptor
: public PortableInterceptor::ServerRequestInterceptor
545 return const_cast<char *>("");
552 void receive_request_service_contexts(
553 PortableInterceptor::ServerRequestInfo_ptr
557 // Note this helper only deals with the types inserted into
558 // the any that we defined for this test.
559 static void display_any( const CORBA::Any
&arg
)
561 const CORBA::Any
*holding
;
562 const Test::MyVarStruct
*vS
;
563 const Test::MyNonVarStruct
*fS
;
566 const Test::MyVarUnion
*vU
;
567 const Test::MyNonVarUnion
*fU
;
568 const Test::MySeqOfLong
*sL
;
569 Test::MyArray_forany arr
;
570 CORBA::Object_var obj
;
574 ACE_DEBUG( (LM_INFO
, "MyVarStruct (") );
576 ACE_DEBUG( (LM_INFO
, vS
->val
.in()) );
578 ACE_DEBUG( (LM_INFO
, "*Null*") );
582 ACE_DEBUG( (LM_INFO
, "MyNonVarStruct (") );
584 ACE_DEBUG( (LM_INFO
, "%d", fS
->val
) );
586 ACE_DEBUG( (LM_INFO
, "*Null*") );
588 else if (arg
>>= pString
)
590 ACE_DEBUG( (LM_INFO
, "String (") );
592 ACE_DEBUG( (LM_INFO
, pString
) );
594 ACE_DEBUG( (LM_INFO
, "*Null*") );
596 else if (arg
>>= theLong
)
597 ACE_DEBUG( (LM_INFO
, "Long (%d", theLong
) );
600 ACE_DEBUG( (LM_INFO
, "MyNonVarUnion (") );
601 if (fU
) switch (fU
->_d())
604 ACE_DEBUG( (LM_INFO
, "Long %d", fU
->valLong()) );
608 ACE_DEBUG( (LM_INFO
, "Short %d", fU
->valShort()) );
612 ACE_DEBUG( (LM_INFO
, "*Unknown*") );
615 ACE_DEBUG( (LM_INFO
, "*Null*") );
619 ACE_DEBUG( (LM_INFO
, "MyVarUnion (") );
620 if (vU
) switch (vU
->_d())
623 ACE_DEBUG( (LM_INFO
, "Long %d", vU
->valLong()) );
627 ACE_DEBUG( (LM_INFO
, "String %C", vU
->valString()));
631 ACE_DEBUG( (LM_INFO
, "*Unknown*") );
634 ACE_DEBUG( (LM_INFO
, "*Null*") );
638 ACE_DEBUG( (LM_INFO
, "MySeqOfLong (") );
641 if (0u < sL
->length())
643 for (unsigned int i
= 0u; i
< sL
->length() - 1u; ++i
)
644 ACE_DEBUG( (LM_INFO
, "%d, ", (*sL
)[ i
]) );
645 ACE_DEBUG( (LM_INFO
, "%d", (*sL
)[ sL
->length() - 1u ]) );
648 ACE_DEBUG( (LM_INFO
, "*Empty*") );
651 ACE_DEBUG( (LM_INFO
, "*Null*") );
653 else if (arg
>>= holding
)
655 ACE_DEBUG( (LM_INFO
, "Any (") );
658 if (*holding
>>= theLong
)
659 ACE_DEBUG( (LM_INFO
, "Long %d", theLong
) );
661 ACE_DEBUG( (LM_INFO
, "*Not Long*") );
664 ACE_DEBUG( (LM_INFO
, "*Null*") );
666 else if (arg
>>= arr
)
668 ACE_DEBUG( (LM_INFO
, "MyArray (") );
669 for (CORBA::ULong a_idx
= 0; a_idx
< 2; ++a_idx
)
671 CORBA::ULong length
= arr
[a_idx
].length ();
672 ACE_DEBUG( (LM_INFO
, "[%u].length () == %u ", a_idx
, length
));
675 else if (arg
>>= CORBA::Any::to_object(obj
))
677 ACE_DEBUG( (LM_INFO
, "CORBA::Object (") );
680 ACE_DEBUG( (LM_INFO
, "Unknown (") );
681 ACE_DEBUG( (LM_INFO
, ") parameter\n") );
684 // Useful parameter dumping helper method.-----------| Note this VAR
685 // which will automatically delete after the call! V
686 static void display_arg_list( Dynamic::ParameterList_var param_list
)
688 for (unsigned int i
= 0u; i
< param_list
->length(); ++i
)
690 ACE_DEBUG( (LM_INFO
, " param %d is an ", i
) );
691 switch( (*param_list
)[i
].mode
)
693 case CORBA::PARAM_IN
:
694 ACE_DEBUG( (LM_INFO
, "in ") );
697 case CORBA::PARAM_OUT
:
698 ACE_DEBUG( (LM_INFO
, "out ") );
701 case CORBA::PARAM_INOUT
:
702 ACE_DEBUG( (LM_INFO
, "inout ") );
706 ACE_DEBUG( (LM_INFO
, "non-directional ") );
710 display_any( (*param_list
)[i
].argument
);
714 void receive_request(
715 PortableInterceptor::ServerRequestInfo_ptr ri
718 ACE_DEBUG( (LM_INFO
, "AnInterceptor::receive_request\n") );
719 Dynamic::ParameterList
720 *pArgs
= ri
->arguments( );
721 display_arg_list( pArgs
);
724 // This send_reply() method would cause the problem due to it's
725 // ri->arguments() call. When the returned arguments list was
726 // deleted (due to the display_arg_list( Dynamic::ParameterList_var ))
727 // going out of scope, the "Owned" out pointer 'Argument B' would
728 // be premiturely deleted before being sent back to the client.
730 PortableInterceptor::ServerRequestInfo_ptr ri
733 ACE_DEBUG( (LM_INFO
, "AnInterceptor::send_reply\n") );
734 Dynamic::ParameterList
735 *pArgs
= ri
->arguments( );
736 display_arg_list( pArgs
);
737 ACE_DEBUG( (LM_INFO
, " result is an ") );
739 *pAny
= ri
->result( );
740 display_any( CORBA::Any_var( pAny
).in() );
741 ACE_DEBUG( (LM_INFO
, "\n") );
745 PortableInterceptor::ServerRequestInfo_ptr
750 PortableInterceptor::ServerRequestInfo_ptr
757 : public virtual PortableInterceptor::ORBInitializer
758 , public virtual CORBA::LocalObject
761 Initialiser( AnInterceptor
* interceptor
)
763 this->interceptor_
= interceptor
;
767 PortableInterceptor::ORBInitInfo_ptr
773 PortableInterceptor::ORBInitInfo_ptr info
776 info
->add_server_request_interceptor( interceptor_
);
780 AnInterceptor
*interceptor_
;
783 int ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
787 ACE_DEBUG( (LM_INFO
, "Server start\n") );
790 PortableInterceptor::ORBInitializer_ptr
792 ACE_NEW_RETURN( initialiser_p
, Initialiser( &interceptor
), -1 );
793 PortableInterceptor::ORBInitializer_var
794 initialiser
= initialiser_p
;
795 PortableInterceptor::register_orb_initializer( initialiser
.in() );
797 orb
= CORBA::ORB_init (argc
, argv
);
799 Object
= orb
->resolve_initial_references( "RootPOA" );
800 PortableServer::POA_var rootPOA
=
801 PortableServer::POA::_narrow( Object
.in() );
802 PortableServer::POAManager_var
803 rootPOAMgr
= rootPOA
->the_POAManager( );
805 if (parse_args (argc
, argv
) != 0)
810 PortableServer::ObjectId_var
811 phooeyId
= rootPOA
->activate_object( &phooey
);
813 phooeyObj
= rootPOA
->id_to_reference( phooeyId
.in() );
815 stringifiedObj
= orb
->object_to_string( phooeyObj
.in() );
816 ofstream
file( ACE_TEXT_ALWAYS_CHAR(ior_output_file
) );
817 file
<< stringifiedObj
;
820 rootPOAMgr
->activate( );
826 catch (const CORBA::SystemException
& exception
)
828 exception
._tao_print_exception ("CORBA::SystemException: ");
831 catch (const CORBA::Exception
& ex
)
833 ex
._tao_print_exception ("CORBA::Exception: ");
838 ACE_DEBUG( (LM_ERROR
, "Unexpected general exception.\n") );
842 ACE_DEBUG( (LM_INFO
, "Server stopped\n") );