A messenger application for Raspberry Pi Zerofor A.U.TH (Real time Embedded systems).
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

217 linhas
7.5 KiB

  1. /*!
  2. * \file client.c
  3. *
  4. * \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr>
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <time.h>
  11. #include <sys/select.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14. #include "client.h"
  15. char_t tx_buffer [MSG_TEXT_SIZE];
  16. static bool_t ping (devAEM_t dev) {
  17. char_t cmd[72];
  18. devIP_t ip = AEM2ip (dev);
  19. // ask host to ping and make a little pre-process before take the answer
  20. sprintf (cmd,
  21. "test $(ping -c1 -w%d %u.%u.%u.%u| grep received |cut -d' ' -f4) = 1",
  22. (int)settings.pingTimeout, ip.A, ip.B, ip.C, ip.D
  23. );
  24. return (system(cmd) == 0) ? true:false;
  25. }
  26. static size_t seeker (void) {
  27. size_t cnt =0; // count devices on range
  28. log_debug ("Debug: Pinging devices...\n");
  29. for (int i=0 ; i<AEMLIST_SIZE ; ++i) {
  30. if (devList[i].dev == settings.me) {// Don't ping me, I'm not here, go away...
  31. devList[i].onRange = false;
  32. continue;
  33. }
  34. if (ping (devList[i].dev)) { // Noc noc....
  35. devList[i].onRange = true; // Who's there?
  36. ++cnt; // No one, bye bye!
  37. if (!devList[i].begin)
  38. devList[i].begin = time(NULL);
  39. devList[i].end = time(NULL);
  40. log_debug ("Debug: Device %u found\n", devList[i].dev);
  41. }
  42. else
  43. devList[i].onRange = false; // Where is everybody?
  44. }
  45. log_debug ("Debug: %d devices found\n", cnt);
  46. return cnt;
  47. }
  48. static bool_t sendMsg (devAEM_t dev, cMsg_t* msg) {
  49. int sock;
  50. sockaddr_in_t srvAddr;
  51. timeval_t timeout = settings.sendTimeout;
  52. long arg;
  53. bool_t ret = true; // have faith
  54. // Make address
  55. memset(&srvAddr, 0, sizeof (srvAddr));
  56. srvAddr.sin_family= AF_INET;
  57. srvAddr.sin_port= htons (settings.port);
  58. srvAddr.sin_addr.s_addr = htonl (devAEM2addr (dev));
  59. devIP_t ip = AEM2ip (dev);
  60. // Create socket for sending
  61. if ((sock = socket (PF_INET, SOCK_STREAM, 0)) == -1)
  62. return false;
  63. log_debug ("Debug: Socket for sending to %u.%u.%u.%u created\n", ip.A, ip.B, ip.C, ip.D);
  64. do {
  65. // Set non-blocking connect
  66. if((arg = fcntl(sock, F_GETFL, NULL)) < 0) {
  67. ret = false;
  68. log_debug ("Debug: Reading socket's file status failed\n");
  69. break;
  70. }
  71. if(fcntl(sock, F_SETFL, arg | O_NONBLOCK) < 0) {
  72. ret = false;
  73. log_debug ("Debug: Set socket to non-blocking mode failed\n");
  74. break;
  75. }
  76. log_debug ("Debug: Socket switched to non-blocking mode\n");
  77. // Trying to connect with timeout
  78. log_debug ("Debug: Try to connect with timeout\n");
  79. if (connect (sock, (sockaddr_t*)&srvAddr, sizeof(srvAddr)) == -1) {
  80. if (errno == EINPROGRESS) {
  81. fd_set myset;
  82. FD_ZERO (&myset);
  83. FD_SET (sock, &myset);
  84. if (select (sock+1, NULL, &myset, NULL, &timeout) <= 0) {
  85. ret = false;
  86. log_debug ("Debug: Connection failed in select()\n");
  87. break;
  88. }
  89. // Socket selected for write
  90. int valopt;
  91. socklen_t lon = sizeof(int);
  92. if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
  93. ret = false;
  94. log_debug ("Debug: Reading socket's options failed\n");
  95. break;
  96. }
  97. // Check the value returned...
  98. if (valopt) {
  99. ret = false;
  100. log_debug ("Debug: Delayed connection failed\n");
  101. break;
  102. }
  103. }
  104. else {
  105. ret = false;
  106. log_debug ("Debug: Connection failed in select()\n");
  107. break;
  108. }
  109. }
  110. log_debug ("Debug: Connection to %u.%u.%u.%u succeed\n", ip.A, ip.B, ip.C, ip.D);
  111. // Set to blocking mode again...
  112. if( (arg = fcntl(sock, F_GETFL, NULL)) < 0) {
  113. ret = false;
  114. log_debug ("Debug: Reading socket's file status failed\n");
  115. break;
  116. }
  117. arg &= (~O_NONBLOCK);
  118. if( fcntl(sock, F_SETFL, arg) < 0) {
  119. ret = false;
  120. log_debug ("Debug: Set socket back to blocking mode failed\n");
  121. break;
  122. }
  123. log_debug ("Debug: Socket switched to blocking mode\n");
  124. // send the data with timeout
  125. if (setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&timeout, sizeof(timeout)) == -1) {
  126. ret = false;
  127. log_debug ("Debug: Setting send timeout failed\n");
  128. break;
  129. }
  130. log_debug ("Debug: Setting send timeout succeed\n");
  131. size_t len = cMsg_cat (msg, tx_buffer);
  132. if (send (sock, tx_buffer, len, MSG_CONFIRM) == -1) {
  133. ret = false;
  134. log_debug ("Debug: Sending failed\n");
  135. break;
  136. }
  137. log_debug ("Debug: Sending succeed\n");
  138. } while (0);
  139. close (sock);
  140. log_debug ("Debug: Closing socket\n");
  141. return ret;
  142. }
  143. static status_t client (void) {
  144. msg_t msg; // new message buffer
  145. while (true) {
  146. sleep (settings.msgInterval); // Idle until the time comes
  147. memset ((void*)&msg, 0, sizeof (msg)); // create a new message
  148. cMsg_make (&msg.cMsg);
  149. msg.sender = settings.me;
  150. log_msg_new (&msg);
  151. statsUpdateCreate (&msg);
  152. msgList_acquire (); // try to lock resources
  153. mIter_t at = msgList_add (&msgList, &msg); // Add message to msgList
  154. log_debug ("Debug: Message added to msgList at %d\n", at);
  155. if (!seeker ()) { // If we are alone skip the rest
  156. msgList_release (); // but unlock resources first
  157. continue;
  158. }
  159. log_debug ("Debug: Devices found on range\n");
  160. mIter_t it = msgList_begin (&msgList); // get a message iterator
  161. // begin with old messages first
  162. // for each message -> for each recipient
  163. for (size_t i=0 ; i<msgList_size(&msgList) ; ++i, msgList_preInc (&it)) {
  164. for (size_t j=0 ; j<AEMLIST_SIZE ; ++j) {
  165. // check when to send
  166. if (devList[j].onRange // is on range
  167. && !msgList.m[it].recipients[j] // we haven't send the message to that device
  168. && msgList.m[it].cMsg.to != settings.me // the message it's not for me
  169. ) {
  170. if (sendMsg (devList[j].dev, &msgList.m[it].cMsg)) {
  171. msgList.m[it].recipients[j] = true;
  172. statsUpdateOut (&msg, devList[j].dev);
  173. log_debug ("Debug: Send message to device %u succeed\n", devList[j].dev);
  174. }
  175. else {
  176. log_debug ("Debug: Send message to device %u failed\n", devList[j].dev);
  177. }
  178. //^ we try to send the message and mark the transmission on success
  179. // if send fail, don't worry it may succeed the next time.
  180. }
  181. }
  182. }
  183. msgList_release (); // Unlock resources
  184. if (statsPrint (&stats) == MSG_ERROR)
  185. log_error ("Error: Writing to statistics file failed\n");
  186. }
  187. return MSG_ERROR;
  188. }
  189. void* pthClient (void* ptr) {
  190. (void)&ptr; // use parameter
  191. if (client () == MSG_ERROR)
  192. exit(1); // we should not be here, client never returns
  193. return NULL;
  194. }