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.
 
 
 
 
 

151 lines
4.6 KiB

  1. /*!
  2. * \file listener.c
  3. * \brief Listener related functionality
  4. *
  5. * \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr>
  6. */
  7. #include <sys/socket.h>
  8. #include <arpa/inet.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "listener.h"
  14. char_t rx_buffer[4*MSG_TEXT_SIZE]; //!< receive buffer
  15. /*!
  16. * Incoming message handling
  17. * @param dev Pointer to sender/client's device
  18. * @param buffer Buffer to message
  19. * @param size Size of message
  20. */
  21. static void listen_handler (devAEM_t dev, char_t* buffer, size_t size) {
  22. msg_t msg;
  23. msg_init (&msg);
  24. msg.sender = dev;
  25. if (cMsg_parse (&msg.cMsg, buffer, size) == MSG_ERROR) // parse the message
  26. return;
  27. log_debug("Debug: Message parsed\n");
  28. msgList_acquire ();
  29. mIter_t myCopy = msgList_find (&msgList, &msg); // try to find message in msgList
  30. if (myCopy == -1) {
  31. // We don't have a copy, accept and store it
  32. mIter_t slot = msgList_add (&msgList, &msg);
  33. msgList_release ();
  34. statsUpdateIn (&msg, false); // message process
  35. log_msg_in (&msg); // log
  36. // Processing...
  37. devList_acquire();
  38. dIter_t d = devList_getIter (dev);
  39. dIter_t f = devList_getIter (msg.cMsg.from);
  40. devList_release();
  41. msgList_acquire ();
  42. // Do not echo message to sender, he already has it
  43. msgList.m[slot].recipients[d] = true;
  44. // don't push back message to creator, he already has it
  45. msgList.m[slot].recipients[f] = true;
  46. msgList_release ();
  47. }
  48. else {
  49. // We have a copy
  50. msgList_release ();
  51. statsUpdateIn (&msg, true); // message process
  52. log_debug ("Debug: Duplicate message from: %d\n", msg.sender);
  53. }
  54. }
  55. /*!
  56. * Listener. This function normally never returns. If it does it is to
  57. * report unrecoverable error.
  58. * @return Error creating server side socket
  59. */
  60. static status_t listener(void) {
  61. int srvSock;
  62. sockaddr_in_t srvAddPort;
  63. // Create socket
  64. memset(&srvAddPort, 0, sizeof(srvAddPort));
  65. srvAddPort.sin_family= AF_INET;
  66. srvAddPort.sin_port= htons(settings.port);
  67. srvAddPort.sin_addr.s_addr = htonl(INADDR_ANY);
  68. // try to create tcp socket
  69. if ((srvSock = socket (PF_INET, SOCK_STREAM, 0)) == -1) {
  70. log_error ("Error: Can not create socket\n");
  71. goto _list_error1;
  72. }
  73. log_debug("Debug: Socket for listening created\n");
  74. // Try to bind socket
  75. if(bind(srvSock, (sockaddr_t *) &srvAddPort, sizeof(srvAddPort)) == -1) {
  76. log_error ("Error: Can not bind socket to port %d\n", settings.port);
  77. goto _list_error0;
  78. }
  79. // try to setup listener. We use DEVICE_LIST_SIZE for pending request
  80. if (listen (srvSock, DEVICE_LIST_SIZE) == -1) {
  81. log_error ("Error: Can not enable socket\n");
  82. goto _list_error0;
  83. }
  84. log_debug("Debug: Listening on [0.0.0.0], port %d\n", settings.port);
  85. while (1) {
  86. sockaddr_in_t clntAddr;
  87. socklen_t clntLen= sizeof(clntAddr);
  88. int clntSock;
  89. int rcvBytes;
  90. // block in accept and get client's connection socket
  91. if ((clntSock = accept (srvSock, (sockaddr_t *)&clntAddr, &clntLen)) == -1) {
  92. continue;
  93. }
  94. // make a device from clients address
  95. devAEM_t dev = addr2devAEM (ntohl(clntAddr.sin_addr.s_addr));
  96. devIP_t ip = AEM2ip (dev);
  97. log_debug (
  98. "Debug: Connection from %u.%u.%u.%u port:%u received\n",
  99. ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
  100. );
  101. // Block in receive, after the connection is accepted
  102. if ((rcvBytes = recv(clntSock, rx_buffer, sizeof(rx_buffer), 0)) < 0) {
  103. log_error ("Error: Fail to receive from socket\n");
  104. close (clntSock);
  105. continue;
  106. }
  107. rx_buffer[rcvBytes] = '\0'; // add null termination to buffer
  108. close(clntSock); // close the client socket
  109. // call listen handler for the device and message
  110. log_debug (
  111. "Debug: Message from %u.%u.%u.%u port:%u received\n",
  112. ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
  113. );
  114. listen_handler (dev, rx_buffer, rcvBytes);
  115. }
  116. // Local error return handling
  117. _list_error0:
  118. close(srvSock); // server socket clean up
  119. log_debug ("Debug: Socket for listening closed\n");
  120. _list_error1:
  121. return MSG_ERROR; // report back
  122. }
  123. /*!
  124. * pthread listener wrapper
  125. * @param ptr Not used
  126. */
  127. void* pthListener(void* ptr) {
  128. (void)&ptr; // use parameter
  129. if (listener() == MSG_ERROR)
  130. exit(1); // this is a deal breaker sorry.
  131. return NULL;
  132. }