libsocket
libunixsocket.c
Go to the documentation of this file.
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE // accept4()
3 #endif
4 
5 #include <conf.h>
6 
7 #include <errno.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <sys/un.h> // UNIX domain sockets
14 #include <unistd.h> // read()/write()
15 
48 /*
49  * Structure of the functions defined here:
50  *
51  * <Declarations>
52  * <Checks on passed arguments>
53  * <actual code>
54  *
55  */
56 
57 //# define VERBOSE
58 
59 // Macro definitions
60 
61 #define LIBSOCKET_BACKLOG 128
62 
63 #define LIBSOCKET_STREAM 1
64 #define LIBSOCKET_DGRAM 2
65 
66 #define LIBSOCKET_READ 1
67 #define LIBSOCKET_WRITE 2
68 
69 #define debug_write(str) \
70  { \
71  int verbose_errno_save = errno; \
72  write(2, str, strlen(str)); \
73  errno = verbose_errno_save; \
74  }
75 
89 static inline signed int check_error(int return_value) {
90 #ifdef VERBOSE
91  const char* errbuf;
92 #endif
93  if (return_value < 0) {
94 #ifdef VERBOSE
95  errbuf = strerror(errno);
96  debug_write(errbuf);
97 #endif
98  return -1;
99  }
100 
101  return 0;
102 }
103 
104 static int set_unix_socket_path(struct sockaddr_un* saddr, const char* path_or_name) {
105  memset(&saddr->sun_path, 0, sizeof(saddr->sun_path));
106  if (path_or_name[0] != 0) {
107  strncpy(saddr->sun_path, path_or_name, sizeof(saddr->sun_path) - 1);
108  } else {
109  // Abstract socket address.
110  // Make sure this is not a nulled memory region.
111  if (path_or_name[1] == 0) {
112  errno = EINVAL;
113 #ifdef VERBOSE
114  debug_write("set_unix_socket_path: Socket address is too many 0s\n");
115 #endif
116  return -1;
117  }
118  size_t max_len = 1 + strlen(path_or_name+1);
119  if (max_len > sizeof(saddr->sun_path) - 1) {
120 #ifdef VERBOSE
121  debug_write("set_unix_socket_path: Abstract socket address is too long\n");
122 #endif
123  errno = ENAMETOOLONG;
124  return -1;
125  }
126  memcpy(saddr->sun_path, path_or_name, max_len);
127  }
128  return 0;
129 }
130 
143 int create_unix_stream_socket(const char* path, int flags) {
144  struct sockaddr_un saddr;
145  int sfd;
146 
147  if (path == NULL) return -1;
148 
149  if (-1 == check_error(sfd = socket(AF_UNIX, SOCK_STREAM | flags, 0)))
150  return -1;
151 
152  memset(&saddr, 0, sizeof(struct sockaddr_un));
153 
154  if (strlen(path) > (sizeof(saddr.sun_path) - 1)) {
155 #ifdef VERBOSE
156  debug_write(
157  "create_unix_stream_socket: UNIX socket destination path too "
158  "long\n");
159 #endif
160  return -1;
161  }
162 
163  saddr.sun_family = AF_UNIX;
164  if (-1 == check_error(set_unix_socket_path(&saddr, path)))
165  return -1;
166  size_t pathlen = strlen(saddr.sun_path);
167  if (pathlen == 0) // likely abstract socket address
168  pathlen = sizeof(saddr.sun_path);
169 
170 
171  if (-1 == check_error(
172  connect(sfd, (struct sockaddr*)&saddr,
173  sizeof(saddr.sun_family) + pathlen))) {
174  close(sfd);
175  return -1;
176  }
177 
178  return sfd;
179 }
180 
191 int create_unix_dgram_socket(const char* bind_path, int flags) {
192  int sfd, retval;
193  struct sockaddr_un saddr;
194 
195  if (-1 == check_error(sfd = socket(AF_UNIX, SOCK_DGRAM | flags, 0)))
196  return -1;
197 
198  memset(&saddr, 0, sizeof(struct sockaddr_un));
199 
200  if (bind_path != NULL) {
201  if ((retval = unlink(bind_path)) == -1 &&
202  errno != ENOENT) // If there's another error than "doesn't exist"
203  {
204  check_error(retval);
205  return -1;
206  }
207 
208  if (strlen(bind_path) > (sizeof(saddr.sun_path) - 1)) {
209 #ifdef VERBOSE
210  debug_write(
211  "create_unix_dgram_socket: UNIX socket path too long\n");
212 #endif
213  return -1;
214  }
215 
216  saddr.sun_family = AF_UNIX;
217  if (-1 == check_error(set_unix_socket_path(&saddr, bind_path)))
218  return -1;
219 
220  size_t pathlen = strlen(saddr.sun_path);
221  if (pathlen == 0) // likely abstract socket address
222  pathlen = sizeof(saddr.sun_path);
223 
224  bind(sfd, (struct sockaddr*)&saddr,
225  sizeof(saddr.sun_family) + pathlen);
226  }
227 
228  return sfd;
229 }
230 
243 int connect_unix_dgram_socket(int sfd, const char* path) {
244  struct sockaddr_un new_addr;
245  struct sockaddr deconnect;
246 
247  if (sfd < 0) return -1;
248 
249  if (path == NULL) {
250  memset(&deconnect, 0, sizeof(struct sockaddr));
251 
252  deconnect.sa_family = AF_UNSPEC;
253 
254  if (check_error(connect(sfd, &deconnect, sizeof(struct sockaddr))))
255  return -1;
256 
257  return 0;
258  }
259 
260  memset(&new_addr, 0, sizeof(struct sockaddr_un));
261 
262  new_addr.sun_family = AF_UNIX;
263 
264  if (strlen(path) > sizeof(new_addr.sun_path) - 1) {
265 #ifdef VERBOSE
266  debug_write("connect_unix_dgram_socket: Path too long\n");
267 #endif
268  return -1;
269  }
270 
271  if (-1 == check_error(set_unix_socket_path(&new_addr, path))) {
272  return -1;
273  }
274 
275  size_t pathlen = strlen(new_addr.sun_path);
276  if (pathlen == 0) // likely abstract socket address
277  pathlen = sizeof(new_addr.sun_path);
278 
279  if (-1 == check_error(connect(
280  sfd, (struct sockaddr*)&new_addr,
281  sizeof(new_addr.sun_family) + pathlen)))
282  return -1;
283 
284  return 0;
285 }
286 
297 int destroy_unix_socket(int sfd) {
298  if (sfd < 0) return -1;
299 
300  if (-1 == check_error(close(sfd))) return -1;
301 
302  return 0;
303 }
304 
319 int shutdown_unix_stream_socket(int sfd, int method) {
320  if (sfd < 0) return -1;
321 
322  if ((method != LIBSOCKET_READ) && (method != LIBSOCKET_WRITE) &&
323  (method != (LIBSOCKET_READ | LIBSOCKET_WRITE)))
324  return -1;
325 
326  if (method & LIBSOCKET_READ) // READ is set (0001 && 0001 => 0001)
327  {
328  if (-1 == check_error(shutdown(sfd, SHUT_RD))) return -1;
329  }
330 
331  if (method & LIBSOCKET_WRITE) // WRITE is set (0010 && 0010 => 0010)
332  {
333  if (-1 == check_error(shutdown(sfd, SHUT_WR))) return -1;
334  }
335 
336  return 0;
337 }
338 
353 int create_unix_server_socket(const char* path, int socktype, int flags) {
354  struct sockaddr_un saddr;
355  int sfd, type, retval;
356 
357  if (path == NULL) return -1;
358 
359  if (strlen(path) > (sizeof(saddr.sun_path) - 1)) {
360 #ifdef VERBOSE
361  debug_write("create_unix_server_socket: Path too long\n");
362 #endif
363  return -1;
364  }
365 
366  switch (socktype) {
367  case LIBSOCKET_STREAM:
368  type = SOCK_STREAM;
369  break;
370  case LIBSOCKET_DGRAM:
371  type = SOCK_DGRAM;
372  break;
373  default:
374  return -1;
375  }
376 
377  if (-1 == check_error(sfd = socket(AF_UNIX, type | flags, 0))) return -1;
378 
379  if ((retval = unlink(path)) == -1 &&
380  errno != ENOENT) // If there's another error than "doesn't exist"
381  {
382  check_error(retval);
383  return -1;
384  }
385 
386  memset(&saddr, 0, sizeof(struct sockaddr_un));
387 
388  saddr.sun_family = AF_UNIX;
389 
390  if (-1 == check_error(set_unix_socket_path(&saddr, path)))
391  return -1;
392 
393  size_t pathlen = strlen(saddr.sun_path);
394  if (pathlen == 0) // likely abstract socket address
395  pathlen = sizeof(saddr.sun_path);
396 
397  if (-1 ==
398  check_error(bind(sfd, (struct sockaddr*)&saddr,
399  sizeof(saddr.sun_family) + pathlen)))
400  return -1;
401 
402  if (type == SOCK_STREAM) {
403  if (-1 == check_error(listen(sfd, LIBSOCKET_BACKLOG))) return -1;
404  }
405 
406  return sfd;
407 }
408 
419 int accept_unix_stream_socket(int sfd, int flags) {
420  int cfd;
421 
422  if (sfd < 0) return -1;
423 #if LIBSOCKET_LINUX
424  if (-1 == check_error(cfd = accept4(sfd, 0, 0, flags))) return -1;
425 #else
426  if (-1 == check_error(cfd = accept(sfd, 0, 0))) return -1;
427 #endif
428  return cfd;
429 }
430 
444 ssize_t recvfrom_unix_dgram_socket(int sfd, void* buf, size_t size, char* from,
445  size_t from_size, int recvfrom_flags) {
446  int bytes;
447  socklen_t socksize = sizeof(struct sockaddr_un);
448  struct sockaddr_un saddr;
449 
450  memset(buf, 0, size);
451  memset(from, 0, from_size);
452 
453  if (-1 ==
454  check_error(bytes = recvfrom(sfd, buf, size, recvfrom_flags,
455  (struct sockaddr*)&saddr, &socksize)))
456  return -1;
457 
458  if (from != NULL && from_size > 0) {
459  memcpy(from, saddr.sun_path,
460  from_size < sizeof(saddr.sun_path) ? from_size
461  : sizeof(saddr.sun_path));
462  }
463 
464  return bytes;
465 }
466 
479 ssize_t sendto_unix_dgram_socket(int sfd, const void* buf, size_t size,
480  const char* path, int sendto_flags) {
481  int bytes;
482  struct sockaddr_un saddr;
483 
484  if (strlen(path) > sizeof(saddr.sun_path) - 1) {
485 #ifdef VERBOSE
486  debug_write(
487  "sendto_unix_dgram_socket: UNIX destination socket path too "
488  "long\n");
489 #endif
490  return -1;
491  }
492 
493  memset(&saddr, 0, sizeof(struct sockaddr_un));
494 
495  saddr.sun_family = AF_UNIX;
496  if (-1 == check_error(set_unix_socket_path(&saddr, path)))
497  return -1;
498 
499  if (-1 == check_error(bytes = sendto(sfd, buf, size, sendto_flags,
500  (struct sockaddr*)&saddr,
501  sizeof(struct sockaddr_un))))
502  return -1;
503 
504  return bytes;
505 }
506 
511 #undef debug_write
static signed int check_error(int return_value)
Checks return value for error.
Definition: libunixsocket.c:89
int accept_unix_stream_socket(int sfd, int flags)
Accept connections on a passive UNIX socket.
int create_unix_dgram_socket(const char *bind_path, int flags)
Create a UNIX DGRAM socket.
int connect_unix_dgram_socket(int sfd, const char *path)
Connect a datagram socket.
ssize_t recvfrom_unix_dgram_socket(int sfd, void *buf, size_t size, char *from, size_t from_size, int recvfrom_flags)
Receive datagram from another UNIX socket.
int create_unix_stream_socket(const char *path, int flags)
Create and connect a new UNIX STREAM socket.
int shutdown_unix_stream_socket(int sfd, int method)
Shut a socket down.
int destroy_unix_socket(int sfd)
Close a socket.
ssize_t sendto_unix_dgram_socket(int sfd, const void *buf, size_t size, const char *path, int sendto_flags)
Send datagram to socket.
int create_unix_server_socket(const char *path, int socktype, int flags)
Create a passive UNIX socket.