|
- /*!
- * \file listener.c
- * \brief Listener related functionality
- *
- * \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr>
- */
-
- #include <sys/socket.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- #include "listener.h"
-
- char_t rx_buffer[4*MSG_TEXT_SIZE]; //!< receive buffer
-
- /*!
- * Incoming message handling
- * @param d Pointer to sender/client's device
- * @param buffer Buffer to message
- * @param size Size of message
- */
- static void listen_handler (devAEM_t dev, char_t* buffer, size_t size) {
- msg_t msg;
- msg_init (&msg);
- cMsg_parse (&msg.cMsg, buffer, size); // parse the message
- log_debug("Debug: Message parsed\n");
-
- msgList_acquire ();
- mIter_t myCopy = msgList_find (&msgList, &msg); // try to find message in msgList
- if (myCopy == -1) {
- // We don't have a copy, accept and store it
- msgList_add (&msgList, &msg);
- statsUpdateIn (&msg, false); // message process
- log_msg_io (&msg); // log
- }
- else {
- // We have a copy
- // Do not forward a duplicate message to sender, he already has it
- msgList.m[myCopy].recipients[devList_getIter (dev)] = true;
- statsUpdateIn (&msg, true); // message process
- log_debug("Debug: Duplicate message from: %d\n", msg.sender);
- }
- msgList_release ();
- }
-
- /*!
- * Listener. This function normally never returns. If it does it is to
- * report unrecoverable error.
- * @return Error creating server side socket
- */
- static status_t listener(void) {
- int srvSock;
- sockaddr_in_t srvAddPort;
-
- // Create socket
- memset(&srvAddPort, 0, sizeof(srvAddPort));
- srvAddPort.sin_family= AF_INET;
- srvAddPort.sin_port= htons(settings.port);
- srvAddPort.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // try to create tcp socket
- if ((srvSock = socket (PF_INET, SOCK_STREAM, 0)) == -1) {
- log_error ("Error: Can not create socket\n");
- goto _list_error1;
- }
- log_debug("Debug: Socket for listening created\n");
-
- // Try to bind socket
- if(bind(srvSock, (sockaddr_t *) &srvAddPort, sizeof(srvAddPort)) == -1) {
- log_error ("Error: Can not bind socket to port %d\n", settings.port);
- goto _list_error0;
- }
- // try to setup listener. We use DEVICE_LIST_SIZE for pending request
- if (listen (srvSock, DEVICE_LIST_SIZE) == -1) {
- log_error ("Error: Can not enable socket\n");
- goto _list_error0;
- }
- log_debug("Debug: Listening on [0.0.0.0], port %d\n", settings.port);
-
- while (1) {
- sockaddr_in_t clntAddr;
- socklen_t clntLen= sizeof(clntAddr);
- int clntSock;
- int rcvBytes;
- // block in accept and get client's connection socket
- if ((clntSock = accept (srvSock, (sockaddr_t *)&clntAddr, &clntLen)) == -1) {
- continue;
- }
- // make a device from clients address
- devAEM_t dev = addr2devAEM (ntohl(clntAddr.sin_addr.s_addr));
- devIP_t ip = AEM2ip (dev);
- log_debug (
- "Debug: Connection from %u.%u.%u.%u port:%u received\n",
- ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
- );
-
- // Block in receive, after the connection is accepted
- if ((rcvBytes = recv(clntSock, rx_buffer, sizeof(rx_buffer), 0)) < 0) {
- log_error ("Error: Fail to receive from socket\n");
- close (clntSock);
- continue;
- }
- rx_buffer[rcvBytes] = '\0'; // add null termination to buffer
- close(clntSock); // close the client socket
-
- // call listen handler for the device and message
- log_debug (
- "Debug: Message from %u.%u.%u.%u port:%u received\n",
- ip.A, ip.B, ip.C, ip.D, clntAddr.sin_port
- );
- listen_handler (dev, rx_buffer, rcvBytes);
- }
-
- // Local error return handling
- _list_error0:
- close(srvSock); // server socket clean up
- log_debug ("Debug: Socket for listening closed\n");
- _list_error1:
- return MSG_ERROR; // report back
- }
-
-
- /*!
- * pthread listener wrapper
- * @param ptr Not used
- */
- void* pthListener(void* ptr) {
- (void)&ptr; // use parameter
- if (listener() == MSG_ERROR)
- exit(1); // this is a deal breaker sorry.
- return NULL;
- }
-
|