bes  Updated for version 3.19.1
UnixSocket.cc
1 // UnixSocket.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 // szednik Stephan Zednik <zednik@ucar.edu>
33 
34 #include <unistd.h> // for unlink
35 #include <sys/un.h>
36 #include <sys/socket.h>
37 #include <sys/types.h>
38 
39 #include <cstdio>
40 #include <cerrno>
41 #include <cstring>
42 
43 #include "UnixSocket.h"
44 #include "BESInternalError.h"
45 #include "SocketUtilities.h"
46 
47 void UnixSocket::connect()
48 {
49  if (_listening) {
50  string err("Socket is already listening");
51  throw BESInternalError(err, __FILE__, __LINE__);
52  }
53 
54  if (_connected) {
55  string err("Socket is already connected");
56  throw BESInternalError(err, __FILE__, __LINE__);
57  }
58 
59  struct sockaddr_un client_addr;
60  struct sockaddr_un server_addr;
61 
62  // what is the max size of the path to the unix socket
63  unsigned int max_len = sizeof(client_addr.sun_path);
64 
65  char path[107] = "";
66  getcwd(path, sizeof(path));
67  _tempSocket = path;
68  _tempSocket += "/";
69  _tempSocket += SocketUtilities::create_temp_name();
70  _tempSocket += ".unixSocket";
71  // maximum path for struct sockaddr_un.sun_path is 108
72  // get sure we will not exceed to max for creating sockets
73  // 107 characters in pathname + '\0'
74  if (_tempSocket.length() > max_len - 1) {
75  string msg = "path to temporary unix socket ";
76  msg += _tempSocket + " is too long";
77  throw(BESInternalError(msg, __FILE__, __LINE__));
78  }
79  if (_unixSocket.length() > max_len - 1) {
80  string msg = "path to unix socket ";
81  msg += _unixSocket + " is too long";
82  throw(BESInternalError(msg, __FILE__, __LINE__));
83  }
84 
85  strncpy(server_addr.sun_path, _unixSocket.c_str(), _unixSocket.size());
86  server_addr.sun_path[_unixSocket.size()] = '\0';
87  server_addr.sun_family = AF_UNIX;
88 
89  int descript = socket( AF_UNIX, SOCK_STREAM, 0);
90  if (descript != -1) {
91  strncpy(client_addr.sun_path, _tempSocket.c_str(), _tempSocket.size());
92  client_addr.sun_path[_tempSocket.size()] = '\0';
93  client_addr.sun_family = AF_UNIX;
94 
95  int clen = sizeof(client_addr.sun_family);
96  clen += strlen(client_addr.sun_path) + 1;
97 
98  if (bind(descript, (struct sockaddr*) &client_addr, clen + 1) != -1) {
99  int slen = sizeof(server_addr.sun_family);
100  slen += strlen(server_addr.sun_path) + 1;
101 
102  // we aren't setting the send and receive buffer sizes for a
103  // unix socket. These will default to a set value
104 
105  if (::connect(descript, (struct sockaddr*) &server_addr, slen) != -1) {
106  _socket = descript;
107  _connected = true;
108  }
109  else {
110  ::close(descript);
111  string msg = "could not connect via ";
112  msg += _unixSocket;
113  char *err = strerror( errno);
114  if (err)
115  msg = msg + "\n" + err;
116  else
117  msg = msg + "\nCould not retrieve error message";
118  throw BESInternalError(msg, __FILE__, __LINE__);
119  }
120  }
121  else {
122  ::close(descript);
123  string msg = "could not bind to Unix socket ";
124  msg += _tempSocket;
125  char *err = strerror( errno);
126  if (err)
127  msg = msg + "\n" + err;
128  else
129  msg = msg + "\nCould not retrieve error message";
130  throw BESInternalError(msg, __FILE__, __LINE__);
131  }
132  }
133  else {
134  string msg = "could not create a Unix socket";
135  char *err = strerror( errno);
136  if (err)
137  msg = msg + "\n" + err;
138  else
139  msg = msg + "\nCould not retrieve error message";
140  throw BESInternalError(msg, __FILE__, __LINE__);
141  }
142 }
143 
144 void UnixSocket::listen()
145 {
146  if (_connected) {
147  string err("Socket is already connected");
148  throw BESInternalError(err, __FILE__, __LINE__);
149  }
150 
151  if (_listening) {
152  string err("Socket is already listening");
153  throw BESInternalError(err, __FILE__, __LINE__);
154  }
155 
156  int on = 1;
157  static struct sockaddr_un server_add;
158  _socket = socket( AF_UNIX, SOCK_STREAM, 0);
159  if (_socket >= 0) {
160  server_add.sun_family = AF_UNIX;
161  // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
162  // on OS/X. jhrg 5/26/06
163  strncpy(server_add.sun_path, _unixSocket.c_str(), 103);
164  server_add.sun_path[103] = '\0';
165 
166  (void) unlink(_unixSocket.c_str());
167  if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &on, sizeof(on))) {
168  string error("could not set SO_REUSEADDR on Unix socket");
169  const char *error_info = strerror( errno);
170  if (error_info) error += " " + (string) error_info;
171  throw BESInternalError(error, __FILE__, __LINE__);
172  }
173 
174  // we aren't setting the send and receive buffer sizes for a unix
175  // socket. These will default to a set value
176 
177  // Added a +1 to the size computation. jhrg 5/26/05
178  if (bind(_socket, (struct sockaddr*) &server_add,
179  sizeof(server_add.sun_family) + strlen(server_add.sun_path) + 1) != -1) {
180  if (::listen(_socket, 5) == 0) {
181  _listening = true;
182  }
183  else {
184  string error("could not listen Unix socket");
185  const char* error_info = strerror( errno);
186  if (error_info) error += " " + (string) error_info;
187  throw BESInternalError(error, __FILE__, __LINE__);
188  }
189  }
190  else {
191  string error("could not bind Unix socket");
192  const char* error_info = strerror( errno);
193  if (error_info) error += " " + (string) error_info;
194  throw BESInternalError(error, __FILE__, __LINE__);
195  }
196  }
197  else {
198  string error("could not get Unix socket");
199  const char *error_info = strerror( errno);
200  if (error_info) error += " " + (string) error_info;
201  throw BESInternalError(error, __FILE__, __LINE__);
202  }
203 }
204 
205 void UnixSocket::close()
206 {
207  Socket::close();
208  if (_tempSocket != "") {
209 #if 0
210  // This is flaggeed as a 'Time of check, time of use' error by
211  // coverity. I think the test to see if the file exists is not
212  // needed since the code ignores the error return by remove.
213  // jhrg 10/23/15
214  if (!access(_tempSocket.c_str(), F_OK)) {
215  (void) remove(_tempSocket.c_str());
216  }
217 #endif
218  (void) remove(_tempSocket.c_str());
219  _connected = false;
220  }
221  if (_listening && _unixSocket != "") {
222 #if 0
223  if (!access(_unixSocket.c_str(), F_OK)) {
224  (void) remove(_unixSocket.c_str());
225  }
226 #endif
227  (void) remove(_unixSocket.c_str());
228  _listening = false;
229  }
230 }
231 
236 {
237  return true;
238 }
239 
246 void UnixSocket::dump(ostream &strm) const
247 {
248  strm << BESIndent::LMarg << "UnixSocket::dump - (" << (void *) this << ")" << endl;
249  BESIndent::Indent();
250  strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl;
251  strm << BESIndent::LMarg << "temp socket: " << _tempSocket << endl;
252  Socket::dump(strm);
253  BESIndent::UnIndent();
254 }
255 
exception thrown if inernal error encountered
virtual bool allowConnection()
is there any wrapper code for unix sockets
Definition: UnixSocket.cc:235
virtual void dump(ostream &strm) const
dumps information about this object
Definition: Socket.cc:134
static string create_temp_name()
virtual void dump(ostream &strm) const
dumps information about this object
Definition: UnixSocket.cc:246