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