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