PageRenderTime 64ms CodeModel.GetById 11ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

/src/socket.c

https://github.com/mchaland/libusbmuxd
C | 435 lines | 340 code | 57 blank | 38 comment | 59 complexity | b0b1ff115ae4587d0907b7de91d45b2f MD5 | raw file
  1/*
  2 * socket.c
  3 *
  4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
  5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved.
  6 *
  7 * This library is free software; you can redistribute it and/or
  8 * modify it under the terms of the GNU Lesser General Public
  9 * License as published by the Free Software Foundation; either
 10 * version 2.1 of the License, or (at your option) any later version.
 11 * 
 12 * This library is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15 * Lesser General Public License for more details.
 16 * 
 17 * You should have received a copy of the GNU Lesser General Public
 18 * License along with this library; if not, write to the Free Software
 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA 
 20 */
 21
 22#include <stdio.h>
 23#include <stddef.h>
 24#include <stdlib.h>
 25#include <string.h>
 26#include <unistd.h>
 27#include <errno.h>
 28#include <sys/time.h>
 29#include <sys/stat.h>
 30#ifdef WIN32
 31#include <winsock2.h>
 32#include <windows.h>
 33static int wsa_init = 0;
 34#else
 35#include <sys/socket.h>
 36#include <sys/un.h>
 37#include <netinet/in.h>
 38#include <netdb.h>
 39#include <arpa/inet.h>
 40#endif
 41#include "socket.h"
 42
 43#define RECV_TIMEOUT 20000
 44
 45static int verbose = 0;
 46
 47void socket_set_verbose(int level)
 48{
 49	verbose = level;
 50}
 51
 52#ifndef WIN32
 53int socket_create_unix(const char *filename)
 54{
 55	struct sockaddr_un name;
 56	int sock;
 57	size_t size;
 58#ifdef SO_NOSIGPIPE
 59	int yes = 1;
 60#endif
 61
 62	// remove if still present
 63	unlink(filename);
 64
 65	/* Create the socket. */
 66	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 67	if (sock < 0) {
 68		perror("socket");
 69		return -1;
 70	}
 71
 72#ifdef SO_NOSIGPIPE
 73	if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
 74		perror("setsockopt()");
 75		socket_close(sock);
 76		return -1;
 77	}
 78#endif
 79
 80	/* Bind a name to the socket. */
 81	name.sun_family = AF_LOCAL;
 82	strncpy(name.sun_path, filename, sizeof(name.sun_path));
 83	name.sun_path[sizeof(name.sun_path) - 1] = '\0';
 84
 85	/* The size of the address is
 86	   the offset of the start of the filename,
 87	   plus its length,
 88	   plus one for the terminating null byte.
 89	   Alternatively you can just do:
 90	   size = SUN_LEN (&name);
 91	 */
 92	size = (offsetof(struct sockaddr_un, sun_path)
 93			+ strlen(name.sun_path) + 1);
 94
 95	if (bind(sock, (struct sockaddr *) &name, size) < 0) {
 96		perror("bind");
 97		socket_close(sock);
 98		return -1;
 99	}
