=default for generated implementation copy ctor
[ACE_TAO.git] / TAO / tao / MCAST_Parser.cpp
bloba9b44d460df46161d1afcb01972ebc3a164d318b
1 #include "tao/MCAST_Parser.h"
3 #if (TAO_HAS_MCAST_PARSER == 1)
5 #include "tao/default_ports.h"
6 #include "tao/ORB_Core.h"
7 #include "tao/ORB.h"
8 #include "tao/debug.h"
10 #include "ace/SOCK_Acceptor.h"
11 #include "ace/SOCK_Dgram.h"
12 #include "ace/OS_NS_strings.h"
13 #include "ace/OS_NS_string.h"
14 #include "ace/Truncate.h"
15 #include <cstring>
17 #if !defined(__ACE_INLINE__)
18 #include "tao/MCAST_Parser.inl"
19 #endif /* __ACE_INLINE__ */
21 static const char mcast_prefix[] = "mcast:";
23 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
25 TAO_MCAST_Parser::~TAO_MCAST_Parser ()
29 bool
30 TAO_MCAST_Parser::match_prefix (const char *ior_string) const
32 return (ACE_OS::strncmp (ior_string,
33 ::mcast_prefix,
34 sizeof (::mcast_prefix) - 1) == 0);
37 CORBA::Object_ptr
38 TAO_MCAST_Parser::parse_string (const char *ior, CORBA::ORB_ptr orb)
40 char const * const mcast_name =
41 ior + sizeof (::mcast_prefix) + 1;
43 this->assign_to_variables (mcast_name);
46 * Now that we got the global variables.
47 * we can invoke multicast_to_service and multicast_query
49 ACE_Time_Value *timeout = orb->get_timeout ();
51 return
52 this->multicast_to_service (service_name_.in (),
53 this->mcast_port_,
54 this->mcast_address_.in (),
55 this->mcast_ttl_,
56 this->mcast_nic_.in (),
57 orb,
58 timeout);
61 CORBA::Object_ptr
62 TAO_MCAST_Parser::multicast_to_service (const char *service_name,
63 unsigned short port,
64 const char *mcast_address,
65 int mcast_ttl,
66 const char *mcast_nic,
67 CORBA::ORB_ptr orb,
68 ACE_Time_Value *timeout)
70 char buf[TAO_DEFAULT_IOR_SIZE];
71 char * ior = buf;
73 // Use UDP multicast to locate the service.
74 int const result = this->multicast_query (ior,
75 service_name,
76 port,
77 mcast_address,
78 mcast_ttl,
79 mcast_nic,
80 timeout,
81 orb);
83 CORBA::Object_var return_value;
85 if (result == 0)
87 CORBA::String_var cleaner;
88 // If the IOR didn't fit into <buf>, memory for it was dynamically
89 // allocated - make sure it gets deallocated.
90 if (ior != buf)
91 cleaner = ior;
93 // Convert IOR to an object reference.
94 return_value =
95 orb->string_to_object (ior);
98 // Return object reference.
99 return return_value._retn ();
103 TAO_MCAST_Parser::multicast_query (char* & buf,
104 const char *service_name,
105 unsigned short port,
106 const char *mcast_address,
107 int mcast_ttl,
108 const char *mcast_nic,
109 ACE_Time_Value *timeout,
110 CORBA::ORB_ptr orb)
112 ACE_INET_Addr my_addr;
113 ACE_SOCK_Acceptor acceptor;
114 ACE_SOCK_Stream stream;
115 ACE_SOCK_Dgram dgram;
117 ssize_t result = 0;
119 // Bind listener to any port and then find out what the port was.
120 #if defined (ACE_HAS_IPV6)
121 if (acceptor.open (ACE_Addr::sap_any, 0, AF_INET6) == -1
122 #else /* ACE_HAS_IPV6 */
123 if (acceptor.open (ACE_Addr::sap_any) == -1
124 #endif /* !ACE_HAS_IPV6 */
125 || acceptor.get_local_addr (my_addr) == -1)
127 TAOLIB_ERROR ((LM_ERROR,
128 ACE_TEXT ("acceptor.open () || ")
129 ACE_TEXT ("acceptor.get_local_addr () failed\n")));
130 result = -1;
132 else
134 if (TAO_debug_level > 0)
136 ACE_TCHAR addr[64];
137 my_addr.addr_to_string (addr, sizeof(addr));
138 TAOLIB_DEBUG ((LM_DEBUG,
139 ACE_TEXT("TAO (%P|%t) - MCAST_Parser: acceptor local address %s.\n"),
140 addr));
143 ACE_INET_Addr multicast_addr (port,
144 mcast_address);
146 // Set the address if multicast_discovery_endpoint option
147 // is specified for the Naming Service.
148 ACE_CString mde (orb->orb_core ()->orb_params ()
149 ->mcast_discovery_endpoint ());
151 if (ACE_OS::strcasecmp (service_name,
152 "NameService") == 0
153 && mde.length () != 0)
154 if (multicast_addr.set (mde.c_str()) == -1)
156 TAOLIB_ERROR ((LM_ERROR,
157 ACE_TEXT("ORB.cpp: Multicast address setting failed\n")));
158 stream.close ();
159 dgram.close ();
160 acceptor.close ();
161 return -1;
164 // Open the datagram.
165 if (dgram.open (ACE_Addr::sap_any, multicast_addr.get_type ()) == -1)
167 TAOLIB_ERROR ((LM_ERROR,
168 ACE_TEXT ("Unable to open the Datagram!\n")));
169 result = -1;
171 else
173 // Set NIC
174 dgram.set_nic (ACE_TEXT_CHAR_TO_TCHAR (mcast_nic),
175 multicast_addr.get_type ());
177 // Set TTL
178 int mcast_ttl_optval = mcast_ttl;
180 #if defined (ACE_HAS_IPV6)
181 if (multicast_addr.get_type () == AF_INET6)
183 if (dgram.set_option (
184 IPPROTO_IPV6,
185 IPV6_MULTICAST_HOPS,
186 &mcast_ttl_optval,
187 sizeof (mcast_ttl_optval)) != 0)
188 return -1;
190 else
191 #endif /* ACE_HAS_IPV6 */
192 if (dgram.set_option (
193 IPPROTO_IP,
194 IP_MULTICAST_TTL,
195 &mcast_ttl_optval,
196 sizeof (mcast_ttl_optval)) != 0)
197 result = -1;
199 // Convert the acceptor port into network byte order.
200 ACE_UINT16 response_port =
201 (ACE_UINT16) ACE_HTONS (my_addr.get_port_number ());
203 // Length of service name we will send.
204 CORBA::Short data_len =
205 (CORBA::Short) ACE_HTONS (
206 ACE_Utils::truncate_cast<ACE_UINT16> (
207 std::strlen (service_name) + 1));
209 // Vector we will send. It contains: 1) length of service
210 // name string, 2)port on which we are listening for
211 // replies, and 3) name of service we are looking for.
212 const int iovcnt = 3;
213 iovec iovp[iovcnt];
215 // The length of service name string.
216 iovp[0].iov_base = (char *) &data_len;
217 iovp[0].iov_len = sizeof (CORBA::Short);
219 // The port at which we are listening.
220 iovp[1].iov_base = (char *) &response_port;
221 iovp[1].iov_len = sizeof (ACE_UINT16);
223 // The service name string.
224 iovp[2].iov_base = (char *) service_name;
225 iovp[2].iov_len =
226 static_cast<u_long> (std::strlen (service_name) + 1);
228 // Send the multicast.
229 result = dgram.send (iovp,
230 iovcnt,
231 multicast_addr);
233 if (TAO_debug_level > 0)
234 TAOLIB_DEBUG ((LM_DEBUG,
235 ACE_TEXT ("\nsent multicast request.")));
237 // Check for errors.
238 if (result == -1)
239 TAOLIB_ERROR ((LM_ERROR,
240 ACE_TEXT ("%p\n"),
241 ACE_TEXT ("error sending IIOP multicast")));
242 else
244 if (TAO_debug_level > 0)
245 TAOLIB_DEBUG ((LM_DEBUG,
246 ACE_TEXT ("\n%N; Sent multicast.")
247 ACE_TEXT ("# of bytes sent is %d.\n"),
248 result));
249 // Wait for response until timeout.
250 ACE_Time_Value tv (
251 timeout == nullptr
252 ? ACE_Time_Value (TAO_DEFAULT_SERVICE_RESOLUTION_TIMEOUT)
253 : *timeout);
255 // Accept reply connection from server.
256 if (acceptor.accept (stream,
257 nullptr,
258 &tv) == -1)
260 if (TAO_debug_level > 0)
262 TAOLIB_ERROR ((LM_ERROR,
263 ACE_TEXT ("%p\n"),
264 ACE_TEXT ("multicast_query: unable to accept")));
266 result = -1;
268 else
270 // Receive the IOR.
272 // IOR length.
273 CORBA::Short ior_len;
274 result = stream.recv_n (&ior_len,
275 sizeof ior_len,
277 &tv);
278 if (result != (ssize_t)sizeof (ior_len))
280 if (TAO_debug_level > 0)
282 TAOLIB_ERROR ((LM_ERROR,
283 ACE_TEXT ("%p\n"),
284 ACE_TEXT ("multicast_query: unable to receive ")
285 ACE_TEXT ("ior length")));
287 result = -1;
289 else
291 // Allocate more space for the ior if we don't
292 // have enough.
293 ior_len = (CORBA::Short) ACE_NTOHS (ior_len);
294 if (ior_len >= TAO_DEFAULT_IOR_SIZE)
296 buf = CORBA::string_alloc (ior_len);
297 if (buf == nullptr)
299 if (TAO_debug_level > 0)
301 TAOLIB_ERROR ((LM_ERROR,
302 ACE_TEXT ("%p\n"),
303 ACE_TEXT ("multicast_query: unable to ")
304 ACE_TEXT ("allocate memory")));
306 result = -1;
310 if (result != -1)
312 // Receive the ior.
313 result = stream.recv_n (buf,
314 ior_len,
316 &tv);
317 if (result == -1)
318 TAOLIB_ERROR ((LM_ERROR,
319 ACE_TEXT ( "%p\n"),
320 ACE_TEXT ("error reading ior")));
321 else if (TAO_debug_level > 0)
322 TAOLIB_DEBUG ((LM_DEBUG,
323 ACE_TEXT ("%N: service resolved to IOR <%C>\n"),
324 buf));
330 if (result == -1)
332 TAOLIB_ERROR ((LM_ERROR,
333 ACE_TEXT("\nmulticast discovery of %C failed.\n"),
334 service_name));
336 if (ACE_OS::strcasecmp (service_name,
337 "NameService") == 0)
339 TAOLIB_ERROR ((LM_ERROR,
340 ACE_TEXT("Specify -m 1 when starting Naming_Service,\n")
341 ACE_TEXT("or see http://www.theaceorb.com/faq/#115\n")
342 ACE_TEXT("for using NameService without multicast.\n\n")));
347 // Clean up.
348 stream.close ();
349 dgram.close ();
350 acceptor.close ();
352 return result == -1 ? -1 : 0;
355 void
356 TAO_MCAST_Parser::assign_to_variables (char const * mcast_name)
359 * The format now is "multicast_address:port:nicaddress:ttl/object_key"
361 ACE_CString mcast_name_cstring (mcast_name);
363 ACE_CString::size_type pos_colon1 = mcast_name_cstring.find (':', 0);
365 #if defined (ACE_HAS_IPV6)
366 // IPv6 numeric address in host string?
367 bool ipv6_in_host = false;
369 // Check if this is an mcast address containing a
370 // decimal IPv6 address representation.
371 if (mcast_name_cstring[0] == '[')
373 // In this case we have to find the end of the numeric address and
374 // start looking for the port separator from there.
375 ACE_CString::size_type const cp_pos = mcast_name_cstring.find (']', 0);
376 if (cp_pos == 0)
378 // No valid IPv6 address specified.
379 if (TAO_debug_level > 0)
381 TAOLIB_ERROR ((LM_ERROR,
382 ACE_TEXT ("\nTAO (%P|%t) MCAST_Parser: ")
383 ACE_TEXT ("Invalid IPv6 decimal address specified.\n")));
386 return;
388 else
390 if (mcast_name_cstring[cp_pos + 1] == ':') // Look for a port
391 pos_colon1 = cp_pos + 1;
392 else
393 pos_colon1 = cp_pos;
394 ipv6_in_host = true; // host string contains full IPv6 numeric address
397 #endif /* ACE_HAS_IPV6 */
399 if (pos_colon1 == 0)
401 #if defined (ACE_HAS_IPV6)
402 const char default_addr[] = ACE_DEFAULT_MULTICASTV6_ADDR;
403 #else /* ACE_HAS_IPV6 */
404 const char default_addr[] = ACE_DEFAULT_MULTICAST_ADDR;
405 #endif /* !ACE_HAS_IPV6 */
406 this->mcast_address_ = default_addr;
408 else
410 #if defined (ACE_HAS_IPV6)
411 if (ipv6_in_host)
412 this->mcast_address_ =
413 mcast_name_cstring.substring (1,
414 pos_colon1 - 2).c_str ();
415 else
416 #endif /* ACE_HAS_IPV6 */
417 this->mcast_address_ =
418 mcast_name_cstring.substring (0,
419 pos_colon1).c_str ();
421 mcast_name_cstring =
422 mcast_name_cstring.substring (pos_colon1 + 1,
423 mcast_name_cstring.length() -
424 pos_colon1);
426 ACE_CString::size_type const pos_colon2 = mcast_name_cstring.find (':', 0);
428 if (pos_colon2 == 0)
430 if (mcast_name_cstring.find ("InterfaceRepository") != ACE_CString::npos)
432 this->mcast_port_ =
433 TAO_DEFAULT_INTERFACEREPO_SERVER_REQUEST_PORT;
435 else if (mcast_name_cstring.find ("ImplRepoService") != ACE_CString::npos)
437 this->mcast_port_ =
438 TAO_DEFAULT_IMPLREPO_SERVER_REQUEST_PORT;
440 else if (mcast_name_cstring.find ("TradingService") != ACE_CString::npos)
442 this->mcast_port_ = TAO_DEFAULT_TRADING_SERVER_REQUEST_PORT;
445 else
447 int const the_port =
448 ACE_OS::atoi (mcast_name_cstring.substring (0, pos_colon2).c_str ());
450 if (the_port >= 0 && the_port <= ACE_MAX_DEFAULT_PORT)
451 this->mcast_port_ = the_port;
454 mcast_name_cstring =
455 mcast_name_cstring.substring (pos_colon2 + 1,
456 mcast_name_cstring.length() - pos_colon2);
459 ACE_CString::size_type const pos_colon3 = mcast_name_cstring.find (':', 0);
461 this->mcast_nic_ = mcast_name_cstring.substring (0, pos_colon3).c_str ();
463 mcast_name_cstring =
464 mcast_name_cstring.substring (pos_colon3 + 1,
465 mcast_name_cstring.length() - pos_colon3);
467 ACE_CString::size_type const pos_colon4 = mcast_name_cstring.find ('/', 0);
469 if (pos_colon4 != 0)
471 // Change TTL to non-default value.
472 int const the_ttl =
473 ACE_OS::atoi (mcast_name_cstring.substring (0, pos_colon4).c_str ());
475 if (the_ttl > 0 && the_ttl <= 255) // Valid TTLs: (0, 255]
476 this->mcast_ttl_ = the_ttl;
479 mcast_name_cstring =
480 mcast_name_cstring.substring (pos_colon4,
481 mcast_name_cstring.length() - pos_colon4);
483 this->service_name_ =
484 mcast_name_cstring.substring (1, mcast_name_cstring.length() - 1).c_str ();
487 ACE_STATIC_SVC_DEFINE (TAO_MCAST_Parser,
488 ACE_TEXT ("MCAST_Parser"),
489 ACE_SVC_OBJ_T,
490 &ACE_SVC_NAME (TAO_MCAST_Parser),
491 ACE_Service_Type::DELETE_THIS |
492 ACE_Service_Type::DELETE_OBJ,
495 ACE_FACTORY_DEFINE (TAO, TAO_MCAST_Parser)
497 TAO_END_VERSIONED_NAMESPACE_DECL
500 #endif /* TAO_HAS_MCAST_PARSER == 1 */