aff7a623081fdd8740e985bdc4b3767e68be3d8a
[multipath-tools/.git] / libmultipath / uxsock.c
1 /*
2  * Original author : tridge@samba.org, January 2002
3  *
4  * Copyright (c) 2005 Christophe Varoqui
5  * Copyright (c) 2005 Alasdair Kergon, Redhat
6  */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <stdarg.h>
11 #include <fcntl.h>
12 #include <sys/ioctl.h>
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 #include <sys/poll.h>
17 #include <signal.h>
18 #include <errno.h>
19 #ifdef USE_SYSTEMD
20 #include <systemd/sd-daemon.h>
21 #endif
22
23 #include "memory.h"
24 #include "uxsock.h"
25 #include "debug.h"
26
27 /*
28  * connect to a unix domain socket
29  */
30 int ux_socket_connect(const char *name)
31 {
32         int fd, len;
33         struct sockaddr_un addr;
34
35         memset(&addr, 0, sizeof(addr));
36         addr.sun_family = AF_LOCAL;
37         addr.sun_path[0] = '\0';
38         len = strlen(name) + 1 + sizeof(sa_family_t);
39         strncpy(&addr.sun_path[1], name, len);
40
41         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
42         if (fd == -1) {
43                 condlog(3, "Couldn't create ux_socket, error %d", errno);
44                 return -1;
45         }
46
47         if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
48                 condlog(3, "Couldn't connect to ux_socket, error %d", errno);
49                 close(fd);
50                 return -1;
51         }
52
53         return fd;
54 }
55
56 /*
57  * create a unix domain socket and start listening on it
58  * return a file descriptor open on the socket
59  */
60 int ux_socket_listen(const char *name)
61 {
62         int fd, len;
63 #ifdef USE_SYSTEMD
64         int num;
65 #endif
66         struct sockaddr_un addr;
67
68 #ifdef USE_SYSTEMD
69         num = sd_listen_fds(0);
70         if (num > 1) {
71                 condlog(3, "sd_listen_fds returned %d fds", num);
72                 return -1;
73         } else if (num == 1) {
74                 fd = SD_LISTEN_FDS_START + 0;
75                 condlog(3, "using fd %d from sd_listen_fds", fd);
76                 return fd;
77         }
78 #endif
79         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
80         if (fd == -1) {
81                 condlog(3, "Couldn't create ux_socket, error %d", errno);
82                 return -1;
83         }
84
85         memset(&addr, 0, sizeof(addr));
86         addr.sun_family = AF_LOCAL;
87         addr.sun_path[0] = '\0';
88         len = strlen(name) + 1 + sizeof(sa_family_t);
89         strncpy(&addr.sun_path[1], name, len);
90
91         if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
92                 condlog(3, "Couldn't bind to ux_socket, error %d", errno);
93                 close(fd);
94                 return -1;
95         }
96
97         if (listen(fd, 10) == -1) {
98                 condlog(3, "Couldn't listen to ux_socket, error %d", errno);
99                 close(fd);
100                 return -1;
101         }
102         return fd;
103 }
104
105 /*
106  * keep writing until it's all sent
107  */
108 size_t write_all(int fd, const void *buf, size_t len)
109 {
110         size_t total = 0;
111
112         while (len) {
113                 ssize_t n = write(fd, buf, len);
114                 if (n < 0) {
115                         if ((errno == EINTR) || (errno == EAGAIN))
116                                 continue;
117                         return total;
118                 }
119                 if (!n)
120                         return total;
121                 buf = n + (char *)buf;
122                 len -= n;
123                 total += n;
124         }
125         return total;
126 }
127
128 /*
129  * keep reading until its all read
130  */
131 size_t read_all(int fd, void *buf, size_t len)
132 {
133         size_t total = 0;
134         ssize_t n;
135         int ret;
136         struct pollfd pfd;
137
138         while (len) {
139                 pfd.fd = fd;
140                 pfd.events = POLLIN;
141                 ret = poll(&pfd, 1, 1000);
142                 if (!ret) {
143                         errno = ETIMEDOUT;
144                         return total;
145                 } else if (ret < 0) {
146                         if (errno == EINTR)
147                                 continue;
148                         return total;
149                 } else if (!pfd.revents & POLLIN)
150                         continue;
151                 n = read(fd, buf, len);
152                 if (n < 0) {
153                         if ((errno == EINTR) || (errno == EAGAIN))
154                                 continue;
155                         return total;
156                 }
157                 if (!n)
158                         return total;
159                 buf = n + (char *)buf;
160                 len -= n;
161                 total += n;
162         }
163         return total;
164 }
165
166 /*
167  * send a packet in length prefix format
168  */
169 int send_packet(int fd, const char *buf, size_t len)
170 {
171         int ret = 0;
172         sigset_t set, old;
173
174         /* Block SIGPIPE */
175         sigemptyset(&set);
176         sigaddset(&set, SIGPIPE);
177         pthread_sigmask(SIG_BLOCK, &set, &old);
178
179         if (write_all(fd, &len, sizeof(len)) != sizeof(len))
180                 ret = -1;
181         if (!ret && write_all(fd, buf, len) != len)
182                 ret = -1;
183
184         /* And unblock it again */
185         pthread_sigmask(SIG_SETMASK, &old, NULL);
186
187         return ret;
188 }
189
190 /*
191  * receive a packet in length prefix format
192  */
193 int recv_packet(int fd, char **buf, size_t *len)
194 {
195         if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) {
196                 (*buf) = NULL;
197                 *len = 0;
198                 return -1;
199         }
200         if (len == 0) {
201                 (*buf) = NULL;
202                 return 0;
203         }
204         (*buf) = MALLOC(*len);
205         if (!*buf)
206                 return -1;
207         if (read_all(fd, *buf, *len) != *len) {
208                 FREE(*buf);
209                 (*buf) = NULL;
210                 *len = 0;
211                 return -1;
212         }
213         return 0;
214 }