Jack2  1.9.13
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  fSocket = -1;
141  return -1;
142  }
143 
144 #ifdef __APPLE__
145  int on = 1;
146  if (setsockopt(fSocket, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&on, sizeof(on)) < 0) {
147  jack_log("setsockopt SO_NOSIGPIPE fd = %ld err = %s", fSocket, strerror(errno));
148  }
149 #endif
150 
151  return 0;
152 }
153 
154 int JackClientSocket::Close()
155 {
156  jack_log("JackClientSocket::Close");
157  if (fSocket > 0) {
158  shutdown(fSocket, SHUT_RDWR);
159  close(fSocket);
160  fSocket = -1;
161  return 0;
162  } else {
163  return -1;
164  }
165 }
166 
167 int JackClientSocket::Read(void* data, int len)
168 {
169  int res;
170 
171 #if defined(__sun__) || defined(sun)
172  if (fTimeOut > 0) {
173 
174  struct timeval tv;
175  fd_set fdset;
176  ssize_t res;
177 
178  tv.tv_sec = fTimeOut;
179  tv.tv_usec = 0;
180 
181  FD_ZERO(&fdset);
182  FD_SET(fSocket, &fdset);
183 
184  do {
185  res = select(fSocket + 1, &fdset, NULL, NULL, &tv);
186  } while (res < 0 && errno == EINTR);
187 
188  if (res < 0) {
189  return res;
190  } else if (res == 0) {
191  return -1;
192  }
193  }
194 #endif
195 
196  if ((res = read(fSocket, data, len)) != len) {
197  if (errno == EWOULDBLOCK || errno == EAGAIN) {
198  jack_error("JackClientSocket::Read time out");
199  return 0; // For a non blocking socket, a read failure is not considered as an error
200  } else if (res != 0) {
201  jack_error("Cannot read socket fd = %d err = %s", fSocket, strerror(errno));
202  //return 0;
203  return -1;
204  } else {
205  jack_error("Cannot read socket fd = %d err = %s", fSocket, strerror(errno));
206  return -1;
207  }
208  } else {
209  return 0;
210  }
211 }
212 
213 int JackClientSocket::Write(void* data, int len)
214 {
215  int res;
216 
217 #if defined(__sun__) || defined(sun)
218  if (fTimeOut > 0) {
219 
220  struct timeval tv;
221  fd_set fdset;
222  ssize_t res;
223 
224  tv.tv_sec = fTimeOut;
225  tv.tv_usec = 0;
226 
227  FD_ZERO(&fdset);
228  FD_SET(fSocket, &fdset);
229 
230  do {
231  res = select(fSocket + 1, NULL, &fdset, NULL, &tv);
232  } while (res < 0 && errno == EINTR);
233 
234  if (res < 0) {
235  return res;
236  } else if (res == 0) {
237  return -1;
238  }
239  }
240 #endif
241 
242  if ((res = write(fSocket, data, len)) != len) {
243  if (errno == EWOULDBLOCK || errno == EAGAIN) {
244  jack_log("JackClientSocket::Write time out");
245  return 0; // For a non blocking socket, a write failure is not considered as an error
246  } else if (res != 0) {
247  jack_error("Cannot write socket fd = %ld err = %s", fSocket, strerror(errno));
248  //return 0;
249  return -1;
250  } else {
251  jack_error("Cannot write socket fd = %ld err = %s", fSocket, strerror(errno));
252  return -1;
253  }
254  } else {
255  return 0;
256  }
257 }
258 
259 JackServerSocket::JackServerSocket(): fSocket( -1)
260 {
261  const char* promiscuous = getenv("JACK_PROMISCUOUS_SERVER");
262  fPromiscuous = (promiscuous != NULL);
263  fPromiscuousGid = jack_group2gid(promiscuous);
264 }
265 
266 int JackServerSocket::Bind(const char* dir, const char* name, int which) // A revoir : utilisation de "which"
267 {
268  struct sockaddr_un addr;
269 
270  if ((fSocket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
271  jack_error("Cannot create server socket err = %s", strerror(errno));
272  return -1;
273  }
274 
275  addr.sun_family = AF_UNIX;
276  // Socket name has to be kept in fName to be "unlinked".
277  BuildName(name, fName, dir, which, sizeof(addr.sun_path), fPromiscuous);
278  strncpy(addr.sun_path, fName, sizeof(addr.sun_path) - 1);
279 
280  jack_log("JackServerSocket::Bind : addr.sun_path %s", addr.sun_path);
281  unlink(fName); // Security...
282 
283  if (bind(fSocket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
284  jack_error("Cannot bind server to socket err = %s", strerror(errno));
285  goto error;
286  }
287 
288  if (listen(fSocket, 100) < 0) {
289  jack_error("Cannot enable listen on server socket err = %s", strerror(errno));
290  goto error;
291  }
292 
293  if (fPromiscuous && (jack_promiscuous_perms(-1, fName, fPromiscuousGid) < 0))
294  goto error;
295 
296  return 0;
297 
298 error:
299  unlink(fName);
300  close(fSocket);
301  fSocket = -1;
302  return -1;
303 }
304 
305 JackClientSocket* JackServerSocket::Accept()
306 {
307  struct sockaddr_un client_addr;
308  socklen_t client_addrlen;
309 
310  memset(&client_addr, 0, sizeof(client_addr));
311  client_addrlen = sizeof(client_addr);
312 
313  int fd = accept(fSocket, (struct sockaddr*)&client_addr, &client_addrlen);
314  if (fd < 0) {
315  jack_error("Cannot accept new connection err = %s", strerror(errno));
316  return 0;
317  } else {
318  return new JackClientSocket(fd);
319  }
320 }
321 
322 int JackServerSocket::Close()
323 {
324  if (fSocket > 0) {
325  jack_log("JackServerSocket::Close %s", fName);
326  shutdown(fSocket, SHUT_RDWR);
327  close(fSocket);
328  unlink(fName);
329  fSocket = -1;
330  return 0;
331  } else {
332  return -1;
333  }
334 }
335 
336 } // end of namespace
337 
338 
SERVER_EXPORT void jack_error(const char *fmt,...)
Definition: JackError.cpp:92
SERVER_EXPORT void jack_log(const char *fmt,...)
Definition: JackError.cpp:108