Jack2: JackSocket.cpp Source File

Jack2 1.9.12

JackSocket.cpp
1 /*
2 Copyright (C) 2004-2008 Grame
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as published by
6 the Free Software Foundation; either version 2.1 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18 */
19
20 #include "JackSocket.h"
21 #include "JackConstants.h"
22 #include "JackTools.h"
23 #include "JackError.h"
24 #include "promiscuous.h"
25 #include <string.h>
26 #include <stdio.h>
27 #include <pthread.h>
28 #include <fcntl.h>
29
30 namespace Jack
31 {
32
33 static void BuildName(const char* client_name, char* res, const char* dir, int which, int size, bool promiscuous)
34 {
35 char ext_client_name[SYNC_MAX_NAME_SIZE + 1];
36 JackTools::RewriteName(client_name, ext_client_name);
37 if (promiscuous) {
38 snprintf(res, size, "%s/jack_%s_%d", dir, ext_client_name, which);
39 } else {
40 snprintf(res, size, "%s/jack_%s_%d_%d", dir, ext_client_name, JackTools::GetUID(), which);
41 }
42 }
43
44 JackClientSocket::JackClientSocket(): JackClientRequestInterface(), fSocket(-1), fTimeOut(0)
45 {
46 const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
47 fPromiscuous = (promiscuous != NULL);
48 fPromiscuousGid = jack_group2gid(promiscuous);
49 }
50
51 JackClientSocket::JackClientSocket(int socket): JackClientRequestInterface(), fSocket(socket),fTimeOut(0), fPromiscuous(false), fPromiscuousGid(-1)
52 {}
53
54 #if defined(__sun__) || defined(sun)
55
56 void JackClientSocket::SetReadTimeOut(long sec)
57 {
58 int flags;
59 fTimeOut = sec;
60
61 if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) {
62 jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_GETFL");
63 return;
64 }
65
66 flags |= O_NONBLOCK;
67 if (fcntl(fSocket, F_SETFL, flags) < 0) {
68 jack_error("JackClientSocket::SetReadTimeOut error in fcntl F_SETFL");
69 return;
70 }
71 }
72
73 void JackClientSocket::SetWriteTimeOut(long sec)
74 {
75 int flags;
76 fTimeOut = sec;
77
78 if ((flags = fcntl(fSocket, F_GETFL, 0)) < 0) {
79 jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_GETFL");
80 return;
81 }
82
83 flags |= O_NONBLOCK;
84 if (fcntl(fSocket, F_SETFL, flags) < 0) {
85 jack_error("JackClientSocket::SetWriteTimeOut error in fcntl F_SETFL");
86 return;
87 }
88 }
89
90 #else
91
92 void JackClientSocket::SetReadTimeOut(long sec)
93 {
94 struct timeval timout;
95 timout.tv_sec = sec;
96 timout.tv_usec = 0;
97 if (setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timout, sizeof(timeval)) < 0) {
98 jack_error("SetReadTimeOut fd = %ld err = %s", fSocket, strerror(errno));
99 }
100 }
101
102 void JackClientSocket::SetWriteTimeOut(long sec)
103 {
104 struct timeval timout;
105 timout.tv_sec = sec ;
106 timout.tv_usec = 0;
107 if (setsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timout, sizeof(timeval)) < 0) {
108 jack_error("SetWriteTimeOut fd = %ld err = %s", fSocket, strerror(errno));
109 }
110 }
111
112 #endif
113
114 void JackClientSocket::SetNonBlocking(bool onoff)
115 {
116 if (onoff) {
117 long flags = 0;
118 if (fcntl(fSocket, F_SETFL, flags | O_NONBLOCK) < 0) {
119 jack_error("SetNonBlocking fd = %ld err = %s", fSocket, strerror(errno));
120 }
121 }
122 }
123
124 int JackClientSocket::Connect(const char* dir, const char* name, int which) // A revoir : utilisation de "which"
125 {
126 struct sockaddr_un addr;
127
128 if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
129 jack_error("Cannot create socket err = %s", strerror(errno));
130 return -1;
131 }
132
133 addr.sun_family = AF_UNIX;
134 BuildName(name, addr.sun_path, dir, which, sizeof(addr.sun_path), fPromiscuous);
135 jack_log("JackClientSocket::Connect : addr.sun_path %s", addr.sun_path);
136
137 if (connect(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
138 jack_error("Cannot connect to server socket err = %s", strerror(errno));
139 close(fSocket);
140 return -1;
141 }
142
143 #ifdef __APPLE__
144 int on = 1;
145 if (setsockopt(fSocket, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&on, sizeof(on)) < 0) {
146 jack_log("setsockopt SO_NOSIGPIPE fd = %ld err = %s", fSocket, strerror(errno));
147 }
148 #endif
149
150 return 0;
151 }
152
153 int JackClientSocket::Close()
154 {
155 jack_log("JackClientSocket::Close");
156 if (fSocket > 0) {
157 shutdown(fSocket, SHUT_RDWR);
158 close(fSocket);
159 fSocket = -1;
160 return 0;
161 } else {
162 return -1;
163 }
164 }
165
166 int JackClientSocket::Read(void* data, int len)
167 {
168 int res;
169
170 #if defined(__sun__) || defined(sun)
171 if (fTimeOut > 0) {
172
173 struct timeval tv;
174 fd_set fdset;
175 ssize_t res;
176
177 tv.tv_sec = fTimeOut;
178 tv.tv_usec = 0;
179
180 FD_ZERO(&fdset);
181 FD_SET(fSocket, &fdset);
182
183 do {
184 res = select(fSocket + 1, &fdset, NULL, NULL, &tv);
185 } while (res < 0 && errno == EINTR);
186
187 if (res < 0) {
188 return res;
189 } else if (res == 0) {
190 return -1;
191 }
192 }
193 #endif
194
195 if ((res = read(fSocket, data, len)) != len) {
196 if (errno == EWOULDBLOCK || errno == EAGAIN) {
197 jack_error("JackClientSocket::Read time out");
198 return 0; // For a non blocking socket, a read failure is not considered as an error
199 } else if (res != 0) {
200 jack_error("Cannot read socket fd = %d err = %s", fSocket, strerror(errno));
201 //return 0;
202 return -1;
203 } else {
204 jack_error("Cannot read socket fd = %d err = %s", fSocket, strerror(errno));
205 return -1;
206 }
207 } else {
208 return 0;
209 }
210 }
211
212 int JackClientSocket::Write(void* data, int len)
213 {
214 int res;
215
216 #if defined(__sun__) || defined(sun)
217 if (fTimeOut > 0) {
218
219 struct timeval tv;
220 fd_set fdset;
221 ssize_t res;
222
223 tv.tv_sec = fTimeOut;
224 tv.tv_usec = 0;
225
226 FD_ZERO(&fdset);
227 FD_SET(fSocket, &fdset);
228
229 do {
230 res = select(fSocket + 1, NULL, &fdset, NULL, &tv);
231 } while (res < 0 && errno == EINTR);
232
233 if (res < 0) {
234 return res;
235 } else if (res == 0) {
236 return -1;
237 }
238 }
239 #endif
240
241 if ((res = write(fSocket, data, len)) != len) {
242 if (errno == EWOULDBLOCK || errno == EAGAIN) {
243 jack_log("JackClientSocket::Write time out");
244 return 0; // For a non blocking socket, a write failure is not considered as an error
245 } else if (res != 0) {
246 jack_error("Cannot write socket fd = %ld err = %s", fSocket, strerror(errno));
247 //return 0;
248 return -1;
249 } else {
250 jack_error("Cannot write socket fd = %ld err = %s", fSocket, strerror(errno));
251 return -1;
252 }
253 } else {
254 return 0;
255 }
256 }
257
258 JackServerSocket::JackServerSocket(): fSocket( -1)
259 {
260 const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
261 fPromiscuous = (promiscuous != NULL);
262 fPromiscuousGid = jack_group2gid(promiscuous);
263 }
264
265 int JackServerSocket::Bind(const char* dir, const char* name, int which) // A revoir : utilisation de "which"
266 {
267 struct sockaddr_un addr;
268
269 if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
270 jack_error("Cannot create server socket err = %s", strerror(errno));
271 return -1;
272 }
273
274 addr.sun_family = AF_UNIX;
275 // Socket name has to be kept in fName to be "unlinked".
276 BuildName(name, fName, dir, which, sizeof(addr.sun_path), fPromiscuous);
277 strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1);
278
279 jack_log("JackServerSocket::Bind : addr.sun_path %s", addr.sun_path);
280 unlink(fName); // Security...
281
282 if (bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
283 jack_error("Cannot bind server to socket err = %s", strerror(errno));
284 goto error;
285 }
286
287 if (listen(fSocket, 100) < 0) {
288 jack_error("Cannot enable listen on server socket err = %s", strerror(errno));
289 goto error;
290 }
291
292 if (fPromiscuous && (jack_promiscuous_perms(-1, fName, fPromiscuousGid) < 0))
293 goto error;
294
295 return 0;
296
297 error:
298 unlink(fName);
299 close(fSocket);
300 return -1;
301 }
302
303 JackClientSocket* JackServerSocket::Accept()
304 {
305 struct sockaddr_un client_addr;
306 socklen_t client_addrlen;
307
308 memset(&client_addr, 0, sizeof(client_addr));
309 client_addrlen = sizeof(client_addr);
310
311 int fd = accept(fSocket, (struct sockaddr*)&client_addr, &client_addrlen);
312 if (fd < 0) {
313 jack_error("Cannot accept new connection err = %s", strerror(errno));
314 return 0;
315 } else {
316 return new JackClientSocket(fd);
317 }
318 }
319
320 int JackServerSocket::Close()
321 {
322 if (fSocket > 0) {
323 jack_log("JackServerSocket::Close %s", fName);
324 shutdown(fSocket, SHUT_RDWR);
325 close(fSocket);
326 unlink(fName);
327 fSocket = -1;
328 return 0;
329 } else {
330 return -1;
331 }
332 }
333
334 } // end of namespace
335
336
jack_log
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108
jack_error
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92