1 // Copyright 2007 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include <mach/mach.h> 30 #include <servers/bootstrap.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <sys/stat.h> 34 #include <unistd.h> 35 36 //============================================================================== 37 // class OnDemandServer : 38 // A basic on-demand server launcher supporting a single named service port 39 // 40 // Example Usage : 41 // 42 // kern_return_t result; 43 // OnDemandServer* server = OnDemandServer::Create("/tmp/myserver", 44 // "com.MyCompany.MyServiceName", 45 // true, 46 // &result); 47 // 48 // if (server) { 49 // server->LaunchOnDemand(); 50 // mach_port_t service_port = GetServicePort(); 51 // 52 // // Send a mach message to service_port and "myserver" will be launched 53 // } 54 // 55 // 56 // ---- Now in the server code ---- 57 // 58 // // "myserver" should get the service port and read the message which 59 // // launched it: 60 // mach_port_t service_rcv_port_; 61 // kern_return_t kr = bootstrap_check_in(bootstrap_port, 62 // "com.MyCompany.MyServiceName", 63 // &service_rcv_port_); 64 // // mach_msg() read service_rcv_port_ .... 65 // 66 // .... 67 // 68 // // Later "myserver" may want to unregister the service if it doesn't 69 // // want its bootstrap service to stick around after it exits. 70 // 71 // // DO NOT use mach_port_deallocate() here -- it will fail and the 72 // // following bootstrap_register() will also fail leaving our service 73 // // name hanging around forever (until reboot) 74 // kern_return_t kr = mach_port_destroy(mach_task_self(), service_rcv_port_); 75 // 76 // kr = bootstrap_register(bootstrap_port, 77 // "com.MyCompany.MyServiceName", 78 // MACH_PORT_NULL); 79 80 class OnDemandServer { 81 public: 82 // must call Initialize() to be useful OnDemandServer()83 OnDemandServer() 84 : server_port_(MACH_PORT_NULL), 85 service_port_(MACH_PORT_NULL), 86 unregister_on_cleanup_(true) { 87 } 88 89 // Creates the bootstrap server and service 90 kern_return_t Initialize(const char* server_command, 91 const char* service_name, 92 bool unregister_on_cleanup); 93 94 // Returns an OnDemandServer object if successful, or NULL if there's 95 // an error. The error result will be returned in out_result. 96 // 97 // server_command : the full path name including optional command-line 98 // arguments to the executable representing the server 99 // 100 // service_name : represents service name 101 // something like "com.company.ServiceName" 102 // 103 // unregister_on_cleanup : if true, unregisters the service name 104 // when the OnDemandServer is deleted -- unregistering will 105 // ONLY be possible if LaunchOnDemand() has NOT been called. 106 // If false, then the service will continue to be registered 107 // even after the current process quits. 108 // 109 // out_result : if non-NULL, returns the result 110 // this value will be KERN_SUCCESS if Create() returns non-NULL 111 // 112 static OnDemandServer* Create(const char *server_command, 113 const char* service_name, 114 bool unregister_on_cleanup, 115 kern_return_t* out_result); 116 117 // Cleans up and if LaunchOnDemand() has not yet been called then 118 // the bootstrap service will be unregistered. 119 ~OnDemandServer(); 120 121 // This must be called if we intend to commit to launching the server 122 // by sending a mach message to our service port. Do not call it otherwise 123 // or it will be difficult (impossible?) to unregister the service name. 124 void LaunchOnDemand(); 125 126 // This is the port we need to send a mach message to after calling 127 // LaunchOnDemand(). Sending a message causing an immediate launch 128 // of the server GetServicePort()129 mach_port_t GetServicePort() { return service_port_; } 130 131 private: 132 // Disallow copy constructor 133 OnDemandServer(const OnDemandServer&); 134 135 // Cleans up and if LaunchOnDemand() has not yet been called then 136 // the bootstrap service will be unregistered. 137 void Unregister(); 138 139 name_t service_name_; 140 141 mach_port_t server_port_; 142 mach_port_t service_port_; 143 bool unregister_on_cleanup_; 144 }; 145