[ create a new paste ] login | about

Link: http://codepad.org/GY8HSF7X    [ raw code | output | fork ]

C++, pasted on Apr 24:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <thread>
#include <signal.h>
#include <cstring>
#include <ctime>

#include <iostream>

const char HELLO_GROUP[] = "225.0.0.37";
const int HELLO_PORT = 12345;
const int MSG_BUF_SIZE = 256;

static volatile bool keepRunning = true;

void usage(const char* progname)
{
    printf("Usage:\n    %s [<mcast_group> <port>]\n", progname);
    printf("Example:\n    %s %s %d\n", progname, HELLO_GROUP, HELLO_PORT);
}

void sigIntHandler(int)
{
    printf("Got SIGINT (Ctrl+C). Quitting...\n");
    keepRunning = false;
}

void sigTermHandler(int)
{
    printf("Got SIGTERM. Cleaning up. Quitting...\n");
    keepRunning = false;
}

void sigHupHandler(int)
{
    printf("Got SIGHUP. Ignoring.\n");
}

int main(int argc, const char* argv[])
{
    // Handle Ctrl+C and quit gracefully
    signal(SIGINT, sigIntHandler);

    // Handle SIGTERM (15) and quit gracefully
    signal(SIGTERM, sigTermHandler);

    // Handle SIGHUP: Ignore
    signal(SIGHUP, sigHupHandler);

    if (argc != 3)
    {
        usage(argv[0]);

        exit(0);
    }

    const char* mcastGroup = argv[1];
    int portNum = std::atoi(argv[2]);

    struct sockaddr_in addr;
    int fd, nbytes;
    struct ip_mreq mreq;
    char msgbuf[MSG_BUF_SIZE];

    // Create a UDP socket
    if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        perror("socket");
        exit(1);
    }

    // Allow multiple sockets to use the same PORT number
    // We use both SO_REUSEADDR & SO_REUSEPORT to make sure that it works on different systems
    unsigned int yes = 1;
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
    {
        perror("Reusing ADDR failed");
        exit(1);
    }
    /*
    // http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)) < 0)
    {
        perror("Reusing PORT failed");
        exit(1);
    }
    */

    // Timeout on the listening so the app could quit gracefully
    struct timeval tv;
    tv.tv_sec = 2; // 2 seconds
    tv.tv_usec = 1000; // 1000 microseconds
    if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
    {
        perror("Could not set timeout on the RECV");
        exit(1);
    }

    // Set up destination address
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    // Differs from the publisher that must use mcastGroup/HELLO_GROUP
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(portNum);

    // Bind to receive address
    if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        exit(1);
    }

    // Use setsockopt() to request the kernel to join the multicast group
    mreq.imr_multiaddr.s_addr = inet_addr(mcastGroup);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
    {
        perror("Cannot join multicast group");
        exit(1);
    }

    // Keep sending until get a signal to terminate
    socklen_t addrlen = sizeof(addr);
    while (keepRunning)
    {
        if ((nbytes = recvfrom(fd, msgbuf, MSG_BUF_SIZE, 0, (struct sockaddr*)&addr, &addrlen)) < 0)
        {
            // Try again because we got timeout
            // We don't want to print timeout every single time ("Resource temporarily unavailable")
            if (errno == EAGAIN) continue;

            // Handle so the app doesn't die with error = 1 because SIGNIT/SIGHUP/SIGTERM were already handled
            if (errno == EINTR)
            {
                perror("recvfrom was interrupted");
                continue;
            }

            perror("recvfrom");
            exit(1);
        }

        // Make sure we have no issues before printing/processing data
        if (nbytes > 0)
        {
            // Don't use puts! Use std::cout.write with nbytes for safety!
            std::cout.write(msgbuf, nbytes);
            std::cout << std::endl;

            // Reset
            nbytes = 0;
        }

        // https://www.securecoding.cert.org/confluence/pages/viewpage.action?pageId=6619179
        // Reset errno so you can keep receiving. Otherwise it will always be EAGAIN or != 0
        if (errno != 0) errno = 0;
    }

    return 0;
}


Output:
1
2
3
In file included from t.cpp:3:
Line 19: error: stddef.h: No such file or directory
Line 17: error: thread: No such file or directory


Create a new paste based on this one


Comments: