A messenger application for Raspberry Pi Zerofor A.U.TH (Real time Embedded systems).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

217 lines
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. }