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.
 
 
 
 
 

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