Code

utils unixsock: Fixed EOF handling in recv().
[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;
49 };
51 /*
52  * public API
53  */
55 sc_unixsock_client_t *
56 sc_unixsock_client_create(const char *path)
57 {
58         sc_unixsock_client_t *client;
60         if (! path)
61                 return NULL;
63         client = malloc(sizeof(*client));
64         if (! client)
65                 return NULL;
66         memset(client, 0, sizeof(*client));
67         client->fh = NULL;
69         client->path = strdup(path);
70         if (! client->path) {
71                 sc_unixsock_client_destroy(client);
72                 return NULL;
73         }
74         return client;
75 } /* sc_unixsock_client_create */
77 int
78 sc_unixsock_client_connect(sc_unixsock_client_t *client)
79 {
80         struct sockaddr_un sa;
81         int fd;
83         if ((! client) || (! client->path))
84                 return -1;
86         memset(&sa, 0, sizeof(sa));
88         if (client->fh)
89                 fclose(client->fh);
91         fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0);
92         if (fd < 0) {
93                 char errbuf[1024];
94                 fprintf(stderr, "unixsock: Failed to open socket: %s\n",
95                                 sc_strerror(errno, errbuf, sizeof(errbuf)));
96                 return -1;
97         }
99         sa.sun_family = AF_UNIX;
100         strncpy(sa.sun_path, client->path, sizeof(sa.sun_path));
101         sa.sun_path[sizeof(sa.sun_path) - 1] = '\0';
103         if (connect(fd, (struct sockaddr *)&sa, sizeof(sa))) {
104                 char errbuf[1024];
105                 fprintf(stderr, "unixsock: Failed to connect to %s: %s\n",
106                                 sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf)));
107                 close(fd);
108                 return -1;
109         }
111         client->fh = fdopen(fd, "r+");
112         if (! client->fh) {
113                 char errbuf[1024];
114                 fprintf(stderr, "unixsock: Failed to open I/O stream for %s: %s\n",
115                                 sa.sun_path, sc_strerror(errno, errbuf, sizeof(errbuf)));
116                 close(fd);
117                 return -1;
118         }
119         return 0;
120 } /* sc_unixsock_client_connect */
122 int
123 sc_unixsock_client_send(sc_unixsock_client_t *client, const char *msg)
125         int status;
127         if ((! client) || (! client->fh))
128                 return -1;
130         status = fprintf(client->fh, "%s\r\n", msg);
131         if (status < 0) {
132                 char errbuf[1024];
133                 fprintf(stderr, "unixsock: Failed to write to socket (%s): %s\n",
134                                 client->path, sc_strerror(errno, errbuf, sizeof(errbuf)));
135                 return status;
136         }
137         return status;
138 } /* sc_unixsock_client_send */
140 char *
141 sc_unixsock_client_recv(sc_unixsock_client_t *client, char *buffer, size_t buflen)
143         if ((! client) || (! client->fh) || (! buffer))
144                 return NULL;
146         buffer = fgets(buffer, (int)buflen - 1, client->fh);
147         if (! buffer) {
148                 if (! feof(client->fh)) {
149                         char errbuf[1024];
150                         fprintf(stderr, "unixsock: Failed to read from socket (%s): %s\n",
151                                         client->path, sc_strerror(errno, errbuf, sizeof(errbuf)));
152                 }
153                 return buffer;
154         }
155         buffer[buflen - 1] = '\0';
157         buflen = strlen(buffer);
158         while ((buffer[buflen - 1] == '\n') || (buffer[buflen - 1] == '\r')) {
159                 buffer[buflen - 1] = '\0';
160                 --buflen;
161         }
162         return buffer;
163 } /* sc_unixsock_client_recv */
165 void
166 sc_unixsock_client_destroy(sc_unixsock_client_t *client)
168         if (! client)
169                 return;
171         if (client->path)
172                 free(client->path);
173         client->path = NULL;
175         if (client->fh)
176                 fclose(client->fh);
177         client->fh = NULL;
179         free(client);
180 } /* sc_unixsock_client_destroy */
182 const char *
183 sc_unixsock_client_path(sc_unixsock_client_t *client)
185         if (! client)
186                 return NULL;
187         return client->path;
188 } /* sc_unixsock_client_path */
190 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */