Просмотр исходного кода

Merge pull request #1 from SummerGGift/master

【添加】lssdp 软件包 RT-Thread 移植
朱天龙 (Armink) 6 лет назад
Родитель
Сommit
a805183732

+ 0 - 29
.gitignore

@@ -1,29 +0,0 @@
-# Object files
-*.o
-*.ko
-*.obj
-*.elf
-
-# Precompiled Headers
-*.gch
-*.pch
-
-# Libraries
-*.lib
-*.a
-*.la
-*.lo
-
-# Shared objects (inc. Windows DLLs)
-*.dll
-*.so
-*.so.*
-*.dylib
-
-# Executables
-*.exe
-*.out
-*.app
-*.i*86
-*.x86_64
-*.hex

+ 0 - 6
Makefile

@@ -1,6 +0,0 @@
-all:
-	$(MAKE) -C test
-
-clean:
-	rm -rf *.o
-	$(MAKE) -C test clean

+ 38 - 115
README.md

@@ -1,144 +1,67 @@
-# lssdp
-light weight SSDP library
+# LSSDP
 
-### What is SSDP
+## 1. 介绍 
 
-The Simple Service Discovery Protocol (SSDP) is a network protocol based on the Internet Protocol Suite for advertisement and discovery of network services and presence information.
+LSSDP (Lightweight Simple Sever Discovery Protocol),简单服务发现协议是一种应用层协议,此协议为网络客户提供一种无需任何配置、管理和维护网络设备服务的机制,此协议采用基于通知和发现路由的多播发现方式实现。
 
-====
+通过使用该软件包,可以让连接到局域网中的 RT-Thread 设备被客户端自动发现,并使用 RT-Thread 设备所提供的服务。例如 adb 软件包提供的文件传输服务。
 
-### Support Platform
+### 1.1 许可证
 
-* Linux Ubuntu
-* MAC OSX
-* Android
-* iOS
+The MIT License (MIT)
 
-====
+## 2. 获取软件包
 
-### How To Build and Test
+在使用的 BSP 目录下,使用 ENV 工具打开 menuconfig 来获取软件包。
 
