1 /* GNet - Networking library
2  * Copyright (C) 2000  David Helder
3  * Copyright (C) 2001  Mark Ferlatte
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA  02111-1307, USA.
19  */
20 
21 #include "gnet-private.h"
22 
23 #ifndef GNET_WIN32
24 
25 #include "unix.h"
26 #include <errno.h>
27 #include <string.h>
28 
29 struct _GUnixSocket
30 {
31   gint sockfd;
32   guint ref_count;
33   GIOChannel *iochannel;
34   struct sockaddr_un sa;
35 
36   gboolean server;
37   gboolean abstract;        /* Abstract unix socket? */
38 };
39 
40 #define PATH(S) (((struct sockaddr_un *) (&(S)->sa))->sun_path)
41 
42 #ifndef SUN_LEN
43 #define SUN_LEN(sa_un) \
44     G_STRUCT_OFFSET (struct sockaddr_un, sun_path) + strlen (sa_un->sun_path)
45 #endif
46 
47 /* GNET_SUN_LEN: our own version of SUN_LEN that also works for abstract
48  * sockets where SUN_LEN fails because it doesn't take into account the
49  * initial zero in the path string in the case of abstract sockets */
50 #define GNET_SUN_LEN(sa_un) gnet_sun_len(sa_un)
51 
52 static gboolean gnet_unix_socket_unlink (const gchar *path);
53 
54 static guint
gnet_sun_len(struct sockaddr_un * sa_un)55 gnet_sun_len (struct sockaddr_un *sa_un)
56 {
57   /* normal unix socket */
58   if (sa_un->sun_path[0] != '\0')
59     return SUN_LEN (sa_un);
60 
61   /* abstract socket, has a zero byte before the path */
62   return G_STRUCT_OFFSET (struct sockaddr_un, sun_path) + 1
63        + strlen (sa_un->sun_path + 1);
64 }
65 
66 static GUnixSocket*
gnet_unix_socket_new_internal(const gchar * path,gboolean abstract)67 gnet_unix_socket_new_internal (const gchar * path, gboolean abstract)
68 {
69   struct sockaddr_un *sa_un;
70   GUnixSocket *s;
71 
72   g_return_val_if_fail (path != NULL, NULL);
73 
74 #ifndef HAVE_ABSTRACT_SOCKETS
75   /* if abstract unix sockets are not available, create a normal unix socket */
76   abstract = FALSE;
77 #endif
78 
79   /* Create socket */
80   s = g_new0 (GUnixSocket, 1);
81   sa_un = (struct sockaddr_un *) &s->sa;
82   s->ref_count = 1;
83   s->server = FALSE;
84   s->sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
85   if (!GNET_IS_SOCKET_VALID (s->sockfd)) {
86     g_warning ("socket(%s) failed: %s", path, g_strerror (errno));
87     g_free(s);
88     return NULL;
89   }
90 
91   if (abstract) {
92     sa_un->sun_path[0] = '\0';
93     strncpy (sa_un->sun_path + 1, path, sizeof (sa_un->sun_path) - 2);
94     s->abstract = TRUE;
95   } else {
96     strncpy (sa_un->sun_path, path, sizeof (sa_un->sun_path) - 1);
97   }
98 
99   sa_un->sun_family = AF_UNIX;
100   if (connect (s->sockfd, (struct sockaddr*) sa_un, GNET_SUN_LEN (sa_un)) != 0) {
101     g_warning ("connect(%s) failed: %s", path, g_strerror (errno));
102     GNET_CLOSE_SOCKET (s->sockfd);
103     g_free(s);
104     return NULL;
105   }
106 
107   return s;
108 }
109 
110 /**
111  *  gnet_unix_socket_new
112  *  @path: path
113  *
114  *  Creates a #GUnixSocket and connects to @path.  This function will
115  *  block to connect.  Use this constructor to create a #GUnixSocket
116  *  for a client.
117  *
118  *  Returns: a new #GUnixSocket; NULL on failure.
119  *
120  **/
121 GUnixSocket*
gnet_unix_socket_new(const gchar * path)122 gnet_unix_socket_new (const gchar * path)
123 {
124   return gnet_unix_socket_new_internal (path, FALSE);
125 }
126 
127 /**
128  *  gnet_unix_socket_new_abstract
129  *  @path: path
130  *
131  *  Creates a #GUnixSocket and connects to @path in the abstract
132  *  unix socket domain. This function will block to connect.  Use this
133  *  constructor to create a #GUnixSocket for a client.
134  *
135  *  If the abstract unix sockets are not available on the platform in use,
136  *  this function will behave like gnet_unix_socket_new().
137  *
138  *  Returns: a new #GUnixSocket, or NULL on failure.
139  *
140  *  Since: 2.0.8
141  **/
142 GUnixSocket*
gnet_unix_socket_new_abstract(const gchar * path)143 gnet_unix_socket_new_abstract (const gchar * path)
144 {
145   return gnet_unix_socket_new_internal (path, TRUE);
146 }
147 
148 
149 /**
150  *  gnet_unix_socket_delete
151  *  @socket: a #GUnixSocket
152  *
153  *  Deletes a #GUnixSocket.
154  *
155  **/
156 void
gnet_unix_socket_delete(GUnixSocket * socket)157 gnet_unix_socket_delete (GUnixSocket* socket)
158 {
159   if (socket != NULL)
160     gnet_unix_socket_unref (socket);
161 }
162 
163 
164 /**
165  *  gnet_unix_socket_ref
166  *  @socket: a #GUnixSocket
167  *
168  *  Adds a reference to a #GUnixSocket.
169  *
170  **/
171 void
gnet_unix_socket_ref(GUnixSocket * socket)172 gnet_unix_socket_ref (GUnixSocket* socket)
173 {
174   g_return_if_fail (socket != NULL);
175 
176   socket->ref_count++;
177 }
178 
179 
180 /**
181  *  gnet_unix_socket_unref
182  *  @socket: a #GUnixSocket
183  *
184  *  Removes a reference from a #GUnixSocket.  A #GUnixSocket is
185  *  deleted when the reference count reaches 0.
186  *
187  **/
188 void
gnet_unix_socket_unref(GUnixSocket * socket)189 gnet_unix_socket_unref (GUnixSocket* socket)
190 {
191   g_return_if_fail (socket != NULL);
192 
193   socket->ref_count--;
194   if (socket->ref_count == 0)  {
195     GNET_CLOSE_SOCKET(socket->sockfd); /* Don't care if this fails. */
196     if (socket->iochannel)
197       g_io_channel_unref (socket->iochannel);
198     if (socket->server && !socket->abstract)
199       gnet_unix_socket_unlink (PATH (socket));
200     g_free(socket);
201   }
202 }
203 
204 
205 /**
206  *  gnet_unix_socket_get_io_channel
207  *  @socket: a #GUnixSocket
208  *
209  *  Gets the #GIOChannel of a #GUnixSocket.
210  *
211  *  For a client socket, the #GIOChannel represents the data stream.
212  *  Use it like you would any other #GIOChannel.
213  *
214  *  For a server socket, however, the #GIOChannel represents the
215  *  listening socket.  When it's readable, there's a connection
216  *  waiting to be accepted.
217  *
218  *  Every #GUnixSocket has one and only one #GIOChannel.  If you ref
219  *  the channel, then you must unref it eventually.  Do not close the
220  *  channel.  The channel is closed by GNet when the socket is
221  *  deleted.
222  *
223  *  Returns: a #GIOChannel.
224  *
225  **/
226 GIOChannel*
gnet_unix_socket_get_io_channel(GUnixSocket * socket)227 gnet_unix_socket_get_io_channel (GUnixSocket* socket)
228 {
229   g_return_val_if_fail(socket != NULL, NULL);
230 
231   if (socket->iochannel == NULL)
232     socket->iochannel = _gnet_io_channel_new (socket->sockfd);
233 
234   return socket->iochannel;
235 }
236 
237 
238 /**
239  *  gnet_unix_socket_get_path
240  *  @socket: a #GUnixSocket
241  *
242  *  Gets the path of a #GUnixSocket.
243  *
244  *  Returns: the path.
245  *
246  **/
247 gchar*
gnet_unix_socket_get_path(const GUnixSocket * socket)248 gnet_unix_socket_get_path(const GUnixSocket* socket)
249 {
250   g_return_val_if_fail(socket != NULL, NULL);
251 
252   return g_strdup (PATH(socket));
253 }
254 
255 static GUnixSocket*
gnet_unix_socket_server_new_internal(const gchar * path,gboolean abstract)256 gnet_unix_socket_server_new_internal (const gchar * path, gboolean abstract)
257 {
258   struct sockaddr_un *sa_un;
259   GUnixSocket *s;
260   gint flags;
261   socklen_t n;
262 
263   g_return_val_if_fail (path != NULL, NULL);
264 
265 #ifndef HAVE_ABSTRACT_SOCKETS
266   /* if abstract unix sockets are not available, create a normal unix socket */
267   abstract = FALSE;
268 #endif
269 
270   s = g_new0 (GUnixSocket, 1);
271   sa_un = (struct sockaddr_un *) &s->sa;
272   sa_un->sun_family = AF_UNIX;
273   s->ref_count = 1;
274   s->server = TRUE;
275 
276   if (abstract) {
277     sa_un->sun_path[0] = '\0';
278     strncpy (sa_un->sun_path + 1, path, sizeof (sa_un->sun_path) - 2);
279     s->abstract = TRUE;
280   } else {
281     strncpy (sa_un->sun_path, path, sizeof (sa_un->sun_path) - 1);
282     if (!gnet_unix_socket_unlink (PATH (s)))
283       goto error;
284   }
285 
286   s->sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
287   if (!GNET_IS_SOCKET_VALID(s->sockfd)) {
288     g_warning ("socket(%s) failed: %s", path, g_strerror (errno));
289     goto error;
290   }
291 
292   flags = fcntl(s->sockfd, F_GETFL, 0);
293   if (flags == -1) {
294     g_warning ("fcntl(%s) failed: %s", path, g_strerror (errno));
295     goto error;
296   }
297 
298   /* Make the socket non-blocking */
299   if (fcntl(s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
300     g_warning ("fcntl(%s) failed: %s", path, g_strerror (errno));
301     goto error;
302   }
303 
304   if (bind (s->sockfd, (struct sockaddr*) sa_un, GNET_SUN_LEN (sa_un)) != 0)
305     goto error;
306 
307   /* Get the socket name FIXME (why? -DAH) */
308   n = sizeof(s->sa);
309   if (getsockname (s->sockfd, (struct sockaddr*) &s->sa, &n) != 0)
310     goto error;
311 
312   if (listen (s->sockfd, 10) != 0)
313     goto error;
314 
315   return s;
316 
317 error:
318   gnet_unix_socket_delete (s);
319   return NULL;
320 }
321 
322 /**
323  *  gnet_unix_socket_server_new
324  *  @path: path
325  *
326  *  Creates a #GUnixSocket bound to @path.  Use this constructor to
327  *  create a #GUnixSocket for a server.
328  *
329  *  Returns: a new #GUnixSocket; NULL on error.
330  *
331  **/
332 GUnixSocket*
gnet_unix_socket_server_new(const gchar * path)333 gnet_unix_socket_server_new (const gchar * path)
334 {
335   return gnet_unix_socket_server_new_internal (path, FALSE);
336 }
337 
338 /**
339  *  gnet_unix_socket_server_new_abstract
340  *  @path: path
341  *
342  *  Creates a #GUnixSocket bound to @path in the abstract unix socket
343  *  domain.  Use this constructor to create a #GUnixSocket for a
344  *  server.
345  *
346  *  If the abstract unix sockets are not available on the platform in use,
347  *  this function will behave the same as gnet_unix_socket_server_new().
348  *
349  *  Returns: a new #GUnixSocket, or NULL on error.
350  *
351  *
352  *  Since: 2.0.8
353  **/
354 GUnixSocket*
gnet_unix_socket_server_new_abstract(const gchar * path)355 gnet_unix_socket_server_new_abstract (const gchar * path)
356 {
357   return gnet_unix_socket_server_new_internal (path, TRUE);
358 }
359 
360 /**
361  *  gnet_unix_socket_server_accept
362  *  @socket: a #GUnixSocket
363  *
364  *  Accepts a connection from a #GUnixSocket.  The socket must have
365  *  been created using gnet_unix_socket_server_new(). This function
366  *  will block.  Even if the socket's #GIOChannel is readable, the
367  *  function may still block.
368  *
369  *  Returns: a new #GUnixSocket representing a new connection; NULL on
370  *  error.
371  *
372  **/
373 GUnixSocket*
gnet_unix_socket_server_accept(const GUnixSocket * socket)374 gnet_unix_socket_server_accept (const GUnixSocket *socket)
375 {
376   gint sockfd;
377   struct sockaddr sa;
378   fd_set fdset;
379   socklen_t n;
380   GUnixSocket *s;
381 
382   g_return_val_if_fail(socket != NULL, NULL);
383 
384  try_again:
385   FD_ZERO(&fdset);
386   FD_SET(socket->sockfd, &fdset);
387 
388   if (select(socket->sockfd + 1, &fdset, NULL, NULL, NULL) == -1) {
389     if (errno == EINTR)
390       goto try_again;
391     return NULL;
392   }
393   n = sizeof(s->sa);
394   if ((sockfd = accept(socket->sockfd, &sa, &n)) == -1) {
395     if (errno == EWOULDBLOCK ||
396 	errno == ECONNABORTED ||
397 #ifdef EPROTO		/* OpenBSD does not have EPROTO */
398 	errno == EPROTO ||
399 #endif /* EPROTO */
400 	errno == EINTR)
401       goto try_again;
402     return NULL;
403   }
404   s = g_new0(GUnixSocket, 1);
405   s->ref_count = 1;
406   s->sockfd = sockfd;
407   memcpy(&s->sa, &sa, sizeof(s->sa));
408   return s;
409 }
410 
411 
412 /**
413  *  gnet_unix_socket_server_accept_nonblock
414  *  @socket: a #GUnixSocket
415  *
416  *  Accepts a connection from a #GUnixSocket without blocking.  The
417  *  socket must have been created using gnet_unix_socket_server_new().
418  *
419  *  Note that if the socket's #GIOChannel is readable, then there is
420  *  PROBABLY a new connection.  It is possible for the connection
421  *  to close by the time this function is called, so it may return
422  *  NULL.
423  *
424  *  Returns: a new #GUnixSocket representing a new connection; NULL
425  *  otherwise.
426  *
427  **/
428 GUnixSocket*
gnet_unix_socket_server_accept_nonblock(const GUnixSocket * socket)429 gnet_unix_socket_server_accept_nonblock (const GUnixSocket *socket)
430 {
431   gint sockfd;
432   struct sockaddr sa;
433   fd_set fdset;
434   socklen_t n;
435   GUnixSocket *s;
436   struct timeval tv = {0, 0};
437 
438   g_return_val_if_fail (socket != NULL, NULL);
439 
440  try_again:
441   FD_ZERO(&fdset);
442   FD_SET(socket->sockfd, &fdset);
443 
444   if(select(socket->sockfd + 1, &fdset, NULL, NULL, &tv) == -1) {
445     if (errno == EINTR)
446       goto try_again;
447     return NULL;
448   }
449 
450   n = sizeof(sa);
451 
452   if ((sockfd = accept(socket->sockfd, &sa, &n)) == -1) {
453     /* If we get an error, return.  We don't want to try again
454        as we do in gnet_unix_socket_server_accept() - it might
455        cause a block. */
456     return NULL;
457   }
458 
459   s = g_new0(GUnixSocket, 1);
460   s->ref_count = 1;
461   s->sockfd = sockfd;
462   memcpy(&s->sa, &sa, sizeof(s->sa));
463 
464   return s;
465 }
466 
467 static gboolean
gnet_unix_socket_unlink(const gchar * path)468 gnet_unix_socket_unlink(const gchar * path)
469 {
470   struct stat stbuf;
471 
472   g_return_val_if_fail (path != NULL, FALSE);
473 
474   if (stat (path, &stbuf) == 0) {
475     if (S_ISSOCK(stbuf.st_mode)) {
476       if (unlink(path) == 0) {
477         return TRUE;
478       } else {
479         /* Can't unlink */
480         return FALSE;
481       }
482     } else {
483       /* path is not a socket */
484       return FALSE;
485     }
486   } else if (errno == ENOENT) {
487     /* File doesn't exist, so we're okay */
488     return TRUE;
489   }
490   return FALSE;
491 }
492 
493 #endif /* !GNET_WIN32 */
494