1/*
2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <TargetConditionals.h>
25
26#if TARGET_IPHONE_SIMULATOR
27struct _not_empty;
28#else
29
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/socket.h>
33#include <netinet/in.h>
34#include <arpa/inet.h>
35#include <sys/un.h>
36#include <sys/uio.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <fcntl.h>
41#include <errno.h>
42#include <unistd.h>
43#include <netdb.h>
44#include "daemon.h"
45
46#define forever for(;;)
47
48#define UDP_SOCKET_NAME "NetworkListener"
49#define MY_ID "udp_in"
50#define MAXLINE 4096
51
52#define MAXSOCK 16
53static int nsock = 0;
54static int ufd[MAXSOCK];
55static dispatch_source_t ufd_src[MAXSOCK];
56
57static char uline[MAXLINE + 1];
58
59static dispatch_source_t in_src[MAXSOCK];
60static dispatch_queue_t in_queue;
61
62#define FMT_LEGACY 0
63#define FMT_ASL 1
64
65void
66udp_in_acceptmsg(int fd)
67{
68	socklen_t fromlen;
69	ssize_t len;
70	struct sockaddr_storage from;
71	char fromstr[64], *r, *p;
72	struct sockaddr_in *s4;
73	struct sockaddr_in6 *s6;
74	asl_msg_t *m;
75
76	fromlen = sizeof(struct sockaddr_storage);
77	memset(&from, 0, fromlen);
78
79	len = recvfrom(fd, uline, MAXLINE, 0, (struct sockaddr *)&from, &fromlen);
80	if (len <= 0) return;
81
82	fromstr[0] = '\0';
83	r = NULL;
84
85	if (from.ss_family == AF_INET)
86	{
87		s4 = (struct sockaddr_in *)&from;
88		inet_ntop(from.ss_family, &(s4->sin_addr), fromstr, 64);
89		r = fromstr;
90		asldebug("%s: fd %d recvfrom %s len %d\n", MY_ID, fd, fromstr, len);
91	}
92	else if (from.ss_family == AF_INET6)
93	{
94		s6 = (struct sockaddr_in6 *)&from;
95		inet_ntop(from.ss_family, &(s6->sin6_addr), fromstr, 64);
96		r = fromstr;
97		asldebug("%s: fd %d recvfrom %s len %d\n", MY_ID, fd, fromstr, len);
98	}
99
100	uline[len] = '\0';
101
102	p = strrchr(uline, '\n');
103	if (p != NULL) *p = '\0';
104
105	m = asl_input_parse(uline, len, r, SOURCE_UDP_SOCKET);
106	process_message(m, SOURCE_UDP_SOCKET);
107}
108
109int
110udp_in_init()
111{
112	int i, rbufsize, len, fd;
113	launch_data_t sockets_dict, fd_array, fd_dict;
114	static dispatch_once_t once;
115
116	dispatch_once(&once, ^{
117		in_queue = dispatch_queue_create(MY_ID, NULL);
118	});
119
120	asldebug("%s: init\n", MY_ID);
121	if (nsock > 0) return 0;
122
123	if (global.launch_dict == NULL)
124	{
125		asldebug("%s: launchd dict is NULL\n", MY_ID);
126		return -1;
127	}
128
129	sockets_dict = launch_data_dict_lookup(global.launch_dict, LAUNCH_JOBKEY_SOCKETS);
130	if (sockets_dict == NULL)
131	{
132		asldebug("%s: launchd lookup of LAUNCH_JOBKEY_SOCKETS failed\n", MY_ID);
133		return -1;
134	}
135
136	fd_array = launch_data_dict_lookup(sockets_dict, UDP_SOCKET_NAME);
137	if (fd_array == NULL)
138	{
139		asldebug("%s: launchd lookup of UDP_SOCKET_NAME failed\n", MY_ID);
140		return -1;
141	}
142
143	nsock = launch_data_array_get_count(fd_array);
144	if (nsock <= 0)
145	{
146		asldebug("%s: launchd fd array is empty\n", MY_ID);
147		return -1;
148	}
149
150	for (i = 0; i < nsock; i++)
151	{
152		ufd[i] = -1;
153
154		fd_dict = launch_data_array_get_index(fd_array, i);
155		if (fd_dict == NULL)
156		{
157			asldebug("%s: launchd file discriptor array element 0 is NULL\n", MY_ID);
158			return -1;
159		}
160
161		fd = launch_data_get_fd(fd_dict);
162
163		rbufsize = 128 * 1024;
164		len = sizeof(rbufsize);
165
166		if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rbufsize, len) < 0)
167		{
168			asldebug("%s: couldn't set receive buffer size for file descriptor %d: %s\n", MY_ID, fd, strerror(errno));
169		}
170
171		if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
172		{
173			asldebug("%s: couldn't set O_NONBLOCK for file descriptor %d: %s\n", MY_ID, fd, strerror(errno));
174		}
175
176		ufd[i] = fd;
177
178		in_src[i] = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, (uintptr_t)fd, 0, in_queue);
179		dispatch_source_set_event_handler(in_src[i], ^{ udp_in_acceptmsg(fd); });
180
181		dispatch_resume(in_src[i]);
182	}
183
184	return 0;
185}
186
187/* N.B. Does NOT close fds.  They "belong" to launchd. */
188int
189udp_in_close(void)
190{
191	int i;
192
193	if (nsock == 0) return -1;
194
195	for (i = 0; i < nsock; i++)
196	{
197		if (ufd_src[i] != NULL)
198		{
199			dispatch_source_cancel(in_src[i]);
200			dispatch_release(in_src[i]);
201			in_src[i] = NULL;
202		}
203
204		if (ufd[i] != -1)
205		{
206			ufd[i] = -1;
207		}
208	}
209
210	nsock = 0;
211
212	return 0;
213}
214
215int
216udp_in_reset(void)
217{
218	if (udp_in_close() != 0) return -1;
219	return udp_in_init();
220}
221
222#endif /* TARGET_IPHONE_SIMULATOR */
223