100
101	if (listen(sock, 10) < 0) {
102		perror("listen");
103		socket_close(sock);
104		return -1;
105	}
106
107	return sock;
108}
109
110int socket_connect_unix(const char *filename)
111{
112	struct sockaddr_un name;
113	int sfd = -1;
114	size_t size;
115	struct stat fst;
116#ifdef SO_NOSIGPIPE
117	int yes = 1;
118#endif
119
120	// check if socket file exists...
121	if (stat(filename, &fst) != 0) {
122		if (verbose >= 2)
123			fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
124					strerror(errno));
125		return -1;
126	}
127	// ... and if it is a unix domain socket
128	if (!S_ISSOCK(fst.st_mode)) {
129		if (verbose >= 2)
130			fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
131					filename);
132		return -1;
133	}
134	// make a new socket
135	if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
136		if (verbose >= 2)
137			fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
138		return -1;
139	}
140
141#ifdef SO_NOSIGPIPE
142	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
143		perror("setsockopt()");
144		socket_close(sfd);
145		return -1;
146	}
147#endif
148
149	// and connect to 'filename'
150	name.sun_family = AF_LOCAL;
151	strncpy(name.sun_path, filename, sizeof(name.sun_path));
152	name.sun_path[sizeof(name.sun_path) - 1] = 0;
153
154	size = (offsetof(struct sockaddr_un, sun_path)
155			+ strlen(name.sun_path) + 1);
156
157	if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
158		socket_close(sfd);
159		if (verbose >= 2)
160			fprintf(stderr, "%s: connect: %s\n", __func__,
161					strerror(errno));
162		return -1;
163	}
164
165	return sfd;
166}
167#endif
168
169int socket_create(uint16_t port)
170{
171	int sfd = -1;
172	int yes = 1;
173#ifdef WIN32
174	WSADATA wsa_data;
175	if (!wsa_init) {
176		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
177			fprintf(stderr, "WSAStartup failed!\n");
178			ExitProcess(-1);
179		}
180		wsa_init = 1;
181	}
182#endif
183	struct sockaddr_in saddr;
184
185	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
186		perror("socket()");
187		return -1;
188	}
189
190	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
191		perror("setsockopt()");
192		socket_close(sfd);
193		return -1;
194	}
195
196#ifdef SO_NOSIGPIPE
197	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
198		perror("setsockopt()");
199		socket_close(sfd);
200		return -1;
201	}
202#endif
203
204	memset((void *) &saddr, 0, sizeof(saddr));
205	saddr.sin_family = AF_INET;
206	saddr.sin_addr.s_addr = htonl(INADDR_ANY);
207	saddr.sin_port = htons(port);
208
209	if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
210		perror("bind()");
211		socket_close(sfd);
212		return -1;
213	}
214
215	if (listen(sfd, 1) == -1) {
216		perror("listen()");
217		socket_close(sfd);
218		return -1;
219	}
220
221	return sfd;
222}
223
224int socket_connect(const char *addr, uint16_t port)
225{
226	int sfd = -1;
227	int yes = 1;
228	struct hostent *hp;
229	struct sockaddr_in saddr;
230#ifdef WIN32
231	WSADATA wsa_data;
232	if (!wsa_init) {
233		if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
234			fprintf(stderr, "WSAStartup failed!\n");
235			ExitProcess(-1);
236		}
237		wsa_init = 1;
238	}
239#endif
240
241	if (!addr) {
242		errno = EINVAL;
243		return -1;
244	}
245
246	if ((hp = gethostbyname(addr)) == NULL) {
247		if (verbose >= 2)
248			fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
249		return -1;
250	}
251
252	if (!hp->h_addr) {
253		if (verbose >= 2)
254			fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
255					__func__);
256		return -1;
257	}
258
259	if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
260		perror("socket()");
261		return -1;
262	}
263
264	if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
265		perror("setsockopt()");
266		socket_close(sfd);
267		return -1;
268	}
269
270#ifdef SO_NOSIGPIPE
271	if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
272		perror("setsockopt()");
273		socket_close(sfd);
274		return -1;
275	}
276#endif
277
278	memset((void *) &saddr, 0, sizeof(saddr));
279	saddr.sin_family = AF_INET;
280	saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
281	saddr.sin_port = htons(port);
282
283	if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
284		perror("connect");
285		socket_close(sfd);
286		return -2;
287	}
288
289	return sfd;
290}
291
292int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
293{
294	fd_set fds;
295	int sret;
296	int eagain;
297	struct timeval to;
298	struct timeval *pto;
299
300	if (fd < 0) {
301		if (verbose >= 2)
302			fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
303		return -1;
304	}
305
306	FD_ZERO(&fds);
307	FD_SET(fd, &fds);
308
309	if (timeout > 0) {
310		to.tv_sec = (time_t) (timeout / 1000);
311		to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
312		pto = &to;
313	} else {
314		pto = NULL;
315	}
316
317	sret = -1;
318
319	do {
320		eagain = 0;
321		switch (fdm) {
322		case FDM_READ:
323			sret = select(fd + 1, &fds, NULL, NULL, pto);
324			break;
325		case FDM_WRITE:
326			sret = select(fd + 1, NULL, &fds, NULL, pto);
327			break;
328		case FDM_EXCEPT:
329			sret = select(fd + 1, NULL, NULL, &fds, pto);
330			break;
331		default:
332			return -1;
333		}
334
335		if (sret < 0) {
336			switch (errno) {
337			case EINTR:
338				// interrupt signal in select
339				if (verbose >= 2)
340					fprintf(stderr, "%s: EINTR\n", __func__);
341				eagain = 1;
342				break;
343			case EAGAIN:
344				if (verbose >= 2)
345					fprintf(stderr, "%s: EAGAIN\n", __func__);
346				break;
347			default:
348				if (verbose >= 2)
349					fprintf(stderr, "%s: select failed: %s\n", __func__,
350							strerror(errno));
351				return -1;
352			}
353		}
354	} while (eagain);
355
356	return sret;
357}
358
359int socket_accept(int fd, uint16_t port)
360{
361#ifdef WIN32
362	int addr_len;
363#else
364	socklen_t addr_len;
365#endif
366	int result;
367	struct sockaddr_in addr;
368
369	memset(&addr, 0, sizeof(addr));
370	addr.sin_family = AF_INET;
371	addr.sin_addr.s_addr = htonl(INADDR_ANY);
372	addr.sin_port = htons(port);
373
374	addr_len = sizeof(addr);
375	result = accept(fd, (struct sockaddr*)&addr, &addr_len);
376
377	return result;
378}
379
380int socket_shutdown(int fd, int how)
381{
382	return shutdown(fd, how);
383}
384
385int socket_close(int fd) {
386#ifdef WIN32
387	return closesocket(fd);
388#else
389	return close(fd);
390#endif
391}
392
393int socket_receive(int fd, void *data, size_t length)
394{
395	return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
396}
397
398int socket_peek(int fd, void *data, size_t length)
399{
400	return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
401}
402
403int socket_receive_timeout(int fd, void *data, size_t length, int flags,
404					 unsigned int timeout)
405{
406	int res;
407	int result;
408
409	// check if data is available
410	res = socket_check_fd(fd, FDM_READ, timeout);
411	if (res <= 0) {
412		return res;
413	}
414	// if we get here, there _is_ data available
415	result = recv(fd, data, length, flags);
416	if (res > 0 && result == 0) {
417		// but this is an error condition
418		if (verbose >= 3)
419			fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
420		return -EAGAIN;
421	}
422	if (result < 0) {
423		return -errno;
424	}
425	return result;
426}
427
428int socket_send(int fd, void *data, size_t length)
429{
430	int flags = 0;
431#ifdef MSG_NOSIGNAL
432	flags |= MSG_NOSIGNAL;
433#endif
434	return send(fd, data, length, flags);
435}