2018년 4월 22일 일요일

SSDP receiver - C언어

SSDP receiver

함수 설명

  • create_ssdp_receiver - socket 생성/bind/multicast join
  • release_ssdp_receiver - 소켓 구조체 메모리 해제
  • pending_ssdp_receiver - multiplex wait (select 함수)
  • receive_ssdp_packet - packet 수신 및 출력
  • main - 샘플 프로그램



#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <net/if.h>

#define SSDP_HOST "239.255.255.250"
#define SSDP_PORT 1900
#define SSDP_PORTSTR "1900"

typedef struct _ssdp_receiver_t
{
    int sock;
    fd_set read_fds;
} ssdp_receiver_t;


static ssdp_receiver_t * create_ssdp_receiver(void)
{
    int on = 1;
    struct addrinfo hints, * res;
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    ssdp_receiver_t * receiver = (ssdp_receiver_t*)malloc(sizeof(ssdp_receiver_t));
    memset(receiver, 0, sizeof(ssdp_receiver_t));
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;
    assert(getaddrinfo(NULL, SSDP_PORTSTR, &hints, &res) == 0);
    receiver->sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    assert(receiver->sock >= 0);
    assert(setsockopt(receiver->sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == 0);
    assert(bind(receiver->sock, res->ai_addr, res->ai_addrlen) == 0);
    freeaddrinfo(res);
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_NUMERICHOST;
    assert(getaddrinfo(SSDP_HOST, NULL, &hints, &res) == 0);
    memcpy(&mreq.imr_multiaddr, &(((struct sockaddr_in*)res->ai_addr)->sin_addr), sizeof(mreq.imr_multiaddr));
    freeaddrinfo(res);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    assert(setsockopt(receiver->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) == 0);
    FD_ZERO(&receiver->read_fds);
    FD_SET(receiver->sock, &(receiver->read_fds));
    return receiver;
}

static void release_ssdp_receiver(ssdp_receiver_t * receiver) {

    /*
     * IP_DROP_MEMBERSHIP is not necessary
     * ----
     * [http://www.tldp.org/HOWTO/Multicast-HOWTO-6.html]
     */
    close(receiver->sock);
    free(receiver);
}

static int pending_ssdp_receiver(ssdp_receiver_t * receiver, unsigned long wait_milli) {
    fd_set fds = receiver->read_fds;
    struct timeval timeout;
    timeout.tv_sec = wait_milli / 1000;
    timeout.tv_usec = (wait_milli % 1000) * 1000;
    return select(receiver->sock + 1, &fds, NULL, NULL, &timeout);
}

static void receive_ssdp_packet(ssdp_receiver_t * receiver) {
    char buffer[4096] = {0,};
    struct sockaddr_in addr = {0,};
    socklen_t addr_len = sizeof(addr);
    int len = recvfrom(receiver->sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &addr_len);
    assert(len > 0);
    printf("[RECV]\n");
    printf("%s", buffer);
}

int main(int argc, char *argv[])
{
    ssdp_receiver_t * receiver = NULL;
    receiver = create_ssdp_receiver();
    int count = 0;
    while (1)
    {
        if (pending_ssdp_receiver(receiver, 100) > 0)
        {
            printf("count: %d\n", count++);
            receive_ssdp_packet(receiver);
        }
    }

    return 0;
}




댓글 없음:

댓글 쓰기

UPnP 용어 정리

용어 정리 https://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0.pdf https://openconnectivity.org/upnp-specs/UPnP-arch-DeviceArchitecture...