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.
 
 
 
 
 

145 lines
4.5 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. msgList_add (&msgList, &msg);
  33. msgList_release ();
  34. statsUpdateIn (&msg, false); // message process
  35. log_msg_in (&msg); // log
  36. }
  37. else {
  38. // We have a copy
  39. msgList_release ();
  40. statsUpdateIn (&msg, true); // message process
  41. log_debug("Debug: Duplicate message from: %d\n", msg.sender);
  42. }
  43. // Processing...
  44. msgList_acquire ();
  45. // Do not echo message to sender, he already has it
  46. msgList.m[myCopy].recipients[devList_getIter (dev)] = true;
  47. // don't push back message to creator, he already has it
  48. msgList.m[myCopy].recipients[devList_getIter (msg.cMsg.from)] = true;
  49. msgList_release ();
  50. }
  51. /*!
  52. * Listener. This function normally never returns. If it does it is to
  53. * report unrecoverable error.
  54. * @return Error creating server side socket
  55. */
  56. static status_t listener(void) {
  57. int srvSock;
  58. sockaddr_in_t srvAddPort;
  59. // Create socket
  60. memset(&srvAddPort, 0, sizeof(srvAddPort));
  61. srvAddPort.sin_family= AF_INET;
  62. srvAddPort.sin_port= htons(settings.port);
  63. srvAddPort.sin_addr.s_addr = htonl(INADDR_ANY);
  64. // try to create tcp socket
  65. if ((srvSock = socket (PF_INET, SOCK_STREAM, 0)) == -1) {
  66. log_error ("Error: Can not create socket\n");
  67. goto _list_error1;
  68. }
  69. log_debug("Debug: Socket for listening created\n");
  70. // Try to bind socket
  71. if(bind(srvSock, (sockaddr_t *) &srvAddPort, sizeof(srvAddPort)) == -1) {
  72. log_error ("Error: Can not bind socket to port %d\n", settings.port);
  73. goto _list_error0;
  74. }
  75. // try to setup listener. We use DEVICE_LIST_SIZE for pending request
  76. if (listen (srvSock, DEVICE_LIST_SIZE) == -1) {
  77. log_error ("Error: Can not enable socket\n");
  78. goto _list_error0;
  79. }
  80. log_debug("Debug: Listening on [0.0.0.0], port %d\n", settings.port);
  81. while (1) {
  82. sockaddr_in_t clntAddr;
  83. socklen_t clntLen= sizeof(clntAddr);
  84. int clntSock;
  85. int rcvBytes;
  86. // block in accept and get client's connection socket
  87. if ((clntSock = accept (srvSock, (sockaddr_t *)&clntAddr, &clntLen)) == -1) {
  88. continue;
  89. }
  90. // make a device from clients address
  91. devAEM_t dev = addr2devAEM (ntohl(clntAddr.sin_addr.s_addr));
  92. devIP_t ip = AEM2ip (dev);
  93. log_debug (
  94. "Debug: Connection from %u.%u.%u.%u port:%u received\n",
  95. ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
  96. );
  97. // Block in receive, after the connection is accepted
  98. if ((rcvBytes = recv(clntSock, rx_buffer, sizeof(rx_buffer), 0)) < 0) {
  99. log_error ("Error: Fail to receive from socket\n");
  100. close (clntSock);
  101. continue;
  102. }
  103. rx_buffer[rcvBytes] = '\0'; // add null termination to buffer
  104. close(clntSock); // close the client socket
  105. // call listen handler for the device and message
  106. log_debug (
  107. "Debug: Message from %u.%u.%u.%u port:%u received\n",
  108. ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
  109. );
  110. listen_handler (dev, rx_buffer, rcvBytes);
  111. }
  112. // Local error return handling
  113. _list_error0:
  114. close(srvSock); // server socket clean up
  115. log_debug ("Debug: Socket for listening closed\n");
  116. _list_error1:
  117. return MSG_ERROR; // report back
  118. }
  119. /*!
  120. * pthread listener wrapper
  121. * @param ptr Not used
  122. */
  123. void* pthListener(void* ptr) {
  124. (void)&ptr; // use parameter
  125. if (listener() == MSG_ERROR)
  126. exit(1); // this is a deal breaker sorry.
  127. return NULL;
  128. }