libmultipath: do not stall on recv_packet()
[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
20 #include "memory.h"
21 #include "uxsock.h"
22
23 /*
24  * connect to a unix domain socket
25  */
26 int ux_socket_connect(const char *name)
27 {
28         int fd, len;
29         struct sockaddr_un addr;
30
31         memset(&addr, 0, sizeof(addr));
32         addr.sun_family = AF_LOCAL;
33         addr.sun_path[0] = '\0';
34         len = strlen(name) + 1 + sizeof(sa_family_t);
35         strncpy(&addr.sun_path[1], name, len);
36
37         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
38         if (fd == -1) {
39                 return -1;
40         }
41
42         if (connect(fd, (struct sockaddr *)&addr, len) == -1) {
43                 close(fd);
44                 return -1;
45         }
46
47         return fd;
48 }
49
50 /*
51  * create a unix domain socket and start listening on it
52  * return a file descriptor open on the socket
53  */
54 int ux_socket_listen(const char *name)
55 {
56         int fd, len;
57         struct sockaddr_un addr;
58
59         fd = socket(AF_LOCAL, SOCK_STREAM, 0);
60         if (fd == -1) return -1;
61
62         memset(&addr, 0, sizeof(addr));
63         addr.sun_family = AF_LOCAL;
64         addr.sun_path[0] = '\0';
65         len = strlen(name) + 1 + sizeof(sa_family_t);
66         strncpy(&addr.sun_path[1], name, len);
67
68         if (bind(fd, (struct sockaddr *)&addr, len) == -1) {
69                 close(fd);
70                 return -1;
71         }
72
73         if (listen(fd, 10) == -1) {
74                 close(fd);
75                 return -1;
76         }
77
78         return fd;
79 }
80
81 /*
82  * keep writing until it's all sent
83  */
84 size_t write_all(int fd, const void *buf, size_t len)
85 {
86         size_t total = 0;
87
88         while (len) {
89                 ssize_t n = write(fd, buf, len);
90                 if (n < 0) {
91                         if ((errno == EINTR) || (errno == EAGAIN))
92                                 continue;
93                         return total;
94                 }
95                 if (!n)
96                         return total;
97                 buf = n + (char *)buf;
98                 len -= n;
99                 total += n;
100         }
101         return total;
102 }
103
104 /*
105  * keep reading until its all read
106  */
107 size_t read_all(int fd, void *buf, size_t len)
108 {
109         size_t total = 0;
110         ssize_t n;
111         int ret;
112         struct pollfd pfd;
113
114         while (len) {
115                 pfd.fd = fd;
116                 pfd.events = POLLIN;
117                 ret = poll(&pfd, 1, 1000);
118                 if (!ret) {
119                         errno = ETIMEDOUT;
120                         return total;
121                 } else if (ret < 0) {
122                         if (errno == EINTR)
123                                 continue;
124                         return total;
125                 } else if (!pfd.revents & POLLIN)
126                         continue;
127                 n = read(fd, buf, len);
128                 if (n < 0) {
129                         if ((errno == EINTR) || (errno == EAGAIN))
130                                 continue;
131                         return total;
132                 }
133                 if (!n)
134                         return total;
135                 buf = n + (char *)buf;
136                 len -= n;
137                 total += n;
138         }
139         return total;
140 }
141
142 /*
143  * send a packet in length prefix format
144  */
145 int send_packet(int fd, const char *buf, size_t len)
146 {
147         int ret = 0;
148         sigset_t set, old;
149
150         /* Block SIGPIPE */
151         sigemptyset(&set);
152         sigaddset(&set, SIGPIPE);
153         pthread_sigmask(SIG_BLOCK, &set, &old);
154
155         if (write_all(fd, &len, sizeof(len)) != sizeof(len))
156                 ret = -1;
157         if (!ret && write_all(fd, buf, len) != len)
158                 ret = -1;
159
160         /* And unblock it again */
161         pthread_sigmask(SIG_SETMASK, &old, NULL);
162
163         return ret;
164 }
165
166 /*
167  * receive a packet in length prefix format
168  */
169 int recv_packet(int fd, char **buf, size_t *len)
170 {
171         if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) {
172                 (*buf) = NULL;
173                 *len = 0;
174                 return -1;
175         }
176         if (len == 0) {
177                 (*buf) = NULL;
178                 return 0;
179         }
180         (*buf) = MALLOC(*len);
181         if (!*buf)
182                 return -1;
183         if (read_all(fd, *buf, *len) != *len) {
184                 FREE(*buf);
185                 (*buf) = NULL;
186                 *len = 0;
187                 return -1;
188         }
189         return 0;
190 }