|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- /*!
- * \file client.c
- * This file contains all the client and device search functionalities.
- *
- * \author Christos Choutouridis AEM:8997 <cchoutou@ece.auth.gr>
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <time.h>
- #include <sys/select.h>
- #include <fcntl.h>
- #include <errno.h>
-
- #include "client.h"
- /*!
- * Transmit buffer
- */
- static char_t tx_buffer [MSG_TEXT_SIZE];
-
- /*!
- * Ping functionality. We use system and pass a test command in order to
- * find out if a particular device is on range.
- * @param dev The device to ping
- * @return The status of the operation
- * @arg true The device was on range and replyed to our ping
- * @arg false The device wasn't on range
- */
- static bool_t ping (devAEM_t dev) {
- char_t cmd[72];
- devIP_t ip = AEM2ip (dev);
-
- // ask host to ping and make a little pre-process before take the answer
- sprintf (cmd,
- "test $(ping -c1 -w%d %u.%u.%u.%u| grep received |cut -d' ' -f4) = 1",
- (int)settings.pingTimeout, ip.A, ip.B, ip.C, ip.D
- );
- return (system(cmd) == 0) ? true:false;
- }
-
- /*!
- * Search for devices on range and mark the time of first and last sight
- * @return The number of devices on range
- */
- static size_t seeker (void) {
- size_t cnt =0; // count devices on range
-
- sleep (settings.seekerInterval);
-
- log_debug ("Debug: Pinging devices...\n");
- devList_acquire ();
- for (int i=0 ; i<AEMLIST_SIZE ; ++i) {
- if (devList[i].dev == settings.me) {// Don't ping me, I'm not here, go away...
- devList[i].onRange = false;
- continue;
- }
- if (ping (devList[i].dev)) { // Noc noc....
- devList[i].onRange = true; // Who's there?
- ++cnt; // No one, bye bye!
- // Mark the time for first and last time we saw this device
- if (!devList[i].begin)
- devList[i].begin = time(NULL); // first time only
- devList[i].end = time(NULL); // every time
- devList_t cDev = devList[i];
- devList_release ();
- log_debug ("Debug: Device %u found\n", cDev.dev);
- devList_acquire ();
- }
- else
- devList[i].onRange = false; // Where is everybody?
- }
- statsTimesPrint (devList);
- devList_release ();
- log_debug ("Debug: %d devices found\n", cnt);
- return cnt;
- }
-
- /*!
- * @brief
- * Send message functionality
- * TCP socket communication for sending a message to device. We use non-blocking
- * connect/select in order to be able to timeout from select. We also use send with
- * timeout.
- *
- * @param dev The device to send the message
- * @param msg Pointer to message to send
- * @return The status of the operation
- * @note
- * We treat all error of this function as "non-fatal".
- */
- static bool_t sendMsg (devAEM_t dev, cMsg_t* msg) {
- int sock;
- sockaddr_in_t srvAddr;
- timeval_t timeout = settings.sendTimeout;
- long arg;
- bool_t ret = true; // have faith
-
- // Make address
- memset(&srvAddr, 0, sizeof (srvAddr));
- srvAddr.sin_family= AF_INET;
- srvAddr.sin_port= htons (settings.port);
- srvAddr.sin_addr.s_addr = htonl (devAEM2addr (dev));
- devIP_t ip = AEM2ip (dev);
-
- // Create socket for sending
- if ((sock = socket (PF_INET, SOCK_STREAM, 0)) == -1)
- return false;
- log_debug ("Debug: Socket for sending to %u.%u.%u.%u created\n", ip.A, ip.B, ip.C, ip.D);
- do {
- // Set non-blocking connect
- if((arg = fcntl(sock, F_GETFL, NULL)) < 0) {
- ret = false;
- log_debug ("Debug: Reading socket's file status failed\n");
- break;
- }
- if(fcntl(sock, F_SETFL, arg | O_NONBLOCK) < 0) {
- ret = false;
- log_debug ("Debug: Set socket to non-blocking mode failed\n");
- break;
- }
- log_debug ("Debug: Socket switched to non-blocking mode\n");
-
- // Trying to connect with timeout
- log_debug ("Debug: Try to connect with timeout\n");
- if (connect (sock, (sockaddr_t*)&srvAddr, sizeof(srvAddr)) == -1) {
- if (errno == EINPROGRESS) {
- fd_set myset;
- FD_ZERO (&myset);
- FD_SET (sock, &myset);
- if (select (sock+1, NULL, &myset, NULL, &timeout) <= 0) {
- ret = false;
- log_debug ("Debug: Connection failed in select()\n");
- break;
- }
- // Socket selected for write
- int valopt;
- socklen_t lon = sizeof(int);
- if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
- ret = false;
- log_debug ("Debug: Reading socket's options failed\n");
- break;
- }
- // Check the value returned...
- if (valopt) {
- ret = false;
- log_debug ("Debug: Delayed connection failed\n");
- break;
- }
- }
- else {
- ret = false;
- log_debug ("Debug: Connection failed in select()\n");
- break;
- }
- }
- log_debug ("Debug: Connection to %u.%u.%u.%u succeed\n", ip.A, ip.B, ip.C, ip.D);
-
- // Set to blocking mode again...
- if( (arg = fcntl(sock, F_GETFL, NULL)) < 0) {
- ret = false;
- log_debug ("Debug: Reading socket's file status failed\n");
- break;
- }
- arg &= (~O_NONBLOCK);
- if( fcntl(sock, F_SETFL, arg) < 0) {
- ret = false;
- log_debug ("Debug: Set socket back to blocking mode failed\n");
- break;
- }
- log_debug ("Debug: Socket switched to blocking mode\n");
-
- // send the data with timeout
- if (setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&timeout, sizeof(timeout)) == -1) {
- ret = false;
- log_debug ("Debug: Setting send timeout failed\n");
- break;
- }
- log_debug ("Debug: Setting send timeout succeed\n");
- size_t len = cMsg_serialize (msg, tx_buffer);
- if (send (sock, tx_buffer, len, MSG_CONFIRM) == -1) {
- ret = false;
- log_debug ("Debug: Sending failed\n");
- break;
- }
- log_debug ("Debug: Sending succeed\n");
- } while (0);
-
- close (sock);
- log_debug ("Debug: Closing socket\n");
- return ret;
- }
-
- /*!
- * @brief
- * Client functionality
- *
- * Creates a message in a random interval, seeks for devices on range
- * and loop in entire msgList in order to send all messages
- * @note
- * This function never returns
- */
- static void client (void) {
- msg_t msg; // new message buffer
- while (true) {
- // Idle until the time comes
- sleep (settings.msgInterval + (rand()%settings.msgRand));
- memset ((void*)&msg, 0, sizeof (msg)); // create a new message
- cMsg_make (&msg.cMsg);
- msg.sender = settings.me;
- log_msg_new (&msg);
-
- statsUpdateCreate (&msg);
-
- msgList_acquire (); // try to lock resources
- mIter_t at = msgList_add (&msgList, &msg); // Add message to msgList
- msgList_release ();
- log_debug ("Debug: Message added to msgList at %d\n", at);
-
- msgList_acquire ();
- mIter_t it = msgList_begin (&msgList); // get a message iterator
- // for each message -> for each recipient
- for (size_t i=0 ; i<msgList_size(&msgList) ; ++i, msgList_preInc (&it)) {
- for (size_t j=0 ; j<AEMLIST_SIZE ; ++j) {
- // get current dev instance
- devList_acquire ();
- devList_t currentDev = devList[j];
- devList_release ();
- // check when to send
- if (currentDev.onRange // is on range
- && !msgList.m[it].recipients[j] // we haven't send the message to that device
- && msgList.m[it].cMsg.to != settings.me // the message it's not for me
- ) {
- if (sendMsg (currentDev.dev, &msgList.m[it].cMsg)) {
- msgList.m[it].recipients[j] = true;
- msgList_release ();
- statsUpdateOut (&msg, currentDev.dev);
- log_msg_out (&msg, currentDev.dev);
- log_debug ("Debug: Send message to device %u succeed\n", currentDev.dev);
- msgList_acquire ();
- }
- else {
- msgList_release ();
- log_debug ("Debug: Send message to device %u failed\n", currentDev.dev);
- msgList_acquire ();
- }
- //^ we try to send the message and mark the transmission on success
- // if send fail, don't worry it may succeed the next time.
- }
- }
- }
- msgList_release (); // Unlock resources
- if (statsPrint (&stats) == MSG_ERROR)
- log_error ("Error: Writing to statistics file failed\n");
- }
- return;
- }
-
- /*!
- * pthread wrapper for \sa seeker()
- * @param ptr
- */
- void* pthSeeker (void* ptr) {
- (void)&ptr; // use parameter
-
- while (true)
- seeker ();
- exit(1); // we should not be here
- return NULL;
- }
-
- /*!
- * pthread wrapper for \sa client()
- * @param ptr
- */
- void* pthClient (void* ptr) {
- (void)&ptr; // use parameter
-
- client ();
- exit(1); // we should not be here, client never returns
- return NULL;
- }
-
-
|