1 // -*- Mode: C++; -*-
2 //                            Package   : omniORB
3 // unixAddress.cc             Created on: 6 Aug 2001
4 //                            Author    : Sai Lai Lo (sll)
5 //
6 //    Copyright (C) 2006-2013 Apasphere Ltd
7 //    Copyright (C) 2001 AT&T Laboratories Cambridge
8 //
9 //    This file is part of the omniORB library
10 //
11 //    The omniORB 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, see http://www.gnu.org/licenses/
23 //
24 //
25 // Description:
26 //	*** PROPRIETARY INTERFACE ***
27 //
28 
29 #include <omniORB4/CORBA.h>
30 #include <omniORB4/giopEndpoint.h>
31 #include <unix/unixConnection.h>
32 #include <unix/unixAddress.h>
33 #include <stdio.h>
34 #include <omniORB4/linkHacks.h>
35 #include <sys/un.h>
36 
37 #if defined(USE_FAKE_INTERRUPTABLE_RECV)
38 #  include <orbParameters.h>
39 #endif
40 
41 OMNI_EXPORT_LINK_FORCE_SYMBOL(unixAddress);
42 
43 #ifndef AF_LOCAL
44 #  ifdef  AF_UNIX
45 #    define AF_LOCAL AF_UNIX
46 #  endif
47 #endif
48 
OMNI_NAMESPACE_BEGIN(omni)49 OMNI_NAMESPACE_BEGIN(omni)
50 
51 /////////////////////////////////////////////////////////////////////////
52 unixAddress::unixAddress(const char* filename) {
53 
54   pd_filename = (const char*) filename;
55   pd_address_string = unixConnection::unToString(filename);
56 }
57 
58 /////////////////////////////////////////////////////////////////////////
59 const char*
type() const60 unixAddress::type() const {
61   return "giop:unix";
62 }
63 
64 /////////////////////////////////////////////////////////////////////////
65 const char*
address() const66 unixAddress::address() const {
67   return pd_address_string;
68 }
69 
70 /////////////////////////////////////////////////////////////////////////
71 giopAddress*
duplicate() const72 unixAddress::duplicate() const {
73   return new unixAddress(pd_filename);
74 }
75 
76 /////////////////////////////////////////////////////////////////////////
77 giopActiveConnection*
Connect(const omni_time_t & deadline,CORBA::ULong strand_flags,CORBA::Boolean & timed_out) const78 unixAddress::Connect(const omni_time_t& deadline,
79 		     CORBA::ULong    	strand_flags,
80 		     CORBA::Boolean& 	timed_out) const {
81 
82   struct sockaddr_un raddr;
83   int                rc;
84   SocketHandle_t     sock;
85 
86   if ((sock = socket(AF_LOCAL,SOCK_STREAM,0)) == RC_INVALID_SOCKET) {
87     return 0;
88   }
89 
90   memset((void*)&raddr, 0, sizeof(raddr));
91   raddr.sun_family = AF_LOCAL;
92   strncpy(raddr.sun_path, pd_filename, sizeof(raddr.sun_path) - 1);
93 
94 #if !defined(USE_NONBLOCKING_CONNECT)
95 
96   if (::connect(sock, (struct sockaddr *)&raddr,
97                 sizeof(raddr)) == RC_SOCKET_ERROR) {
98 
99     omniORB::logs(25, "Failed to connect to Unix socket.");
100     CLOSESOCKET(sock);
101     return 0;
102   }
103 
104 #else
105 
106   if (tcpSocket::setNonBlocking(sock) == RC_INVALID_SOCKET) {
107     omniORB::logs(25, "Failed to set Unix socket to non-blocking mode.");
108     CLOSESOCKET(sock);
109     return 0;
110   }
111 
112   if (::connect(sock,(struct sockaddr *)&raddr,
113                 sizeof(raddr)) == RC_SOCKET_ERROR) {
114 
115     int err = ERRNO;
116     if (err && err != RC_EINPROGRESS) {
117       omniORB::logs(25, "Failed to connect to Unix socket.");
118       CLOSESOCKET(sock);
119       return 0;
120     }
121   }
122 
123   struct timeval t;
124 
125   do {
126     if (tcpSocket::setAndCheckTimeout(deadline, t)) {
127       // Already timed out
128       omniORB::logs(25, "Timed out connecting to Unix socket.");
129       CLOSESOCKET(sock);
130       timed_out = 1;
131       return 0;
132     }
133 
134     rc = tcpSocket::waitWrite(sock, t);
135 
136     if (rc == 0) {
137       // Timed out
138 #if defined(USE_FAKE_INTERRUPTABLE_RECV)
139       continue;
140 #else
141       omniORB::logs(25, "Timed out connecting to Unix socket.");
142       CLOSESOCKET(sock);
143       timed_out = 1;
144       return 0;
145 #endif
146     }
147     else if (rc == RC_SOCKET_ERROR) {
148       if (ERRNO == RC_EINTR) {
149 	continue;
150       }
151       else {
152         omniORB::logs(25, "Failed to connect to Unix socket "
153                       "(waiting for writable socket)");
154 	CLOSESOCKET(sock);
155 	return 0;
156       }
157     }
158 
159     // Check to make sure that the socket is connected.
160     OMNI_SOCKADDR_STORAGE peer;
161     SOCKNAME_SIZE_T len = sizeof(peer);
162     rc = getpeername(sock, (struct sockaddr*)&peer, &len);
163 
164     if (rc == RC_SOCKET_ERROR) {
165       if (ERRNO == RC_EINTR) {
166 	continue;
167       }
168       else {
169 	omniORB::logs(25, "Failed to connect to Unix socket (no peer name).");
170 	CLOSESOCKET(sock);
171 	return 0;
172       }
173     }
174     break;
175 
176   } while (1);
177 #endif
178 
179   if (tcpSocket::setBlocking(sock) == RC_INVALID_SOCKET) {
180     omniORB::logs(25, "Failed to set Unix socket to blocking mode");
181     CLOSESOCKET(sock);
182     return 0;
183   }
184   return new unixActiveConnection(sock, pd_filename);
185 }
186 
187 /////////////////////////////////////////////////////////////////////////
188 CORBA::Boolean
Poke() const189 unixAddress::Poke() const {
190 
191   struct sockaddr_un raddr;
192   int  rc;
193   SocketHandle_t sock;
194 
195   if ((sock = socket(AF_LOCAL,SOCK_STREAM,0)) == RC_INVALID_SOCKET) {
196     return 0;
197   }
198 
199   memset((void*)&raddr,0,sizeof(raddr));
200   raddr.sun_family = AF_LOCAL;
201   strncpy(raddr.sun_path, pd_filename, sizeof(raddr.sun_path) - 1);
202 
203 
204 #if defined(USE_NONBLOCKING_CONNECT)
205 
206   if (tcpSocket::setNonBlocking(sock) == RC_INVALID_SOCKET) {
207     CLOSESOCKET(sock);
208     return 0;
209   }
210 
211 #endif
212 
213   if (::connect(sock,(struct sockaddr *)&raddr,
214                 sizeof(raddr)) == RC_SOCKET_ERROR) {
215 
216     if (ERRNO != RC_EINPROGRESS) {
217       CLOSESOCKET(sock);
218       return 0;
219     }
220   }
221 
222   // The connect has not necessarily completed by this stage, but
223   // we've done enough to poke the endpoint.
224   CLOSESOCKET(sock);
225   return 1;
226 }
227 
228 
229 OMNI_NAMESPACE_END(omni)
230