control.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #include <ev++.h>
  2. // Control connection for dinit
  3. // forward-declaration of callback:
  4. static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents);
  5. // Packet types:
  6. constexpr static int DINIT_CP_STARTSERVICE = 0;
  7. constexpr static int DINIT_CP_STOPSERVICE = 1;
  8. // "packet" format:
  9. // (1 byte) packet type
  10. // (N bytes) additional data (service name, etc)
  11. // for STARTSERVICE/STOPSERVICE:
  12. // (2 bytes) service name length
  13. // (M buyes) service name (without nul terminator)
  14. class ControlConn
  15. {
  16. struct ev_io iob;
  17. struct ev_loop *loop;
  18. ServiceSet *service_set;
  19. char * iobuf;
  20. int bufidx;
  21. // The packet length before we need to re-check if the packet is complete
  22. int chklen;
  23. public:
  24. ControlConn(struct ev_loop * loop, ServiceSet * service_set, int fd) : loop(loop), service_set(service_set), bufidx(0), chklen(0)
  25. {
  26. iobuf = new char[1024];
  27. ev_io_init(&iob, control_conn_cb, fd, EV_READ);
  28. iob.data = this;
  29. ev_io_start(loop, &iob);
  30. }
  31. void processPacket()
  32. {
  33. using std::string;
  34. int pktType = iobuf[0];
  35. if (pktType == DINIT_CP_STARTSERVICE || pktType == DINIT_CP_STOPSERVICE) {
  36. if (bufidx < 4) {
  37. chklen = 4;
  38. return;
  39. }
  40. uint16_t svcSize;
  41. memcpy(&svcSize, iobuf + 1, 2);
  42. if (svcSize <= 0) {
  43. // TODO error response
  44. bufidx = 1024; // dataReady will delete - TODO clean up
  45. }
  46. chklen = svcSize + 3;
  47. if (chklen > 1024) {
  48. // We can't have a service name this long
  49. // TODO error response
  50. bufidx = 1024; // TODO cleanup.
  51. }
  52. if (bufidx < chklen) {
  53. // packet not complete yet; read more
  54. return;
  55. }
  56. string serviceName(iobuf + 3, (size_t) svcSize);
  57. if (pktType == DINIT_CP_STARTSERVICE) {
  58. service_set->startService(serviceName.c_str());
  59. // TODO catch exceptions, error response
  60. }
  61. else {
  62. // TODO verify the named service exists?
  63. service_set->stopService(serviceName.c_str());
  64. }
  65. // Clear the packet from the buffer
  66. memmove(iobuf, iobuf + chklen, 1024 - chklen);
  67. bufidx -= chklen;
  68. chklen = 0;
  69. return;
  70. }
  71. }
  72. void dataReady()
  73. {
  74. int fd = iob.fd;
  75. int buffree = 1024 - bufidx;
  76. int r = read(fd, iobuf + bufidx, buffree);
  77. // Note file descriptor is non-blocking
  78. if (r == -1) {
  79. if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
  80. return;
  81. }
  82. // TODO log error
  83. delete this;
  84. return;
  85. }
  86. if (r == 0) {
  87. delete this;
  88. return;
  89. }
  90. bufidx += r;
  91. buffree -= r;
  92. // complete packet?
  93. if (bufidx >= chklen) {
  94. processPacket();
  95. }
  96. if (bufidx == 1024) {
  97. // Too big packet
  98. // TODO log error?
  99. // TODO error response?
  100. delete this;
  101. }
  102. }
  103. ~ControlConn()
  104. {
  105. close(iob.fd);
  106. ev_io_stop(loop, &iob);
  107. delete [] iobuf;
  108. }
  109. };
  110. static void control_conn_cb(struct ev_loop * loop, ev_io * w, int revents)
  111. {
  112. ControlConn *conn = (ControlConn *) w->data;
  113. conn->dataReady();
  114. }