Fix some socket issues
[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
111         while (len) {
112                 ssize_t n = read(fd, buf, len);
113                 if (n < 0) {
114                         if ((errno == EINTR) || (errno == EAGAIN))
115                                 continue;
116                         return total;
117                 }
118                 if (!n)
119                         return total;
120                 buf = n + (char *)buf;
121                 len -= n;
122                 total += n;
123         }
124         return total;
125 }
126
127 /*
128  * send a packet in length prefix format
129  */
130 int send_packet(int fd, const char *buf, size_t len)
131 {
132         int ret = 0;
133         sigset_t set, old;
134
135         /* Block SIGPIPE */
136         sigemptyset(&set);
137         sigaddset(&set, SIGPIPE);
138         pthread_sigmask(SIG_BLOCK, &set, &old);
139
140         if (write_all(fd, &len, sizeof(len)) != sizeof(len))
141                 ret = -1;
142         if (!ret && write_all(fd, buf, len) != len)
143                 ret = -1;
144
145         /* And unblock it again */
146         pthread_sigmask(SIG_SETMASK, &old, NULL);
147
148         return ret;
149 }
150
151 /*
152  * receive a packet in length prefix format
153  */
154 int recv_packet(int fd, char **buf, size_t *len)
155 {
156         if (read_all(fd, len, sizeof(*len)) != sizeof(*len)) {
157                 (*buf) = NULL;
158                 *len = 0;
159                 return -1;
160         }
161         if (len == 0) {
162                 (*buf) = NULL;
163                 return 0;
164         }
165         (*buf) = MALLOC(*len);
166         if (!*buf)
167                 return -1;
168         if (read_all(fd, *buf, *len) != *len) {
169                 FREE(*buf);
170                 (*buf) = NULL;
171                 *len = 0;
172                 return -1;
173         }
174         return 0;
175 }