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