| /* |
| * Copyright 2014 Google Inc. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * ssdptax (SSDP Taxonomy) |
| * |
| * A client implementing the API described in |
| * http://miniupnp.free.fr/minissdpd.html |
| * |
| * Requests the list of all known SSDP nodes, requests |
| * device info from them, and tries to figure out what |
| * they are. |
| */ |
| |
| #include <arpa/inet.h> |
| #include <asm/types.h> |
| #include <ctype.h> |
| #include <curl/curl.h> |
| #include <getopt.h> |
| #include <netinet/in.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/socket.h> |
| #include <sys/time.h> |
| #include <sys/types.h> |
| #include <sys/un.h> |
| #include <unistd.h> |
| |
| #include "l2utils.h" |
| |
| /* Encode length by using 7bit per Byte : |
| * Most significant bit of each byte specifies that the |
| * following byte is part of the code */ |
| #define DECODELENGTH(n, p) { \ |
| n = 0; \ |
| do { n = (n << 7) | (*p & 0x7f); } \ |
| while (*(p++)&0x80); \ |
| } |
| |
| #define CODELENGTH(n, p) { \ |
| if(n>=0x10000000) *(p++) = (n >> 28) | 0x80; \ |
| if(n>=0x200000) *(p++) = (n >> 21) | 0x80; \ |
| if(n>=0x4000) *(p++) = (n >> 14) | 0x80; \ |
| if(n>=0x80) *(p++) = (n >> 7) | 0x80; \ |
| *(p++) = n & 0x7f; \ |
| } |
| |
| #define SOCK_PATH "/var/run/minissdpd.sock" |
| |
| |
| typedef struct { |
| char server[512]; |
| char url[512]; |
| char friendlyName[64]; |
| int failed; |
| } ssdp_info_t; |
| |
| |
| /* Unit test support */ |
| char *get_test_ssdp_data(); |
| void get_test_l2_map(L2Map *l2map); |
| |
| static void memcpy_printable(char *dst, const char *src, size_t n) |
| { |
| size_t i; |
| for (i = 0; i < n; ++i) { |
| unsigned char s = src[i]; |
| if (isspace(s)) { |
| dst[i] = ' '; // deliberately convert newline to space |
| } else if (isprint(s)) { |
| dst[i] = s; |
| } else { |
| dst[i] = '_'; |
| } |
| } |
| } |
| |
| |
| /* |
| * Send a request to minissdpd. Returns a pointer to a buffer |
| * allocated using malloc(). Caller must free() the buffer when done. |
| */ |
| char *request_from_ssdpd(int reqtype, const char *device) |
| { |
| int s = socket(AF_UNIX, SOCK_STREAM, 0); |
| struct sockaddr_un addr; |
| size_t siz = 256 * 1024; |
| char *buffer, *p; |
| ssize_t len; |
| int device_len = (int)strlen(device); |
| fd_set readfds; |
| struct timeval tv; |
| |
| if (s < 0) { |
| perror("socket AF_UNIX failed"); |
| exit(1); |
| } |
| memset(&addr, 0, sizeof(addr)); |
| addr.sun_family = AF_UNIX; |
| strncpy(addr.sun_path, SOCK_PATH, sizeof(addr.sun_path)); |
| if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) { |
| perror("connect to minisspd failed"); |
| exit(1); |
| } |
| |
| if ((buffer = (char *)malloc(siz)) == NULL) { |
| fprintf(stderr, "malloc(%zu) failed\n", siz); |
| exit(1); |
| } |
| memset(buffer, 0, siz); |
| |
| buffer[0] = reqtype; |
| p = buffer + 1; |
| CODELENGTH(device_len, p); |
| memcpy(p, device, device_len); |
| p += device_len; |
| if (write(s, buffer, p - buffer) < 0) { |
| perror("write to minissdpd failed"); |
| exit(1); |
| } |
| |
| FD_ZERO(&readfds); |
| FD_SET(s, &readfds); |
| memset(&tv, 0, sizeof(tv)); |
| tv.tv_sec = 2; |
| |
| if (select(s + 1, &readfds, NULL, NULL, &tv) < 1) { |
| fprintf(stderr, "select failed\n"); |
| exit(1); |
| } |
| |
| if ((len = read(s, buffer, siz)) < 0) { |
| perror("read from minissdpd failed"); |
| exit(1); |
| } |
| |
| close(s); |
| return(buffer); |
| } |
| |
| |
| static void print_responses(const std::string &ipaddr, |
| const ssdp_info_t *info, L2Map *l2map) |
| { |
| const char *mac; |
| |
| if (info->failed) { |
| /* |
| * We could not fetch information from this client. That often means that |
| * the device was powered off recently. minissdpd still remembers that |
| * it is there, but we cannot contact it. |
| * |
| * Don't print anything for these, as we'd end up calling them "Unknown" |
| * and that is misleading. We only report information about devices which |
| * are active right now. |
| */ |
| return; |
| } |
| |
| L2Map::const_iterator ii = l2map->find(ipaddr); |
| if (ii != l2map->end()) { |
| mac = ii->second.c_str(); |
| } else { |
| mac = "00:00:00:00:00:00"; |
| } |
| |
| /* taxonomy information to stdout */ |
| if (strlen(info->friendlyName)) { |
| printf("ssdp %s %s\n", mac, info->friendlyName); |
| } else { |
| printf("ssdp %s Unknown;%s\n", mac, info->server); |
| } |
| } |
| |
| |
| const char *parse_minissdpd_response(const char *response, |
| char *key, size_t key_len, |
| char *url, size_t url_len, |
| char *value, size_t value_len) |
| { |
| const char *p = response; |
| size_t copylen, slen; |
| int prefix = 0; |
| struct in6_addr in6; |
| struct in_addr in; |
| char ip[INET6_ADDRSTRLEN]; |
| |
| key[0] = url[0] = value[0] = '\0'; |
| |
| DECODELENGTH(slen, p); |
| copylen = (slen >= url_len) ? url_len - 1 : slen; |
| memcpy_printable(url, p, copylen); |
| url[copylen] = '\0'; |
| p += slen; |
| |
| DECODELENGTH(slen, p); |
| copylen = (slen >= value_len) ? value_len - 1 : slen; |
| memcpy_printable(value, p, copylen); |
| value[copylen] = '\0'; |
| p += slen; |
| |
| if (strncasecmp(url, "https://[", 9) == 0) prefix = 9; |
| if (strncasecmp(url, "http://[", 8) == 0) prefix = 8; |
| if (strncasecmp(url, "https://", 8) == 0) prefix = 8; |
| if (strncasecmp(url, "http://", 7) == 0) prefix = 7; |
| strncpy(ip, url + prefix, sizeof(ip)); |
| strtok(ip, ":/@"); |
| |
| if (inet_pton(AF_INET6, ip, &in6)) { |
| inet_ntop(AF_INET6, &in6, key, key_len); |
| } |
| if (inet_pton(AF_INET, ip, &in)) { |
| inet_ntop(AF_INET, &in, key, key_len); |
| } |
| |
| return p; |
| } |
| |
| |
| ssdp_info_t *dupinfo(ssdp_info_t *info) |
| { |
| ssdp_info_t *i = (ssdp_info_t *)malloc(sizeof(*info)); |
| |
| if (i == NULL) { |
| perror("malloc"); |
| exit(1); |
| } |
| |
| memcpy(i, info, sizeof(*i)); |
| return i; |
| } |
| |
| |
| const char *findXmlField(const char *ptr, const char *label, ssize_t *len) |
| { |
| char openlabel[64], closelabel[64]; |
| const char *start, *end; |
| |
| snprintf(openlabel, sizeof(openlabel), "<%s>", label); |
| snprintf(closelabel, sizeof(closelabel), "</%s>", label); |
| |
| start = strcasestr(ptr, openlabel) + strlen(openlabel); |
| end = strcasestr(ptr, closelabel); |
| |
| if ((end - start) > 0) { |
| *len = end - start; |
| return start; |
| } |
| |
| return NULL; |
| } |
| |
| |
| /* |
| * libcurl calls this function back with the result of the HTTP GET. |
| * |
| * Expected value is an XML blob of |
| * http://upnp.org/specs/basic/UPnP-basic-Basic-v1-Device.pdf |
| * |
| * Like this (a Samsung TV): |
| * <?xml version="1.0"?> |
| * <root xmlns='urn:schemas-upnp-org:device-1-0' ... |
| * <device> |
| * <deviceType>urn:dial-multiscreen-org:device:dialreceiver:1</deviceType> |
| * <friendlyName>[TV]Samsung LED60</friendlyName> |
| * <manufacturer>Samsung Electronics</manufacturer> |
| * <manufacturerURL>http://www.samsung.com/sec</manufacturerURL> |
| * <modelDescription>Samsung TV NS</modelDescription> |
| * <modelName>UN60F6300</modelName> |
| * <modelNumber>1.0</modelNumber> |
| * <modelURL>http://www.samsung.com/sec</modelURL> |
| * ... etc, etc ... |
| */ |
| size_t callback(const char *ptr, size_t size, size_t nmemb, void *userdata) |
| { |
| ssdp_info_t *info = (ssdp_info_t *)userdata; |
| const char *p; |
| ssize_t len; |
| ssize_t max = (ssize_t)sizeof(info->friendlyName); |
| |
| if ((p = findXmlField(ptr, "friendlyName", &len)) == NULL) { |
| p = findXmlField(ptr, "modelDescription", &len); |
| } |
| |
| if (p && (len > 0) && (len < max)) { |
| /* the len < max check ensures there will be a NUL byte at the end */ |
| memcpy(info->friendlyName, p, len); |
| } |
| |
| return size * nmemb; |
| } |
| |
| |
| /* |
| * SSDP returned an endpoint URL, use curl to GET its contents. |
| */ |
| void fetch_device_info(const char *url, ssdp_info_t *ssdp) |
| { |
| CURL *curl = curl_easy_init(); |
| int rc; |
| |
| if (!curl) { |
| fprintf(stderr, "curl_easy_init failed\n"); |
| return; |
| } |
| curl_easy_setopt(curl, CURLOPT_URL, url); |
| curl_easy_setopt(curl, CURLOPT_PATH_AS_IS, 1L); |
| curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &callback); |
| curl_easy_setopt(curl, CURLOPT_WRITEDATA, ssdp); |
| curl_easy_setopt(curl, CURLOPT_USERAGENT, "ssdptax/1.0"); |
| curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L); |
| if ((rc = curl_easy_perform(curl)) != CURLE_OK) { |
| ssdp->failed = 1; |
| } |
| curl_easy_cleanup(curl); |
| } |
| |
| |
| void usage(char *progname) { |
| printf("usage: %s [-t]\n", progname); |
| printf("\t-t\ttest mode, run a test with fake SSDP data.\n"); |
| exit(1); |
| } |
| |
| |
| int main(int argc, char **argv) |
| { |
| char *buffer; |
| const char *p; |
| typedef std::tr1::unordered_map<std::string, ssdp_info_t*> ResponsesMap; |
| ResponsesMap responses; |
| L2Map l2map; |
| int c, num; |
| int testmode = 0; |
| |
| setlinebuf(stdout); |
| if (curl_global_init(CURL_GLOBAL_NOTHING)) { |
| fprintf(stderr, "curl_global_init failed\n"); |
| exit(1); |
| } |
| |
| while ((c = getopt(argc, argv, "t")) != -1) { |
| switch(c) { |
| case 't': testmode = 1; break; |
| default: usage(argv[0]); break; |
| } |
| } |
| |
| if (!testmode) { |
| /* 5 == request all device server IDs */ |
| buffer = request_from_ssdpd(5, "ssdp:all"); |
| } else { |
| buffer = get_test_ssdp_data(); |
| } |
| |
| num = buffer[0]; |
| p = buffer + 1; |
| while ((num-- > 0) && (p < (buffer + sizeof(buffer)))) { |
| char key[INET6_ADDRSTRLEN]; |
| ssdp_info_t info; |
| |
| memset(&info, 0, sizeof(info)); |
| p = parse_minissdpd_response(p, key, sizeof(key), |
| info.url, sizeof(info.url), info.server, sizeof(info.server)); |
| if (strlen(key) && responses.find(std::string(key)) == responses.end()) { |
| if (!testmode) { |
| fetch_device_info(info.url, &info); |
| } else { |
| snprintf(info.friendlyName, sizeof(info.friendlyName), "Test Device"); |
| } |
| responses.insert(std::make_pair<std::string, |
| ssdp_info_t*>(std::string(key), dupinfo(&info))); |
| } |
| } |
| free(buffer); |
| |
| if (!testmode) { |
| get_l2_map(&l2map); |
| } else { |
| get_test_l2_map(&l2map); |
| } |
| |
| for(ResponsesMap::const_iterator ii = responses.begin(); |
| ii != responses.end(); ++ii) { |
| print_responses(ii->first, ii->second, &l2map); |
| } |
| |
| curl_global_cleanup(); |
| exit(0); |
| } |
| |
| |
| /* |
| * data for a unit test, response from a single SSDP |
| * client. |
| */ |
| uint8_t test_ssdp_data[] = { |
| 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, |
| 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, |
| 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, |
| 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, |
| 0x5f, 0x32, 0x39, 0x5f, 0x23, 0x53, 0x48, 0x50, |
| 0x2c, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, |
| 0x2e, 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, |
| 0x75, 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, |
| 0x20, 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, |
| 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, |
| 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, |
| 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, |
| 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, |
| 0x32, 0x39, 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, |
| 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, |
| 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, |
| 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, |
| 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, |
| 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, |
| 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, |
| 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x32, |
| 0x39, 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, |
| 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, |
| 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, |
| 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, |
| 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, |
| 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, |
| 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, |
| 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, |
| 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x32, 0x39, |
| 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, |
| 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, |
| 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, 0x74, |
| 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, |
| 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, |
| 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, |
| 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x31, 0x39, 0x5f, |
| 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, |
| 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, |
| 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, |
| 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, |
| 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, 0x74, 0x74, |
| 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, |
| 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, 0x31, |
| 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, 0x2f, |
| 0x73, 0x6d, 0x70, 0x5f, 0x31, 0x39, 0x5f, 0x23, |
| 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, |
| 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, |
| 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, |
| 0x31, 0x2e, 0x30, 0x22, 0x68, 0x74, 0x74, 0x70, |
| 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, |
| 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, |
| 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, |
| 0x6d, 0x70, 0x5f, 0x31, 0x39, 0x5f, 0x23, 0x53, |
| 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, 0x50, |
| 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, 0x61, |
| 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, 0x50, |
| 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, 0x31, |
| 0x2e, 0x30, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, |
| 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, |
| 0x38, 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, |
| 0x3a, 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, |
| 0x70, 0x5f, 0x31, 0x39, 0x5f, 0x23, 0x53, 0x48, |
| 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, |
| 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, |
| 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, |
| 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, |
| 0x30, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, |
| 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, |
| 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, |
| 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, |
| 0x5f, 0x31, 0x39, 0x5f, 0x23, 0x53, 0x48, 0x50, |
| 0x2c, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, |
| 0x2e, 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, |
| 0x75, 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, |
| 0x20, 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, |
| 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, |
| 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, |
| 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, |
| 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, |
| 0x31, 0x39, 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, |
| 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, |
| 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, |
| 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, |
| 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, |
| 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, |
| 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, |
| 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x31, |
| 0x31, 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, |
| 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, |
| 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, |
| 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, |
| 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, |
| 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, |
| 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, |
| 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, |
| 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x31, 0x31, |
| 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, |
| 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, |
| 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, 0x74, |
| 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, |
| 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, |
| 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, |
| 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x31, 0x31, 0x5f, |
| 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, |
| 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, |
| 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, |
| 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, |
| 0x2f, 0x31, 0x2e, 0x30, 0x22, 0x68, 0x74, 0x74, |
| 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, |
| 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, 0x31, |
| 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, 0x2f, |
| 0x73, 0x6d, 0x70, 0x5f, 0x31, 0x31, 0x5f, 0x23, |
| 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, |
| 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, |
| 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, |
| 0x31, 0x2e, 0x30, 0x21, 0x68, 0x74, 0x74, 0x70, |
| 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, |
| 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, |
| 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, |
| 0x6d, 0x70, 0x5f, 0x32, 0x5f, 0x23, 0x53, 0x48, |
| 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, |
| 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, |
| 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, |
| 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, |
| 0x30, 0x21, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, |
| 0x2f, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, |
| 0x2e, 0x34, 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, |
| 0x37, 0x36, 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, |
| 0x5f, 0x32, 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, |
| 0x30, 0x2c, 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, |
| 0x6e, 0x67, 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, |
| 0x53, 0x44, 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x21, |
| 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, |
| 0x39, 0x32, 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, |
| 0x32, 0x2e, 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, |
| 0x37, 0x36, 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x32, |
| 0x5f, 0x23, 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, |
| 0x20, 0x53, 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, |
| 0x20, 0x55, 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, |
| 0x4b, 0x2f, 0x31, 0x2e, 0x30, 0x21, 0x68, 0x74, |
| 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x39, 0x32, |
| 0x2e, 0x31, 0x36, 0x38, 0x2e, 0x34, 0x32, 0x2e, |
| 0x31, 0x32, 0x35, 0x3a, 0x37, 0x36, 0x37, 0x36, |
| 0x2f, 0x73, 0x6d, 0x70, 0x5f, 0x32, 0x5f, 0x23, |
| 0x53, 0x48, 0x50, 0x2c, 0x20, 0x55, 0x50, 0x6e, |
| 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x2c, 0x20, 0x53, |
| 0x61, 0x6d, 0x73, 0x75, 0x6e, 0x67, 0x20, 0x55, |
| 0x50, 0x6e, 0x50, 0x20, 0x53, 0x44, 0x4b, 0x2f, |
| 0x31, 0x2e, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00 |
| }; |
| |
| |
| char *get_test_ssdp_data() |
| { |
| size_t len = sizeof(test_ssdp_data); |
| char *buffer = (char *)malloc(len); |
| |
| if (buffer == NULL) { |
| perror("malloc failed"); |
| exit(1); |
| } |
| |
| memcpy(buffer, test_ssdp_data, len); |
| return buffer; |
| } |
| |
| |
| void get_test_l2_map(L2Map *l2map) |
| { |
| (*l2map)[std::string("192.168.42.125")] = std::string("00:01:02:03:04:05"); |
| } |