/fbus/fbus_service_manager_daemon.c

http://ftk.googlecode.com/ · C · 399 lines · 300 code · 70 blank · 29 comment · 44 complexity · 41251563313e95e0a7d663db683c1869 MD5 · raw file

  1. /*
  2. * File: fbus_service_manager_daemon.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: service manager daemon.
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2010-07-25 Li XianJing <xianjimli@hotmail.com> created
  28. *
  29. */
  30. #include "ftk_log.h"
  31. #include <sys/wait.h>
  32. #include <sys/types.h>
  33. #include "ftk_globals.h"
  34. #include "ftk_main_loop.h"
  35. #include "fbus_service.h"
  36. #include "ftk_source_timer.h"
  37. #include "fbus_service_infos.h"
  38. #include "fbus_service_manager.h"
  39. typedef struct _PrivInfo
  40. {
  41. int quiting;
  42. FBusServiceInfos* service_infos;
  43. }PrivInfo;
  44. static int process_start(const char* exec)
  45. {
  46. int pid = fork();
  47. if(pid == 0)
  48. {
  49. execl(exec, exec, NULL);
  50. }
  51. return pid;
  52. }
  53. static Ret process_stop(int pid)
  54. {
  55. int ret = kill(pid, SIGTERM);
  56. return ret == 0 ? RET_OK : RET_FAIL;
  57. }
  58. static int process_wait_child(void)
  59. {
  60. int status = 0;
  61. return waitpid(-1, &status, WNOHANG);
  62. }
  63. static const char* fbus_service_service_manager_get_name(FBusService* thiz)
  64. {
  65. return FBUS_SERVICE_MANAGER_NAME;
  66. }
  67. static Ret fbus_service_service_manager_handle_get_nr(FBusService* thiz, int* nr)
  68. {
  69. DECL_PRIV(thiz, priv);
  70. *nr = fbus_service_infos_get_nr(priv->service_infos);
  71. return RET_OK;
  72. }
  73. static Ret fbus_service_service_manager_handle_get(FBusService* thiz, int i, FBusServiceInfo* info)
  74. {
  75. DECL_PRIV(thiz, priv);
  76. FBusServiceInfo* found = fbus_service_infos_get(priv->service_infos, i);
  77. return_val_if_fail(found != NULL, RET_FAIL);
  78. memcpy(info, found, sizeof(FBusServiceInfo));
  79. return RET_OK;
  80. }
  81. static Ret fbus_service_service_manager_handle_stop(FBusService* thiz, const char* name)
  82. {
  83. DECL_PRIV(thiz, priv);
  84. FBusServiceInfo* info = fbus_service_infos_find(priv->service_infos, name);
  85. return_val_if_fail(info != NULL, RET_NOT_FOUND);
  86. if(info->status == FBUS_SERVICE_STARTED)
  87. {
  88. process_stop(info->pid);
  89. info->status = FBUS_SERVICE_STOPING;
  90. }
  91. return RET_OK;
  92. }
  93. static Ret fbus_service_service_manager_handle_start(FBusService* thiz, const char* name)
  94. {
  95. DECL_PRIV(thiz, priv);
  96. FBusServiceInfo* info = fbus_service_infos_find(priv->service_infos, name);
  97. return_val_if_fail(info != NULL, RET_NOT_FOUND);
  98. if(info->status == FBUS_SERVICE_STOPED)
  99. {
  100. process_start(info->exec);
  101. info->status = FBUS_SERVICE_STARTING;
  102. }
  103. return RET_OK;
  104. }
  105. static Ret fbus_service_service_manager_handle_query(FBusService* thiz, const char* name, FBusServiceInfo* info)
  106. {
  107. DECL_PRIV(thiz, priv);
  108. FBusServiceInfo* found = fbus_service_infos_find(priv->service_infos, name);
  109. return_val_if_fail(found != NULL, RET_NOT_FOUND);
  110. memcpy(info, found, sizeof(FBusServiceInfo));
  111. return RET_OK;
  112. }
  113. static Ret fbus_service_service_manager_handle_register(FBusService* thiz, const char* name,
  114. FBusServiceInfo* info, const char* host, int pid)
  115. {
  116. DECL_PRIV(thiz, priv);
  117. FBusServiceInfo* found = fbus_service_infos_find(priv->service_infos, name);
  118. return_val_if_fail(found != NULL, RET_NOT_FOUND);
  119. return_val_if_fail(host != NULL, RET_FAIL);
  120. found->pid = pid;
  121. ftk_strncpy(found->host, host, sizeof(found->host)-1);
  122. found->status = FBUS_SERVICE_STARTED;
  123. memcpy(info, found, sizeof(FBusServiceInfo));
  124. return RET_OK;
  125. }
  126. static Ret fbus_service_service_manager_handle_unregister(FBusService* thiz, const char* name,
  127. const char* host, int pid)
  128. {
  129. DECL_PRIV(thiz, priv);
  130. FBusServiceInfo* found = fbus_service_infos_find(priv->service_infos, name);
  131. return_val_if_fail(found != NULL, RET_NOT_FOUND);
  132. return_val_if_fail(found->pid == pid && strcmp(found->host, host) == 0, RET_FAIL);
  133. return_val_if_fail(host != NULL, RET_FAIL);
  134. found->status = FBUS_SERVICE_STOPED;
  135. return RET_OK;
  136. }
  137. static Ret fbus_service_service_manager_check_children(FBusService* thiz)
  138. {
  139. int pid = 0;
  140. DECL_PRIV(thiz, priv);
  141. do
  142. {
  143. int i = 0;
  144. int nr = 0;
  145. if((pid = process_wait_child()) <= 0) break;
  146. nr = fbus_service_infos_get_nr(priv->service_infos);
  147. for(i = 0; i < nr; i++)
  148. {
  149. FBusServiceInfo* info = fbus_service_infos_get(priv->service_infos, i);
  150. if(info->pid == pid)
  151. {
  152. info->status = FBUS_SERVICE_STOPED;
  153. ftk_logd("%s: service %s %d stoped.\n", __func__, info->name, info->pid);
  154. if(!priv->quiting)
  155. {
  156. if(info->start_type == FBUS_SERVICE_RUN_FOREVER)
  157. {
  158. process_start(info->exec);
  159. info->status = FBUS_SERVICE_STARTING;
  160. ftk_logd("%s: restart service %s\n", __func__, info->name);
  161. }
  162. }
  163. break;
  164. }
  165. }
  166. }while(pid > 0);
  167. return RET_OK;
  168. }
  169. static Ret fbus_service_service_manager_handle_request(FBusService* thiz, int client_id, FBusParcel* req_resp)
  170. {
  171. int pid = 0;
  172. Ret ret = RET_OK;
  173. int req_code = fbus_parcel_get_int(req_resp);
  174. switch(req_code)
  175. {
  176. case FBUS_SERVICE_MANAGER_REQ_GET:
  177. {
  178. FBusServiceInfo info = {0};
  179. int index = fbus_parcel_get_int(req_resp);
  180. ret = fbus_service_service_manager_handle_get(thiz, index, &info);
  181. fbus_parcel_reset(req_resp);
  182. fbus_parcel_write_int(req_resp, ret);
  183. if(ret == RET_OK)
  184. {
  185. fbus_parcel_write_data(req_resp, &info, sizeof(info));
  186. }
  187. break;
  188. }
  189. case FBUS_SERVICE_MANAGER_REQ_GET_NR:
  190. {
  191. int nr = 0;
  192. ret = fbus_service_service_manager_handle_get_nr(thiz, &nr);
  193. fbus_parcel_reset(req_resp);
  194. fbus_parcel_write_int(req_resp, ret);
  195. fbus_parcel_write_int(req_resp, nr);
  196. break;
  197. }
  198. case FBUS_SERVICE_MANAGER_REQ_STOP:
  199. {
  200. const char* name = fbus_parcel_get_string(req_resp);
  201. ret = fbus_service_service_manager_handle_stop(thiz, name);
  202. fbus_parcel_reset(req_resp);
  203. fbus_parcel_write_int(req_resp, ret);
  204. break;
  205. }
  206. case FBUS_SERVICE_MANAGER_REQ_START:
  207. {
  208. const char* name = fbus_parcel_get_string(req_resp);
  209. ret = fbus_service_service_manager_handle_start(thiz, name);
  210. fbus_parcel_reset(req_resp);
  211. fbus_parcel_write_int(req_resp, ret);
  212. break;
  213. }
  214. case FBUS_SERVICE_MANAGER_REQ_QUERY:
  215. {
  216. FBusServiceInfo info = {0};
  217. const char* name = fbus_parcel_get_string(req_resp);
  218. ret = fbus_service_service_manager_handle_query(thiz, name, &info);
  219. fbus_parcel_reset(req_resp);
  220. fbus_parcel_write_int(req_resp, ret);
  221. if(ret == RET_OK)
  222. {
  223. fbus_parcel_write_data(req_resp, &info, sizeof(info));
  224. }
  225. break;
  226. }
  227. case FBUS_SERVICE_MANAGER_REQ_REGISTER:
  228. {
  229. FBusServiceInfo info = {0};
  230. const char* name = fbus_parcel_get_string(req_resp);
  231. const char* host = fbus_parcel_get_string(req_resp);
  232. pid = fbus_parcel_get_int(req_resp);
  233. ret = fbus_service_service_manager_handle_register(thiz, name, &info, host, pid);
  234. fbus_parcel_reset(req_resp);
  235. fbus_parcel_write_int(req_resp, ret);
  236. if(ret == RET_OK)
  237. {
  238. fbus_parcel_write_data(req_resp, &info, sizeof(info));
  239. }
  240. break;
  241. }
  242. case FBUS_SERVICE_MANAGER_REQ_UNREGISTER:
  243. {
  244. const char* name = fbus_parcel_get_string(req_resp);
  245. const char* host = fbus_parcel_get_string(req_resp);
  246. pid = fbus_parcel_get_int(req_resp);
  247. ret = fbus_service_service_manager_handle_unregister(thiz, name, host, pid);
  248. fbus_parcel_reset(req_resp);
  249. fbus_parcel_write_int(req_resp, ret);
  250. break;
  251. }
  252. default:
  253. {
  254. ftk_logd("%s: not supported: %d\n", __func__, req_code);
  255. break;
  256. }
  257. }
  258. fbus_service_service_manager_check_children(thiz);
  259. return RET_OK;
  260. }
  261. static void fbus_service_service_manager_destroy(FBusService* thiz)
  262. {
  263. if(thiz != NULL)
  264. {
  265. int i = 0;
  266. int nr = 0;
  267. DECL_PRIV(thiz, priv);
  268. priv->quiting = 1;
  269. nr = fbus_service_infos_get_nr(priv->service_infos);
  270. for(i = 0; i < nr; i++)
  271. {
  272. FBusServiceInfo* info = fbus_service_infos_get(priv->service_infos, i);
  273. if(info->status == FBUS_SERVICE_STARTED)
  274. {
  275. process_stop(info->pid);
  276. }
  277. }
  278. fbus_service_service_manager_check_children(thiz);
  279. fbus_service_infos_destroy(priv->service_infos);
  280. FTK_FREE(thiz);
  281. }
  282. return;
  283. }
  284. static FBusService* fbus_service_service_manager_create(void)
  285. {
  286. FBusService* thiz = FTK_ZALLOC(sizeof(FBusService) + sizeof(PrivInfo));
  287. if(thiz != NULL)
  288. {
  289. int i = 0;
  290. int nr = 0;
  291. DECL_PRIV(thiz, priv);
  292. FtkSource* timer = NULL;
  293. char path[FTK_MAX_PATH + 1] = {0};
  294. thiz->get_name = fbus_service_service_manager_get_name;
  295. thiz->handle_request = fbus_service_service_manager_handle_request;
  296. thiz->destroy = fbus_service_service_manager_destroy;
  297. priv->service_infos = fbus_service_infos_create(16);
  298. ftk_snprintf(path, sizeof(path)-1, DATA_DIR"/services");
  299. fbus_service_infos_load_dir(priv->service_infos, path);
  300. fbus_service_register(thiz);
  301. timer = ftk_source_timer_create(5000, (FtkTimer)fbus_service_service_manager_check_children, thiz);
  302. ftk_main_loop_add_source(ftk_default_main_loop(), timer);
  303. nr = fbus_service_infos_get_nr(priv->service_infos);
  304. for(i = 0; i < nr; i++)
  305. {
  306. FBusServiceInfo* info = fbus_service_infos_get(priv->service_infos, i);
  307. if(info->start_type == FBUS_SERVICE_START_ON_LOAD)
  308. {
  309. process_start(info->exec);
  310. info->status = FBUS_SERVICE_STARTING;
  311. ftk_logd("%s: launch %s:%s\n", __func__, info->name, info->exec);
  312. }
  313. }
  314. }
  315. return thiz;
  316. }
  317. int main(int argc, char* argv[])
  318. {
  319. fbus_service_init(argc, argv);
  320. if(fbus_service_service_manager_create() != NULL)
  321. {
  322. fbus_service_run();
  323. }
  324. else
  325. {
  326. ftk_loge("Create service manager failed.\n");
  327. }
  328. return 0;
  329. }