summaryrefslogtreecommitdiffstats
path: root/libusbmuxd/sock_stuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusbmuxd/sock_stuff.c')
-rw-r--r--libusbmuxd/sock_stuff.c301
1 files changed, 301 insertions, 0 deletions
diff --git a/libusbmuxd/sock_stuff.c b/libusbmuxd/sock_stuff.c
new file mode 100644
index 0000000..137375d
--- /dev/null
+++ b/libusbmuxd/sock_stuff.c
@@ -0,0 +1,301 @@
1#include <stdio.h>
2#include <stddef.h>
3#include <unistd.h>
4#include <errno.h>
5#include <sys/time.h>
6#include <sys/stat.h>
7#include <sys/socket.h>
8#include <sys/un.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include "sock_stuff.h"
13
14#define RECV_TIMEOUT 20000
15
16static int verbose = 0;
17
18void sock_stuff_set_verbose(int level)
19{
20 verbose = level;
21}
22
23int create_unix_socket(const char *filename)
24{
25 struct sockaddr_un name;
26 int sock;
27 size_t size;
28
29 // remove if still present
30 unlink(filename);
31
32 /* Create the socket. */
33 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
34 if (sock < 0) {
35 perror("socket");
36 return -1;
37 }
38
39 /* Bind a name to the socket. */
40 name.sun_family = AF_LOCAL;
41 strncpy(name.sun_path, filename, sizeof(name.sun_path));
42 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
43
44 /* The size of the address is
45 the offset of the start of the filename,
46 plus its length,
47 plus one for the terminating null byte.
48 Alternatively you can just do:
49 size = SUN_LEN (&name);
50 */
51 size = (offsetof(struct sockaddr_un, sun_path)
52 + strlen(name.sun_path) + 1);
53
54 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
55 perror("bind");
56 close(sock);
57 return -1;
58 }
59
60 if (listen(sock, 10) < 0) {
61 perror("listen");
62 close(sock);
63 return -1;
64 }
65
66 return sock;
67}
68
69int connect_unix_socket(const char *filename)
70{
71 struct sockaddr_un name;
72 int sfd = -1;
73 size_t size;
74 struct stat fst;
75
76 // check if socket file exists...
77 if (stat(filename, &fst) != 0) {
78 if (verbose >= 2)
79 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
80 strerror(errno));
81 return -1;
82 }
83 // ... and if it is a unix domain socket
84 if (!S_ISSOCK(fst.st_mode)) {
85 if (verbose >= 2)
86 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
87 filename);
88 return -1;
89 }
90 // make a new socket
91 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
92 if (verbose >= 2)
93 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
94 return -1;
95 }
96 // and connect to 'filename'
97 name.sun_family = AF_LOCAL;
98 strncpy(name.sun_path, filename, sizeof(name.sun_path));
99 name.sun_path[sizeof(name.sun_path) - 1] = 0;
100
101 size = (offsetof(struct sockaddr_un, sun_path)
102 + strlen(name.sun_path) + 1);
103
104 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
105 close(sfd);
106 if (verbose >= 2)
107 fprintf(stderr, "%s: connect: %s\n", __func__,
108 strerror(errno));
109 return -1;
110 }
111
112 return sfd;
113}
114
115int create_socket(uint16_t port)
116{
117 int sfd = -1;
118 int yes = 1;
119 struct sockaddr_in saddr;
120
121 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
122 perror("socket()");
123 return -1;
124 }
125
126 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
127 perror("setsockopt()");
128 close(sfd);
129 return -1;
130 }
131
132 memset((void *) &saddr, 0, sizeof(saddr));
133 saddr.sin_family = AF_INET;
134 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
135 saddr.sin_port = htons(port);
136
137 if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
138 perror("bind()");
139 close(sfd);
140 return -1;
141 }
142
143 if (listen(sfd, 1) == -1) {
144 perror("listen()");
145 close(sfd);
146 return -1;
147 }
148
149 return sfd;
150}
151
152int connect_socket(const char *addr, uint16_t port)
153{
154 int sfd = -1;
155 int yes = 1;
156 struct hostent *hp;
157 struct sockaddr_in saddr;
158
159 if (!addr) {
160 errno = EINVAL;
161 return -1;
162 }
163
164 if ((hp = gethostbyname(addr)) == NULL) {
165 if (verbose >= 2)
166 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
167 return -1;
168 }
169
170 if (!hp->h_addr) {
171 if (verbose >= 2)
172 fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
173 __func__);
174 return -1;
175 }
176
177 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
178 perror("socket()");
179 return -1;
180 }
181
182 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
183 perror("setsockopt()");
184 close(sfd);
185 return -1;
186 }
187
188 memset((void *) &saddr, 0, sizeof(saddr));
189 saddr.sin_family = AF_INET;
190 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
191 saddr.sin_port = htons(port);
192
193 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
194 perror("connect");
195 close(sfd);
196 return -2;
197 }
198
199 return sfd;
200}
201
202int check_fd(int fd, fd_mode fdm, unsigned int timeout)
203{
204 fd_set fds;
205 int sret;
206 int eagain;
207 struct timeval to;
208
209 if (fd <= 0) {
210 if (verbose >= 2)
211 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
212 return -1;
213 }
214
215 FD_ZERO(&fds);
216 FD_SET(fd, &fds);
217
218 to.tv_sec = (time_t) (timeout / 1000);
219 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
220
221 sret = -1;
222
223 do {
224 eagain = 0;
225 switch (fdm) {
226 case FD_READ:
227 sret = select(fd + 1, &fds, NULL, NULL, &to);
228 break;
229 case FD_WRITE:
230 sret = select(fd + 1, NULL, &fds, NULL, &to);
231 break;
232 case FD_EXCEPT:
233 sret = select(fd + 1, NULL, NULL, &fds, &to);
234 break;
235 default:
236 return -1;
237 }
238
239 if (sret < 0) {
240 switch (errno) {
241 case EINTR:
242 // interrupt signal in select
243 if (verbose >= 2)
244 fprintf(stderr, "%s: EINTR\n", __func__);
245 eagain = 1;
246 break;
247 case EAGAIN:
248 if (verbose >= 2)
249 fprintf(stderr, "%s: EAGAIN\n", __func__);
250 break;
251 default:
252 if (verbose >= 2)
253 fprintf(stderr, "%s: select failed: %s\n", __func__,
254 strerror(errno));
255 return -1;
256 }
257 }
258 } while (eagain);
259
260 return sret;
261}
262
263int recv_buf(int fd, void *data, size_t length)
264{
265 return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT);
266}
267
268int peek_buf(int fd, void *data, size_t length)
269{
270 return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
271}
272
273int recv_buf_timeout(int fd, void *data, size_t length, int flags,
274 unsigned int timeout)
275{
276 int res;
277 int result;
278
279 // check if data is available
280 res = check_fd(fd, FD_READ, timeout);
281 if (res <= 0) {
282 return res;
283 }
284 // if we get here, there _is_ data available
285 result = recv(fd, data, length, flags);
286 if (res > 0 && result == 0) {
287 // but this is an error condition
288 if (verbose >= 3)
289 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
290 return -EAGAIN;
291 }
292 if (result < 0) {
293 return -errno;
294 }
295 return result;
296}
297
298int send_buf(int fd, void *data, size_t length)
299{
300 return send(fd, data, length, 0);
301}