2018년 4월 27일 금요일

uuid - C언어

UUID


설치


$ sudo apt install uuid-dev

sample code


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uuid/uuid.h>

int main(int argc, char *argv[])
{
    char uuid_str[37];
    uuid_t uuid;
    uuid_generate_time_safe(uuid);
    uuid_unparse_lower(uuid, uuid_str);
    printf("uuid: %s\n", uuid_str);
   
    return 0;
}


Build


$ gcc -o gen main.c `pkg-config --cflags --libs uuid`

실행


$ ./gen
uuid: 1b4e28ba-2fa1-11d2-883f-0016d3cca427



xml - libxml

xml - libxml


http://xmlsoft.org/

설치


$ sudo apt install libxml2-dev


sample code



#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libxml/parser.h>


static void s_print_attributes(xmlNode * node)
{
    xmlAttr * props = node->properties;
    xmlNode * attr;
    if (props == NULL) {
        return;
    }
    printf("{");
    for (; props; props = props->next) {
        if (props->prev) {
            printf(" ");
        }
        printf("%s: %s", props->name, props->xmlChildrenNode->content);
    }
    printf("}");
}


static void s_print_first_child(xmlNode * node, const char * prefix)
{
    xmlNode * first = node->xmlChildrenNode;
    if (!first || first->next) {
        return;
    }

    printf("%s", prefix);
    printf("Content: '%s'\n", first->content);
}

static void s_print_child_elements(xmlNode * node, const char * prefix)
{
    xmlNode * child;
    for (child = node->xmlChildrenNode; child; child = child->next) {
        if (child->type == XML_ELEMENT_NODE) {
            char prefix_[10] = {0,};
            snprintf(prefix_, sizeof(prefix_), "  %s", prefix);
            printf("%s", prefix);
            printf("Name: %s ", child->name);
            s_print_attributes(child);
            printf("\n");
            s_print_first_child(child, prefix_);
            s_print_child_elements(child, prefix_);
        }
    }
}


int main(int argc, char *argv[])
{
    LIBXML_TEST_VERSION
    xmlDoc * doc;
    xmlNode * root;
    xmlNode * cur_node = NULL;

    if (argc < 2) {
        fprintf(stderr, "usage: %s <xml path>\n", argv[0]);
        exit(1);
    }
   
    doc = xmlReadFile(argv[1], NULL, 0);
    if (doc == NULL) {
        fprintf(stderr, "xmlReadFile() failed\n");
        exit(1);
    }

    root = xmlDocGetRootElement(doc);
    s_print_child_elements(root, "");
   
    xmlFreeDoc(doc);
    xmlCleanupParser();
    xmlMemoryDump();
    return 0;
}


빌드


$ gcc -o parse main.c `pkg-config --cflags --libs libxml-2.0`

light.xml


<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
  <specVersion>
    <major>1</major>
    <minor>0</minor>
  </specVersion>
  <device>
    <deviceType>urn:schemas-upnp-org:device:BinaryLight:0.9</deviceType>
    <friendlyName>Living Room</friendlyName>
    <manufacturer>My company</manufacturer>
    <manufacturerURL>URL to manufacturer site</manufacturerURL>
    <modelDescription>Remote Light Control</modelDescription>
    <modelName>Light</modelName>
    <modelNumber>0001</modelNumber>
    <modelURL>URL to model site</modelURL>
    <serialNumber>SN0001</serialNumber>
    <UDN>uuid:UUID</UDN>
    <serviceList>
      <service>
        <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>
        <serviceId>urn:upnp-org:serviceId:SwitchPower:1</serviceId>
        <SCPDURL>/switchpower.xml</SCPDURL>
        <controlURL>URL for control</controlURL>
        <eventSubURL>URL for eventing</eventSubURL>
      </service>
    </serviceList>
  </device>
</root>



실행


$ ./parse light.xml
Name: specVersion
  Name: major
    Content: '1'
  Name: minor
    Content: '0'
Name: device
  Name: deviceType
    Content: 'urn:schemas-upnp-org:device:BinaryLight:0.9'
  Name: friendlyName
    Content: 'Living Room'
  Name: manufacturer
    Content: 'My company'
  Name: manufacturerURL
    Content: 'URL to manufacturer site'
  Name: modelDescription
    Content: 'Remote Light Control'
  Name: modelName
    Content: 'Light'
  Name: modelNumber
    Content: '0001'
  Name: modelURL
    Content: 'URL to model site'
  Name: serialNumber
    Content: 'SN0001'
  Name: UDN
    Content: 'uuid:UUID'
  Name: serviceList
    Name: service
      Name: serviceType
        Content: 'urn:schemas-upnp-org:service:SwitchPower:1'
      Name: serviceId
        Content: 'urn:upnp-org:serviceId:SwitchPower:1'
      Name: SCPDURL
        Content: '/switchpower.xml'
      Name: controlURL
        Content: 'URL for control'
      Name: eventSubURL
        Content: 'URL for eventing'


