/*! * \file listener.c * \brief Listener related functionality * * \author Christos Choutouridis AEM:8997 */ #include #include #include #include #include #include #include "listener.h" char_t rx_buffer[4*MSG_TEXT_SIZE]; //!< receive buffer /*! * Incoming message handling * @param dev 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); msg.sender = dev; if (cMsg_parse (&msg.cMsg, buffer, size) == MSG_ERROR) // parse the message return; 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 statsUpdateIn (&msg, true); // message process log_debug("Debug: Duplicate message from: %d\n", msg.sender); } // Processing... // Do not echo message to sender, he already has it msgList.m[myCopy].recipients[devList_getIter (dev)] = true; // don't push back message to creator, he already has it msgList.m[myCopy].recipients[devList_getIter (msg.cMsg.from)] = true; 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; }