backend.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (C) 2010 Michael Buesch <m@bues.ch>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include "backend.h"
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <unistd.h>
  19. #include <fcntl.h>
  20. #include <netinet/in.h>
  21. #include <sys/socket.h>
  22. #include <sys/un.h>
  23. #include <iostream>
  24. #include <QApplication>
  25. using namespace std;
  26. Backend::Backend()
  27. : fd (-1)
  28. , notifier (NULL)
  29. , errcount (0)
  30. {
  31. }
  32. Backend::~Backend()
  33. {
  34. struct pt_message msg;
  35. int err;
  36. if (fd != -1) {
  37. ::memset(&msg, 0, sizeof(msg));
  38. msg.id = htons(PTREQ_XEVREP);
  39. err = sendMessageSyncReply(&msg);
  40. if (err)
  41. cerr << "Failed to disable X11 input event notifications" << endl;
  42. close(fd);
  43. }
  44. }
  45. int Backend::connectToBackend()
  46. {
  47. struct sockaddr_un sockaddr;
  48. int err;
  49. struct pt_message msg;
  50. if (fd >= 0)
  51. return 0;
  52. fd = socket(AF_UNIX, SOCK_STREAM, 0);
  53. if (fd == -1) {
  54. cerr << "Failed to create backend socket: "
  55. << strerror(errno) << endl;
  56. goto error;
  57. }
  58. sockaddr.sun_family = AF_UNIX;
  59. strncpy(sockaddr.sun_path, PT_SOCKET, sizeof(sockaddr.sun_path) - 1);
  60. err = ::connect(fd, (struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr));
  61. if (err) {
  62. cerr << "Failed to connect to backend socket: "
  63. << strerror(errno) << endl;
  64. goto err_close;
  65. }
  66. ::memset(&msg, 0, sizeof(msg));
  67. msg.id = htons(PTREQ_PING);
  68. err = sendMessageSyncReply(&msg);
  69. if (err) {
  70. cerr << "Failed to send ping to backend" << endl;
  71. goto err_close;
  72. }
  73. cout << "Connected to backend" << endl;
  74. notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
  75. connect(notifier, SIGNAL(activated(int)),
  76. this, SLOT(readNotification(int)));
  77. ::memset(&msg, 0, sizeof(msg));
  78. msg.id = htons(PTREQ_WANT_NOTIFY);
  79. msg.flags = htons(PT_FLG_ENABLE);
  80. err = sendMessageSyncReply(&msg);
  81. if (err) {
  82. cerr << "Failed to enable backend notifications" << endl;
  83. goto err_free_noti;
  84. }
  85. ::memset(&msg, 0, sizeof(msg));
  86. msg.id = htons(PTREQ_XEVREP);
  87. msg.flags = htons(PT_FLG_ENABLE);
  88. err = sendMessageSyncReply(&msg);
  89. if (err)
  90. cerr << "Failed to enable X11 input event notifications" << endl;
  91. return 0;
  92. err_free_noti:
  93. delete notifier;
  94. notifier = NULL;
  95. err_close:
  96. close(fd);
  97. fd = -1;
  98. error:
  99. return -1;
  100. }
  101. int Backend::sendMessage(struct pt_message *msg)
  102. {
  103. ssize_t ret;
  104. size_t count, pos = 0;
  105. msg->flags |= htons(PT_FLG_OK);
  106. count = sizeof(*msg);
  107. while (count) {
  108. ret = ::send(fd, reinterpret_cast<uint8_t *>(msg) + pos,
  109. count, 0);
  110. if (ret < 0)
  111. return -1;
  112. count -= ret;
  113. pos += ret;
  114. }
  115. return 0;
  116. }
  117. int Backend::sendMessageSyncReply(struct pt_message *msg)
  118. {
  119. uint16_t id = msg->id;
  120. int err;
  121. QList<struct pt_message> msgs;
  122. err = sendMessage(msg);
  123. if (err)
  124. return err;
  125. while (1) {
  126. err = recvMessage(msg);
  127. if (err)
  128. return err;
  129. if ((msg->id != id) || !(msg->flags & htons(PT_FLG_REPLY))) {
  130. msgs.append(*msg);
  131. continue;
  132. }
  133. break;
  134. }
  135. QList<struct pt_message>::iterator i;
  136. for (i = msgs.begin(); i != msgs.end(); ++i)
  137. processReceivedMessage(&(*i));
  138. if (!(msg->flags & htons(PT_FLG_OK)))
  139. return -ETXTBSY;
  140. return 0;
  141. }
  142. int Backend::recvMessage(struct pt_message *msg)
  143. {
  144. ssize_t count;
  145. size_t pos = 0;
  146. ::memset(msg, 0, sizeof(*msg));
  147. do {
  148. count = ::recv(fd, reinterpret_cast<uint8_t *>(msg) + pos,
  149. sizeof(*msg) - pos, 0);
  150. if (count < 0)
  151. return -1;
  152. pos += count;
  153. } while (count != 0 && pos != sizeof(*msg));
  154. if (pos != sizeof(*msg))
  155. return -1;
  156. return 0;
  157. }
  158. void Backend::processReceivedMessage(struct pt_message *msg)
  159. {
  160. switch (ntohs(msg->id)) {
  161. case PTNOTI_SRVDOWN:
  162. cout << "Backend server is going down." << endl;
  163. QApplication::instance()->exit(1);
  164. break;
  165. case PTNOTI_BL_CHANGED:
  166. emit backlightStateChanged(msg);
  167. break;
  168. case PTNOTI_BAT_CHANGED:
  169. emit batteryStateChanged(msg);
  170. break;
  171. default:
  172. cerr << "Received unknown message: " << ntohs(msg->id) << endl;
  173. }
  174. }
  175. void Backend::checkErrorCount()
  176. {
  177. if (errcount < 25)
  178. return;
  179. cerr << "Too many backend errors. Is the backend dead?" << endl;
  180. QApplication::instance()->exit(1);
  181. }
  182. void Backend::readNotification(int sock)
  183. {
  184. struct pt_message msg;
  185. int err;
  186. err = recvMessage(&msg);
  187. if (err) {
  188. cerr << "Got read notification, but failed to read message" << endl;
  189. errcount++;
  190. checkErrorCount();
  191. return;
  192. }
  193. errcount = 0;
  194. processReceivedMessage(&msg);
  195. }
  196. int Backend::getBatteryState(struct pt_message *msg)
  197. {
  198. int err;
  199. ::memset(msg, 0, sizeof(*msg));
  200. msg->id = htons(PTREQ_BAT_GETSTATE);
  201. err = sendMessageSyncReply(msg);
  202. return err;
  203. }
  204. int Backend::getBacklightState(struct pt_message *msg)
  205. {
  206. int err;
  207. ::memset(msg, 0, sizeof(*msg));
  208. msg->id = htons(PTREQ_BL_GETSTATE);
  209. err = sendMessageSyncReply(msg);
  210. return err;
  211. }
  212. int Backend::setBacklight(int value)
  213. {
  214. struct pt_message msg;
  215. ::memset(&msg, 0, sizeof(msg));
  216. msg.id = htons(PTREQ_BL_SETBRIGHTNESS);
  217. msg.bl_set.brightness = value;
  218. return sendMessageSyncReply(&msg);
  219. }
  220. int Backend::setBacklightAutodim(bool enable, bool enable_on_ac, int max_percent)
  221. {
  222. struct pt_message msg;
  223. ::memset(&msg, 0, sizeof(msg));
  224. msg.id = htons(PTREQ_BL_AUTODIM);
  225. msg.bl_autodim.flags = enable ? htonl(PT_AUTODIM_FLG_ENABLE) : 0;
  226. msg.bl_autodim.flags |= enable_on_ac ? htonl(PT_AUTODIM_FLG_ENABLE_AC) : 0;
  227. msg.bl_autodim.max_percent = htonl(max_percent);
  228. return sendMessageSyncReply(&msg);
  229. }
  230. #include "moc/backend.moc"