switchpower.xml


<?xml version="1.0"?>
<scpd xmlns="urn:schemas-upnp-org:service-1-0">
  <specVersion>
    <major>1</major>
    <minor>0</minor>
  </specVersion>
  <actionList>
    <action>
      <name>SetTarget</name>
      <argumentList>
        <argument>
          <name>newTargetValue</name>
          <relatedStateVariable>Target</relatedStateVariable>
          <direction>in</direction>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>GetTarget</name>
      <argumentList>
        <argument>
          <name>RetTargetValue</name>
          <relatedStateVariable>Target</relatedStateVariable>
          <direction>out</direction>
        </argument>
      </argumentList>
    </action>
    <action>
      <name>GetStatus</name>
      <argumentList>
        <argument>
          <name>ResultStatus</name>
          <relatedStateVariable>Status</relatedStateVariable>
          <direction>out</direction>
        </argument>
      </argumentList>
    </action>
  </actionList>
  <serviceStateTable>
    <stateVariable sendEvents="no">
      <name>Target</name>
      <dataType>boolean</dataType>
      <defaultValue>0</defaultValue>
    </stateVariable>
    <stateVariable sendEvents="yes">
      <name>Status</name>
      <dataType>boolean</dataType>
      <defaultValue>0</defaultValue>
    </stateVariable>
  </serviceStateTable>
</scpd>


실행


$ ./parse switchpower.xml
Name: specVersion
  Name: major
    Content: '1'
  Name: minor
    Content: '0'
Name: actionList
  Name: action
    Name: name
      Content: 'SetTarget'
    Name: argumentList
      Name: argument
        Name: name
         Content: 'newTargetValue'
        Name: relatedStateVariable
         Content: 'Target'
        Name: direction
         Content: 'in'
  Name: action
    Name: name
      Content: 'GetTarget'
    Name: argumentList
      Name: argument
        Name: name
         Content: 'RetTargetValue'
        Name: relatedStateVariable
         Content: 'Target'
        Name: direction
         Content: 'out'
  Name: action
    Name: name
      Content: 'GetStatus'
    Name: argumentList
      Name: argument
        Name: name
         Content: 'ResultStatus'
        Name: relatedStateVariable
         Content: 'Status'
        Name: direction
         Content: 'out'
Name: serviceStateTable
  Name: stateVariable {sendEvents: no}
    Name: name
      Content: 'Target'
    Name: dataType
      Content: 'boolean'
    Name: defaultValue
      Content: '0'
  Name: stateVariable {sendEvents: yes}
    Name: name
      Content: 'Status'
    Name: dataType
      Content: 'boolean'
    Name: defaultValue
      Content: '0'



2018년 4월 23일 월요일

http client - libcurl

http client - libcurl


참고:

Http get sample

  • http get
  • 응답 데이터를 .out 파일로 저장

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>


static size_t cb_write(void * contents, size_t size, size_t nmemb, void * userp)
{
    FILE * fp = (FILE*)userp;
    fwrite(contents, size, nmemb, fp);
    return size * nmemb;
}

static void dumpfile(const char * path);

int main(int argc, char *argv[])
{
    FILE * out;
    CURLcode res;
    CURL * curl;

    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if (!curl) {
        printf("curl_easy_init() failed\n");
        exit(1);
    }

    out = fopen(".out", "wb");
    if (!out) {
        printf("fopen() failed\n");
        exit(1);
    }

    curl_easy_setopt(curl, CURLOPT_URL, "http://httpbin.org/get");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb_write);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)out);
    res = curl_easy_perform(curl);
    if (res != CURLE_OK) {
        fclose(out);
        printf("curl_easy_perform() failed\n");
        exit(1);
    }
    fclose(out);

    dumpfile(".out");

    curl_easy_cleanup(curl);

    curl_global_cleanup();

    return 0;
}

static void dumpfile(const char * path) {

    int len;
    char buf[1024] = {0,};
    FILE * fp = fopen(path, "rb");
    if (!fp) {
        perror("fopen() failed");
        exit(1);
    }

    while ((len = fread(buf, sizeof(char), sizeof(buf), fp)) > 0) {
        printf("%.*s", len, buf);
    }

    fclose(fp);
}
 


빌드


$ gcc -o httpget main.c `pkg-config --cflags --libs libcurl`

실행


$ ./httpget
{
  "args": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Host": "httpbin.org"
  },
  "origin": "xx.xx.xx.xx",
  "url": "http://httpbin.org/get"
}



Http post sample


  • http post
  • Content-Type: text/plain


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>

static size_t cb_write(void * contents, size_t size, size_t nmemb, void * userp)
{
    FILE * fp = (FILE*)userp;
    fwrite(contents, size, nmemb, fp);
    return size * nmemb;
}

