service.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #pragma once
  2. #include <signal.h>
  3. namespace nall {
  4. struct service {
  5. inline explicit operator bool() const;
  6. inline auto command(const string& name, const string& command) -> bool;
  7. inline auto receive() -> string;
  8. inline auto name() const -> string;
  9. inline auto stop() const -> bool;
  10. private:
  11. shared_memory shared;
  12. string _name;
  13. bool _stop = false;
  14. };
  15. service::operator bool() const {
  16. return (bool)shared;
  17. }
  18. //returns true on new service process creation (false is not necessarily an error)
  19. auto service::command(const string& name, const string& command) -> bool {
  20. if(!name) return false;
  21. if(!command) return print("[{0}] usage: {service} command\n"
  22. "commands:\n"
  23. " status : query whether service is running\n"
  24. " start : start service if it is not running\n"
  25. " stop : stop service if it is running\n"
  26. " remove : remove semaphore lock if service crashed\n"
  27. " {value} : send custom command to service\n"
  28. "", string_format{name}), false;
  29. if(shared.open(name, 4096)) {
  30. if(command == "start") {
  31. print("[{0}] already started\n", string_format{name});
  32. } else if(command == "status") {
  33. print("[{0}] running\n", string_format{name});
  34. }
  35. if(auto data = shared.acquire()) {
  36. if(command == "stop") print("[{0}] stopped\n", string_format{name});
  37. memory::copy(data, 4096, command.data(), command.size());
  38. shared.release();
  39. }
  40. if(command == "remove") {
  41. shared.remove();
  42. print("[{0}] removed\n", string_format{name});
  43. }
  44. return false;
  45. }
  46. if(command == "start") {
  47. if(shared.create(name, 4096)) {
  48. print("[{0}] started\n", string_format{name});
  49. auto pid = fork();
  50. if(pid == 0) {
  51. signal(SIGHUP, SIG_IGN);
  52. signal(SIGPIPE, SIG_IGN);
  53. _name = name;
  54. return true;
  55. }
  56. shared.close();
  57. } else {
  58. print("[{0}] start failed ({1})\n", string_format{name, strerror(errno)});
  59. }
  60. return false;
  61. }
  62. if(command == "status") {
  63. print("[{0}] stopped\n", string_format{name});
  64. return false;
  65. }
  66. return false;
  67. }
  68. auto service::receive() -> string {
  69. string command;
  70. if(shared) {
  71. if(auto data = shared.acquire()) {
  72. if(*data) {
  73. command.resize(4095);
  74. memory::copy(command.get(), data, 4095);
  75. memory::fill(data, 4096);
  76. }
  77. shared.release();
  78. if(command == "remove") {
  79. _stop = true;
  80. return "";
  81. } else if(command == "start") {
  82. return "";
  83. } else if(command == "status") {
  84. return "";
  85. } else if(command == "stop") {
  86. _stop = true;
  87. shared.remove();
  88. return "";
  89. }
  90. }
  91. }
  92. return command;
  93. }
  94. auto service::name() const -> string {
  95. return _name;
  96. }
  97. auto service::stop() const -> bool {
  98. return _stop;
  99. }
  100. }