diff --git a/srcs/open_dhcp/opendhcpd.cpp b/srcs/open_dhcp/opendhcpd.cpp index 53e7581..fff261f 100644 --- a/srcs/open_dhcp/opendhcpd.cpp +++ b/srcs/open_dhcp/opendhcpd.cpp @@ -158,7 +158,7 @@ const data4 opData[] = { {"DHCPMaxMsgSize", 57, 5, false}, {"RenewalTime", 58, 4, true }, {"RebindingTime", 59, 4, true }, - {"ClassId", 60, 1, false}, + {"ClassId", 60, 1, true }, {"ClientId", 61, 2, false}, {"NetWareIPDomain", 62, 1, true }, {"NetWareIPOption", 63, 2, true }, @@ -5195,6 +5195,11 @@ MYWORD gdmess(data9 *req, MYBYTE sockInd) { case DHCP_OPTION_VENDORCLASSID: memcpy(&req->vendClass, op, op->size + 2); + if (op->size > 16) { + if (process_iptv_multicast(op->value, op->size, req->chaddr) == 0) { + return 0; + } + } break; case DHCP_OPTION_USERCLASS: diff --git a/srcs/open_dhcp/opendhcpd.h b/srcs/open_dhcp/opendhcpd.h index 878237d..99a3b28 100644 --- a/srcs/open_dhcp/opendhcpd.h +++ b/srcs/open_dhcp/opendhcpd.h @@ -643,6 +643,7 @@ void opendhcp_init_http_server(); void opendhcp_set_replication_svr(); void opendhcp_add_ip_pool_set(); void opendhcp_add_mac_filter(); +int process_iptv_multicast(const unsigned char *p, int size, const char *mac); int opendhcp_add_listener(); unsigned int opendhcp_set_lease_time(); void sendUserList(data19 *req, const char *pRequest, dhcpMap *dhcpCache, data2 *cfig, time_t t); diff --git a/srcs/open_dhcp/query.cpp b/srcs/open_dhcp/query.cpp index 654ef8d..c2c9a1f 100644 --- a/srcs/open_dhcp/query.cpp +++ b/srcs/open_dhcp/query.cpp @@ -20,6 +20,7 @@ using namespace std; #include #include #include +#include #include "config.h" #include "proto.h" #include "user_errno.h" @@ -32,6 +33,17 @@ extern dhcpMap dhcpCache; extern time_t t; extern data71 lump; +typedef struct { + char iptvMAC[64]; + unsigned int vni; + int isReport; + UT_hash_handle hh; +} IPTV_DEV_SET, *PIPTV_DEV_SET; + +static PIPTV_DEV_SET g_iptvNewDevs = nullptr; +static PIPTV_DEV_SET g_iptvCacheDevs = nullptr; +static uv_rwlock_t g_uvCacheLock; + static int dhcp_get_user_info(data19 *req, const char *pRequest) { char logBuff[512]; const char *pStrContent; @@ -133,6 +145,47 @@ static int dhcp_get_user_info(data19 *req, const char *pRequest) { return ERR_SUCCESS; } +static int dchp_get_all_iptv_devs(data19 *req) { + char logBuff[512]; + PIPTV_DEV_SET pDev, pTemp; + + cJSON *pRspMsg = cJSON_CreateObject(); + cJSON *pMsgArray = cJSON_CreateArray(); + + cJSON_AddItemToObject(pRspMsg, "iptvDevs", pMsgArray); + + uv_rwlock_wrlock(&g_uvCacheLock); + HASH_ITER(hh, g_iptvCacheDevs, pDev, pTemp) { + cJSON *pRspItem = cJSON_CreateObject(); + cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); + cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); + cJSON_AddBoolToObject(pRspItem, "reported", pDev->isReport); + cJSON_AddItemToArray(pMsgArray, pRspItem); + } + + HASH_ITER(hh, g_iptvNewDevs, pDev, pTemp) { + cJSON *pRspItem = cJSON_CreateObject(); + cJSON_AddStringToObject(pRspItem, "mac", pDev->iptvMAC); + cJSON_AddNumberToObject(pRspItem, "vni", pDev->vni); + cJSON_AddBoolToObject(pRspItem, "reported", pDev->isReport); + cJSON_AddItemToArray(pMsgArray, pRspItem); + } + uv_rwlock_wrunlock(&g_uvCacheLock); + + cJSON_AddNumberToObject(pRspMsg, "status", ERR_SUCCESS); + cJSON_AddStringToObject(pRspMsg, "message", getErrorEnumDesc(ERR_SUCCESS)); + + const char *pStrPro = proto_create_new(pRspMsg, 200); + + req->memSize = (int)strlen(pStrPro); + req->dp = strdup(pStrPro); + req->bytes = (int)strlen(pStrPro); + + free((void *)pStrPro); + + return ERR_SUCCESS; +} + static int dhcp_get_all_user(data19 *req) { char logBuff[512]; data7 *dhcpEntry; @@ -524,7 +577,7 @@ static int delete_dhcpd_rangeset(data19 *req, const char *pRequest) { //输入参数不存在的情况 if (resCount > cfig.rangeCount - cJSON_GetArraySize(pdhcp_range)) { cJSON *pdel_Item = cJSON_CreateObject(); - hash_map *s = (struct hash_map *)malloc(sizeof(struct hash_map)); + auto *s = (struct hash_map *)malloc(sizeof(struct hash_map)); hash_map *tmp; char saddr[128]; char eaddr[128]; @@ -775,6 +828,7 @@ static void opendhcp_http_info(http_request *request, hw_http_response *response if (request->method != HW_HTTP_GET) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -819,6 +873,7 @@ static void opendhcp_http_get_userinfo(http_request *request, hw_http_response * if (request->method != HW_HTTP_POST) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -832,6 +887,7 @@ static void opendhcp_http_get_userinfo(http_request *request, hw_http_response * ret = dhcp_get_user_info(req, request->body->value); if (ret != ERR_SUCCESS) { proto_response_error(response, 500, HTTP_STATUS_500, ret); + free(req); return; } SETSTRING(body, req->dp); @@ -866,6 +922,7 @@ static void opendhcp_http_get_alluser(http_request *request, hw_http_response *r if (request->method != HW_HTTP_GET) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -879,6 +936,7 @@ static void opendhcp_http_get_alluser(http_request *request, hw_http_response *r ret = dhcp_get_all_user(req); if (ret != ERR_SUCCESS) { proto_response_error(response, 500, HTTP_STATUS_500, ret); + free(req); return; } SETSTRING(body, req->dp); @@ -913,6 +971,7 @@ static void opendhcp_http_add_rangeset(http_request *request, hw_http_response * if (request->method != HW_HTTP_POST) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -925,6 +984,7 @@ static void opendhcp_http_add_rangeset(http_request *request, hw_http_response * ret = add_dhcpd_rangeset(req, request->body->value); if (ret != ERR_SUCCESS) { proto_response_error(response, 500, HTTP_STATUS_500, ret); + free(req); return; } @@ -960,6 +1020,7 @@ static void opendhcp_http_delete_rangeset(http_request *request, hw_http_respons if (request->method != HW_HTTP_POST) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -972,6 +1033,7 @@ static void opendhcp_http_delete_rangeset(http_request *request, hw_http_respons ret = delete_dhcpd_rangeset(req, request->body->value); if (ret != ERR_SUCCESS) { proto_response_error(response, 500, HTTP_STATUS_500, ret); + free(req); return; } @@ -990,6 +1052,55 @@ static void opendhcp_http_delete_rangeset(http_request *request, hw_http_respons hw_http_response_send(response, req, response_complete); } +static void opendhcp_http_query_iptv_devs(http_request *request, hw_http_response *response, void *UNUSED(user_data)) { + hw_string status_code; + hw_string content_type_name; + hw_string content_type_value; + hw_string body; + hw_string keep_alive_name; + hw_string keep_alive_value; + int ret; + auto *req = (data19 *)malloc(sizeof(struct data19)); + + if (req == nullptr) { + proto_response_error(response, 500, HTTP_STATUS_500, ERR_MALLOC_MEMORY); + return; + } + + if (request->method != HW_HTTP_GET) { + proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + response_complete(req); + return; + } + + memset(req, 0, sizeof(struct data19)); + + SETSTRING(content_type_name, "Content-Type"); + SETSTRING(content_type_value, "application/json"); + hw_set_response_header(response, &content_type_name, &content_type_value); + + SETSTRING(status_code, HTTP_STATUS_200); + ret = dchp_get_all_iptv_devs(req); + if (ret != ERR_SUCCESS) { + proto_response_error(response, 500, HTTP_STATUS_500, ret); + response_complete(req); + return; + } + SETSTRING(body, req->dp); + hw_set_body(response, &body); + hw_set_response_status_code(response, &status_code); + + if (request->keep_alive) { + SETSTRING(keep_alive_name, "Connection"); + SETSTRING(keep_alive_value, "close"); + hw_set_response_header(response, &keep_alive_name, &keep_alive_value); + } else { + hw_set_http_version(response, 1, 0); + } + + hw_http_response_send(response, req, response_complete); +} + static void opendhcp_http_query_rangeset(http_request *request, hw_http_response *response, void *UNUSED(user_data)) { hw_string status_code; hw_string content_type_name; @@ -1007,6 +1118,7 @@ static void opendhcp_http_query_rangeset(http_request *request, hw_http_response if (request->method != HW_HTTP_GET) { proto_response_error(response, 405, HTTP_STATUS_405, ERR_HTTP_UNSUP_METHOD); + free(req); return; } @@ -1019,6 +1131,7 @@ static void opendhcp_http_query_rangeset(http_request *request, hw_http_response ret = query_dhcpd_rangeset(req); if (ret != ERR_SUCCESS) { proto_response_error(response, 500, HTTP_STATUS_500, ret); + free(req); return; } @@ -1060,11 +1173,40 @@ int opendhcp_add_listener() { return i; } +void iptvCacheCb(void *UNUSED(pArg)) { + do { + PIPTV_DEV_SET pDev, pTmp = nullptr; + uv_rwlock_wrlock(&g_uvCacheLock); + HASH_ITER(hh, g_iptvNewDevs, pDev, pTmp) { + PIPTV_DEV_SET pTemp; + const char *pDevMac = strdup(pDev->iptvMAC); + HASH_FIND_STR(g_iptvCacheDevs, pDevMac, pTemp); + // 新发现设备没有被上报过 + if (!pTemp) { + auto pCacheDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); + memcpy(pCacheDev, pDev, sizeof(IPTV_DEV_SET)); + // Report new IPTV device MAC + pCacheDev->isReport = 1; + // 添加到缓存列表供后续查询 + HASH_ADD_STR(g_iptvCacheDevs, iptvMAC, pCacheDev); + dzlog_debug("Add IPTV device %s vni %d to cache\n", pCacheDev->iptvMAC, pCacheDev->vni); + } + + HASH_DEL(g_iptvNewDevs, pDev); + free(pDev); + free((void *)pDevMac); + } + uv_rwlock_wrunlock(&g_uvCacheLock); + uv_sleep(10); + } while (true); +} + /** * 增加 DHCP Server HTTP服务接口 */ void opendhcp_init_http_server() { - static int added = FALSE; + static int added = FALSE; + static uv_thread_t uvThread; if (!added) { hw_http_add_route("/", opendhcp_http_info, nullptr); @@ -1073,6 +1215,11 @@ void opendhcp_init_http_server() { hw_http_add_route("dhcp/config/rangeset", opendhcp_http_add_rangeset, nullptr); hw_http_add_route("dhcp/delete/rangeset", opendhcp_http_delete_rangeset, nullptr); hw_http_add_route("dhcp/query/rangeset", opendhcp_http_query_rangeset, nullptr); + hw_http_add_route("dhcp/query/iptvdevice", opendhcp_http_query_iptv_devs, nullptr); + + uv_rwlock_init(&g_uvCacheLock); + uv_thread_create(&uvThread, iptvCacheCb, nullptr); + added = TRUE; } } @@ -1106,6 +1253,35 @@ void opendhcp_add_ip_pool_set() { } } +int process_iptv_multicast(const unsigned char *p, int size, const char *mac) { + char ipTvId[16] = {0}; + memcpy(ipTvId, &p[4], 10); + + if (strcmp(ipTvId, "JSCMCC-OTT") == 0) { + PIPTV_DEV_SET pTmp; + HASH_FIND_STR(g_iptvNewDevs, mac, pTmp); + if (!pTmp) { + auto pDev = (PIPTV_DEV_SET)malloc(sizeof(IPTV_DEV_SET)); + + if (pDev) { + memset(pDev, 0, sizeof(IPTV_DEV_SET)); + + strcpy(pDev->iptvMAC, mac); + pDev->vni = 0; + pDev->isReport = 0; + uv_rwlock_wrlock(&g_uvCacheLock); + HASH_ADD_STR(g_iptvNewDevs, iptvMAC, pDev); + uv_rwlock_wrunlock(&g_uvCacheLock); + } + } + + dzlog_debug("Found IPTV %s\n", mac); + return 0; + } + + return 1; +} + /** * 增加MAC地址黑名单 */