-```
-make clean
-make
+- 配置软件包并使能示例
 
-cd test
-./daemon.exe
+```c
+RT-Thread online packages --->
+     IoT - internet of things  --->
+         Lssdp: SSDP protocol implemented on rt-thread
+             [*]   Enable LSSDP add/del samples
+                   Version (latest)  --->
 ```
 
-====
-
-#### lssdp_ctx:
-
-lssdp context
-
-**port** - SSDP UDP port, 1900 port is general.
-
-**sock** - SSDP socket, created by `lssdp_socket_create`, and close by `lssdp_socket_close`
-
-**neighbor_list** - neighbor list, when received *NOTIFY* or *RESPONSE* packet, neighbor list will be updated.
-
-**neighbor_timeout** - this value will be used by `lssdp_neighbor_check_timeout`. If neighbor is timeout, then remove from neighbor list.
-
-**debug** - SSDP debug mode, show debug message.
-
-**interface** - Network Interface list. Call `lssdp_network_interface_update` to update the list.
-
-**interface_num** - the number of Network Interface list.
-
-**header.search_target** - SSDP Search Target (ST). A potential search target.
-
-**header.unique_service_name** - SSDP Unique Service Name (USN). A composite identifier for the advertisement.
+- 使用 `pkgs --update` 命令下载软件包
 
-**header.location = prefix + domain + suffix** - [http://] + IP + [:PORT/URI]
+## 3. 使用 LSSDP
 
-**header.sm_id** - Optional field.
+### 3.1 打开软件包示例
 
-**header.device_type** - Optional field.
+配置软件包时打开 lssdp 软件包的添加 `[*]   Enable LSSDP add/del samples` 选项,重新编译下载运行。
 
-**network_interface_changed_callback** - when interface is changed, this callback would be invoked.
+lssdp_add_example 命令会注册一个名为 `urn:rt-thread:service:ssdp` 的服务到 ssdp 中:
 
-**neighbor_list_changed_callback** - when neighbor list is changed, this callback would be invoked.
+![1557565323474](docs/figures/1557565323474.png)
 
-**packet_received_callback** - when received any SSDP packet, this callback would be invoked. It callback is usally used for debugging.
+从示例代码中可以看到注册的设备信息:
 
-====
+![1557571840845](docs/figures/1557571840845.png)
 
-#### Function API (8)
+## 3.2 运行桌面端测试程序
 
-##### 01. lssdp_network_interface_update
+通过 tools 目录下的测试程序,可以看到在局域网中提供 `urn:rt-thread:service:ssdp` 服务的设备,如下图所示:
 
-update network interface.
+![1557571616388](docs/figures/1557571616388.png)
 
-```
-- lssdp.interface, lssdp.interface_num will be updated.
-```
-
-
-##### 02. lssdp_socket_create
-
-create SSDP socket.
-
-```
-- SSDP port must be setup ready before call this function. (lssdp.port > 0)
-
-- if SSDP socket is already exist (lssdp.sock > 0), the socket will be closed, and create a new one.
-
-- SSDP neighbor list will be force clean up.
-```
+从上图可以看到从 RT-Thread 设备收到了提供  `urn:rt-thread:service:ssdp` 服务的设备信息。从 LOCATION 属性可以得知提供该服务的设备地址和端口号。
 
-##### 03. lssdp_socket_close
+## 3.3 添加 lssdp 服务
 
-close SSDP socket.
+可以参考 lssdp_sample 中的示例代码,使用如下 API 在 lssdp 中添加或者删除服务。
 
-```
-- if SSDP socket <= 0, will be ignore, and lssdp.sock will be set -1.
-- SSDP neighbor list will be force clean up.
-```
+| API 接口                                        | 功能                |
+| ----------------------------------------------- | ------------------- |
+| int lssdp_service_add(struct lssdp_service *h); | 添加服务到 lssdp    |
+| int lssdp_service_del(struct lssdp_service *h); | 从 lssdp 中删除服务 |
 
-##### 04. lssdp_socket_read
+## 4、参考资料
 
-read SSDP socket.
-
-```
-1. if read success, packet_received_callback will be invoked.
-
-2. if received SSDP packet is match to Search Target (lssdp.header.search_target),
-   - M-SEARCH: send RESPONSE back
-   - NOTIFY/RESPONSE: add/update to SSDP neighbor list
-```
-
-```
-- SSDP socket and port must be setup ready before call this function. (sock, port > 0)
-- if SSDP neighbor list has been changed, neighbor_list_changed_callback will be invoked.
-```
-
-##### 05. lssdp_send_msearch
-
-send SSDP M-SEARCH packet to multicast address (239.255.255.250)
-
-```
-- SSDP port must be setup ready before call this function. (lssdp.port > 0)
-```
-
-##### 06. lssdp_send_notify
-
-send SSDP NOTIFY packet to multicast address (239.255.255.250)
-
-```
-- SSDP port must be setup ready before call this function. (lssdp.port > 0)
-```
-
-##### 07. lssdp_neighbor_check_timeout
-
-check neighbor in list is timeout or not. (lssdp.neighbor_timeout)
-
-the timeout neighbor will be remove from the list.
-
-```
-- if neighbor be removed, neighbor_list_changed_callback will be invoked.
-```
+- 无
 
-##### 08. lssdp_set_log_callback
+## 5、 联系方式 & 感谢
 
-setup SSDP log callback. All SSDP library log will be forward to here.
+- 维护: RT-Thread 开发团队
+- 主页: https://github.com/RT-Thread-packages/lssdp

+ 19 - 0
SConscript

@@ -0,0 +1,19 @@
+from building import *
+Import('rtconfig')
+
+src   = []
+cwd   = GetCurrentDir()
+
+src += Glob('src/daemon.c')
+src += Glob('src/lssdp.c')
+src += Glob('src/lssdp_service.c')
+
+if GetDepend('LSSDP_USING_SAMPLES'):
+    src += Glob('samples/lssdp_sample.c')
+
+path  = [cwd + '/inc']
+
+# add src and include to group.
+group = DefineGroup('lssdp', src, depend = [''], CPPPATH = path)
+
+Return('group')

BIN
docs/figures/1557565323474.png


BIN
docs/figures/1557571616388.png


BIN
docs/figures/1557571840845.png


+ 8 - 7
lssdp.h → inc/lssdp.h

@@ -13,8 +13,8 @@ enum LSSDP_LOG {
 };
 
 /* Struct : lssdp_nbr */
-#define LSSDP_FIELD_LEN         128
-#define LSSDP_LOCATION_LEN      256
+#define LSSDP_FIELD_LEN         64
+#define LSSDP_LOCATION_LEN      128
 typedef struct lssdp_nbr {
     char            usn         [LSSDP_FIELD_LEN];          // Unique Service Name (Device Name or MAC)
     char            location    [LSSDP_LOCATION_LEN];       // URL or IP(:Port)
@@ -29,7 +29,7 @@ typedef struct lssdp_nbr {
 
 /* Struct : lssdp_ctx */
 #define LSSDP_INTERFACE_NAME_LEN    16                      // IFNAMSIZ
-#define LSSDP_INTERFACE_LIST_SIZE   16
+#define LSSDP_INTERFACE_LIST_SIZE   1
 #define LSSDP_IP_LEN                16
 typedef struct lssdp_ctx {
     int             sock;                                   // SSDP socket
@@ -52,15 +52,16 @@ typedef struct lssdp_ctx {
         /* SSDP Standard Header Fields */
         char        search_target       [LSSDP_FIELD_LEN];  // Search Target
         char        unique_service_name [LSSDP_FIELD_LEN];  // Unique Service Name: MAC or User Name
+
+        /* Additional SSDP Header Fields */
+        char        sm_id               [LSSDP_FIELD_LEN];
+        char        device_type         [LSSDP_FIELD_LEN];
+
         struct {                                            // Location (optional):
             char    prefix              [LSSDP_FIELD_LEN];  // Protocal: "https://" or "http://"
             char    domain              [LSSDP_FIELD_LEN];  // if domain is empty, using Interface IP as default
             char    suffix              [LSSDP_FIELD_LEN];  // URI or Port: "/index.html" or ":80"
         } location;
-
-        /* Additional SSDP Header Fields */
-        char        sm_id       [LSSDP_FIELD_LEN];
-        char        device_type [LSSDP_FIELD_LEN];
     } header;
 
     /* Callback Function */

+ 55 - 0
inc/lssdp_service.h

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: MIT License
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-11     SummerGift   first version
+ */
+ 
+#ifndef __LSSDP_SERVICE_H__
+#define __LSSDP_SERVICE_H__
+
+#include <rtthread.h>
+#include "lssdp.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct lssdp_device
+{
+    unsigned short  port;
+    long            neighbor_timeout;
+
+    char        search_target          [LSSDP_FIELD_LEN];
+    char        unique_service_name    [LSSDP_FIELD_LEN];
+    char        sm_id                  [LSSDP_FIELD_LEN];
+    char        device_type            [LSSDP_FIELD_LEN];
+    char        suffix                 [LSSDP_FIELD_LEN];
+};
+
+struct lssdp_service
+{
+    rt_slist_t list;
+
+    char name[LSSDP_FIELD_LEN];
+
+    uint8_t is_search;
+    uint8_t is_notify;
+
+    struct lssdp_device info;
+};
+typedef struct lssdp_service * lssdp_service_t;
+
+int lssdp_service_add(struct lssdp_service *h);
+int lssdp_service_del(struct lssdp_service *h);
+int lssdp_service_len(void);
+int lssdp_service_send_notify(lssdp_ctx * lssdp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LSSDP_SERVICE_H__ */

+ 56 - 0
samples/lssdp_sample.c

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: MIT License
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-11     SummerGift   first version
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "lssdp_service.h"
+
+#define DBG_SECTION_NAME  "lssdp example"
+#define DBG_LEVEL         DBG_INFO
+#include <rtdbg.h>
+
+// lssdp service add example
+static int lssdp_add_example(void)
+{
+    struct lssdp_service service;
+    char service_name        [LSSDP_FIELD_LEN] = "service_name";                // local service name
+    char search_target       [LSSDP_FIELD_LEN] = "urn:rt-thread:service:ssdp";  // search name in network
+    char unique_service_name [LSSDP_FIELD_LEN] = "unique service name";         // unique service name
+    char sm_id               [LSSDP_FIELD_LEN] = "700000123";                   // device id
+    char device_type         [LSSDP_FIELD_LEN] = "RT-Thread device";            // device type
+    char suffix              [LSSDP_FIELD_LEN] = ":5555";                       // service port
+
+    memcpy(service.name,                      service_name,        LSSDP_FIELD_LEN);
+    memcpy(service.info.search_target,        search_target,       LSSDP_FIELD_LEN);
+    memcpy(service.info.unique_service_name,  unique_service_name, LSSDP_FIELD_LEN);
+    memcpy(service.info.sm_id,                sm_id,               LSSDP_FIELD_LEN);
+    memcpy(service.info.device_type,          device_type,         LSSDP_FIELD_LEN);
+    memcpy(service.info.suffix,               suffix,              LSSDP_FIELD_LEN);
+
+    if (lssdp_service_add(&service) != 0)
+    {
+        LOG_E("service %s add failed!", service_name );
+    }
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT(lssdp_add_example, lssdp add service example);
+
+// lssdp service del example
+static int lssdp_del_example(void)
+{
+    struct lssdp_service service;
+    char service_name[LSSDP_FIELD_LEN] = "service_name";
+    memcpy(service.name,                      service_name,        LSSDP_FIELD_LEN);
+    lssdp_service_del(&service);
+
+    return RT_EOK;
+}
+MSH_CMD_EXPORT(lssdp_del_example, lssdp del service example);

+ 30 - 33
test/daemon.c → src/daemon.c

@@ -2,9 +2,12 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h>     // select
-#include <sys/time.h>   // gettimeofday
+#include <unistd.h>
+#include <sys/time.h>
+#include <dfs_posix.h>
+#include <sys/select.h>
 #include "lssdp.h"
+#include "lssdp_service.h"
 
 /* daemon.c
  *
@@ -32,7 +35,7 @@ void log_callback(const char * file, const char * tag, int level, int line, cons
 }
 
 long long get_current_time() {
-    struct timeval time = {};
+    struct timeval time;
     if (gettimeofday(&time, NULL) == -1) {
         printf("gettimeofday failed, errno = %s (%d)\n", strerror(errno), errno);
         return -1;
@@ -43,16 +46,16 @@ long long get_current_time() {
 int show_neighbor_list(lssdp_ctx * lssdp) {
     int i = 0;
     lssdp_nbr * nbr;
-    puts("\nSSDP List:");
+    printf("\nSSDP List:\n");
     for (nbr = lssdp->neighbor_list; nbr != NULL; nbr = nbr->next) {
         printf("%d. id = %-9s, ip = %-20s, name = %-12s, device_type = %-8s (%lld)\n",
-            ++i,
-            nbr->sm_id,
-            nbr->location,
-            nbr->usn,
-            nbr->device_type,
-            nbr->update_time
-        );
+               ++i,
+               nbr->sm_id,
+               nbr->location,
+               nbr->usn,
+               nbr->device_type,
+               nbr->update_time
+              );
     }
     printf("%s\n", i == 0 ? "Empty" : "");
     return 0;
@@ -60,41 +63,33 @@ int show_neighbor_list(lssdp_ctx * lssdp) {
 
 int show_interface_list_and_rebind_socket(lssdp_ctx * lssdp) {
     // 1. show interface list
-    printf("\nNetwork Interface List (%zu):\n", lssdp->interface_num);
+    printf("\nNetwork Interface List (%u):\n", lssdp->interface_num);
     size_t i;
     for (i = 0; i < lssdp->interface_num; i++) {
-        printf("%zu. %-6s: %s\n",
-            i + 1,
-            lssdp->interface[i].name,
-            lssdp->interface[i].ip
-        );
+        printf("%u. %-6s: %s\n",
+               i + 1,
+               lssdp->interface[i].name,
+               lssdp->interface[i].ip
+              );
     }
     printf("%s\n", i == 0 ? "Empty" : "");
 
     // 2. re-bind SSDP socket
     if (lssdp_socket_create(lssdp) != 0) {
-        puts("SSDP create socket failed");
+        printf("SSDP create socket failed");
         return -1;
     }
 
     return 0;
 }
 
-
-int main() {
+int lssdp_daemon(void) {
     lssdp_set_log_callback(log_callback);
 
     lssdp_ctx lssdp = {
         // .debug = true,           // debug
         .port = 1900,
         .neighbor_timeout = 15000,  // 15 seconds
-        .header = {
-            .search_target       = "ST_P2P",
-            .unique_service_name = "f835dd000001",
-            .sm_id               = "700000123",
-            .device_type         = "DEV_TYPE",
-            .location.suffix     = ":5678"
-        },
 
         // callback
         .neighbor_list_changed_callback     = show_neighbor_list,
@@ -112,7 +107,6 @@ int main() {
         return EXIT_SUCCESS;
     }
 
-    // Main Loop
     for (;;) {
         fd_set fs;
         FD_ZERO(&fs);
@@ -139,11 +133,13 @@ int main() {
         }
 
         // doing task per 5 seconds
-        if (current_time - last_time >= 5000) {
-            lssdp_network_interface_update(&lssdp); // 1. update network interface
-            lssdp_send_msearch(&lssdp);             // 2. send M-SEARCH
-            lssdp_send_notify(&lssdp);              // 3. send NOTIFY
-            lssdp_neighbor_check_timeout(&lssdp);   // 4. check neighbor timeout
+        if (current_time - last_time >= 2000) {
+            lssdp_network_interface_update(&lssdp); // update network interface
+            lssdp_service_send_notify(&lssdp);      // send notify messages to network
+
+//            lssdp_send_msearch(&lssdp);             // 2. send M-SEARCH
+//            lssdp_send_notify(&lssdp);              // 3. send NOTIFY
+//            lssdp_neighbor_check_timeout(&lssdp);   // 4. check neighbor timeout
 
             last_time = current_time;               // update last_time
         }
@@ -151,3 +147,4 @@ int main() {
 
     return EXIT_SUCCESS;
 }
+

+ 86 - 120
lssdp.c → src/lssdp.c

@@ -6,12 +6,13 @@
 #include <errno.h>      // errno
 #include <unistd.h>     // close
 #include <sys/time.h>   // gettimeofday
-#include <sys/ioctl.h>  // ioctl, FIONBIO
-#include <net/if.h>     // struct ifconf, struct ifreq
+#include <dfs_posix.h>  // ioctl, FIONBIO
+#include <sys/select.h>
 #include <fcntl.h>      // fcntl, F_GETFD, F_SETFD, FD_CLOEXEC
 #include <sys/socket.h> // struct sockaddr, AF_INET, SOL_SOCKET, socklen_t, setsockopt, socket, bind, sendto, recvfrom
 #include <netinet/in.h> // struct sockaddr_in, struct ip_mreq, INADDR_ANY, IPPROTO_IP, also include <sys/socket.h>
 #include <arpa/inet.h>  // inet_aton, inet_ntop, inet_addr, also include <netinet/in.h>
+#include <netdev.h>
 #include "lssdp.h"
 
 #ifndef _SIZEOF_ADDR_IFREQ
@@ -19,13 +20,12 @@
 #endif
 
 /** Definition **/
-#define LSSDP_BUFFER_LEN    2048
+#define LSSDP_BUFFER_LEN    512
 #define lssdp_debug(fmt, agrs...) lssdp_log(LSSDP_LOG_DEBUG, __LINE__, __func__, fmt, ##agrs)
 #define lssdp_info(fmt, agrs...)  lssdp_log(LSSDP_LOG_INFO,  __LINE__, __func__, fmt, ##agrs)
 #define lssdp_warn(fmt, agrs...)  lssdp_log(LSSDP_LOG_WARN,  __LINE__, __func__, fmt, ##agrs)
 #define lssdp_error(fmt, agrs...) lssdp_log(LSSDP_LOG_ERROR, __LINE__, __func__, fmt, ##agrs)
 
-
 /** Struct: lssdp_packet **/
 typedef struct lssdp_packet {
     char            method      [LSSDP_FIELD_LEN];      // M-SEARCH, NOTIFY, RESPONSE
@@ -39,7 +39,6 @@ typedef struct lssdp_packet {
     long long       update_time;
 } lssdp_packet;
 
-
 /** Internal Function **/
 static int send_multicast_data(const char * data, const struct lssdp_interface interface, unsigned short ssdp_port);
 static int lssdp_send_response(lssdp_ctx * lssdp, struct sockaddr_in address);
@@ -47,14 +46,13 @@ static int lssdp_packet_parser(const char * data, size_t data_len, lssdp_packet
 static int parse_field_line(const char * data, size_t start, size_t end, lssdp_packet * packet);
 static int get_colon_index(const char * string, size_t start, size_t end);
 static int trim_spaces(const char * string, size_t * start, size_t * end);
-static long long get_current_time();
+static long long get_current_time(void);
 static int lssdp_log(int level, int line, const char * func, const char * format, ...);
 static int neighbor_list_add(lssdp_ctx * lssdp, const lssdp_packet packet);
 static int lssdp_neighbor_remove_all(lssdp_ctx * lssdp);
 static void neighbor_list_free(lssdp_nbr * list);
 static struct lssdp_interface * find_interface_in_LAN(lssdp_ctx * lssdp, uint32_t address);
 
-
 /** Global Variable **/
 static struct {
     const char * MSEARCH;
@@ -89,96 +87,67 @@ static struct {
     .log_callback = NULL
 };
 
-
 // 01. lssdp_network_interface_update
 int lssdp_network_interface_update(lssdp_ctx * lssdp) {
+    
+    int result = -1;
+    const size_t SIZE_OF_INTERFACE_LIST = sizeof(struct lssdp_interface) * LSSDP_INTERFACE_LIST_SIZE;
+
     if (lssdp == NULL) {
         lssdp_error("lssdp should not be NULL\n");
         return -1;
     }
 
-    const size_t SIZE_OF_INTERFACE_LIST = sizeof(struct lssdp_interface) * LSSDP_INTERFACE_LIST_SIZE;
-
     // 1. copy orginal interface
-    struct lssdp_interface original_interface[LSSDP_INTERFACE_LIST_SIZE] = {};
+    struct lssdp_interface original_interface[LSSDP_INTERFACE_LIST_SIZE];
     memcpy(original_interface, lssdp->interface, SIZE_OF_INTERFACE_LIST);
 
     // 2. reset lssdp->interface
     lssdp->interface_num = 0;
     memset(lssdp->interface, 0, SIZE_OF_INTERFACE_LIST);
-
-    int result = -1;
-
-    /* Reference to this article:
-     * http://stackoverflow.com/a/8007079
-     */
-
-    // 3. create UDP socket
-    int fd = socket(AF_INET, SOCK_DGRAM, 0);
-    if (fd < 0) {
-        lssdp_error("create socket failed, errno = %s (%d)\n", strerror(errno), errno);
-        goto end;
-    }
-
-    // 4. get ifconfig
-    char buffer[LSSDP_BUFFER_LEN] = {};
-    struct ifconf ifc = {
-        .ifc_len = sizeof(buffer),
-        .ifc_buf = (caddr_t) buffer
-    };
-
-    if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) {
-        lssdp_error("ioctl SIOCGIFCONF failed, errno = %s (%d)\n", strerror(errno), errno);
-        goto end;
-    }
-
-    // 5. setup lssdp->interface
-    size_t i;
-    struct ifreq * ifr;
-    for (i = 0; i < ifc.ifc_len; i += _SIZEOF_ADDR_IFREQ(*ifr)) {
-        ifr = (struct ifreq *)(buffer + i);
-        if (ifr->ifr_addr.sa_family != AF_INET) {
-            // only support IPv4
-            continue;
+    
+    // 3. get ifconfig
+    extern struct netdev *netdev_default;
+    while(netdev_default == NULL)
+    {
+        rt_thread_mdelay(2000);
+        lssdp_error("Can't find default net device, please check the network driver.\r\n");
+    }
+
+    if(netdev_default != NULL)
+    {
+        // check if network is linkup
+        while(!netdev_is_link_up(netdev_default))
+        {
+            rt_thread_mdelay(2000);
         }
 
-        // 5-1. get interface ip string
-        char ip[LSSDP_IP_LEN] = {};
-        struct sockaddr_in * addr = (struct sockaddr_in *) &ifr->ifr_addr;
-        if (inet_ntop(AF_INET, &addr->sin_addr, ip, sizeof(ip)) == NULL) {
+         // get interface ip string
+        if (inet_ntoa(netdev_default->ip_addr) == NULL) {
             lssdp_error("inet_ntop failed, errno = %s (%d)\n", strerror(errno), errno);
-            continue;
-        }
-
-        // 5-2. get network mask
-        struct ifreq netmask = {};
-        strcpy(netmask.ifr_name, ifr->ifr_name);
-        if (ioctl(fd, SIOCGIFNETMASK, &netmask) != 0) {
-            lssdp_error("ioctl SIOCGIFNETMASK failed, errno = %s (%d)\n", strerror(errno), errno);
-            continue;
+            return -1;
         }
 
-        // 5-3. check network interface number
-        if (lssdp->interface_num >= LSSDP_INTERFACE_LIST_SIZE) {
-            lssdp_warn("interface number is over than MAX SIZE (%d)     %s %s\n", LSSDP_INTERFACE_LIST_SIZE, ifr->ifr_name, ip);
-            continue;
-        }
-
-        // 5-4. set interface
-        size_t n = lssdp->interface_num;
-        snprintf(lssdp->interface[n].name, LSSDP_INTERFACE_NAME_LEN, "%s", ifr->ifr_name); // name
-        snprintf(lssdp->interface[n].ip,   LSSDP_IP_LEN,             "%s", ip);            // ip string
-        lssdp->interface[n].addr = addr->sin_addr.s_addr;                                  // address in network byte order
+        // set interface
+        snprintf(lssdp->interface[lssdp->interface_num].name, LSSDP_INTERFACE_NAME_LEN, "%s", netdev_default->name);                // device name
+        snprintf(lssdp->interface[lssdp->interface_num].ip,   LSSDP_IP_LEN,             "%s", inet_ntoa(netdev_default->ip_addr));  // ip string
+        lssdp->interface[lssdp->interface_num].addr = (uint32_t)netdev_default->ip_addr.addr;                                       // address in network byte order
 
         // set network mask
-        addr = (struct sockaddr_in *) &netmask.ifr_addr;
-        lssdp->interface[n].netmask = addr->sin_addr.s_addr;                               // mask in network byte order
+        lssdp->interface[lssdp->interface_num].netmask = (uint32_t)netdev_default->netmask.addr;  
+        // mask in network byte order
+        lssdp->interface_num = 1;
 
-        // increase interface number
-        lssdp->interface_num++;
+        result = 0;
+    }
+    
+    // 4. create UDP socket
+    int fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (fd < 0) {
+        lssdp_error("create socket failed, errno = %s (%d)\n", strerror(errno), errno);
+        goto end;
     }
 
-    result = 0;
 end:
     // close socket
     if (fd >= 0 && close(fd) != 0) {
@@ -211,6 +180,20 @@ int lssdp_socket_create(lssdp_ctx * lssdp) {
         return -1;
     }
 
+    int result = -1;
+    int opt = 1;
+
+    struct sockaddr_in addr = {
+        .sin_family      = AF_INET,
+        .sin_port        = htons(lssdp->port),
+        .sin_addr.s_addr = htonl(INADDR_ANY)
+    };
+
+    struct ip_mreq imr = {
+        .imr_multiaddr.s_addr = inet_addr(Global.ADDR_MULTICAST),
+        .imr_interface.s_addr = htonl(INADDR_ANY)
+    };
+
     if (lssdp->port == 0) {
         lssdp_error("SSDP port (%d) has not been setup.\n", lssdp->port);
         return -1;
@@ -226,10 +209,8 @@ int lssdp_socket_create(lssdp_ctx * lssdp) {
         return -1;
     }
 
-    int result = -1;
-
     // set non-blocking
-    int opt = 1;
+
     if (ioctl(lssdp->sock, FIONBIO, &opt) != 0) {
         lssdp_error("ioctl FIONBIO failed, errno = %s (%d)\n", strerror(errno), errno);
         goto end;
@@ -241,33 +222,13 @@ int lssdp_socket_create(lssdp_ctx * lssdp) {
         goto end;
     }
 
-    // set FD_CLOEXEC (http://kaivy2001.pixnet.net/blog/post/32726732)
-    int sock_opt = fcntl(lssdp->sock, F_GETFD);
-    if (sock_opt == -1) {
-        lssdp_error("fcntl F_GETFD failed, errno = %s (%d)\n", strerror(errno), errno);
-    } else {
-        // F_SETFD
-        if (fcntl(lssdp->sock, F_SETFD, sock_opt | FD_CLOEXEC) == -1) {
-            lssdp_error("fcntl F_SETFD FD_CLOEXEC failed, errno = %s (%d)\n", strerror(errno), errno);
-        }
-    }
-
     // bind socket
-    struct sockaddr_in addr = {
-        .sin_family      = AF_INET,
-        .sin_port        = htons(lssdp->port),
-        .sin_addr.s_addr = htonl(INADDR_ANY)
-    };
     if (bind(lssdp->sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
         lssdp_error("bind failed, errno = %s (%d)\n", strerror(errno), errno);
         goto end;
     }
 
     // set IP_ADD_MEMBERSHIP
-    struct ip_mreq imr = {
-        .imr_multiaddr.s_addr = inet_addr(Global.ADDR_MULTICAST),
-        .imr_interface.s_addr = htonl(INADDR_ANY)
-    };
     if (setsockopt(lssdp->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &imr, sizeof(struct ip_mreq)) != 0) {
         lssdp_error("setsockopt IP_ADD_MEMBERSHIP failed: %s (%d)\n", strerror(errno), errno);
         goto end;
@@ -327,12 +288,14 @@ int lssdp_socket_read(lssdp_ctx * lssdp) {
         return -1;
     }
 
-    char buffer[LSSDP_BUFFER_LEN] = {};
-    struct sockaddr_in address = {};
+    char buffer[LSSDP_BUFFER_LEN] = {0};
+    struct sockaddr_in address;
     socklen_t address_len = sizeof(struct sockaddr_in);
+    lssdp_packet packet = {0};
 
     ssize_t recv_len = recvfrom(lssdp->sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&address, &address_len);
     if (recv_len == -1) {
+        rt_thread_mdelay(2000);
         lssdp_error("recvfrom fd %d failed, errno = %s (%d)\n", lssdp->sock, strerror(errno), errno);
         return -1;
     }
@@ -346,7 +309,6 @@ int lssdp_socket_read(lssdp_ctx * lssdp) {
     }
 
     // parse SSDP packet to struct
-    lssdp_packet packet = {};
     if (lssdp_packet_parser(buffer, recv_len, &packet) != 0) {
         goto end;
     }
@@ -401,7 +363,7 @@ int lssdp_send_msearch(lssdp_ctx * lssdp) {
     }
 
     // 1. set M-SEARCH packet
-    char msearch[LSSDP_BUFFER_LEN] = {};
+    char msearch[LSSDP_BUFFER_LEN];
     snprintf(msearch, sizeof(msearch),
         "%s"
         "HOST:%s:%d\r\n"
@@ -463,7 +425,7 @@ int lssdp_send_notify(lssdp_ctx * lssdp) {
         }
 
         // set notify packet
-        char notify[LSSDP_BUFFER_LEN] = {};
+        char notify[LSSDP_BUFFER_LEN];
         char * domain = lssdp->header.location.domain;
         snprintf(notify, sizeof(notify),
             "%s"
@@ -562,6 +524,20 @@ void lssdp_set_log_callback(void (* callback)(const char * file, const char * ta
 /** Internal Function **/
 
 static int send_multicast_data(const char * data, const struct lssdp_interface interface, unsigned short ssdp_port) {
+    
+    int result = -1;
+    char opt = 0;
+
+    struct sockaddr_in addr = {
+        .sin_family      = AF_INET,
+        .sin_addr.s_addr = interface.addr
+    };
+
+    struct sockaddr_in dest_addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(ssdp_port)
+    };
+    
     if (data == NULL) {
         lssdp_error("data should not be NULL\n");
         return -1;
@@ -578,7 +554,6 @@ static int send_multicast_data(const char * data, const struct lssdp_interface i
         return -1;
     }
 
-    int result = -1;
 
     // 1. create UDP socket
     int fd = socket(AF_INET, SOCK_DGRAM, 0);
@@ -588,27 +563,18 @@ static int send_multicast_data(const char * data, const struct lssdp_interface i
     }
 
     // 2. bind socket
-    struct sockaddr_in addr = {
-        .sin_family      = AF_INET,
-        .sin_addr.s_addr = interface.addr
-    };
     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
         lssdp_error("bind failed, errno = %s (%d)\n", strerror(errno), errno);
         goto end;
     }
 
     // 3. disable IP_MULTICAST_LOOP
-    char opt = 0;
     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &opt, sizeof(opt)) < 0) {
         lssdp_error("setsockopt IP_MULTICAST_LOOP failed, errno = %s (%d)\n", strerror(errno), errno);
         goto end;
     }
 
     // 4. set destination address
-    struct sockaddr_in dest_addr = {
-        .sin_family = AF_INET,
-        .sin_port = htons(ssdp_port)
-    };
     if (inet_aton(Global.ADDR_MULTICAST, &dest_addr.sin_addr) == 0) {
         lssdp_error("inet_aton failed, errno = %s (%d)\n", strerror(errno), errno);
         goto end;
@@ -629,9 +595,10 @@ end:
 }
 
 static int lssdp_send_response(lssdp_ctx * lssdp, struct sockaddr_in address) {
-    // get M-SEARCH IP
-    char msearch_ip[LSSDP_IP_LEN] = {};
-    if (inet_ntop(AF_INET, &address.sin_addr, msearch_ip, sizeof(msearch_ip)) == NULL) {
+
+    char *msearch_ip = inet_ntoa(address.sin_addr);
+    
+    if (msearch_ip == NULL) {
         lssdp_error("inet_ntop failed, errno = %s (%d)\n", strerror(errno), errno);
         return -1;
     }
@@ -650,7 +617,7 @@ static int lssdp_send_response(lssdp_ctx * lssdp, struct sockaddr_in address) {
     }
 
     // 2. set response packet
-    char response[LSSDP_BUFFER_LEN] = {};
+    char response[LSSDP_BUFFER_LEN];
     char * domain = lssdp->header.location.domain;
     int response_len = snprintf(response, sizeof(response),
         "%s"
@@ -701,7 +668,7 @@ static int lssdp_packet_parser(const char * data, size_t data_len, lssdp_packet
     }
 
     if (data_len != strlen(data)) {
-        lssdp_error("data_len (%zu) is not match to the data length (%zu)\n", data_len, strlen(data));
+        lssdp_error("data_len (%u) is not match to the data length (%u)\n", data_len, strlen(data));
         return -1;
     }
 
@@ -846,7 +813,7 @@ static int trim_spaces(const char * string, size_t * start, size_t * end) {
 }
 
 static long long get_current_time() {
-    struct timeval time = {};
+    struct timeval time;
     if (gettimeofday(&time, NULL) == -1) {
         lssdp_error("gettimeofday failed, errno = %s (%d)\n", strerror(errno), errno);
         return -1;
@@ -859,7 +826,7 @@ static int lssdp_log(int level, int line, const char * func, const char * format
         return -1;
     }
 
-    char message[LSSDP_BUFFER_LEN] = {};
+    char message[LSSDP_BUFFER_LEN];
 
     // create message by va_list
     va_list args;
@@ -911,7 +878,6 @@ static int neighbor_list_add(lssdp_ctx * lssdp, const lssdp_packet packet) {
         goto end;
     }
 
-
     /* location is not found in SSDP list: add to list */
 
     // 1. memory allocate lssdp_nbr

+ 194 - 0
src/lssdp_service.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: MIT License
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-05-11     SummerGift   first version
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <netdev.h>
+#include "lssdp_service.h"
+
+#define DBG_SECTION_NAME  "lssdp service"
+#define DBG_LEVEL         DBG_INFO
+#include <rtdbg.h>
+
+static rt_slist_t _lssdp_list = RT_SLIST_OBJECT_INIT(_lssdp_list);
+
+// register a service to lssdp daemon
+static int lssdp_service_register(struct lssdp_service *h)
+{
+    struct rt_slist_node *head;
+
+    if (h == RT_NULL)
+        return -RT_ERROR;
+    
+    /* enter interrupt */
+    rt_interrupt_enter();
+
+    rt_slist_for_each(head, &_lssdp_list)
+    {
+        if (rt_strcmp(h->name, ((lssdp_service_t)head)->name) == 0)
+        {
+            /* leave interrupt */
+            rt_interrupt_leave();
+
+            LOG_E("service %s is already exists!", h->name );
+            return -RT_ERROR;
+        }
+    }
+
+    rt_slist_init(&h->list);
+    rt_slist_append(&_lssdp_list, &h->list);
+    
+    /* leave interrupt */
+    rt_interrupt_leave();
+
+    return RT_EOK;
+}
+
+// unregister a service to lssdp daemon
+static int lssdp_service_unregister(struct lssdp_service *h)
+{
+    struct rt_slist_node *head;
+
+    if (h == RT_NULL)
+        return -RT_ERROR;
+    
+    /* enter interrupt */
+    rt_interrupt_enter();
+
+    rt_slist_for_each(head, &_lssdp_list)
+    {
+        if (rt_strcmp(h->name, ((lssdp_service_t)head)->name) == 0)
+        {
+            rt_slist_remove(&_lssdp_list, head);
+            
+            /* leave interrupt */
+            rt_interrupt_leave();
+            
+            rt_free(head);
+            return RT_EOK;
+        }
+    }
+    
+    /* leave interrupt */
+    rt_interrupt_leave();
+
+    LOG_E("Can't find service name %s to unregister", h->name);
+
+    return -RT_ERROR;
+}
+
+// add a service to lssdp
+int lssdp_service_add(struct lssdp_service *h)
+{
+    struct lssdp_service *ser;
+
+    if (h == RT_NULL)
+        return -RT_ERROR;
+
+    ser = (struct lssdp_service*) rt_malloc (sizeof(struct lssdp_service));
+    if (ser == NULL)
+    {
+        LOG_E("lssdp_service_add malloc failed!");
+    }
+    else
+    {
+        memset(ser, 0, sizeof(sizeof(struct lssdp_service)));
+    }
+
+    ser->info.port = h->info.port;
+    ser->info.neighbor_timeout = h->info.neighbor_timeout;
+
+    memcpy(ser->name,                      h->name,                      LSSDP_FIELD_LEN);
+    memcpy(ser->info.search_target,        h->info.search_target,        LSSDP_FIELD_LEN);
+    memcpy(ser->info.unique_service_name,  h->info.unique_service_name,  LSSDP_FIELD_LEN);
+    memcpy(ser->info.sm_id,                h->info.sm_id,                LSSDP_FIELD_LEN);
+    memcpy(ser->info.device_type,          h->info.device_type,          LSSDP_FIELD_LEN);
+    memcpy(ser->info.suffix,               h->info.suffix,               LSSDP_FIELD_LEN);
+
+    // if register failed
+    if(lssdp_service_register(ser) != 0)
+    {
+        rt_free(ser);
+        return -RT_ERROR;
+    }
+
+    return RT_EOK;
+}
+
+// del a service from lssdp
+int lssdp_service_del(struct lssdp_service *h)
+{
+    if (h == RT_NULL)
+        return -RT_ERROR;
+
+    if(lssdp_service_unregister(h) == 0)
+    {
+        return RT_EOK;
+    } else {
+        LOG_E("lssdp_service_del service %s failed!", h->name);
+    }
+
+    return RT_EOK;
+}
+
+// get the number of lssdp services
+int lssdp_service_count(void)
+{
+    return rt_slist_len((const rt_slist_t*)(&_lssdp_list));
+}
+
+// send notify messages to network
+int lssdp_service_send_notify(lssdp_ctx * lssdp)
+{
+    struct rt_slist_node *head;
+
+    if (!lssdp)
+        return -RT_ERROR;
+
+    rt_slist_for_each(head, &_lssdp_list)
+    {
+        LOG_D("name: %s ", ((struct lssdp_service *)head)->name);
+
+        if((rt_strcmp(lssdp->header.search_target, ((lssdp_service_t)head)->info.search_target) != 0))
+        {
+            memcpy(lssdp->header.search_target,       ((lssdp_service_t)head)->info.search_target,       LSSDP_FIELD_LEN);
+            memcpy(lssdp->header.unique_service_name, ((lssdp_service_t)head)->info.unique_service_name, LSSDP_FIELD_LEN);
+            memcpy(lssdp->header.sm_id,               ((lssdp_service_t)head)->info.sm_id,               LSSDP_FIELD_LEN);
+            memcpy(lssdp->header.device_type,         ((lssdp_service_t)head)->info.device_type,         LSSDP_FIELD_LEN);
+            memcpy(lssdp->header.location.suffix,     ((lssdp_service_t)head)->info.suffix,              LSSDP_FIELD_LEN);
+        }
+
+        lssdp_send_notify(lssdp);
+    }
+
+    return RT_EOK;
+}
+
+#define THREAD_PRIORITY         10
+#define THREAD_STACK_SIZE       4096
+#define THREAD_TIMESLICE        5
+
+int lssdp_start(void)
+{
+    rt_thread_t tid1 = RT_NULL;
+    extern int lssdp_daemon();
+    tid1 = rt_thread_create("lssdp",
+                            (void (*)(void *))lssdp_daemon, RT_NULL,
+                            THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);
+    if (tid1 != RT_NULL)
+        rt_thread_startup(tid1);
+    else
+        return -1;
+
+    return RT_EOK;
+}
+
+INIT_APP_EXPORT(lssdp_start);

+ 0 - 17
test/Makefile

@@ -1,17 +0,0 @@
-CFLAGS = -g -Wall -I../
-
-OBJS = ../lssdp.o
-
-all: daemon network_interface packet_listener
-
-network_interface: $(OBJS) network_interface.o
-	$(CC) $(CFLAGS) -o $@.exe $@.o $(OBJS)
-
-daemon: $(OBJS) daemon.o
-	$(CC) $(CFLAGS) -o $@.exe $@.o $(OBJS)
-
-packet_listener: $(OBJS) packet_listener.o
-	$(CC) $(CFLAGS) -o $@.exe $@.o $(OBJS)
-
-clean:
-	rm -rf *.o *.exe

+ 0 - 54
test/network_interface.c

@@ -1,54 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>     // sleep
-#include "lssdp.h"
-
-/* network_interface.c
- *
- * 1. call lssdp_network_interface_update per second
- * 2. when network interface is changed, show interface list
- */
-
-void log_callback(const char * file, const char * tag, int level, int line, const char * func, const char * message) {
-    char * level_name = "DEBUG";
-    if (level == LSSDP_LOG_INFO)   level_name = "INFO";
-    if (level == LSSDP_LOG_WARN)   level_name = "WARN";
-    if (level == LSSDP_LOG_ERROR)  level_name = "ERROR";
-
-    printf("[%-5s][%s] %s", level_name, tag, message);
-}
-
-int show_interface_list(lssdp_ctx * lssdp) {
-    printf("\nNetwork Interface List (%zu):\n", lssdp->interface_num);
-    size_t i;
-    for (i = 0; i < lssdp->interface_num; i++) {
-        printf("%zu. %-6s: %-15s (%d.%d.%d.%d)\n",
-            i + 1,
-            lssdp->interface[i].name,
-            lssdp->interface[i].ip,
-            (lssdp->interface[i].netmask >> 0)  & 0xff,
-            (lssdp->interface[i].netmask >> 8)  & 0xff,
-            (lssdp->interface[i].netmask >> 16) & 0xff,
-            (lssdp->interface[i].netmask >> 24) & 0xff
-        );
-    }
-    printf("%s\n", i == 0 ? "Empty" : "");
-    return 0;
-}
-
-int main() {
-    lssdp_set_log_callback(log_callback);
-
-    lssdp_ctx lssdp = {
-        .network_interface_changed_callback = show_interface_list
-    };
-
-    // Main Loop
-    for (;; sleep(1)) {
-        puts(".");
-        lssdp_network_interface_update(&lssdp);
-    }
-
-    return EXIT_SUCCESS;
-}

+ 0 - 125
test/packet_listener.c

@@ -1,125 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>     // select
-#include <sys/time.h>   // gettimeofday
-#include "lssdp.h"
-
-/* packet_listener.c
- *
- * show all SSDP packet payload completely
- *
- * 1. create SSDP socket with port 1900
- * 2. select SSDP socket with timeout 0.5 seconds
- *    - when select return value > 0, invoke lssdp_socket_read
- * 3. update network interface per 5 seconds
- * 4. when network interface is changed
- *    - show interface list
- *    - re-bind the socket
- */
-
-void log_callback(const char * file, const char * tag, int level, int line, const char * func, const char * message) {
-    char * level_name = "DEBUG";
-    if (level == LSSDP_LOG_INFO)   level_name = "INFO";
-    if (level == LSSDP_LOG_WARN)   level_name = "WARN";
-    if (level == LSSDP_LOG_ERROR)  level_name = "ERROR";
-
-    printf("[%-5s][%s] %s", level_name, tag, message);
-}
-
-long long get_current_time() {
-    struct timeval time = {};
-    if (gettimeofday(&time, NULL) == -1) {
-        printf("gettimeofday failed, errno = %s (%d)\n", strerror(errno), errno);
-        return -1;
-    }
-    return (long long) time.tv_sec * 1000 + (long long) time.tv_usec / 1000;
-}
-
-int show_interface_list_and_rebind_socket(lssdp_ctx * lssdp) {
-    // 1. show interface list
-    printf("\nNetwork Interface List (%zu):\n", lssdp->interface_num);
-    size_t i;
-    for (i = 0; i < lssdp->interface_num; i++) {
-        printf("%zu. %-6s: %s\n",
-            i + 1,
-            lssdp->interface[i].name,
-            lssdp->interface[i].ip
-        );
-    }
-    printf("%s\n", i == 0 ? "Empty" : "");
-
-    // 2. re-bind SSDP socket
-    if (lssdp_socket_create(lssdp) != 0) {
-        puts("SSDP create socket failed");
-        return -1;
-    }
-
-    return 0;
-}
-
-int show_ssdp_packet(struct lssdp_ctx * lssdp, const char * packet, size_t packet_len) {
-    printf("%s", packet);
-    return 0;
-}
-
-
-int main() {
-    lssdp_set_log_callback(log_callback);
-
-    lssdp_ctx lssdp = {
-        .port = 1900,
-        // .debug = true,           // debug
-
-        // callback
-        .network_interface_changed_callback = show_interface_list_and_rebind_socket,
-        .packet_received_callback           = show_ssdp_packet
-    };
-
-    /* get network interface at first time, network_interface_changed_callback will be invoke
-     * SSDP socket will be created in callback function
-     */
-    lssdp_network_interface_update(&lssdp);
-
-    long long last_time = get_current_time();
-    if (last_time < 0) {
-        printf("got invalid timestamp %lld\n", last_time);
-        return EXIT_SUCCESS;
-    }
-
-    // Main Loop
-    for (;;) {
-        fd_set fs;
-        FD_ZERO(&fs);
-        FD_SET(lssdp.sock, &fs);
-        struct timeval tv = {
-            .tv_usec = 500 * 1000   // 500 ms
-        };
-
-        int ret = select(lssdp.sock + 1, &fs, NULL, NULL, &tv);
-        if (ret < 0) {
-            printf("select error, ret = %d\n", ret);
-            break;
-        }
-
-        if (ret > 0) {
-            lssdp_socket_read(&lssdp);
-        }
-
-        // get current time
-        long long current_time = get_current_time();
-        if (current_time < 0) {
-            printf("got invalid timestamp %lld\n", current_time);
-            break;
-        }
-
-        // doing task per 5 seconds
-        if (current_time - last_time >= 5000) {
-            lssdp_network_interface_update(&lssdp); // update network interface
-            last_time = current_time;               // update last_time
-        }
-    }
-
-    return EXIT_SUCCESS;
-}

+ 97 - 0
tools/ssdp_server.py

@@ -0,0 +1,97 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import socket
+
+SSDP_ADDR    = '239.255.255.250'
+SSDP_PORT    =  1900
+SERVICE_NAME = "urn:rt-thread:service:ssdp"
+
+class Connection():
+    def __init__(self, s, data, addr):
+        self.__s = s
+        self.__data = data
+        self.__addr = addr
+        self.is_find_service = False
+
+    def handle_request(self):
+        if self.__data.startswith('NOTIFY * HTTP/1.1\r\n'):
+            self.__handle_notify()
+
+    def __handle_notify(self):
+        props = self.__parse_props(['HOST'])
+
+        if isinstance(props, dict):
+            if props.has_key('NT') and props['NT'] == SERVICE_NAME:
+                print("NT        : %s"%props['NT'])
+                print("SM_ID     : %s"%props['SM_ID'])
+                print("DEV_TYPE  : %s"%props['DEV_TYPE'])
+                print("USN       : %s"%props['USN'])
+                print("HOST      : %s"%props['HOST'])
+                print("LOCATION  : %s\r\n"%props['LOCATION'])
+
+    def __parse_props(self, target_keys):
+        lines = self.__data.split('\r\n')
+
+        props = {}
+        for i in range(1, len(lines)):
+            if not lines[i]:
+                continue
+
+            index = lines[i].find(':')
+            if index == -1:
+                return None
+
+            props[lines[i][:index]] = lines[i][index + 1:].strip()
+
+        if not set(target_keys).issubset(set(props.keys())):
+            return None
+
+        return props
+
+class SSDPServer():
+    def __init__(self):
+        self.__s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        self.__s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+        def get_address():
+            try:
+                address = socket.gethostbyname(socket.gethostname())
+            except:
+                address = ''
+            if not address or address.startswith('127.'):
+                # ...the hard way.
+                s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+                s.connect(('1.1.1.1', 0))
+                address = s.getsockname()[0]
+            return address
+
+        local_ip = get_address()
+        any_ip = '0.0.0.0'
+
+        self.__s.bind((any_ip, SSDP_PORT))
+
+        # self.__s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
+        # self.__s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
+        # self.__s.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
+        # socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
+
+        self.__s.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
+                            socket.inet_aton(SSDP_ADDR) + socket.inet_aton(local_ip))
+        self.local_ip = local_ip
+
+    def start(self):
+
+        print("The SSDP service has been started.\n")
+
+        while True:
+            data, addr = self.__s.recvfrom(2048)
+            conn = Connection(self.__s, data, addr)
+            conn.handle_request()
+        self.__s.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP,
+                            socket.inet_aton(SSDP_ADDR) + socket.inet_aton(self.local_ip))
+        self.__s.close()
+
+if __name__ == '__main__':
+    port = SSDPServer()
+    port.start()