static void dumpfile(const char * path);

int main(int argc, char *argv[])
{
    struct curl_slist * headers = NULL;
    static const char * msg = "hello world";
    FILE * out;
    CURLcode res;
    CURL * curl;

    curl_global_init(CURL_GLOBAL_ALL);

    curl = curl_easy_init();
    if (!curl) {
        printf("curl_easy_init() failed\n");
        exit(1);
    }

    out = fopen(".out", "wb");
    if (!out) {
        printf("fopen() failed\n");
        exit(1);
    }

    headers = curl_slist_append(headers, "Content-Type: text/plain");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

    curl_easy_setopt(curl, CURLOPT_URL, "http://httpbin.org/post");
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    curl_easy_setopt(curl, CURLOPT_POST, 1L);

    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, msg);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(msg));
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb_write);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)out);
    res = curl_easy_perform(curl);
    curl_slist_free_all(headers);
    if (res != CURLE_OK) {
        fclose(out);
        fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
        exit(1);
    }
    fclose(out);
    dumpfile(".out");
    curl_easy_cleanup(curl);
    curl_global_cleanup();

    return 0;
}

static void dumpfile(const char * path) {
    int len;
    char buf[1024] = {0,};
    FILE * fp = fopen(path, "rb");
    if (!fp) {
        perror("fopen() failed");
        exit(1);
    }

    while ((len = fread(buf, sizeof(char), sizeof(buf), fp)) > 0) {
        printf("%.*s", len, buf);
    }

    fclose(fp);
}



빌드


$ gcc -o httppost main.c `pkg-config --cflags --libs libcurl`

실행


$ ./httppost
{
  "args": {},
  "data": "hello world",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Content-Length": "11",
    "Content-Type": "text/plain",
    "Host": "httpbin.org"
  },
  "json": null,
  "origin": "xx.xx.xx.xx",
  "url": "http://httpbin.org/post"
}




2018년 4월 22일 일요일

http server - microhttpd

http server - microhttpd


micro http server



설치


$ brew install libmicrohttpd

sample code


#include <microhttpd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define PAGE "<html><head><title>libmicrohttpd demo</title>"\
             "</head><body>libmicrohttpd demo</body></html>"

static int ahc_echo(void * cls,
   struct MHD_Connection * connection,
   const char * url,
   const char * method,
                    const char * version,
   const char * upload_data,
   size_t * upload_data_size,
                    void ** ptr) {
  static int dummy;
  const char * page = cls;
  struct MHD_Response * response;
  int ret;

  if (0 != strcmp(method, "GET"))
    return MHD_NO; /* unexpected method */
  if (&dummy != *ptr)
    {
      /* The first time only the headers are valid,
         do not respond in the first round... */
      *ptr = &dummy;
      return MHD_YES;
    }
  if (0 != *upload_data_size)
    return MHD_NO; /* upload data in a GET!? */
  *ptr = NULL; /* clear context pointer */
  response = MHD_create_response_from_buffer (strlen(page),
                                              (void*) page,
       MHD_RESPMEM_PERSISTENT);
  ret = MHD_queue_response(connection,
  MHD_HTTP_OK,
  response);
  MHD_destroy_response(response);
  return ret;
}

int main(int argc,
char ** argv) {
  struct MHD_Daemon * d;
  if (argc != 2) {
    printf("%s PORT\n",
  argv[0]);
    return 1;
  }
  d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
      atoi(argv[1]),
      NULL,
      NULL,
      &ahc_echo,
      PAGE,
      MHD_OPTION_END);
  if (d == NULL)
    return 1;
  (void) getc (stdin);
  MHD_stop_daemon(d);
  return 0;
}

빌드


$ gcc -o server main.c `pkg-config --cflags --libs libmicrohttpd`


Network interface list - C언어

Network interface list


Sample code


#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.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>

int main(int argc, char *argv[])
{
    struct ifaddrs * addrs, * tmp;
    getifaddrs(&addrs);
    tmp = addrs;

    while (tmp) {
        char ipstr[INET6_ADDRSTRLEN] = {0,};
        struct sockaddr * addr = (struct sockaddr*)tmp->ifa_addr;
        printf("[%s]\n", tmp->ifa_name);
        if (addr) {
            inet_ntop(addr->sa_family,
                      (addr->sa_family == AF_INET ?
                       (void*)&((struct sockaddr_in*)addr)->sin_addr :
                       (void*)&((struct sockaddr_in6 *)addr)->sin6_addr),
                      ipstr, sizeof(ipstr));
            printf(" * type: %d, addr: %s\n", addr->sa_family, ipstr);
        }

        tmp = tmp->ifa_next;
    }

    freeifaddrs(addrs);

    return 0;

}

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...