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