I2C ext_flag解析

关于I2C 传输前,通常会遇到这样的设置:

struct i2c_client * client;

client->ext_flag = client->ext_flag | I2C_DMA_FLAG;

ret = i2c_master_send(client,pData,lens);

......

i2c传输前需要对 client->ext_flag 做设定,或上相关标志,各个flag解释如下:

 I2C_DMA_FLAG
–开启DMA传输,default 为fifo mode传输
I2C_WR_FLAG
 –Enable write and read tranfer mode, Must set I2C_RS_FLAG ,Don’t support in DMA mode
I2C_RS_FLAG  
 –Enable REPEATED-START
I2C_HS_FLAG 
–Enable high speed mode,default 为低速和快速
 I2C_PUSHPULL_FLAG
–使能pushpull mode,default 为open drain
I2C_ENEXT_FLAG 
–Allows slaves to hold the SCL line low if it is not yet ready for further processing ,Open open-drain mode of the SCL line

遇到标志:

client->ext_flag = client->ext_flag | I2C_A_FILTER_MSG;

其中该标记作用是移除i2c ack error。定义路径:工程代码/kernel/include/linux/i2c.h

#define I2C_A_FILTER_MSG    0x8000    /* filer out error messages    */
#define I2C_A_CHANGE_TIMING    0x4000    /* change timing paramters    */
#define I2C_MASK_FLAG    (0x00ff)
#define I2C_DMA_FLAG    (0x2000)
#define I2C_WR_FLAG        (0x1000)
#define I2C_RS_FLAG        (0x0800)
#define I2C_HS_FLAG   (0x0400)
#define I2C_ENEXT_FLAG (0x0200)
#define I2C_DISEXT_FLAG (0x0000)
#define I2C_POLL_FLAG (0x4000)
#define I2C_CH2_FLAG    (0x8000)

#define I2C_POLLING_FLAG (0x00000001)
#define I2C_PUSHPULL_FLAG (0x00000002)
#define I2C_3DCAMERA_FLAG (0x00000004)
#define I2C_DIRECTION_FLAG (0x00000008)



