Code

11ddd7d7b2545be3ec686d8dcb8d6c496045de3f
[sysdb.git] / src / utils / unixsock.c
1 /*
2  * syscollector - src/utils/unixsock.c
3  * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "utils/unixsock.h"
29 #include "utils/string.h"
31 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <strings.h>
37 #include <unistd.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
42 /*
43  * private data types
44  */
46 struct sc_unixsock_client {
47         char *path;
48         FILE *fh;
50         int shutdown;
51 };
53 #define SC_SHUT_RD   (1 << SHUT_RD)
54 #define SC_SHUT_WR   (1 << SHUT_WR)
55 #define SC_SHUT_RDWR (SC_SHUT_RD | SC_SHUT_WR)
57 /*
58  * public API
59  */
61 sc_unixsock_client_t *
62 sc_unixsock_client_create(const char *path)
63 {
64         sc_unixsock_client_t *client;
66         if (! path)
67                 return NULL;
69         client = malloc(sizeof(*client));
70         if (! client)
71                 return NULL;
72         memset(client, 0, sizeof(*client));
73         client->fh = NULL;
75         client->path = strdup(path);
76         if (! client->path) {
77                 sc_unixsock_client_destroy(client);
78                 return NULL;
79         }
81         client->shutdown = 0;
82         return client;
83 } /* sc_unixsock_client_create */
85 int
86 sc_unixsock_client_connect(sc_unixsock_client_t *client)
87 {
88         struct sockaddr_un sa;
89         int fd;
91         if ((! client) || (! client->path))
92                 return -1;
94         memset(&sa, 0, sizeof(sa));
96         if (client->fh)
97                 fclose(client->fh);
99         fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
100         if (fd < 0) {
101                 char errbuf[1024];
102                 fprintf(stderr, "unixsock: Failed to open socket: %s\n",
103                                 sc_strerror(errno, errbuf, sizeof(errbuf)));
104                 return -1;
105         }
107         sa.sun_family = AF_UNIX;
108         strncpy(sa.sun_path, client->path, sizeof(sa.sun_path));
109         sa.sun_path[sizeof(sa.sun_path) - 1] = '\0';
111         if (connect(fd, (struct sockaddr *)&sa, sizeof(sa))) {
112                 char errbuf[1024];
113                 fprintf(stderr, "unixsock: Failed to connect to %s: %s\n",
114                                 sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf)));
115                 close(fd);
116                 return -1;
117         }
119         client->fh = fdopen(fd, "r+");
120         if (! client->fh) {
121                 char errbuf[1024];
122                 fprintf(stderr, "unixsock: Failed to open I/O stream for %s: %s\n",
123                                 sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf)));
124                 close(fd);
125                 return -1;
126         }
128         client->shutdown = 0;
129         return 0;
130 } /* sc_unixsock_client_connect */
132 int
133 sc_unixsock_client_send(sc_unixsock_client_t *client, const char *msg)
135         int status;
137         if ((! client) || (! client->fh))
138                 return -1;
140         if (client->shutdown & SC_SHUT_WR) /* reconnect */
141                 sc_unixsock_client_connect(client);
143         status = fprintf(client->fh, "%s\r\n", msg);
144         if (status < 0) {
145                 char errbuf[1024];
146                 fprintf(stderr, "unixsock: Failed to write to socket (%s): %s\n",
147                                 client->path, sc_strerror(errno, errbuf, sizeof(errbuf)));
148                 return status;
149         }
150         return status;
151 } /* sc_unixsock_client_send */
153 char *
154 sc_unixsock_client_recv(sc_unixsock_client_t *client, char *buffer, size_t buflen)
156         if ((! client) || (! client->fh) || (! buffer))
157                 return NULL;
159         if (client->shutdown & SC_SHUT_RD) /* reconnect */
160                 sc_unixsock_client_connect(client);
162         buffer = fgets(buffer, (int)buflen - 1, client->fh);
163         if (! buffer) {
164                 if (! feof(client->fh)) {
165                         char errbuf[1024];
166                         fprintf(stderr, "unixsock: Failed to read from socket (%s): %s\n",
167                                         client->path, sc_strerror(errno, errbuf, sizeof(errbuf)));
168                 }
169                 return buffer;
170         }
171         buffer[buflen - 1] = '\0';
173         buflen = strlen(buffer);
174         while ((buffer[buflen - 1] == '\n') || (buffer[buflen - 1] == '\r')) {
175                 buffer[buflen - 1] = '\0';
176                 --buflen;
177         }
178         return buffer;
179 } /* sc_unixsock_client_recv */
181 int
182 sc_unixsock_client_shutdown(sc_unixsock_client_t *client, int how)
184         int status;
186         if (! client) {
187                 errno = ENOTSOCK;
188                 return -1;
189         }
191         fflush(client->fh);
192         status = shutdown(fileno(client->fh), how);
194         if (! status) {
195                 if (how == SHUT_RDWR)
196                         client->shutdown |= SC_SHUT_RDWR;
197                 else
198                         client->shutdown |= 1 << how;
199         }
200         return status;
201 } /* sc_unixsock_client_shutdown */
203 void
204 sc_unixsock_client_clearerr(sc_unixsock_client_t *client)
206         if ((! client) || (! client->fh))
207                 return;
208         clearerr(client->fh);
209 } /* sc_unixsock_client_clearerr */
211 int
212 sc_unixsock_client_eof(sc_unixsock_client_t *client)
214         if ((! client) || (! client->fh)) {
215                 errno = EBADF;
216                 return -1;
217         }
218         return feof(client->fh);
219 } /* sc_unixsock_client_eof */
221 int
222 sc_unixsock_client_error(sc_unixsock_client_t *client)
224         if ((! client) || (! client->fh)) {
225                 errno = EBADF;
226                 return -1;
227         }
228         return ferror(client->fh);
229 } /* sc_unixsock_client_error */
231 void
232 sc_unixsock_client_destroy(sc_unixsock_client_t *client)
234         if (! client)
235                 return;
237         if (client->path)
238                 free(client->path);
239         client->path = NULL;
241         if (client->fh)
242                 fclose(client->fh);
243         client->fh = NULL;
245         free(client);
246 } /* sc_unixsock_client_destroy */
248 const char *
249 sc_unixsock_client_path(sc_unixsock_client_t *client)
251         if (! client)
252                 return NULL;
253         return client->path;
254 } /* sc_unixsock_client_path */
256 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */