DTS Application Library  0.2.3
Application library containing referenced objects and interfaces to common libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
unixsock.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 2012 Gregory Nietsky <gregory@distrotetch.co.za>
3  http://www.distrotech.co.za
4 
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program 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
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
27 #ifdef __WIN32__
28 #include <winsock2.h>
29 #else
30 #include <sys/socket.h>
31 #endif
32 #include <libgen.h>
33 #include <sys/stat.h>
34 #include <linux/un.h>
35 #include <linux/limits.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "include/dtsapp.h"
44 
48  struct fwsocket *sock;
50  char sockpath[UNIX_PATH_MAX+1];
52  int mask;
54  int protocol;
59  void *data;
60 };
61 
65  struct fwsocket *sock;
70  const char *endpoint;
72  void *data;
73 };
74 
75 /*
76  * UNIX sock client
77  */
78 static void *unsock_client(void *data) {
79  struct unixclient_sockthread *unsock = data;
80  struct fwsocket *sock = unsock->sock;
81  struct timeval tv;
82  fd_set rd_set, act_set;
83  int selfd;
84  int on = 1;
85  int fd, fdf;
86 
87 
88  FD_ZERO(&rd_set);
89 
90  fd = sock->sock;
91  fdf = fcntl(fd, F_GETFL);
92  fcntl(fd, F_SETFD, fdf | O_NONBLOCK);
93  /*enable passing credentials*/
94  setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
95  FD_SET(fd, &rd_set);
96 
97  while (framework_threadok()) {
98  act_set = rd_set;
99  tv.tv_sec = 0;
100  tv.tv_usec = 20000;
101 
102  selfd = select(fd + 1, &act_set, NULL, NULL, &tv);
103 
104  /*returned due to interupt continue or timed out*/
105  if ((selfd < 0 && errno == EINTR) || (!selfd)) {
106  continue;
107  } else if (selfd < 0) {
108  break;
109  }
110 
111  if (FD_ISSET(sock->sock, &act_set) && unsock->client) {
112  unsock->client(sock, unsock->data);
113  }
114  }
115  objunref(unsock);
116 
117  return NULL;
118 }
119 
120 static void unixclient_sockthread_free(void *data) {
121  struct unixclient_sockthread *uc = data;
122 
123  if (uc->sock) {
124  objunref(uc->sock);
125  }
126  if (uc->data) {
127  objunref(uc->data);
128  }
129  if (uc->endpoint) {
130  if (!strlenzero(uc->endpoint)) {
131  unlink(uc->endpoint);
132  }
133  free((void*)uc->endpoint);
134  }
135 }
136 
137 static int new_unixclientthread(struct fwsocket *fws, const char *endpoint, socketrecv read, void *data) {
138  struct unixclient_sockthread *unsock;
139  void *thread;
140 
141  if (!(unsock = objalloc(sizeof(*unsock), unixclient_sockthread_free))) {
142  return 0;
143  }
144 
145  unsock->sock = fws;
146  unsock->data = (objref(data)) ? data : NULL;
147  unsock->client = read;
148  unsock->endpoint = endpoint;
149 
150  if (!(thread = framework_mkthread(unsock_client, NULL, NULL, unsock, THREAD_OPTION_RETURN))) {
151  objunref(unsock);
152  return 0;
153  }
154  objunref(thread);
155  return 1;
156 }
157 
158 /*
159  * UNIX sock server
160  */
161 static void *unsock_serv(void *data) {
162  struct unixserv_sockthread *unsock = data;
163  struct fwsocket *newsock, *sock;
164  union sockstruct *adr;
165  unsigned int salen;
166  struct timeval tv;
167  fd_set rd_set, act_set;
168  int selfd;
169  int on = 1;
170  int fd, fdf;
171 
172  /* set user RW */
173  umask(unsock->mask);
174 
175 
176  sock = unsock->sock;
177  sock->flags |= SOCK_FLAG_UNIX;
178  fd = sock->sock;
179 
180  fdf = fcntl(fd, F_GETFL);
181  fcntl(fd, F_SETFD, fdf | O_NONBLOCK);
182 
183  adr = &sock->addr;
184  memset(&adr->un, 0, sizeof(adr->un));
185  adr->un.sun_family = PF_UNIX;
186  salen = sizeof(adr->un);
187  strncpy((char *)adr->un.sun_path, unsock->sockpath, sizeof(adr->un.sun_path) -1);
188 
189  /*enable passing credentials*/
190  setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
191 
192  if (bind(fd, (struct sockaddr *)&adr->un, salen)) {
193  if (errno == EADDRINUSE) {
194  /* delete old file*/
195  unlink(unsock->sockpath);
196  if (bind(fd, (struct sockaddr *)&adr->un, sizeof(struct sockaddr_un))) {
197  objunref(unsock);
198  close(fd);
199  return NULL;
200  }
201  } else {
202  objunref(unsock);
203  close(fd);
204  return NULL;
205  }
206  }
207 
208  if (unsock->protocol == SOCK_STREAM) {
209  if (listen(fd, 10)) {
210  close(fd);
211  objunref(unsock);
212  return NULL;
213  }
214  }
215 
216  FD_ZERO(&rd_set);
217  FD_SET(fd, &rd_set);
218 
219  while (framework_threadok()) {
220  act_set = rd_set;
221  tv.tv_sec = 0;
222  tv.tv_usec = 20000;
223 
224  selfd = select(fd + 1, &act_set, NULL, NULL, &tv);
225 
226  /*returned due to interupt continue or timed out*/
227  if ((selfd < 0 && errno == EINTR) || (!selfd)) {
228  continue;
229  } else if (selfd < 0) {
230  break;
231  }
232 
233  if (FD_ISSET(fd, &act_set)) {
234  if (unsock->protocol == SOCK_STREAM) {
235  if ((newsock = accept_socket(sock))) {
236  if (!(new_unixclientthread(newsock, NULL, unsock->read, unsock->data))) {
237  objunref(newsock);
238  }
239  }
240  } else if (unsock->read) {
241  unsock->read(sock, unsock->data);
242 
243  }
244  }
245  }
246 
247  close(fd);
248  objunref(unsock);
249 
250  return NULL;
251 }
252 
253 static void free_unixserv(void *data) {
254  struct unixserv_sockthread *unsock = data;
255 
256  if (unsock->sock) {
257  objunref(unsock->sock);
258  }
259 
260  if (!strlenzero(unsock->sockpath)) {
261  unlink(unsock->sockpath);
262  }
263 
264  if (unsock->data) {
265  objunref(data);
266  }
267 }
268 
277 extern struct fwsocket *unixsocket_server(const char *sock, int protocol, int mask, socketrecv read, void *data) {
278  struct unixserv_sockthread *unsock;
279 
280  if (!(unsock = objalloc(sizeof(*unsock), free_unixserv))) {
281  return NULL;
282  }
283 
284  strncpy(unsock->sockpath, sock, UNIX_PATH_MAX);
285  unsock->mask = mask;
286  unsock->read = read;
287  unsock->protocol = protocol;
288  unsock->data = (objref(data)) ? data : NULL;
289 
290  /*Create a UNIX socket structure*/
291  if (!(unsock->sock = make_socket(PF_UNIX, protocol, 0, NULL))) {
292  objunref(unsock);
293  return NULL;
294  }
295 
296  framework_mkthread(unsock_serv, NULL, NULL, unsock, 0);
297  return (objref(unsock->sock)) ? unsock->sock : NULL;
298 }
299 
310 extern struct fwsocket *unixsocket_client(const char *sock, int protocol, socketrecv read, void *data) {
311  struct fwsocket *fws;
312  union sockstruct caddr, *saddr;
313  char *temp = NULL;
314  const char *tmpsock;
315  int salen;
316  mode_t omask;
317 
318  /*Create a UNIX socket structure*/
319  if (!(fws = make_socket(PF_UNIX, protocol, 0, NULL))) {
320  return NULL;
321  }
322 
323  /* bind my endpoint to temp file*/
324  if (protocol == SOCK_DGRAM) {
325  /*yip i want only a inode here folks*/
326  omask = umask(S_IXUSR | S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH);
327  tmpsock = basename((char*)sock);
328  temp = tempnam(NULL, tmpsock);
329  if (strlenzero(temp)) {
330  if (temp) {
331  free(temp);
332  }
333  objunref(fws);
334  return NULL;
335  }
336 
337  /*Allocate address and connect to the client*/
338  salen = sizeof(caddr.un);
339  memset(&caddr.un, 0, salen);
340  caddr.un.sun_family = PF_UNIX;
341  strncpy((char *)caddr.un.sun_path, temp, sizeof(caddr.un.sun_path) -1);
342 
343  if (bind(fws->sock, (struct sockaddr *)&caddr.un, salen)) {
344  /*reset umask*/
345  umask(omask);
346  if (temp) {
347  if (!strlenzero(temp)) {
348  unlink(temp);
349  }
350  free(temp);
351  }
352  objunref(fws);
353  return NULL;
354  }
355  /*reset umask*/
356  umask(omask);
357  }
358 
359  /*Allocate address and connect to the server*/
360  saddr = &fws->addr;
361  salen = sizeof(saddr->un);
362  memset(&saddr->un, 0, salen);
363  saddr->un.sun_family = PF_UNIX;
364  strncpy((char *)saddr->un.sun_path, sock, sizeof(saddr->un.sun_path) -1);
365 
366  if (connect(fws->sock, (struct sockaddr *)&saddr->un, salen)) {
367  if (temp) {
368  if (!strlenzero(temp)) {
369  unlink(temp);
370  }
371  free(temp);
372  }
373  objunref(fws);
374  return NULL;
375  }
376 
377  fws->flags |= SOCK_FLAG_UNIX;
378  if (!(new_unixclientthread(fws, temp, read, data))) {
379  if (temp) {
380  if (!strlenzero(temp)) {
381  unlink(temp);
382  }
383  free(temp);
384  }
385  objunref(fws);
386  return NULL;
387  }
388 
389  return (objref(fws)) ? fws : NULL;
390 }
391 
int protocol
Socket protocol.
Definition: unixsock.c:54
int strlenzero(const char *str)
Check if a string is zero length.
Definition: util.c:341
union sockstruct addr
system socket data structure.
Definition: dtsapp.h:143
char sockpath[UNIX_PATH_MAX+1]
Socket path.
Definition: unixsock.c:50
int mask
Socket umask.
Definition: unixsock.c:52
struct sockaddr_un un
Unix sockets.
Definition: dtsapp.h:85
int objref(void *data)
Reference a object.
Definition: refobj.c:153
Unix socket client data structure.
Definition: unixsock.c:63
struct fwsocket * sock
Socket reference.
Definition: unixsock.c:65
struct fwsocket * unixsocket_client(const char *sock, int protocol, socketrecv read, void *data)
Create a client thread on the socket.
Definition: unixsock.c:310
Socket data structure.
Definition: dtsapp.h:131
void * objalloc(int size, objdestroy)
Allocate a referenced lockable object.
Definition: refobj.c:129
socketrecv client
Client read callback.
Definition: unixsock.c:68
const char * endpoint
Client endpoint tmp for SOCK_DGRAM.
Definition: unixsock.c:70
struct fwsocket * sock
Socket reference.
Definition: unixsock.c:48
void * data
Data reference passed to callback.
Definition: unixsock.c:59
int sock
Socket FD.
Definition: dtsapp.h:133
DTS Application library API Include file.
void(* socketrecv)(struct fwsocket *, void *)
Callback function to register with a socket that will be called when there is data available...
Definition: dtsapp.h:259
struct thread_pvt * framework_mkthread(threadfunc, threadcleanup, threadsighandler, void *data, int flags)
create a thread result must be unreferenced
Definition: thread.c:387
Return reference to thread this must be unreferenced.
Definition: dtsapp.h:124
Unix socket server data structure.
Definition: unixsock.c:46
socketrecv read
Thread to begin on client connect.
Definition: unixsock.c:57
void * data
Data reference passed to callback.
Definition: unixsock.c:72
struct fwsocket * make_socket(int family, int type, int proto, void *ssl)
Allocate a socket structure and return reference.
Definition: socket.c:120
int framework_threadok(void)
let threads check there status.
Definition: thread.c:143
struct fwsocket * unixsocket_server(const char *sock, int protocol, int mask, socketrecv read, void *data)
Create and run UNIX server socket thread.
Definition: unixsock.c:277
struct fwsocket * accept_socket(struct fwsocket *sock)
Create and return a socket structure from accept()
Definition: socket.c:144
Socket union describing all address types.
Definition: dtsapp.h:80
enum sock_flags flags
Socket control flags.
Definition: dtsapp.h:140
int objunref(void *data)
Drop reference held.
Definition: refobj.c:184
UNIX Domain Socket.
Definition: dtsapp.h:110