但是/** * @file tx_limit_table.c * @brief Auto-generated TX power limit data in full CLM locale initializer format * Matches exactly: "/* Locale DEFAULT */" style with channel_set, eirp fallback, and tx limits * @generated 2025-11-02 19:12:03 */ /* ====== NORMAL MODES (non-HT) ====== */ /* Locale 2_4G */ CHANNEL_SET_1, 0, /*Auto-generated fallback for 2G band, locale flags */ RESTRICTED_SET_NONE, /* Restricted channels */ CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_EIRP, 1, /* regulatory channel limit element(s) */ 30, RANGE_2G_20M_1_11, /* 30dBm CH1-11 */ CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_COND, 4, /* 4 TX limit element(s) for 20MHz */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_20M_11g, /* 22.0dBm, CH1 */ 102, RANGE_2G_20M_1_11, RATE_SET_2G_20M_11b, /* 24.0dBm, CH1-11 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_20M_11g, /* 24.0dBm, CH2-10 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_20M_11g, /* 22.0dBm, CH11 */ /* ====== HT EXTENDED MODES ====== */ /* Locale 2_4G_HT */ // Total TX Limit Elements: 93 CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_MORE, 16, /* 16 TX limit element(s) */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_11g, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_11n, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_11ac, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_11ax, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_11be, /* 22.00dBm, CH1 */ 102, RANGE_2G_20M_1_11, RATE_SET_2G_HT_20M_11b, /* 24.00dBm, CH1-11 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_11g, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_11n, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_11ac, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_11ax, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_11be, /* 24.00dBm, CH2-10 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_11g, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_11n, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_11ac, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_11ax, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_11be, /* 22.00dBm, CH11 */ CLM_DATA_FLAG_WIDTH_40 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_MORE, 15, /* 15 TX limit element(s) */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_11g, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_11n, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_11ac, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_11ax, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_11be, /* 21.00dBm, CH3 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_11g, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_11n, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_11ac, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_11ax, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_11be, /* 22.00dBm, CH4-8 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_11g, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_11n, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_11ac, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_11ax, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_11be, /* 19.50dBm, CH9 */ CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_FLAG2, CLM_DATA_FLAG2_RATE_TYPE_EXT, 16, /* 16 TX limit element(s) */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT_11g, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT_11n, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT_11ac, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT_11ax, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT_11be, /* 22.00dBm, CH1 */ 102, RANGE_2G_20M_1_11, RATE_SET_2G_HT_20M_EXT_11b, /* 24.00dBm, CH1-11 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT_11g, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT_11n, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT_11ac, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT_11ax, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT_11be, /* 24.00dBm, CH2-10 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT_11g, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT_11n, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT_11ac, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT_11ax, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT_11be, /* 22.00dBm, CH11 */ CLM_DATA_FLAG_WIDTH_40 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_FLAG2, CLM_DATA_FLAG2_RATE_TYPE_EXT, 15, /* 15 TX limit element(s) */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT_11g, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT_11n, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT_11ac, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT_11ax, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT_11be, /* 21.00dBm, CH3 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT_11g, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT_11n, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT_11ac, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT_11ax, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT_11be, /* 22.00dBm, CH4-8 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT_11g, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT_11n, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT_11ac, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT_11ax, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT_11be, /* 19.50dBm, CH9 */ CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_FLAG2, CLM_DATA_FLAG2_RATE_TYPE_EXT4, 16, /* 16 TX limit element(s) */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT4_11g, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT4_11n, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT4_11ac, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT4_11ax, /* 22.00dBm, CH1 */ 94, RANGE_2G_20M_1_1, RATE_SET_2G_HT_20M_EXT4_11be, /* 22.00dBm, CH1 */ 102, RANGE_2G_20M_1_11, RATE_SET_2G_HT_20M_EXT4_11b, /* 24.00dBm, CH1-11 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT4_11g, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT4_11n, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT4_11ac, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT4_11ax, /* 24.00dBm, CH2-10 */ 102, RANGE_2G_20M_2_10, RATE_SET_2G_HT_20M_EXT4_11be, /* 24.00dBm, CH2-10 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT4_11g, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT4_11n, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT4_11ac, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT4_11ax, /* 22.00dBm, CH11 */ 94, RANGE_2G_20M_11_11, RATE_SET_2G_HT_20M_EXT4_11be, /* 22.00dBm, CH11 */ CLM_DATA_FLAG_WIDTH_40 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_FLAG2, CLM_DATA_FLAG2_RATE_TYPE_EXT4, 15, /* 15 TX limit element(s) */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT4_11g, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT4_11n, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT4_11ac, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT4_11ax, /* 21.00dBm, CH3 */ 90, RANGE_2G_40M_3_3, RATE_SET_2G_HT_40M_EXT4_11be, /* 21.00dBm, CH3 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT4_11g, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT4_11n, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT4_11ac, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT4_11ax, /* 22.00dBm, CH4-8 */ 94, RANGE_2G_40M_4_8, RATE_SET_2G_HT_40M_EXT4_11be, /* 22.00dBm, CH4-8 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT4_11g, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT4_11n, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT4_11ac, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT4_11ax, /* 19.50dBm, CH9 */ 84, RANGE_2G_40M_9_9, RATE_SET_2G_HT_40M_EXT4_11be, /* 19.50dBm, CH9 */ 这里CLM_DATA_FLAG_WIDTH_20 | CLM_DATA_FLAG_MEAS_COND | CLM_DATA_FLAG_FLAG2, CLM_DATA_FLAG2_RATE_TYPE_EXT,还不是最后应该模块就没加more,导致后面没有读取
最新发布
11-03
仿照这个#ifdef CFG_DEVMGR_MASTER #include <uci.h> #include <uci_blobmsg.h> #include "api_config.h" #include "devmgr_dev_api.h" #include "devmgr_config.h" #include "devmgr_global.h" #include "devmgr_dev_ctrl.h" #include "tapo_error.h" #define P2PD_PORT 929 static int tcp_connect_local_server(int port) { struct sockaddr_in serv_addr; int fd = -1; fd = socket(AF_INET, SOCK_STREAM, 0); if(-1 == fd) { goto end; } bzero(&serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr); if (connect(fd, (const struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { goto error_end; } goto end; error_end: close(fd); fd = -1; end: return fd; } static int send_and_recv_p2pd_msg(char *msg, int len, char *out, int outlen) { int fd = -1; struct timeval send_timeout = {1, 0}; struct timeval recv_timeout = {3, 0}; int rlen = 0; fd = tcp_connect_local_server(P2PD_PORT); if (fd < 0) { DBG_ERR("connect p2pd error"); return -1; } setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void *)&send_timeout, sizeof(struct timeval)); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&recv_timeout, sizeof(struct timeval)); write(fd, msg, strlen(msg)); memset(out, 0, outlen); rlen = read(fd, out, outlen - 1); close(fd); return (rlen > 0) ? 0 : -1; } static int api_p2p_request_p2p( struct ubus_app *uapp, struct blob_buf* bBuf, struct blob_attr *msg) { DM_PRINT("in api_p2p_request_p2p\n"); int err = SLP_ENONE; struct blob_buf b = {0}; struct ubus_app_ext *uapp_ext = container_of(uapp, struct ubus_app_ext, uapp); struct dev_node *dev = (struct dev_node *)uapp_ext->arg; char *msg_ptr = NULL; char out[256] = {0}; void *table = NULL; if (!dev || !msg) { return -1; } blobmsg_add_string(bBuf, "method", "request_p2p"); table = blobmsg_open_table(bBuf, "result"); struct blobmsg ( blobmsg_string pub_ip, blobmsg_int32 pub_port, blobmsg_string stun_url, blobmsg_string pri_ip, blobmsg_int32 nat_type, blobmsg_int32 pri_port, )(req, msg, false); if (!req.pub_ip || !req.pub_port || !req.stun_url || !req.pri_ip || !req.nat_type || !req.pri_port) { DBG_ERR( "request_p2p format blobmsg err\n"); err = IPC_INTF_PARA_ERR; goto error_leave; } blobmsg_buf_init(&b); blobmsg_add_string(&b, "request", "prepare_p2p"); void *tb1 = NULL; void *tb2 = NULL; tb1 = blobmsg_open_table(&b, "params"); if(tb1) { blobmsg_add_string(&b, "deviceId", dev->devid); blobmsg_add_string(&b, "stun_url", blobmsg_get_string(req.stun_url)); blobmsg_add_u32(&b, "nat_type", blobmsg_get_u32(req.nat_type)); tb2 = blobmsg_open_table(&b, "peer_addr"); if(tb2) { blobmsg_add_string(&b, "pub_ip", blobmsg_get_string(req.pub_ip)); blobmsg_add_u32(&b, "pub_port", blobmsg_get_u32(req.pub_port)); blobmsg_add_string(&b, "pri_ip", blobmsg_get_string(req.pri_ip)); blobmsg_add_u32(&b, "pri_port", blobmsg_get_u32(req.pri_port)); blobmsg_close_table(&b, tb2); } blobmsg_close_table(&b, tb1); } msg_ptr = blobmsg_format_json(b.head, TRUE); send_and_recv_p2pd_msg(msg_ptr, strlen(msg_ptr), out, sizeof(out)); blob_buf_init(&b, 0); if (!blobmsg_add_json_from_string(&b, out)){ err = SLP_ESYSTEM; DBG_ERR("blobmsg_add_json_from_string fail\n"); goto fail; } struct blobmsg ( blobmsg_int32 error_code, blobmsg_table result, )(resp,b.head,false); if (!resp.error_code){ err = SLP_ESYSTEM; DBG_ERR("data.error_code is null\n"); goto fail; } else { err = blobmsg_get_u32(resp.error_code); } if(resp.result) { struct blobmsg ( blobmsg_int32 is_ready, blobmsg_string sid, blobmsg_table dev_addr, blobmsg_int32 nat_type, )(re,resp.result,false); if (re.is_ready){ blobmsg_add_u32(bBuf, "is_ready", blobmsg_get_u32(re.is_ready)); }else { DBG_ERR("data.is_ready is null\n"); } if (re.sid){ blobmsg_add_string(bBuf, "sid", blobmsg_get_string(re.sid)); }else { DBG_ERR("data.sid is null\n"); } if (re.dev_addr){ struct blobmsg ( blobmsg_string pub_ip, blobmsg_int32 pub_port, blobmsg_string pri_ip, blobmsg_int32 pri_port, )(rep,re.dev_addr,false); if (rep.pub_ip){ blobmsg_add_string(bBuf, "pub_ip", blobmsg_get_string(rep.pub_ip)); }else { DBG_ERR("rep.pub_ip is null\n"); } if (rep.pub_port){ blobmsg_add_u32(bBuf, "pub_port", blobmsg_get_u32(rep.pub_port)); }else { DBG_ERR("rep.pub_port is null\n"); } if (rep.pri_ip){ blobmsg_add_string(bBuf, "pri_ip", blobmsg_get_string(rep.pri_ip)); }else { DBG_ERR("rep.pri_ip is null\n"); } if (rep.pri_port){ blobmsg_add_u32(bBuf, "pri_port", blobmsg_get_u32(rep.pri_port)); }else { DBG_ERR("rep.pri_port is null\n"); } }else { DBG_ERR("data.dev_addr is null\n"); } if (re.nat_type){ blobmsg_add_u32(bBuf, "nat_type", blobmsg_get_u32(re.nat_type)); }else { DBG_ERR("data.nat_type is null\n"); } }else { err = SLP_ESYSTEM; DBG_ERR("parse response result error\n"); goto fail; } fail: free(msg_ptr); error_leave: blob_buf_free(&b); if (table) { blobmsg_close_table(bBuf, table); } blobmsg_add_u32(bBuf, "error_code", err); return 0; } static int api_p2p_is_p2p_ready( struct ubus_app *uapp, struct blob_buf* bBuf, struct blob_attr *msg) { DM_PRINT("in api_p2p_request_p2p\n"); int err = DEVICE_OK; struct blob_buf b = {0}; struct ubus_app_ext *uapp_ext = container_of(uapp, struct ubus_app_ext, uapp); struct dev_node *dev = (struct dev_node *)uapp_ext->arg; char *msg_ptr = NULL; char out[256] = {0}; void *table = NULL; if (!dev || !msg) { return -1; } blobmsg_add_string(bBuf, "method", "is_p2p_ready"); table = blobmsg_open_table(bBuf, "result"); struct blobmsg ( blobmsg_string sid, )(req, msg, false); if (!req.sid) { DBG_ERR( "is_p2p_ready format blobmsg err\n"); err = DEVICE_PARAM_ERR; goto error_leave; } blobmsg_buf_init(&b); blobmsg_add_string(&b, "request", "is_p2p_ready"); void *tb1 = blobmsg_open_table(&b, "params"); if(tb1) { blobmsg_add_string(&b, "sid", blobmsg_get_string(req.sid)); blobmsg_close_table(&b, tb1); } msg_ptr = blobmsg_format_json(b.head, TRUE); send_and_recv_p2pd_msg(msg_ptr, strlen(msg_ptr), out, sizeof(out)); blobmsg_buf_init(&b); if (!blobmsg_add_json_from_string(&b, out)){ err = DEVICE_PARAM_ERR; DBG_ERR("blobmsg_add_json_from_string fail\n"); goto fail; } struct blobmsg ( blobmsg_int32 error_code, blobmsg_string error_msg, blobmsg_table result, )(resp,b.head,false); if (!resp.error_code){ err = P2P_P2PD_RESPONSE_ERROR; DBG_ERR("data.error_code is null\n"); goto fail; } else { err = blobmsg_get_u32(resp.error_code); } if(resp.result) { struct blobmsg ( blobmsg_int32 is_ready, blobmsg_string sid, blobmsg_table dev_addr, blobmsg_int32 nat_type, )(re,resp.result,false); if (re.is_ready){ blobmsg_add_u32(bBuf, "is_ready", blobmsg_get_u32(re.is_ready)); }else { DBG_ERR("data.is_ready is null\n"); } if (re.sid){ blobmsg_add_string(bBuf, "sid", blobmsg_get_string(re.sid)); }else { DBG_ERR("data.sid is null\n"); } if (re.dev_addr){ struct blobmsg ( blobmsg_string pub_ip, blobmsg_int32 pub_port, blobmsg_string pri_ip, blobmsg_int32 pri_port, )(rep,re.dev_addr,false); if (rep.pub_ip){ blobmsg_add_string(bBuf, "pub_ip", blobmsg_get_string(rep.pub_ip)); }else { DBG_ERR("rep.pub_ip is null\n"); } if (rep.pub_port){ blobmsg_add_u32(bBuf, "pub_port", blobmsg_get_u32(rep.pub_port)); }else { DBG_ERR("rep.pub_port is null\n"); } if (rep.pri_ip){ blobmsg_add_string(bBuf, "pri_ip", blobmsg_get_string(rep.pri_ip)); }else { DBG_ERR("rep.pri_ip is null\n"); } if (rep.pri_port){ blobmsg_add_u32(bBuf, "pri_port", blobmsg_get_u32(rep.pri_port)); }else { DBG_ERR("rep.pri_port is null\n"); } }else { DBG_ERR("data.dev_addr is null\n"); } if (re.nat_type){ blobmsg_add_u32(bBuf, "nat_type", blobmsg_get_u32(re.nat_type)); }else { DBG_ERR("data.nat_type is null\n"); } }else { err = P2P_P2PD_RESPONSE_ERROR; DBG_ERR("parse response result error\n"); goto fail; } fail: free(msg_ptr); error_leave: blob_buf_free(&b); if (table) { blobmsg_close_table(bBuf, table); } blobmsg_add_u32(bBuf, "error_code", err); return 0; } struct cmd_handler tapo_api_tapo_p2p[] = { { DEVCTL_CMD_S, "request_p2p", api_p2p_request_p2p }, { DEVCTL_CMD_G, "is_p2p_ready", api_p2p_is_p2p_ready }, {DEVCTL_CMD_N, NULL, NULL} }; DEVMGR_CMD_ADD( tapo_api, tapo_p2p, // name "p2p", // domain "", // config tapo_api_tapo_p2p ); #endif改写 /****************************************************************************** * * Copyright (c) 2018 TP-LINK Technologies CO.,LTD. * All rights reserved. * * FILE NAME : upnpc_web.c * VERSION : 1.0 * DESCRIPTION : web界面操作upnp条目,刷新web upnp界面的显示状态 * * AUTHOR : Deng Peng (dengpeng@tp-link.com.cn) * CREATE DATE : 05/07/2019 * * HISTORY : * 01 05/07/2019 Deng Peng Create. * ******************************************************************************/ #include <arpa/inet.h> /* for AF_INET */ #include <string.h> /* for memset() */ #include <sys/time.h> #include <stdlib.h> #include "nsd_common.h" #include "slp_model.h" #include "upnpc.h" #include "port_mapping.h" #include "dms_tool.h" #ifdef UPNPC_ENABLE #define DEFAULT_HTTP_PORT 80 #define DEFAULT_RTSP_PORT 554 #define DEFAULT_VHTTPD_PORT 8080 #define DEFAULT_ONVIF_PORT 2020 #define HTTPS_SERVER_PORT 8443 #ifdef WEBRTC_SUPPORT #define PORT_MAX_LENGTH 6 const U16 webrtc_server_port[] = {64444, 64445, 64446, 64447, 64448};//最大拉流数为5,所以定义好5个内部端口 //最大拉流数为5,定义好5个和路由器交互的str const char description_upnpc_webrtc_str[][DESCRIPTION_UPNPC_WEBRTC_STR_LENGTH] = {"webrtc_1", "webrtc_2", "webrtc_3", "webrtc_4" ,"webrtc_5"}; #define PORT_INTERVAL 100 #endif #define CONFLICT_MAPPING_ENTRY_ERROR_CODE 718 #define NO_SUCH_ENTRY_ERROR_CODE 714 #define CHECK_PORT_MAPPING_STATUS_INTERVAL 60*3 /* 定时查询特定条目间隔时间 */ LOCAL S32 g_check_timer = -1; BOOL g_upnpc_uhttpd_mapped = FALSE; /* 当前的uhttpd条目是否已生效 */ BOOL g_upnpc_rtsp_mapped = FALSE; /* 当前的rtsp条目是否已生效 */ BOOL g_upnpc_vhttpd_mapped = FALSE; /* 当前的vhttpd条目是否已生效 */ #ifdef WEBRTC_SUPPORT BOOL g_upnpc_webrtc_mapped[CLIENTS_CONN_MAX];/* 当前的webrtc条目是否已生效 */ #endif LOCAL U16 cur_added_uhttpd_ext_port = 0; /* 当前生效的uhttpd外部端口号 */ LOCAL U16 cur_added_rtsp_ext_port = 0; /* 当前生效的rtsp外部端口号 */ LOCAL U16 cur_added_vhttpd_ext_port = 0; /* 当前生效的vhttpd外部端口号*/ #ifdef WEBRTC_SUPPORT LOCAL U16 cur_added_webrtc_ext_port[CLIENTS_CONN_MAX];/* 当前生效的webrtc外部端口号*/ #endif LINK_STATUS s_link_status = {0}; LOCAL void upnpc_add_entry(U16 external_port, U16 internal_port, const char * desc, upnp_action_done_cb upnp_action_done_handle #ifdef WEBRTC_SUPPORT , BOOL is_udp #endif ); LOCAL void upnpc_delete_entry(U16 external_port, const char * desc, upnp_action_done_cb upnp_action_done_handle #ifdef WEBRTC_SUPPORT , BOOL is_udp #endif ); LOCAL S32 upnpc_add_entry_done_cb(UPNP_ENTYR_INFO *info); LOCAL S32 upnpc_delete_entry_done_cb(UPNP_ENTYR_INFO *info); LOCAL S32 upnpc_delete_conflict_entry_done_cb(UPNP_ENTYR_INFO *info); LOCAL void upnpc_timer(S32 param); LOCAL void upnpc_save_pub_ip(dms_handler_t *handler, U8 *mbuf, U32 mlen, U32 sender_dms_id) { if (!handler || !mbuf) { UPNPC_ERROR("upnpc_save_pub_ip input nullptr!"); return ; } UPNPC_PUB_IP *event = (UPNPC_PUB_IP*)mbuf; save_pub_ip(event->pub_ip,strlen(event->pub_ip)); return; } #define MAX_PORT 30000 #define MIN_PORT 10000 /*生成范围在MIN_PORT - MAX_PORT之间的随机端口号并返回*/ LOCAL U16 generate_external_mapping_port() { srand((U16)time(NULL)); return (rand() % (MAX_PORT - MIN_PORT + 1) + MIN_PORT); } #ifdef WEBRTC_SUPPORT #define WEBRTC_MAX_PORT 50000 #define WEBRTC_MIN_PORT 30000 LOCAL U16 webrtc_generate_external_mapping_port() { srand((U16)time(NULL)); return (rand() % (WEBRTC_MAX_PORT - WEBRTC_MIN_PORT + 1) + WEBRTC_MIN_PORT); } #endif LOCAL S32 upnpc_add_entry_done_cb(UPNP_ENTYR_INFO *info) { const char *desc = NULL; if (NULL == info) { UPNPC_ERROR("info is null"); return ERROR; } if (info->action != PORT_MAPPING_ACTION_ADD) { UPNPC_ERROR("invalid action[%d]", info->action); return ERROR; } if (UPNPC_ENTRY_FLAG_UHTTPD != info->entry_flag && UPNPC_ENTRY_FLAG_RTSP != info->entry_flag && UPNPC_ENTRY_FLAG_VHTTPD != info->entry_flag #ifdef WEBRTC_SUPPORT && UPNPC_ENTRY_FLAG_WEBRTC_1 != info->entry_flag && UPNPC_ENTRY_FLAG_WEBRTC_2 != info->entry_flag && UPNPC_ENTRY_FLAG_WEBRTC_3 != info->entry_flag && UPNPC_ENTRY_FLAG_WEBRTC_4 != info->entry_flag && UPNPC_ENTRY_FLAG_WEBRTC_5 != info->entry_flag #endif ) { UPNPC_ERROR("invalid entry_flag[%d]", info->entry_flag); return ERROR; } /* 如果添加失败 */ if (FALSE == info->action_successed) { /* 如果添加失败的原因是“条目冲突”,则尝试删除旧条目后再次添加 */ if (CONFLICT_MAPPING_ENTRY_ERROR_CODE == info->error_code) { if (UPNPC_ENTRY_FLAG_UHTTPD == info->entry_flag) { desc = DESCRIPTION_UPNPC_UHTTPD_STR; } else if (UPNPC_ENTRY_FLAG_RTSP == info->entry_flag) { desc = DESCRIPTION_UPNPC_RTSP_STR; } else if (UPNPC_ENTRY_FLAG_VHTTPD == info->entry_flag) { desc = DESCRIPTION_UPNPC_VHTTPD_STR; } #ifdef WEBRTC_SUPPORT else { BOOL find_flag = FALSE; for (int i = 0; i < CLIENTS_CONN_MAX; i++) { if ((UPNPC_ENTRY_FLAG_WEBRTC_1 + i) == info->entry_flag) { desc = description_upnpc_webrtc_str[i]; find_flag = TRUE; break; } } if (!find_flag) { UPNPC_INFO("ENTRY FLAG ERROR!"); return ERROR; } } #else else { UPNPC_INFO("ENTRY FLAG ERROR!"); return ERROR; } #endif UPNPC_INFO("the to be added entry is confilict, delete it and try again."); delete_port_mapping(info->external_port, info->protocol, desc, upnpc_delete_conflict_entry_done_cb); return OK; } else { UPNPC_INFO("error_code:%d", info->error_code); return OK; } } if (UPNPC_ENTRY_FLAG_UHTTPD == info->entry_flag) { cur_added_uhttpd_ext_port = info->external_port; g_upnpc_uhttpd_mapped = TRUE; } else if(UPNPC_ENTRY_FLAG_RTSP == info->entry_flag) { cur_added_rtsp_ext_port = info->external_port; g_upnpc_rtsp_mapped = TRUE; } else if(UPNPC_ENTRY_FLAG_VHTTPD == info->entry_flag) { cur_added_vhttpd_ext_port = info->external_port; g_upnpc_vhttpd_mapped = TRUE; } #ifdef WEBRTC_SUPPORT else { BOOL find_flag = FALSE; for (int i = 0; i < CLIENTS_CONN_MAX; i++) { if ((UPNPC_ENTRY_FLAG_WEBRTC_1 + i) == info->entry_flag) { cur_added_webrtc_ext_port[i] = info->external_port; g_upnpc_webrtc_mapped[i] = TRUE; UPNPC_RTC_PORT port = {{0}, {0}}; sprintf(port.rtc_port, "%d", cur_added_webrtc_ext_port[i]); sprintf(port.inner_port, "%d", webrtc_server_port[i]); msg_send(UPNPC_SAVE_RTC_PORT_MSG_MID, (U8 *)&port, sizeof(UPNPC_RTC_PORT)); find_flag = TRUE; break; } } if (!find_flag) { UPNPC_ERROR("info->entry_flag error = %d", info->entry_flag); return ERROR; } } #else else { UPNPC_ERROR("info->entry_flag error = %d", info->entry_flag); return ERROR; } #endif add_web_entry_record(info->external_port, info->internal_port, info->protocol, info->description); return OK; } LOCAL S32 upnpc_delete_entry_done_cb(UPNP_ENTYR_INFO *info) { if (NULL == info) { UPNPC_ERROR("info is null"); return ERROR; } if (info->action != PORT_MAPPING_ACTION_DELETE) { UPNPC_ERROR("invalid action[%d]", info->action); return ERROR; } if (info->action_successed || NO_SUCH_ENTRY_ERROR_CODE == info->error_code) { if (UPNPC_ENTRY_FLAG_UHTTPD == info->entry_flag) { cur_added_uhttpd_ext_port = 0; g_upnpc_uhttpd_mapped = FALSE; } else if (UPNPC_ENTRY_FLAG_RTSP == info->entry_flag) { cur_added_rtsp_ext_port = 0; g_upnpc_rtsp_mapped = FALSE; } else if (UPNPC_ENTRY_FLAG_VHTTPD == info->entry_flag) { cur_added_vhttpd_ext_port = 0; g_upnpc_vhttpd_mapped = FALSE; } #ifdef WEBRTC_SUPPORT else { BOOL find_flag = FALSE; for (int i = 0; i < CLIENTS_CONN_MAX; i++) { if ((UPNPC_ENTRY_FLAG_WEBRTC_1 + i) == info->entry_flag) { cur_added_webrtc_ext_port[i] = 0; g_upnpc_webrtc_mapped[i] = FALSE; UPNPC_RTC_PORT port = {{0}, {0}}; sprintf(port.rtc_port, "%d", cur_added_webrtc_ext_port[i]); sprintf(port.inner_port, "%d", webrtc_server_port[i]); msg_send(UPNPC_SAVE_RTC_PORT_MSG_MID, (U8 *)&port, sizeof(UPNPC_RTC_PORT)); find_flag = TRUE; break; } } if (!find_flag) { UPNPC_ERROR("invalid entry_flag!"); return ERROR; } } #else else { UPNPC_ERROR("invalid entry_flag!"); return ERROR; } #endif } return OK; } LOCAL S32 add_uhttpd_entry_from_config(PORT_MAPPING_PROTOCOL_TYPE protocol) { UPNPC_INFO upnpc_info; UPNPC_UHTTPD upnpc_uhttpd; UHTTPD_MAIN uhttpd; U16 ext_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { return OK; } /* 从配置文件读取内部端口 */ memset(&uhttpd, 0, sizeof(uhttpd)); if ((0 == ds_read(UHTTPD_MAINSEC_PATH, &uhttpd, sizeof(uhttpd))) || (0 == uhttpd.listen_http)) { uhttpd.listen_http = DEFAULT_HTTP_PORT; } memset(&upnpc_uhttpd, 0, sizeof(upnpc_uhttpd)); ds_read(UPNPC_UHTTPD_PATH, &upnpc_uhttpd, sizeof(upnpc_uhttpd)); if (0 == upnpc_uhttpd.ext_port) { upnpc_uhttpd.ext_port = DEFAULT_HTTP_PORT; } /* 手动模式外部端口号从配置读取,自动模式外部端口号与内部端口号相同 */ ext_port = (MODE_AUTO == upnpc_info.mode) ? uhttpd.listen_http : upnpc_uhttpd.ext_port; /* 添加映射条目 */ add_port_mapping(ext_port, uhttpd.listen_http, protocol, DESCRIPTION_UPNPC_UHTTPD_STR, upnpc_add_entry_done_cb); return OK; } LOCAL S32 add_rtsp_entry_from_config(PORT_MAPPING_PROTOCOL_TYPE protocol) { UPNPC_INFO upnpc_info; UPNPC_RTSP upnpc_rtsp; CET_RTSP rtsp; U16 ext_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { return OK; } /* 从用户配置读取内部端口 */ memset(&rtsp, 0, sizeof(rtsp)); if ((0 == ds_read(CET_RTSP_PATH, &rtsp, sizeof(rtsp))) || (0 == rtsp.port)) { rtsp.port = DEFAULT_RTSP_PORT; } memset(&upnpc_rtsp, 0, sizeof(upnpc_rtsp)); ds_read(UPNPC_RTSP_PATH, &upnpc_rtsp, sizeof(upnpc_rtsp)); if (0 == upnpc_rtsp.ext_port) { upnpc_rtsp.ext_port = DEFAULT_RTSP_PORT; } /* 手动模式外部端口号从配置读取,自动模式外部端口号与内部端口号相同 */ ext_port = (MODE_AUTO == upnpc_info.mode) ? rtsp.port : upnpc_rtsp.ext_port; /* 添加映射条目 */ add_port_mapping(ext_port, rtsp.port, protocol, DESCRIPTION_UPNPC_RTSP_STR, upnpc_add_entry_done_cb); return OK; } LOCAL S32 vhttpd_entry_from_config(PORT_MAPPING_PROTOCOL_TYPE protocol) { UPNPC_INFO upnpc_info; UPNPC_VHTTPD vhttp; U16 ext_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); memset(&vhttp, 0, sizeof(vhttp)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { return OK; } ds_read(UPNPC_VHTTPD_PATH, &vhttp, sizeof(vhttp)); if (upnpc_info.mode == MODE_AUTO) { ext_port = generate_external_mapping_port(); } else { ext_port = vhttp.ext_port; } add_port_mapping(ext_port, HTTPS_SERVER_PORT, protocol, DESCRIPTION_UPNPC_VHTTPD_STR, upnpc_add_entry_done_cb); return OK; } #ifdef WEBRTC_SUPPORT LOCAL S32 webrtc_entry_from_config(PORT_MAPPING_PROTOCOL_TYPE protocol, int index) { UPNPC_INFO upnpc_info; U16 ext_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { return OK; } if (upnpc_info.mode == MODE_AUTO) { ext_port = webrtc_generate_external_mapping_port(); } else { ext_port = webrtc_server_port[index]; } add_port_mapping(ext_port, webrtc_server_port[index], protocol, description_upnpc_webrtc_str[index], upnpc_add_entry_done_cb); return OK; } #endif LOCAL S32 upnpc_delete_conflict_entry_done_cb(UPNP_ENTYR_INFO *info) { if (NULL == info) { UPNPC_ERROR("info is null"); return ERROR; } if (info->action != PORT_MAPPING_ACTION_DELETE) { UPNPC_ERROR("invalid action[%d]", info->action); return ERROR; } /* 如果删除冲突条目成功,则重新添加条目 */ if ((info->action_successed) || (NO_SUCH_ENTRY_ERROR_CODE == info->error_code)) { if (UPNPC_ENTRY_FLAG_UHTTPD == info->entry_flag) { cur_added_uhttpd_ext_port = 0; g_upnpc_uhttpd_mapped = FALSE; add_uhttpd_entry_from_config(info->protocol); } else if (UPNPC_ENTRY_FLAG_RTSP == info->entry_flag) { cur_added_rtsp_ext_port = 0; g_upnpc_rtsp_mapped = FALSE; add_rtsp_entry_from_config(info->protocol); } else if (UPNPC_ENTRY_FLAG_VHTTPD == info->entry_flag) { cur_added_vhttpd_ext_port = 0; g_upnpc_vhttpd_mapped = FALSE; vhttpd_entry_from_config(info->protocol); } #ifdef WEBRTC_SUPPORT else { for (int i = 0; i < CLIENTS_CONN_MAX; i++) { if ((UPNPC_ENTRY_FLAG_WEBRTC_1 + i) == info->entry_flag) { cur_added_webrtc_ext_port[i] = 0; g_upnpc_webrtc_mapped[i] = FALSE; webrtc_entry_from_config(info->protocol, i); break; } } } #endif return OK; } /* 删除冲突条目失败,记录到log */ UPNPC_INFO("delete confilct entry failed. ext_port %hu", info->external_port); return OK; } LOCAL void upnpc_add_entry(U16 external_port, U16 internal_port, const char * desc, upnp_action_done_cb upnp_action_done_handle #ifdef WEBRTC_SUPPORT , BOOL is_udp #endif ) { if (FALSE == is_linked_up() ) { UPNPC_DEBUG("link down, link status = %d ",is_linked_up()); return; } UPNPC_DEBUG("begin to add mapping"); add_port_mapping(external_port, internal_port, #ifdef WEBRTC_SUPPORT is_udp ? PORT_MAPPING_PROTOCOL_UDP : PORT_MAPPING_PROTOCOL_TCP #else PORT_MAPPING_PROTOCOL_TCP #endif , desc, upnp_action_done_handle); } LOCAL void upnpc_delete_entry(U16 external_port, const char * desc, upnp_action_done_cb upnp_action_done_handle #ifdef WEBRTC_SUPPORT , BOOL is_udp #endif ) { if (FALSE == is_linked_up() || FALSE == is_igd_available()) { return; } if (OK == delete_web_entry_record(external_port, #ifdef WEBRTC_SUPPORT is_udp ? PORT_MAPPING_PROTOCOL_UDP : PORT_MAPPING_PROTOCOL_TCP #else PORT_MAPPING_PROTOCOL_TCP #endif )) { delete_port_mapping(external_port, #ifdef WEBRTC_SUPPORT is_udp ? PORT_MAPPING_PROTOCOL_UDP : PORT_MAPPING_PROTOCOL_TCP #else PORT_MAPPING_PROTOCOL_TCP #endif , desc, upnp_action_done_handle); } } LOCAL void upnpc_check_entry_status(U16 external_port, U16 internal_port, const char * desc, upnp_action_done_cb upnp_action_done_handle #ifdef WEBRTC_SUPPORT , BOOL is_udp #endif ) { if (FALSE == is_linked_up() || FALSE == is_igd_available()) { g_upnpc_rtsp_mapped = FALSE; g_upnpc_uhttpd_mapped = FALSE; g_upnpc_vhttpd_mapped = FALSE; #ifdef WEBRTC_SUPPORT for (int i = 0; i < CLIENTS_CONN_MAX; i++) { g_upnpc_webrtc_mapped[i] = FALSE; } #endif delete_web_entry_record(external_port, #ifdef WEBRTC_SUPPORT is_udp ? PORT_MAPPING_PROTOCOL_UDP : PORT_MAPPING_PROTOCOL_TCP #else PORT_MAPPING_PROTOCOL_TCP #endif ); return; } get_specific_port_mapping(external_port, internal_port, #ifdef WEBRTC_SUPPORT is_udp ? PORT_MAPPING_PROTOCOL_UDP : PORT_MAPPING_PROTOCOL_TCP #else PORT_MAPPING_PROTOCOL_TCP #endif , desc, upnp_action_done_handle); } LOCAL S32 upnpc_get_entry_alive_done_cb(UPNP_ENTYR_INFO *info) { if (NULL == info) { UPNPC_ERROR("info is null"); return ERROR; } if (info->action != PORT_MAPPING_ACTION_GET_SPECIFIC) { UPNPC_ERROR("invalid action[%d]", info->action); return ERROR; } if (info->still_alive == FALSE) { if (UPNPC_ENTRY_FLAG_UHTTPD == info->entry_flag) { g_upnpc_uhttpd_mapped = FALSE; } else if (UPNPC_ENTRY_FLAG_RTSP == info->entry_flag) { g_upnpc_rtsp_mapped = FALSE; } else if (UPNPC_ENTRY_FLAG_VHTTPD == info->entry_flag) { g_upnpc_vhttpd_mapped = FALSE; } #ifdef WEBRTC_SUPPORT else { for (int i = 0; i < CLIENTS_CONN_MAX; i++) { if ((UPNPC_ENTRY_FLAG_WEBRTC_1 + i) == info->entry_flag) { g_upnpc_webrtc_mapped[i] = FALSE; break; } } } #endif delete_web_entry_record(info->external_port, info->protocol); } return OK; } LOCAL S32 recv_continuous_fail_time = 0; #define RECV_FAIL_RETRY_INTER 3 #define RECV_MAX_RETRY_TIMES 3 LOCAL S32 upnpc_check_alive_and_add(UPNP_ENTYR_INFO *info) { if (NULL == info) { UPNPC_ERROR("info is null"); return ERROR; } if (info->action != PORT_MAPPING_ACTION_GET_SPECIFIC) { UPNPC_ERROR("invalid action[%d]", info->action); return ERROR; } if (info->recv_successed == FALSE) { recv_continuous_fail_time++; if (recv_continuous_fail_time >= RECV_MAX_RETRY_TIMES) { recv_continuous_fail_time = 0; return ERROR; } inet_add_timer(upnpc_timer, 0, RECV_FAIL_RETRY_INTER, EXECUTE_SINGLE); return ERROR; } /* recv http成功,将连续失败次数置为0 */ recv_continuous_fail_time = 0; if (info->still_alive == FALSE) { reload_web_entries(); } return OK; } #define MAX_PORT_MAPPING_NUM 4 LOCAL void upnpc_timer(S32 param) { NODE *node = NULL; NODE *next = NULL; UPNP_ENTRY_MAP *map_info = NULL; NODE *web_list_head = get_web_entry_list_head(); if (web_list_head == NULL) { UPNPC_DEBUG("web_list_head == NULL!"); return; } list_for_each_safe(node, next, web_list_head) { map_info = (UPNP_ENTRY_MAP *)node; get_specific_port_mapping(map_info->external_port, map_info->internal_port, map_info->protocol, map_info->description, upnpc_check_alive_and_add); } } LOCAL BOOL check_vhttpd_status = FALSE; LOCAL STATUS get_upnp_status_json(DS_HANDLE_CONTEXT *context, JSON_OBJPTR resp_array_obj) { JSON_OBJPTR obj = NULL; JSON_OBJPTR item_obj = NULL; char ip_str[sizeof("255.255.255.255")] = {0}; LINK_STATUS link_status; char *status_str = NULL; LOCAL time_t last_call_time = 0; time_t now = 0; now = time(NULL); /* 如果距离上次进入web upnp界面的时间超过3s(浏览器是每2s请求一次),则认为用户是从其他界面进入web的upnp页面, * 首次进入该界面需要发送查询条目状态的报文 */ if (now - last_call_time > 3) { check_vhttpd_status = TRUE; } last_call_time = now; memset(&link_status, 0, sizeof(link_status)); ds_read(LINK_STATUS_PATH, &link_status, sizeof(link_status)); if (NULL == inet_ntop(AF_INET, &link_status.ipaddr, ip_str, sizeof("255.255.255.255"))) { return ERROR; } /* 构造vhttpd条目 */ obj = jso_new_obj(); jso_add_string(obj, "ipaddr", ip_str); status_str = g_upnpc_vhttpd_mapped ? "on" : "off"; jso_add_string(obj, "status", status_str); jso_add_string(obj, "proto", "TCP"); jso_add_string_from_int(obj, "inner_port", HTTPS_SERVER_PORT); //内部端口 jso_add_string(obj, "desc", "vhttpd"); jso_add_string_from_int(obj, "ext_port", cur_added_vhttpd_ext_port); //外部端口 /* 向路由器查询web界面添加的http条目是否依然生效 */ if (g_upnpc_vhttpd_mapped && TRUE == check_vhttpd_status) { check_vhttpd_status = FALSE; upnpc_check_entry_status(cur_added_vhttpd_ext_port, HTTPS_SERVER_PORT, DESCRIPTION_UPNPC_UHTTPD_STR, upnpc_get_entry_alive_done_cb #ifdef WEBRTC_SUPPORT , FALSE #endif ); } item_obj = jso_new_obj(); jso_obj_add(item_obj, "vhttpd", obj); jso_array_add(resp_array_obj, item_obj); return OK; } LOCAL STATUS get_upnp_communicate_status(DS_HANDLE_CONTEXT *context, JSON_OBJPTR resp_array_obj) { if (!context ) return SLP_EINVARG; UPNPC_STATUS upnpc_status = {{0}}; get_upnp_status(&upnpc_status); jso_add_string(resp_array_obj, "status", upnpc_status.status); jso_add_string(resp_array_obj, "timestamp",upnpc_status.timestamp); return SLP_ENONE; } LOCAL STATUS set_upnp_communicate_status(DS_HANDLE_CONTEXT *context, JSON_OBJPTR obj) { if (NULL == context || NULL == obj || NULL == context->res_obj) { return SLP_EINVARG; } const char *status = NULL; const char *timestamp = NULL; UPNPC_STATUS upnpc_status = {{0}}; status = jso_obj_get_string_origin(obj, "status"); if (NULL == status) { return SLP_EINVARG; } timestamp = jso_obj_get_string_origin(obj,"timestamp"); if (NULL == timestamp) { return SLP_EINVARG; } snprintf(upnpc_status.status,STATUS_STR_LENTH,"%s",status); upnpc_status.status[STATUS_STR_LENTH-1] = '\0'; snprintf(upnpc_status.timestamp,TIME_STAMP_LENTH,"%s",timestamp); upnpc_status.timestamp[TIME_STAMP_LENTH-1] = '\0'; set_upnp_status(&upnpc_status); UPNPC_DEBUG("set timestamp = %s, status = %d !",upnpc_status.timestamp,upnpc_status.status); return SLP_ENONE; } LOCAL STATUS get_pub_ip_json(DS_HANDLE_CONTEXT *context, JSON_OBJPTR resp_array_obj) { if (!context || !context->res_obj) return SLP_EINVARG; jso_add_string(resp_array_obj, "ip", get_pub_ip()); UPNPC_DEBUG("get pub ip = %s",get_pub_ip()); return SLP_ENONE; } LOCAL STATUS get_upnpc_info(DS_HANDLE_CONTEXT *context, JSON_OBJPTR resp_array_obj) { if (!context) { UPNPC_INFO("get_upnpc_info error! "); return SLP_EINVARG; } JSON_OBJPTR upnpc_info = NULL; UPNPC_INFO info = {0}; if ( 0 == ds_read(UPNPC_INFO_PATH, &info, sizeof(UPNPC_INFO))) { UPNPC_ERROR("ds read upnpc info error!"); return ERROR; } upnpc_info = jso_new_obj(); jso_obj_add(resp_array_obj, "upnpc_info", upnpc_info); const char * enabled = (info.enabled)? "on":"off"; jso_add_string(upnpc_info, "enabled", enabled); const char * mode = (MODE_AUTO == info.mode) ? "auto" : "manual"; jso_add_string(upnpc_info, "mode", mode); UPNPC_DEBUG("get_upnpc_info, enabled = %s , mode = %s",enabled,mode); return SLP_ENONE; } LOCAL STATUS set_upnpc_info(DS_HANDLE_CONTEXT *context, JSON_OBJPTR obj) { if (NULL == context || NULL == obj) { return SLP_EINVARG; } const char *enabled = NULL; const char *mode = NULL; UPNPC_INFO info = {0}; UPNPC_INFO old_info = {0}; enabled = jso_obj_get_string_origin(obj, "enabled"); if (enabled == NULL) { UPNPC_ERROR("get enabled failed!"); return SLP_EINVARG; } mode = jso_obj_get_string_origin(obj, "mode"); if (mode == NULL) { UPNPC_ERROR("get mode failed!"); return SLP_EINVARG; } info.enabled = (!strcmp(enabled,"on"))?TRUE:FALSE; info.mode = (!strcmp(mode,"auto"))?MODE_AUTO:MODE_MANUAL; if (0 == ds_read(UPNPC_INFO_PATH,&old_info,sizeof(UPNPC_INFO))) { UPNPC_ERROR("read upnpc info failed"); return SLP_EEXPT; } if (!memcmp(&old_info,&info,sizeof(UPNPC_INFO))) { UPNPC_INFO("status not change"); return SLP_ENONE; } if (0 == ds_advanced_write(UPNPC_INFO_PATH,&info,sizeof(UPNPC_INFO),DS_FLAG_SAVE_FLASH)) { UPNPC_ERROR("write upnpc info failed!"); return SLP_EEXPT; } UPNPC_DEBUG("set_upnpc_info enabled = %d, mode = %d",info.enabled,info.mode); reload_web_entries(); return SLP_ENONE; } LOCAL S32 add_vhttpd_entry() { int ret = 0; UPNPC_INFO upnpc_info; UPNPC_VHTTPD vhttpd_info; U16 vhttpd_external_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); memset(&vhttpd_info, 0, sizeof(vhttpd_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { UPNPC_DEBUG("upnpc_info not enable "); return OK; } ds_read(UPNPC_VHTTPD_PATH,&vhttpd_info,sizeof(vhttpd_info)); if (MODE_AUTO == upnpc_info.mode) { vhttpd_external_port = generate_external_mapping_port(); } else { vhttpd_external_port = vhttpd_info.ext_port; } UPNPC_DEBUG("add mapping port = %d",vhttpd_external_port); /* 添加映射条目 */ g_upnpc_vhttpd_mapped = FALSE; cur_added_vhttpd_ext_port = FALSE; upnpc_add_entry(vhttpd_external_port, HTTPS_SERVER_PORT, DESCRIPTION_UPNPC_VHTTPD_STR, upnpc_add_entry_done_cb #ifdef WEBRTC_SUPPORT , FALSE #endif ); /*添加到list中的操作必须在对应节点的add_uhttpd/rtsp/..._entry函数执行*/ /*不能放在done cb中,因为cb有可能不被调用 */ return ret; } #ifdef WEBRTC_SUPPORT LOCAL S32 add_webrtc_entry(int index) { int ret = 0; UPNPC_INFO upnpc_info; U16 webrtc_external_port = 0; memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (FALSE == upnpc_info.enabled) { UPNPC_DEBUG("upnpc_info not enable "); return OK; } if (MODE_AUTO == upnpc_info.mode) { webrtc_external_port = webrtc_generate_external_mapping_port() + (webrtc_server_port[index] - webrtc_server_port[0]) * PORT_INTERVAL; } else { webrtc_external_port = webrtc_server_port[index]; } UPNPC_DEBUG("add mapping port = %d",webrtc_external_port); /* 添加映射条目 */ g_upnpc_webrtc_mapped[index] = FALSE; cur_added_webrtc_ext_port[index] = FALSE; upnpc_add_entry(webrtc_external_port, webrtc_server_port[index], description_upnpc_webrtc_str[index], upnpc_add_entry_done_cb, TRUE); /*添加到list中的操作必须在对应节点的add_uhttpd/rtsp/..._entry函数执行*/ /*不能放在done cb中,因为函数多层调用提前返回cb有可能不被调用 */ return ret; } #endif LOCAL S32 reload_uhttpd() { /* 暂时不添加web相关条目 */ return 0; } LOCAL S32 reload_rtsp() { /* 暂时不添加web相关条目 */ return 0; } LOCAL S32 reload_vhttpd() { UPNPC_INFO upnpc_info; /* 读取UPNPC配置 /upnpc/upnpc_info */ memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (TRUE == g_upnpc_vhttpd_mapped && 0 != cur_added_vhttpd_ext_port) { UPNPC_ERROR("del old mapping"); g_upnpc_vhttpd_mapped = FALSE; upnpc_delete_entry(cur_added_vhttpd_ext_port, DESCRIPTION_UPNPC_VHTTPD_STR,upnpc_delete_entry_done_cb #ifdef WEBRTC_SUPPORT , FALSE #endif ); } /* 当upnp被启用时,添加 vhttpd 条目 */ if (TRUE == upnpc_info.enabled) { UPNPC_ERROR("upnp enable begin to add entry"); add_vhttpd_entry(); } return OK; } #ifdef WEBRTC_SUPPORT LOCAL S32 reload_webrtc(int index) { UPNPC_INFO upnpc_info; /* 读取UPNPC配置 /upnpc/upnpc_info */ memset(&upnpc_info, 0, sizeof(upnpc_info)); ds_read(UPNPC_INFO_PATH, &upnpc_info, sizeof(upnpc_info)); if (TRUE == g_upnpc_webrtc_mapped[index] && 0 != cur_added_webrtc_ext_port[index]) { UPNPC_ERROR("del old mapping"); g_upnpc_webrtc_mapped[index] = FALSE; upnpc_delete_entry(cur_added_webrtc_ext_port[index], description_upnpc_webrtc_str[index],upnpc_delete_entry_done_cb, TRUE); } /* 当upnp被启用时,添加 webrtc 条目 */ if (TRUE == upnpc_info.enabled) { UPNPC_ERROR("upnp enable begin to add entry"); add_webrtc_entry(index); } return OK; } #endif S32 reload_web_entries() { UPNPC_DEBUG("reload_web_entries"); reload_vhttpd(); #ifdef WEBRTC_SUPPORT for (int i = 0; i < CLIENTS_CONN_MAX; i++) { reload_webrtc(i); } #endif return OK; } LOCAL S32 upnpc_reload(DS_MSG *msg) { LINK_STATUS link_status = {0}; S32 ret = OK; if (msg == NULL) { UPNPC_ERROR("Parameter wrong."); return SLP_EGENERIC; } /* 当upnp开关、模式被更改时,重新添加uhttpd、rtsp条目 */ if (ds_path_id_exist(msg->id, msg->num, UPNPC_INFO_PATH)) { reload_web_entries(); goto out; } /* 当在web端口界面更改内部端口时,重新添加uhttpd、rtsp条目 */ if (ds_path_id_exist(msg->id, msg->num, UHTTPD_MAINSEC_PATH) || ds_path_id_exist(msg->id, msg->num, CET_RTSP_PATH)) { reload_web_entries(); goto out; } /* 当在web upnp界面更改uhttpd外部端口时,重新添加uhttpd条目 */ if (ds_path_id_exist(msg->id, msg->num, UPNPC_UHTTPD_PATH)) { reload_uhttpd(); } /* 当在web upnp界面更改rtsp外部端口时,重新添加rtsp条目 */ if (ds_path_id_exist(msg->id, msg->num, UPNPC_RTSP_PATH)) { reload_rtsp(); } /* 当网关、设备ip有变化时,重新添加全部生效的条目 */ if (ds_path_id_exist(msg->id, msg->num, LINK_STATUS_PATH)) { if (0 == ds_read(LINK_STATUS_PATH, &link_status, sizeof(LINK_STATUS))) { UPNPC_ERROR("ds read %s return 0", LINK_STATUS_PATH); return ERROR; } /* 由未连接变为连接 */ if (link_status.link_status == LINK_UP && link_status.link_status != s_link_status.link_status) { UPNPC_DEBUG("link_status changed to link!"); update_igd_ip(); reload_web_entries(); } /* ipaddr发生变化 */ else if (link_status.ipaddr != s_link_status.ipaddr && link_status.ipaddr != 0) { UPNPC_DEBUG("ipaddr changed!"); /* 当本机ip变化后,重新加载一下upnp条目 */ reload_web_entries(); } /* 网关发生变化 */ else if (link_status.gateway != s_link_status.gateway) { UPNPC_DEBUG("gateway changed!"); update_igd_ip(); reload_web_entries(); } memset(&s_link_status, 0, sizeof(LINK_STATUS)); ds_read(LINK_STATUS_PATH, &s_link_status, sizeof(LINK_STATUS)); } out: UPNPC_INFO("reload over"); return ret; } LOCAL S32 upnpc_init(void) { ds_register_get_json("upnpc", "upnp_status", NULL, get_upnp_status_json); ds_register_get_json("upnpc", "pub_ip","pub_ip", get_pub_ip_json); ds_register_get_json("upnpc", "communicate","communicate", get_upnp_communicate_status ); ds_register_action("upnpc", "communicate", set_upnp_communicate_status); ds_register_get_json("upnpc", "upnpc_info","upnpc_info", get_upnpc_info); ds_register_action("upnpc", "upnpc_info", set_upnpc_info ); /* ubus call */ //msg_attach_handler(MSGID_DMS_CMD, upnpc_call_handle); /* 其他模块通过dms消息添加/删除upnp映射条目 */ //msg_attach_handler(UPNPC_CONTROL_MID, upnpc_control_msg_handle); msg_attach_handler(UPNPC_SAVE_PUB_IP_MSG_MID, upnpc_save_pub_ip); UPNPC_INFO("upnpc init over"); return OK; } LOCAL S32 upnpc_start(void) { memset(&s_link_status, 0, sizeof(LINK_STATUS)); if (0 == ds_read(LINK_STATUS_PATH, &s_link_status, sizeof(LINK_STATUS))) { UPNPC_ERROR("ds read %s return 0", LINK_STATUS_PATH); return ERROR; } UPNPC_INFO("start over"); /* 每隔2min对映射状态进行一次检查 */ if (g_check_timer == -1) { UPNPC_DEBUG("add timer"); g_check_timer = inet_add_timer(upnpc_timer, 0, CHECK_PORT_MAPPING_STATUS_INTERVAL, EXECUTE_FOREVER); } return OK; } LOCAL void upnpc_main() { DS_DAT_MON_DESC upnpc_data_monitor[] = { DS_DAT_MON(UPNPC_INFO_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(UHTTPD_MAINSEC_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(CET_RTSP_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(UPNPC_UHTTPD_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(UPNPC_RTSP_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(LINK_STATUS_PATH, DATA_ATTRI_NOTIFY), DS_DAT_MON(UPNPC_VHTTPD_PATH, DATA_ATTRI_NOTIFY), }; DS_MOD_DESC upnpc_module = DS_STRUCT_MOD(UPNPC_MODULE_NAME, upnpc_init, NULL, upnpc_reload, upnpc_start, NULL, NULL, upnpc_data_monitor); MODULE *module_node = ds_register_module(UPNPC_MODULE_NAME, &upnpc_module); SDM_ASSERT(NULL != module_node); } NSD_INIT(upnpc_main); #endif
10-19
#!/bin/sh RUN_ONCE_FILE=/var/run/upnpc_running RUN_ONCE_FILE_RESTART=/var/run/upnpc_running_restart RUN_ONCE_FILE_STOP=/var/run/upnpc_running_stop if [ -e $RUN_ONCE_FILE ]; then exit 0 fi touch $RUN_ONCE_FILE . /lib/functions.sh . /usr/share/libubox/jshn.sh __network_ipaddr() { local __var="$1" local __family="$2" local __prefix="${3:-0}" local __tmp="$(ubus -t 2 call network wan_status 2>/dev/null)" json_load "${__tmp:-{}}" json_get_type __tmp "ipv${__family}_address" if [ "$__tmp" = array ]; then json_select "ipv${__family}_address" json_get_type __tmp 1 if [ "$__tmp" = object ]; then json_select 1 json_get_var $__var address [ $__prefix -gt 0 ] && { json_get_var __tmp mask eval "export -- \"$__var=\${$__var}/$__tmp\"" } return 0 fi fi return 1 } # IP_ADDR=$(echo $(ifconfig) |cut -d ' ' -f7|cut -d ':' -f2) # IP_ADDR=$(cat /tmp/udhcpc/dhcpip) # network_get_ipaddr() { __network_ipaddr $1 4 0; } BIND_STATUS="" PUB_IP="" COMM_STATUS="" IP_ADDR="" COMPARE_RESULT=0 DELETE_STRING="" ADD_STRING="" # random method RANDOM_INDEX="" RANDOM_MIN=10000 RANDOM_MAX=30000 upnpc_mode=$(uci_get "upnpc" "upnpc_info" "mode") upnpc_enabled=$(uci_get "upnpc" "upnpc_info" "enabled") uhttpd_inner_port=$(uci_get "uhttpd" "main" "listen_https" "443") #vhttpd_inner_port=$(uci_get "cet" "vhttpd" "port" "8080") tp_live_inner_port="19443" tp_vod_inner_port="18443" tp_speaker_inner_port="17443" rtsp_inner_port=$(uci_get "cet" "rtsp" "port" "554") onvif_service_inner_port="2020" uhttpd_status=$(uci_get "upnpc" "uhttpd" "status") uhttpd_ext_port=$(uci_get "upnpc" "uhttpd" "ext_port") uhttpd_proto=$(uci_get "upnpc" "uhttpd" "proto") uhttpd_desc=$(uci_get "upnpc" "uhttpd" "desc") uhttpd_flag=1 uhttpd_mapping=0 rtsp_status=$(uci_get "upnpc" "rtsp" "status") rtsp_ext_port=$(uci_get "upnpc" "rtsp" "ext_port") rtsp_proto=$(uci_get "upnpc" "rtsp" "proto") rtsp_desc=$(uci_get "upnpc" "rtsp" "desc") rtsp_flag=2 rtsp_mapping=0 onvif_service_status=$(uci_get "upnpc" "onvif_service" "status") onvif_service_ext_port=$(uci_get "upnpc" "onvif_service" "ext_port") onvif_service_proto=$(uci_get "upnpc" "onvif_service" "proto") onvif_service_desc=$(uci_get "upnpc" "onvif_service" "desc") onvif_service_flag=4 onvif_service_mapping=0 tp_live_status=$(uci_get "upnpc" "tp_live" "status") tp_live_ext_port=$(uci_get "upnpc" "tp_live" "ext_port") tp_live_proto=$(uci_get "upnpc" "tp_live" "proto") tp_live_desc=$(uci_get "upnpc" "tp_live" "desc") tp_live_flag=8 tp_live_mapping=0 tp_vod_status=$(uci_get "upnpc" "tp_vod" "status") tp_vod_ext_port=$(uci_get "upnpc" "tp_vod" "ext_port") tp_vod_proto=$(uci_get "upnpc" "tp_vod" "proto") tp_vod_desc=$(uci_get "upnpc" "tp_vod" "desc") tp_vod_flag=16 tp_vod_mapping=0 tp_speaker_status=$(uci_get "upnpc" "tp_speaker" "status") tp_speaker_ext_port=$(uci_get "upnpc" "tp_speaker" "ext_port") tp_speaker_proto=$(uci_get "upnpc" "tp_speaker" "proto") tp_speaker_desc=$(uci_get "upnpc" "tp_speaker" "desc") tp_speaker_flag=32 tp_speaker_mapping=0 upnpc_get_mapping() { local compare_times=0 # we will try three times at most to get port mapping while [ "$compare_times" -lt 3 ] do upnpc -l > "/tmp/upnpc_output" if [ -s "/tmp/upnpc_output" ] then break; else let compare_times=$compare_times+1 sleep 1 fi done } upnpc_update_comm() { local port_status=$1 local secname=$2 local port=$3 # check status local config_status local config_ext_port local config_comm_status eval config_get config_status "${secname}" status eval config_get config_ext_port "${secname}" ext_port eval config_get config_comm_status "${secname}" comm_status if [ $config_status == $port_status ] then if [ -z $port ] then return 0 elif [ $config_ext_port == $port ] then return 0 fi fi if [ $port_status == "on" ] then if [ $PUB_IP == "null" ] then if [ $config_comm_status != "failed" ] then uci set upnpc."${secname}".comm_status='failed' timestamp=`date +%s` uci set upnpc."${secname}".timestamp=$timestamp fi else if [ $config_comm_status != "unknown" ] then uci set upnpc."${secname}".comm_status='unknown' timestamp=`date +%s` uci set upnpc."${secname}".timestamp=$timestamp fi fi elif [ $port_status == "off" ] then if [ $config_comm_status != "failed" ] then uci set upnpc."${secname}".comm_status='failed' timestamp=`date +%s` uci set upnpc."${secname}".timestamp=$timestamp fi fi } # get config values from the upnpc config file upnpc_get_config() { local secname="$1" config_get "${secname}_status" "$secname" status config_get "${secname}_ext_port" "$secname" ext_port config_get "${secname}_proto" "$secname" proto config_get "${secname}_desc" "$secname" desc } # set config values base on the "upnpc -l" results upnpc_set_config_from_real() { local secname="$1" local file_path="$2" local ip local inner_port local flag=0 while read proto ext_port ip_port desc do # divide ip_port such as 192.168.0.60:8000 into 192.168.0.60 8000 ip=$(echo $ip_port | sed 's/:.*//g') inner_port=$(echo $ip_port | sed 's/.*://g') local config_inner_port local config_proto local config_desc local config_ext_port eval config_inner_port="\${${secname}_inner_port}" eval config_proto="\${${secname}_proto}" eval config_desc="\${${secname}_desc}" eval config_ext_port="\${${secname}_ext_port}" if [ "$IP_ADDR" == "$ip" ] \ && [ "$config_inner_port" == "$inner_port" ] \ && [ "$config_proto" == "$proto" ] \ && [ "$config_desc" == "$desc" ]; then if [ "manual" == "$upnpc_mode" ] then # upnp works in manual mode # we need to keep user`s config to do port mapping again uci set upnpc."$secname".status='on' flag=1 break fi # 处理一下port变化的情况 if [ $secname == "tp_live" ] \ || [ $secname == "tp_vod" ] \ || [ $secname == "tp_speaker" ]; then upnpc_update_comm "on" $secname $ext_port fi uci set upnpc."$secname".status='on' uci set upnpc."$secname".ext_port=$ext_port flag=1 break fi done < "$file_path" if [ $flag == 0 ] then if [ $secname == "tp_live" ] \ || [ $secname == "tp_vod" ] \ || [ $secname == "tp_speaker" ]; then upnpc_update_comm "off" $secname fi uci set upnpc."$secname".status='off' fi } # compare config values with the "upnpc -l" results upnpc_compare_real_config() { local secname="$1" local file_path="$2" local mode="$3" local flag=1 local ip local inner_port while read proto ext_port ip_port desc do # divide ip_port such as 192.168.0.60:8000 into 192.168.0.60 8000 ip=$(echo $ip_port | sed 's/:.*//g') inner_port=$(echo $ip_port | sed 's/.*://g') local config_inner_port local config_ext_port local config_proto local config_desc eval config_inner_port="\${${secname}_inner_port}" eval config_ext_port="\${${secname}_ext_port}" eval config_proto="\${${secname}_proto}" eval config_desc="\${${secname}_desc}" if [ "$IP_ADDR" == "$ip" ] \ && [ "$config_inner_port" == "$inner_port" ] \ && [ "$config_ext_port" == "$ext_port" ] \ && [ "$config_proto" == "$proto" ] \ && [ "$config_desc" == "$desc" ]; then if [ "auto" == "$mode" ] \ && [ "$ext_port" -le "$RANDOM_MIN" ]; then break fi if [ $secname == "tp_live" ] \ || [ $secname == "tp_vod" ] \ || [ $secname == "tp_speaker" ]; then upnpc_update_comm "on" $secname $ext_port fi uci set upnpc."$secname".status='on' flag=0 break else # delete port, if not in config if [ "$config_desc" == "$desc" ] then upnpc -d $ext_port $proto fi fi done < "$file_path" if [ "$flag" == "1" ] then local config_flag eval config_flag="\${${secname}_flag}" let COMPARE_RESULT=$COMPARE_RESULT+$config_flag fi } # decide whether to delete certain port mapping upnpc_decide_delete_string() { local secname="$1" local proto="$2" local ext_port="$3" local ip_port="$4" local desc="$5" local mode="$6" local inner_port # divide ip_port such as 192.168.0.60:8000 into 192.168.0.60 8000 inner_port=$(echo $ip_port | sed 's/.*://g') local config_inner_port local config_ext_port local config_proto local config_desc eval config_inner_port="\${${secname}_inner_port}" eval config_ext_port="\${${secname}_ext_port}" eval config_proto="\${${secname}_proto}" eval config_desc="\${${secname}_desc}" if [ "$config_inner_port" == "$inner_port" ] \ && [ "$config_ext_port" == "$ext_port" ] \ && [ "$config_proto" == "$proto" ] \ && [ "$config_desc" == "$desc" ]; then if [ "auto" == "$mode" ] \ && [ "$ext_port" -lt "$RANDOM_MIN" ]; then # need to delete this port mapping DELETE_FLAG=1 let ${secname}_mapping=0 else # do not need to delete this port mapping DELETE_FLAG=0 # mark that the port mapping of this secname has already been done let ${secname}_mapping=1 fi fi } # build ADD_STRING upnpc_build_add_string() { local secname="$1" local mode="$2" local config_ext_port local config_proto local config_desc local config_inner_port local port_mapping eval config_inner_port="\${${secname}_inner_port}" eval config_ext_port="\${${secname}_ext_port}" eval config_proto="\${${secname}_proto}" eval config_desc="\${${secname}_desc}" eval port_mapping="\${${secname}_mapping}" if [ "0" == "$port_mapping" ] then # the port mapping of this secname has not already been done # we need to do port mapping of this secname, so add to ADD_STRING if [ "auto" != "$mode" ] \ || [ "$config_ext_port" -ge "$RANDOM_MIN" ]; then ADD_STRING=$ADD_STRING" "$config_inner_port" "$config_ext_port" "$config_proto" "$config_desc fi fi } # reconfigure port mapping in auto mode upnpc_auto_reconfigure() { #RANDOM_INDEX=$(lua -e 'math.randomseed(tostring(os.time()):reverse():sub(1, 6)); print(math.random(10000, 30000))') myrand() { if [ -z "$RANDOM" ] ; then SEED=`tr -cd 0-9 </dev/urandom | head -c 8` else SEED=$RANDOM fi RND_NUM=`echo $SEED $1 $2|awk '{srand($1);printf "%d",rand()*10000%($3-$2)+$2}'` echo $RND_NUM } RANDOM_INDEX=$(myrand 20000 30000) local compare_times=0 # we will try three times at most to do port mapping while [ "$compare_times" -lt 3 ] do COMPARE_RESULT=0 config_foreach upnpc_compare_real_config entry /tmp/upnpc_output auto if [ "0" == "$COMPARE_RESULT" ] then # the port mappings have been all successful break else # the port mappings have not been all successful # we need to build ADD_STRING based on COMPARE_RESULT ADD_STRING=$IP_ADDR local flag # randomly set the external port by +1 let flag="$COMPARE_RESULT"\&"$uhttpd_flag" if [ "$flag" -ne "0" ] then uhttpd_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$uhttpd_inner_port" "$uhttpd_ext_port" "$uhttpd_proto" "$uhttpd_desc fi let flag="$COMPARE_RESULT"\&"$rtsp_flag" if [ "$flag" -ne "0" ] then rtsp_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$rtsp_inner_port" "$rtsp_ext_port" "$rtsp_proto" "$rtsp_desc fi let flag="$COMPARE_RESULT"\&"$onvif_service_flag" if [ "$flag" -ne "0" ] then onvif_service_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$onvif_service_inner_port" "$onvif_service_ext_port" "$onvif_service_proto" "$onvif_service_desc fi let flag="$COMPARE_RESULT"\&"$tp_live_flag" if [ "$flag" -ne "0" ] then tp_live_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$tp_live_inner_port" "$tp_live_ext_port" "$tp_live_proto" "$tp_live_desc fi let flag="$COMPARE_RESULT"\&"$tp_vod_flag" if [ "$flag" -ne "0" ] then tp_vod_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$tp_vod_inner_port" "$tp_vod_ext_port" "$tp_vod_proto" "$tp_vod_desc fi let flag="$COMPARE_RESULT"\&"$tp_speaker_flag" if [ "$flag" -ne "0" ] then tp_speaker_ext_port=$RANDOM_INDEX let RANDOM_INDEX=$RANDOM_INDEX+1 ADD_STRING=$ADD_STRING" "$tp_speaker_inner_port" "$tp_speaker_ext_port" "$tp_speaker_proto" "$tp_speaker_desc fi # execute the upnpc comand to do the port mapping # grep the "upnpc -l" results to get only map values that are belonged to current_ip upnpc -a $ADD_STRING \ -l | grep $IP_ADDR > /tmp/upnpc_output let compare_times=$compare_times+1 fi done } # reconfigure port mapping upnpc_reconfigure() { config_load upnpc config_get upnpc_mode upnpc_info mode config_get PUB_IP pub_ip ip IP_ADDR=$(echo $(ifconfig) |cut -d ' ' -f7|cut -d ':' -f2) if [ -e /tmp/upnpc_pre_ip ] then PRE_IP=`cat /tmp/upnpc_pre_ip` else PRE_IP="" fi if [ -z "$IP_ADDR" ] \ && [ -z "$PRE_IP" ]; then # current ip and preview ip are all empty cat /tmp/upnpc_output > /tmp/upnpc_output1 elif [ "$IP_ADDR" == "$PRE_IP" ] \ || [ -z "$PRE_IP" ] then # preview_ip is equal to current_ip # so we do not need to check PRE_IP PRE_IP="" # grep the "upnpc -l" results to get only map values that are belonged to current_ip cat /tmp/upnpc_output | grep "$IP_ADDR" > /tmp/upnpc_output1 elif [ -z "$IP_ADDR" ] then # grep the "upnpc -l" results to get only map values that are belonged to preview_ip cat /tmp/upnpc_output | grep "$PRE_IP" > /tmp/upnpc_output1 else # grep the "upnpc -l" results to get only map values that are belonged to preview_ip and current_ip cat /tmp/upnpc_output | grep -E "$IP_ADDR|$PRE_IP" > /tmp/upnpc_output1 fi # grep the "upnpc -l" results to get only map values that are belonged to preview_ip and current_ip cat /tmp/upnpc_output | grep -E "$IP_ADDR|$PRE_IP" > /tmp/upnpc_output1 config_foreach upnpc_get_config entry local ip while read proto ext_port ip_port desc do # divide ip_port such as 192.168.0.60:8000 into 192.168.0.60 8000 # and get the ip value such as "192.168.0.60" ip=$(echo $ip_port | sed 's/:.*//g') if [ "$IP_ADDR" == "$ip" ] then # this port mapping is belonged to IP_ADDR DELETE_FLAG=1 config_foreach upnpc_decide_delete_string entry $proto $ext_port $ip_port $desc $upnpc_mode if [ "1" == "$DELETE_FLAG" ] then # this port mapping is not useful, delete it # package the DELETE_STRING with the form: ext_port proto DELETE_STRING=$DELETE_STRING" "$ext_port" "$proto fi fi if [ "$PRE_IP" == "$ip" ] then # this port mapping is belonged to PRE_IP, delete it # package the DELETE_STRING with the form: ext_port proto DELETE_STRING=$DELETE_STRING" "$ext_port" "$proto fi done < "/tmp/upnpc_output1" # begin to build ADD_STRING ADD_STRING=$IP_ADDR config_foreach upnpc_build_add_string entry $upnpc_mode # begin to build upnpc_string local upnpc_string if [ -n "$DELETE_STRING" ] then # DELETE_STRING is not empty, add to upnpc_string upnpc_string=$upnpc_string" -d "$DELETE_STRING fi if [ "$IP_ADDR" != "$ADD_STRING" ] then # ADD_STRING is not default, add to upnpc_string upnpc_string=$upnpc_string" -a "$ADD_STRING fi # add -l to upnpc_string to list all the port mappings upnpc_string=$upnpc_string" -l" # execute the upnpc comand to do the port mapping # grep the "upnpc -l" results to get only map values that are belonged to current_ip upnpc $upnpc_string | grep $IP_ADDR > /tmp/upnpc_output # save current ip into /tmp/upnpc_pre_ip echo $IP_ADDR > /tmp/upnpc_pre_ip if [ "auto" == "$upnpc_mode" ] then # upnp works in auto mode, if failed # we need to use randomly port to do port mapping again upnpc_auto_reconfigure fi # set upnpc config file based on the "upnpc -l" results config_foreach upnpc_set_config_from_real entry /tmp/upnpc_output uci commit upnpc rm -f "/tmp/upnpc_output1" rm -f "/tmp/upnpc_output" } # the following function will be called outside asynchronously # so we need to add lock to prevent them from being called at the same time # maintain port mapping upnpc_maintain() { config_load cloud_brd config_get BIND_STATUS bind status config_load upnpc config_get upnpc_enabled upnpc_info enabled config_get upnpc_mode upnpc_info mode config_get PUB_IP pub_ip ip timestamp=`date +%s` echo $timestamp >/dev/console if [ "$BIND_STATUS" == "1" ] then if [ "$upnpc_enabled" == "on" ] then IP_ADDR=$(echo $(ifconfig) |cut -d ' ' -f7|cut -d ':' -f2) if [ -n "$IP_ADDR" ] then lock "/var/run/upnpc" #upnpc -l > "/tmp/upnpc_output" upnpc_get_mapping # grep the "upnpc -l" results to get only map values that are belonged to current_ip cat /tmp/upnpc_output | grep $IP_ADDR > /tmp/upnpc_output1 COMPARE_RESULT=0 config_foreach upnpc_compare_real_config entry /tmp/upnpc_output1 $upnpc_mode if [ $COMPARE_RESULT == 0 ] then uci commit upnpc # do not need to maintain # save current ip into /tmp/upnpc_pre_ip echo $IP_ADDR > /tmp/upnpc_pre_ip rm -f "/tmp/upnpc_output1" rm -f "/tmp/upnpc_output" else # need to maintain, reconfigure upnpc upnpc_reconfigure fi lock -u "/var/run/upnpc" fi fi else upnpc_stop fi } # stop port mapping upnpc_stop() { if [ -e $RUN_ONCE_FILE_STOP ]; then exit 0 fi touch $RUN_ONCE_FILE_STOP lock "/var/run/upnpc" config_load upnpc config_get PUB_IP pub_ip ip # network_get_ipaddr IP_ADDR IP_ADDR=$(echo $(ifconfig) |cut -d ' ' -f7|cut -d ':' -f2) local DELETE_STRING local PRE_IP local ip if [ -e /tmp/upnpc_pre_ip ] then PRE_IP=`cat /tmp/upnpc_pre_ip` else PRE_IP="" fi # grep the "upnpc -l" results to get only map values that are belonged to preview_ip and current_ip upnpc -l | grep -E "$IP_ADDR|$PRE_IP" > "/tmp/upnpc_output" while read proto ext_port ip_port desc do # divide ip_port such as 192.168.0.60:8000 into 192.168.0.60 8000 # and get the ip value such as "192.168.0.60" ip=$(echo $ip_port | sed 's/:.*//g') if [ "$ip" == "$IP_ADDR" ] \ || [ "$ip" == "$PRE_IP" ]; then DELETE_STRING=$DELETE_STRING" "$ext_port" "$proto fi done < "/tmp/upnpc_output" if [ -n "$DELETE_STRING" ] then upnpc -d $DELETE_STRING \ -l | grep $IP_ADDR > "/tmp/upnpc_output" fi config_foreach upnpc_set_config_from_real entry /tmp/upnpc_output uci commit upnpc rm -f /tmp/upnpc_output lock -u "/var/run/upnpc" rm $RUN_ONCE_FILE_STOP } # restart port mapping upnpc_restart() { if [ -e $RUN_ONCE_FILE_RESTART ]; then exit 0 fi touch $RUN_ONCE_FILE_RESTART config_load cloud_brd config_get BIND_STATUS bind status config_load upnpc config_get upnpc_enabled upnpc_info enabled if [ "$BIND_STATUS" == "1" ] then if [ "$upnpc_enabled" == "on" ] then lock "/var/run/upnpc" upnpc -l > "/tmp/upnpc_output" upnpc_reconfigure lock -u "/var/run/upnpc" else upnpc_stop fi else upnpc_stop fi rm $RUN_ONCE_FILE_RESTART } case "$1" in maintain) upnpc_maintain ;; esac rm $RUN_ONCE_FILE 运行这个脚本有什么作用?
09-18
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值