bes Updated for version 3.20.13
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
47using std::endl;
48using std::ostream;
49using std::string;
50
51void UnixSocket::connect()
52{
53 if (_listening) {
54 string err("Socket is already listening");
55 throw BESInternalError(err, __FILE__, __LINE__);
56 }
57
58 if (_connected) {
59 string err("Socket is already connected");
60 throw BESInternalError(err, __FILE__, __LINE__);
61 }
62
63 struct sockaddr_un client_addr;
64 struct sockaddr_un server_addr;
65
66 // what is the max size of the path to the unix socket
67 unsigned int max_len = sizeof(client_addr.sun_path);
68
69 char path[107] = "";
70 getcwd(path, sizeof(path));
71 _tempSocket = path;
72 _tempSocket += "/";
73 _tempSocket += SocketUtilities::create_temp_name();
74 _tempSocket += ".unixSocket";
75 // maximum path for struct sockaddr_un.sun_path is 108
76 // get sure we will not exceed to max for creating sockets
77 // 107 characters in pathname + '\0'
78 if (_tempSocket.length() > max_len - 1) {
79 string msg = "path to temporary unix socket ";
80 msg += _tempSocket + " is too long";
81 throw(BESInternalError(msg, __FILE__, __LINE__));
82 }
83 if (_unixSocket.length() > max_len - 1) {
84 string msg = "path to unix socket ";
85 msg += _unixSocket + " is too long";
86 throw(BESInternalError(msg, __FILE__, __LINE__));
87 }
88
89 strncpy(server_addr.sun_path, _unixSocket.c_str(), _unixSocket.size());
90 server_addr.sun_path[_unixSocket.size()] = '\0';
91 server_addr.sun_family = AF_UNIX;
92
93 int descript = socket( AF_UNIX, SOCK_STREAM, 0);
94 if (descript != -1) {
95 strncpy(client_addr.sun_path, _tempSocket.c_str(), _tempSocket.size());
96 client_addr.sun_path[_tempSocket.size()] = '\0';
97 client_addr.sun_family = AF_UNIX;
98
99 int clen = sizeof(client_addr.sun_family);
100 clen += strlen(client_addr.sun_path) + 1;
101
102 if (bind(descript, (struct sockaddr*) &client_addr, clen + 1) != -1) {
103 int slen = sizeof(server_addr.sun_family);
104 slen += strlen(server_addr.sun_path) + 1;
105
106 // we aren't setting the send and receive buffer sizes for a
107 // unix socket. These will default to a set value
108
109 if (::connect(descript, (struct sockaddr*) &server_addr, slen) != -1) {
110 _socket = descript;
111 _connected = true;
112 }
113 else {
114 ::close(descript);
115 string msg = "could not connect via ";
116 msg += _unixSocket;
117 char *err = strerror( errno);
118 if (err)
119 msg = msg + "\n" + err;
120 else
121 msg = msg + "\nCould not retrieve error message";
122 throw BESInternalError(msg, __FILE__, __LINE__);
123 }
124 }
125 else {
126 ::close(descript);
127 string msg = "could not bind to Unix socket ";
128 msg += _tempSocket;
129 char *err = strerror( errno);
130 if (err)
131 msg = msg + "\n" + err;
132 else
133 msg = msg + "\nCould not retrieve error message";
134 throw BESInternalError(msg, __FILE__, __LINE__);
135 }
136 }
137 else {
138 string msg = "could not create a Unix socket";
139 char *err = strerror( errno);
140 if (err)
141 msg = msg + "\n" + err;
142 else
143 msg = msg + "\nCould not retrieve error message";
144 throw BESInternalError(msg, __FILE__, __LINE__);
145 }
146}
147
148void UnixSocket::listen()
149{
150 if (_connected) {
151 string err("Socket is already connected");
152 throw BESInternalError(err, __FILE__, __LINE__);
153 }
154
155 if (_listening) {
156 string err("Socket is already listening");
157 throw BESInternalError(err, __FILE__, __LINE__);
158 }
159
160 int on = 1;
161 static struct sockaddr_un server_add;
162 _socket = socket( AF_UNIX, SOCK_STREAM, 0);
163 if (_socket >= 0) {
164 server_add.sun_family = AF_UNIX;
165 // Changed the call below to strncpy; sockaddr_un.sun_path is a char[104]
166 // on OS/X. jhrg 5/26/06
167 strncpy(server_add.sun_path, _unixSocket.c_str(), 103);
168 server_add.sun_path[103] = '\0';
169
170 (void) unlink(_unixSocket.c_str());
171 if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &on, sizeof(on))) {
172 string error("could not set SO_REUSEADDR on Unix socket");
173 const char *error_info = strerror( errno);
174 if (error_info) error += " " + (string) error_info;
175 throw BESInternalError(error, __FILE__, __LINE__);
176 }
177
178 // we aren't setting the send and receive buffer sizes for a unix
179 // socket. These will default to a set value
180
181 // Added a +1 to the size computation. jhrg 5/26/05
182 if (bind(_socket, (struct sockaddr*) &server_add,
183 sizeof(server_add.sun_family) + strlen(server_add.sun_path) + 1) != -1) {
184 if (::listen(_socket, 5) == 0) {
185 _listening = true;
186 }
187 else {
188 string error("could not listen Unix socket");
189 const char* error_info = strerror( errno);
190 if (error_info) error += " " + (string) error_info;
191 throw BESInternalError(error, __FILE__, __LINE__);
192 }
193 }
194 else {
195 string error("could not bind Unix socket");
196 const char* error_info = strerror( errno);
197 if (error_info) error += " " + (string) error_info;
198 throw BESInternalError(error, __FILE__, __LINE__);
199 }
200 }
201 else {
202 string error("could not get Unix socket");
203 const char *error_info = strerror( errno);
204 if (error_info) error += " " + (string) error_info;
205 throw BESInternalError(error, __FILE__, __LINE__);
206 }
207}
208
209void UnixSocket::close()
210{
211 Socket::close();
212 if (_tempSocket != "") {
213#if 0
214 // This is flaggeed as a 'Time of check, time of use' error by
215 // coverity. I think the test to see if the file exists is not
216 // needed since the code ignores the error return by remove.
217 // jhrg 10/23/15
218 if (!access(_tempSocket.c_str(), F_OK)) {
219 (void) remove(_tempSocket.c_str());
220 }
221#endif
222 (void) remove(_tempSocket.c_str());
223 _connected = false;
224 }
225 if (_listening && _unixSocket != "") {
226#if 0
227 if (!access(_unixSocket.c_str(), F_OK)) {
228 (void) remove(_unixSocket.c_str());
229 }
230#endif
231 (void) remove(_unixSocket.c_str());
232 _listening = false;
233 }
234}
235
240{
241 return true;
242}
243
250void UnixSocket::dump(ostream &strm) const
251{
252 strm << BESIndent::LMarg << "UnixSocket::dump - (" << (void *) this << ")" << endl;
253 BESIndent::Indent();
254 strm << BESIndent::LMarg << "unix socket: " << _unixSocket << endl;
255 strm << BESIndent::LMarg << "temp socket: " << _tempSocket << endl;
256 Socket::dump(strm);
257 BESIndent::UnIndent();
258}
259
exception thrown if internal error encountered
static std::string create_temp_name()
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: Socket.cc:137
virtual bool allowConnection()
is there any wrapper code for unix sockets
Definition: UnixSocket.cc:239
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: UnixSocket.cc:250