xref: /haiku/src/servers/net/Services.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "Services.h"
11 #include "NetServer.h"
12 #include "Settings.h"
13 
14 #include <Autolock.h>
15 
16 #include <errno.h>
17 #include <netdb.h>
18 #include <netinet/in.h>
19 #include <new>
20 #include <sys/ioctl.h>
21 #include <sys/socket.h>
22 #include <vector>
23 
24 using namespace std;
25 
26 struct service_address {
27 	struct service *owner;
28 	int		socket;
29 	int		family;
30 	int		type;
31 	int		protocol;
32 	sockaddr address;
33 };
34 
35 typedef vector<service_address> AddressList;
36 
37 struct service {
38 	std::string name;
39 	std::string	launch;
40 	uid_t	user;
41 	gid_t	group;
42 	AddressList addresses;
43 
44 	~service();
45 	bool operator!=(const struct service& other);
46 	bool operator==(const struct service& other);
47 };
48 
49 
50 int
51 parse_type(const char* string)
52 {
53 	if (!strcasecmp(string, "stream"))
54 		return SOCK_STREAM;
55 
56 	return SOCK_DGRAM;
57 }
58 
59 
60 int
61 parse_protocol(const char* string)
62 {
63 	struct protoent* proto = getprotobyname(string);
64 	if (proto == NULL)
65 		return IPPROTO_TCP;
66 
67 	return proto->p_proto;
68 }
69 
70 
71 int
72 type_for_protocol(int protocol)
73 {
74 	// default determined by protocol
75 	switch (protocol) {
76 		case IPPROTO_TCP:
77 			return SOCK_STREAM;
78 
79 		case IPPROTO_UDP:
80 		default:
81 			return SOCK_DGRAM;
82 	}
83 }
84 
85 
86 //	#pragma mark -
87 
88 
89 service::~service()
90 {
91 	// close all open sockets
92 	AddressList::const_iterator iterator = addresses.begin();
93 	for (; iterator != addresses.end(); iterator++) {
94 		const service_address& address = *iterator;
95 
96 		close(address.socket);
97 	}
98 }
99 
100 
101 bool
102 service::operator!=(const struct service& other)
103 {
104 	return !(*this == other);
105 }
106 
107 
108 bool
109 service::operator==(const struct service& other)
110 {
111 	if (name != other.name
112 		|| launch != other.launch)
113 		return false;
114 
115 	// TODO: compare addresses!
116 	return true;
117 }
118 
119 
120 //	#pragma mark -
121 
122 
123 Services::Services(const BMessage& services)
124 	:
125 	fListener(-1),
126 	fUpdate(0),
127 	fMaxSocket(0)
128 {
129 	_Update(services);
130 
131 	// setup pipe to communicate with the listener thread - as the listener
132 	// blocks on select(), we need a mechanism to interrupt it
133 	if (pipe(&fReadPipe) < 0) {
134 		fReadPipe = -1;
135 		return;
136 	}
137 
138 	fcntl(fReadPipe, F_SETFD, FD_CLOEXEC);
139 	fcntl(fWritePipe, F_SETFD, FD_CLOEXEC);
140 
141 	FD_ZERO(&fSet);
142 	FD_SET(fReadPipe, &fSet);
143 
144 	fMinSocket = fWritePipe + 1;
145 	fMaxSocket = fWritePipe + 1;
146 
147 	fListener = spawn_thread(_Listener, "services listener", B_NORMAL_PRIORITY, this);
148 	if (fListener >= B_OK)
149 		resume_thread(fListener);
150 }
151 
152 
153 Services::~Services()
154 {
155 	wait_for_thread(fListener, NULL);
156 }
157 
158 
159 status_t
160 Services::InitCheck() const
161 {
162 	return fListener >= B_OK ? B_OK : fListener;
163 }
164 
165 
166 void
167 Services::MessageReceived(BMessage* message)
168 {
169 	switch (message->what) {
170 		case kMsgUpdateServices:
171 			_Update(*message);
172 			break;
173 
174 		default:
175 			BHandler::MessageReceived(message);
176 	}
177 }
178 
179 
180 void
181 Services::_NotifyListener(bool quit)
182 {
183 	write(fWritePipe, quit ? "q" : "u", 1);
184 }
185 
186 
187 void
188 Services::_UpdateMinMaxSocket(int socket)
189 {
190 	if (socket >= fMaxSocket)
191 		fMaxSocket = socket + 1;
192 	if (socket < fMinSocket)
193 		fMinSocket = socket;
194 }
195 
196 
197 status_t
198 Services::_StartService(struct service& service)
199 {
200 	// create socket
201 
202 	bool failed = false;
203 	AddressList::iterator iterator = service.addresses.begin();
204 	for (; iterator != service.addresses.end(); iterator++) {
205 		service_address& address = *iterator;
206 
207 		address.socket = socket(address.family, address.type, address.protocol);
208 		if (address.socket < 0
209 			|| bind(address.socket, &address.address, address.address.sa_len) < 0
210 			|| fcntl(address.socket, F_SETFD, FD_CLOEXEC) < 0) {
211 			failed = true;
212 			break;
213 		}
214 
215 		if (address.type == SOCK_STREAM && listen(address.socket, 50) < 0) {
216 			failed = true;
217 			break;
218 		}
219 	}
220 
221 	if (failed) {
222 		// open sockets will be closed when the service is deleted
223 		return errno;
224 	}
225 
226 	// add service to maps and activate it
227 
228 	fNameMap[service.name] = &service;
229 
230 	iterator = service.addresses.begin();
231 	for (; iterator != service.addresses.end(); iterator++) {
232 		service_address& address = *iterator;
233 
234 		fSocketMap[address.socket] = &address;
235 		_UpdateMinMaxSocket(address.socket);
236 		FD_SET(address.socket, &fSet);
237 	}
238 
239 	_NotifyListener();
240 printf("Starting service '%s'\n", service.name.c_str());
241 	return B_OK;
242 }
243 
244 
245 status_t
246 Services::_StopService(struct service& service)
247 {
248 	// remove service from maps
249 	{
250 		ServiceNameMap::iterator iterator = fNameMap.find(service.name);
251 		if (iterator != fNameMap.end())
252 			fNameMap.erase(iterator);
253 	}
254 	{
255 		AddressList::const_iterator iterator = service.addresses.begin();
256 		for (; iterator != service.addresses.end(); iterator++) {
257 			const service_address& address = *iterator;
258 
259 			ServiceSocketMap::iterator socketIterator = fSocketMap.find(address.socket);
260 			if (socketIterator != fSocketMap.end())
261 				fSocketMap.erase(socketIterator);
262 
263 			close(address.socket);
264 			FD_CLR(address.socket, &fSet);
265 		}
266 	}
267 
268 	delete &service;
269 	return B_OK;
270 }
271 
272 
273 status_t
274 Services::_ToService(const BMessage& message, struct service*& service)
275 {
276 	// get mandatory fields
277 	const char* name;
278 	const char* launch;
279 	if (message.FindString("name", &name) != B_OK
280 		|| message.FindString("launch", &launch) != B_OK)
281 		return B_BAD_VALUE;
282 
283 	service = new (std::nothrow) ::service;
284 	if (service == NULL)
285 		return B_NO_MEMORY;
286 
287 	service->name = name;
288 	service->launch = launch;
289 
290 	// TODO: user/group is currently ignored!
291 
292 	// Default family/port/protocol/type for all addresses
293 
294 	// we default to inet/tcp/port-from-service-name if nothing is specified
295 	const char* string;
296 	int32 serviceFamilyIndex;
297 	int32 serviceFamily = -1;
298 	if (message.FindString("family", &string) != B_OK)
299 		string = "inet";
300 
301 	if (get_family_index(string, serviceFamilyIndex))
302 		serviceFamily = family_at_index(serviceFamilyIndex);
303 
304 	int32 serviceProtocol;
305 	if (message.FindString("protocol", &string) == B_OK)
306 		serviceProtocol = parse_protocol(string);
307 	else {
308 		string = "tcp";
309 			// we set 'string' here for an eventual call to getservbyname() below
310 		serviceProtocol = IPPROTO_TCP;
311 	}
312 
313 	int32 servicePort;
314 	if (message.FindInt32("port", &servicePort) != B_OK) {
315 		struct servent* servent = getservbyname(name, string);
316 		if (servent != NULL)
317 			servicePort = servent->s_port;
318 		else
319 			servicePort = -1;
320 	}
321 
322 	int32 serviceType = -1;
323 	if (message.FindString("type", &string) == B_OK) {
324 		serviceType = parse_type(string);
325 	} else {
326 		serviceType = type_for_protocol(serviceProtocol);
327 	}
328 
329 	BMessage address;
330 	int32 i = 0;
331 	for (; message.FindMessage("address", i, &address) == B_OK; i++) {
332 		// TODO: dump problems in the settings to syslog
333 		service_address serviceAddress;
334 		if (address.FindString("family", &string) != B_OK)
335 			continue;
336 
337 		int32 familyIndex;
338 		if (!get_family_index(string, familyIndex))
339 			continue;
340 
341 		serviceAddress.family = family_at_index(familyIndex);
342 
343 		if (address.FindString("protocol", &string) == B_OK)
344 			serviceAddress.protocol = parse_protocol(string);
345 		else
346 			serviceAddress.protocol = serviceProtocol;
347 
348 		if (message.FindString("type", &string) == B_OK)
349 			serviceAddress.type = parse_type(string);
350 		else if (serviceAddress.protocol != serviceProtocol)
351 			serviceAddress.type = type_for_protocol(serviceAddress.protocol);
352 		else
353 			serviceAddress.type = serviceType;
354 
355 		if (address.FindString("address", &string) == B_OK) {
356 			if (!parse_address(familyIndex, string, serviceAddress.address))
357 				continue;
358 		} else
359 			set_any_address(familyIndex, serviceAddress.address);
360 
361 		int32 port;
362 		if (address.FindInt32("port", &port) != B_OK)
363 			port = servicePort;
364 
365 		set_port(familyIndex, serviceAddress.address, port);
366 		serviceAddress.socket = -1;
367 
368 		serviceAddress.owner = service;
369 		service->addresses.push_back(serviceAddress);
370 	}
371 
372 	if (i == 0 && (serviceFamily < 0 || servicePort < 0)) {
373 		// no address specified
374 		delete service;
375 		return B_BAD_VALUE;
376 	}
377 
378 	if (i == 0) {
379 		// no address specified, but family/port were given; add empty address
380 		service_address serviceAddress;
381 		serviceAddress.family = serviceFamily;
382 		serviceAddress.type = serviceType;
383 		serviceAddress.protocol = serviceProtocol;
384 
385 		set_any_address(serviceFamilyIndex, serviceAddress.address);
386 		set_port(serviceFamilyIndex, serviceAddress.address, servicePort);
387 		serviceAddress.socket = -1;
388 
389 		serviceAddress.owner = service;
390 		service->addresses.push_back(serviceAddress);
391 	}
392 
393 	return B_OK;
394 }
395 
396 
397 void
398 Services::_Update(const BMessage& services)
399 {
400 	BAutolock locker(fLock);
401 	fUpdate++;
402 
403 	BMessage message;
404 	for (int32 index = 0; services.FindMessage("service", index,
405 			&message) == B_OK; index++) {
406 		const char* name;
407 		if (message.FindString("name", &name) != B_OK)
408 			continue;
409 
410 		struct service* service;
411 		if (_ToService(message, service) != B_OK)
412 			continue;
413 
414 		ServiceNameMap::iterator iterator = fNameMap.find(name);
415 		if (iterator == fNameMap.end()) {
416 			// this service does not exist yet, start it
417 			_StartService(*service);
418 		} else {
419 			// this service does already exist - check for any changes
420 
421 			if (service != iterator->second) {
422 				_StopService(*iterator->second);
423 				_StartService(*service);
424 			}
425 		}
426 	}
427 }
428 
429 
430 status_t
431 Services::_LaunchService(struct service& service, int socket)
432 {
433 	printf("LAUNCH: %s\n", service.launch.c_str());
434 
435 	if (fcntl(socket, F_SETFD, 0) < 0) {
436 		// could not clear FD_CLOEXEC on socket
437 		return errno;
438 	}
439 
440 	pid_t child = fork();
441 	if (child == 0) {
442 		setsid();
443 			// make sure we're in our own session, and don't accidently quit the net_server
444 
445 		// We're the child, replace standard input/output
446 		dup2(socket, STDIN_FILENO);
447 		dup2(socket, STDOUT_FILENO);
448 		dup2(socket, STDERR_FILENO);
449 		close(socket);
450 
451 		// build argument array
452 
453 		const char** args = (const char**)malloc(2 * sizeof(void *));
454 		if (args == NULL)
455 			exit(1);
456 
457 		args[0] = service.launch.c_str();
458 		args[1] = NULL;
459 		if (execv(service.launch.c_str(), (char* const*)args) < 0)
460 			exit(1);
461 
462 		// we'll never trespass here
463 	}
464 
465 	// TODO: make sure child started successfully...
466 	return B_OK;
467 }
468 
469 
470 status_t
471 Services::_Listener()
472 {
473 	while (true) {
474 		fLock.Lock();
475 		fd_set set = fSet;
476 		fLock.Unlock();
477 
478 		if (select(fMaxSocket, &set, NULL, NULL, NULL) < 0) {
479 			// sleep a bit before trying again
480 			snooze(1000000LL);
481 		}
482 
483 printf("select returned!\n");
484 		if (FD_ISSET(fReadPipe, &set)) {
485 			char command;
486 			if (read(fReadPipe, &command, 1) == 1 && command == 'q')
487 				break;
488 		}
489 
490 		BAutolock locker(fLock);
491 
492 		for (int i = fMinSocket; i < fMaxSocket; i++) {
493 			if (!FD_ISSET(i, &set))
494 				continue;
495 
496 			ServiceSocketMap::iterator iterator = fSocketMap.find(i);
497 			if (iterator == fSocketMap.end())
498 				continue;
499 
500 			struct service_address& address = *iterator->second;
501 			int socket;
502 
503 			if (address.type == SOCK_STREAM) {
504 				// accept incoming connection
505 				int value = 1;
506 				ioctl(i, FIONBIO, &value);
507 					// make sure we don't wait for the connection
508 
509 				socket = accept(address.socket, NULL, NULL);
510 
511 				value = 0;
512 				ioctl(i, FIONBIO, &value);
513 
514 				if (socket < 0)
515 					continue;
516 			} else
517 				socket = address.socket;
518 
519 			// launch this service's handler
520 
521 			_LaunchService(*address.owner, socket);
522 		}
523 	}
524 	return B_OK;
525 }
526 
527 
528 /*static*/ status_t
529 Services::_Listener(void* _self)
530 {
531 	Services* self = (Services*)_self;
532 	return self->_Listener();
533 }
534