// Copyright (c) 2007, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <mach/mach.h> #include <servers/bootstrap.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h> //============================================================================== // class OnDemandServer : // A basic on-demand server launcher supporting a single named service port // // Example Usage : // // kern_return_t result; // OnDemandServer *server = OnDemandServer::Create("/tmp/myserver", // "com.MyCompany.MyServiceName", // true, // &result); // // if (server) { // server->LaunchOnDemand(); // mach_port_t service_port = GetServicePort(); // // // Send a mach message to service_port and "myserver" will be launched // } // // // ---- Now in the server code ---- // // // "myserver" should get the service port and read the message which // // launched it: // mach_port_t service_rcv_port_; // kern_return_t kr = bootstrap_check_in(bootstrap_port, // "com.MyCompany.MyServiceName", // &service_rcv_port_); // // mach_msg() read service_rcv_port_ .... // // .... // // // Later "myserver" may want to unregister the service if it doesn't // // want its bootstrap service to stick around after it exits. // // // DO NOT use mach_port_deallocate() here -- it will fail and the // // following bootstrap_register() will also fail leaving our service // // name hanging around forever (until reboot) // kern_return_t kr = mach_port_destroy(mach_task_self(), service_rcv_port_); // // kr = bootstrap_register(bootstrap_port, // "com.MyCompany.MyServiceName", // MACH_PORT_NULL); class OnDemandServer { public: // must call Initialize() to be useful OnDemandServer() : server_port_(MACH_PORT_NULL), service_port_(MACH_PORT_NULL), unregister_on_cleanup_(true) { } // Creates the bootstrap server and service kern_return_t Initialize(const char *server_command, const char *service_name, bool unregister_on_cleanup); // Returns an OnDemandServer object if successful, or NULL if there's // an error. The error result will be returned in out_result. // // server_command : the full path name including optional command-line // arguments to the executable representing the server // // service_name : represents service name // something like "com.company.ServiceName" // // unregister_on_cleanup : if true, unregisters the service name // when the OnDemandServer is deleted -- unregistering will // ONLY be possible if LaunchOnDemand() has NOT been called. // If false, then the service will continue to be registered // even after the current process quits. // // out_result : if non-NULL, returns the result // this value will be KERN_SUCCESS if Create() returns non-NULL // static OnDemandServer *Create(const char *server_command, const char *service_name, bool unregister_on_cleanup, kern_return_t *out_result); // Cleans up and if LaunchOnDemand() has not yet been called then // the bootstrap service will be unregistered. ~OnDemandServer(); // This must be called if we intend to commit to launching the server // by sending a mach message to our service port. Do not call it otherwise // or it will be difficult (impossible?) to unregister the service name. void LaunchOnDemand(); // This is the port we need to send a mach message to after calling // LaunchOnDemand(). Sending a message causing an immediate launch // of the server mach_port_t GetServicePort() { return service_port_; }; private: // Disallow copy constructor OnDemandServer(const OnDemandServer&); // Cleans up and if LaunchOnDemand() has not yet been called then // the bootstrap service will be unregistered. void Unregister(); name_t service_name_; mach_port_t server_port_; mach_port_t service_port_; bool unregister_on_cleanup_; };