2015-11-25 11 views
2

Я бы хотел поискать Sat> IP-серверы в сети. Sat> IP-серверы рекламируют свое присутствие на других серверах и клиентах Sat> IP. Я не должен постоянно отправлять сообщения M-SEARCH, но вместо этого он прослушивает сообщения NOTIFY сервера.Как слушать непрерывный ответ SSDP после отправки M-SEARCH

После инициализации сетевых настроек моего устройства, я отправляю сообщение M-SEARCH и получаю ответ, если есть уже активный Sat> IP-сервер. Однако я не мог получить никакого ответа, если я открою Sat> IP-сервер после отправки сообщения M-SEARCH.

Вот мой код.

void SatIP::InitDiscoverThread() 
{ 
    if(INVALID_THREAD_CHK == DiscoverThreadChk) 
    { 
     pthread_attr_t attr; 
     pthread_attr_init(&attr); 
     pthread_attr_setstacksize(&attr, PTHREAD_STACK_SIZE); 

     printf("InitDiscoverThread pthread_create\n"); 
     DiscoverThreadChk = PTH_RET_CHK(pthread_create(&DiscoverThreadID, &attr, DiscoverThreadFunc, this)); 
     if(DiscoverThreadChk != 0) 
     { 
      ASSERT(0); 
     } 
    } 
} 

void SatIP::FinalizeDiscoverThread() 
{ 
    if(INVALID_THREAD_CHK != DiscoverThreadChk) 
    { 
     printf("FinalizeDiscoverThread pthread_cancel\n"); 
     pthread_cancel(DiscoverThreadID); 
     DiscoverThreadChk = INVALID_THREAD_CHK; 
     close(discoverSocket); 
    } 
} 

void *SatIP::DiscoverThreadFunc(void* arg) 
{ 
    SatIP* satip = (SatIP *)arg; 
    satip->ListenSSDPResponse(); 
    pthread_exit(NULL); 
} 

bool SatIP::SendMSearchMessage() 
{ 
    vSatIPServers.clear(); 
    FinalizeDiscoverThread(); 

    const char *searchSatIPDevice = "M-SEARCH * HTTP/1.1\r\n" \ 
              "HOST: 239.255.255.250:1900\r\n"  \ 
              "MAN: \"ssdp:discover\"\r\n"  \ 
              "MX: 2\r\n"   \ 
              "ST: urn:ses-com:device:SatIPServer:1\r\n\r\n"; 

    struct sockaddr_in upnpControl, broadcast_addr; 
    discoverSocket = socket(AF_INET, SOCK_DGRAM, 0); 
    if (discoverSocket == INVALID_SOCKET) 
    { 
     printf("socked failed INVALID_SOCKET\n"); 
     return false; 
    } 

    struct timeval tv; 
    tv.tv_sec = 1; 
    tv.tv_usec = 0; 
    if(setsockopt(discoverSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == SOCKET_ERROR) 
    { 
     printf("setsockopt timeout failed\n"); 
     close(discoverSocket); 
     return false; 
    } 

    socklen_t ttl = 2; 
    if(setsockopt(discoverSocket, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) == SOCKET_ERROR) 
    { 
     printf("setsockopt TTL failed\n"); 
     close(discoverSocket); 
     return false; 
    } 

    if(setsockopt(discoverSocket, SOL_SOCKET, SO_BROADCAST, searchSatIPDevice, sizeof(searchSatIPDevice)) == SOCKET_ERROR) 
    { 
     printf("setsockopt broadcast failed\n"); 
     close(discoverSocket); 
     return false; 
    } 

    upnpControl.sin_family = AF_INET; 
    upnpControl.sin_port = htons(0); 
    upnpControl.sin_addr.s_addr = INADDR_ANY; 
    if (bind(discoverSocket, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR) 
    { 
     printf("bind failed\n"); 
     close(discoverSocket); 
     return false; 
    } 

    broadcast_addr.sin_family = AF_INET; 
    broadcast_addr.sin_port = htons(1900); 
    broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250"); 

    for(int i = 0; i < 3; i++) 
    { 
     if(sendto(discoverSocket, searchSatIPDevice, strlen(searchSatIPDevice), 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR) 
     { 
      //printf("sendto failed\n"); 
      close(discoverSocket); 
      return false; 
     } 
     else 
     { 
      usleep(10*100); 
     } 
    } 

    InitDiscoverThread(); 

    return true; 
} 

void SatIP::ListenSSDPResponse() 
{ 
    while(1) 
    { 
     char buf[512]; 
     memset(buf, 0, 512); 

     struct sockaddr_in broadcast_addr; 
     broadcast_addr.sin_family = AF_INET; 
     broadcast_addr.sin_port = htons(1900); 
     broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250"); 
     int bcLen = sizeof(broadcast_addr); 

     //bool bRet = false; 
     while (recvfrom(discoverSocket, buf, 512, 0, (struct sockaddr*)&broadcast_addr, (socklen_t*)&bcLen) > 0) 
     { 
      printf("buf:%s\n",buf); 
      SATIP_SERVER_DESCRIPTION stServerDesc; 
      ostringstream ss; 
      if(strstr(buf, "device:SatIPServer")) 
      { 
       int i = 0; 
       char *deviceIp = strstr(buf, "LOCATION:") + 9; // get xml location including server description 
       while(deviceIp[i] == ' ') i++; // remove spaces from string 
       while(!isspace(deviceIp[i])) 
       { 
        ss << deviceIp[i]; 
        ++i; 
       } 
       stServerDesc.location = ss.str().c_str(); 
       printf("location:%s\n",stServerDesc.location.c_str()); 

       ss.str(""); // clear ss 
       i=0; // clear counter 
       deviceIp = strstr(buf, "http://") + 7; // get ip address 
       while(deviceIp[i] != ':') 
       { 
        ss << deviceIp[i]; 
        ++i; 
       } 
       stServerDesc.ipAddr = ss.str().c_str(); 
       printf("ipAddr:%s\n", stServerDesc.ipAddr.c_str()); 

       DownloadDeviceDescription(&stServerDesc); 

       stServerDesc.macAddr = GetMACAddressviaIP(stServerDesc.ipAddr); 
       printf("macAddr:%s\n", stServerDesc.macAddr.c_str()); 

       if(IsServerProperToAdd(&stServerDesc)) 
        vSatIPServers.push_back(stServerDesc); 
       printf("\n"); 
       //bRet = true; 
      } 
      memset(buf, 0, 512); 
     } 
    } 
} 

Как исправить эту проблему? Любая помощь будет оценена по достоинству.

ответ

4

Прослушивание сообщения уведомления SSDP не связано с отправкой сообщения M-SEARCH. Устройства, такие как Sat> IP, периодически посылают сообщение NOTIFY в 239.255.255.250, даже если вы не отправляете сообщение M-SEARCH. Таким образом, вы должны присоединиться к группе многоадресной передачи и получать из группы.

Вы можете использовать программу прослушивания в следующей ссылке, изменив HELLO_PORT как 1900 и HELLO_GROUP как «239.255.255.250».

http://ntrg.cs.tcd.ie/undergrad/4ba2/multicast/antony/example.html

/* 
* listener.c -- joins a multicast group and echoes all data it receives from 
*  the group to its stdout... 
* 
* Antony Courtney, 25/11/94 
* Modified by: Frédéric Bastien (25/03/04) 
* to compile without warning and work correctly 
*/ 

#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <time.h> 
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 


#define HELLO_PORT 1900 
#define HELLO_GROUP "239.255.255.250" 
#define MSGBUFSIZE 256 

main(int argc, char *argv[]) 
{ 
    struct sockaddr_in addr; 
    int fd, nbytes,addrlen; 
    struct ip_mreq mreq; 
    char msgbuf[MSGBUFSIZE]; 

    u_int yes=1;   /*** MODIFICATION TO ORIGINAL */ 

    /* create what looks like an ordinary UDP socket */ 
    if ((fd=socket(AF_INET,SOCK_DGRAM,0)) < 0) { 
     perror("socket"); 
     exit(1); 
    } 

/**** MODIFICATION TO ORIGINAL */ 
    /* allow multiple sockets to use the same PORT number */ 
    if (setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) { 
     perror("Reusing ADDR failed"); 
     exit(1); 
     } 
/*** END OF MODIFICATION TO ORIGINAL */ 

    /* set up destination address */ 
    memset(&addr,0,sizeof(addr)); 
    addr.sin_family=AF_INET; 
    addr.sin_addr.s_addr=htonl(INADDR_ANY); /* N.B.: differs from sender */ 
    addr.sin_port=htons(HELLO_PORT); 

    /* bind to receive address */ 
    if (bind(fd,(struct sockaddr *) &addr,sizeof(addr)) < 0) { 
     perror("bind"); 
     exit(1); 
    } 

    /* use setsockopt() to request that the kernel join a multicast group */ 
    mreq.imr_multiaddr.s_addr=inet_addr(HELLO_GROUP); 
    mreq.imr_interface.s_addr=htonl(INADDR_ANY); 
    if (setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0) { 
     perror("setsockopt"); 
     exit(1); 
    } 

    /* now just enter a read-print loop */ 
    while (1) { 
     addrlen=sizeof(addr); 
     if ((nbytes=recvfrom(fd,msgbuf,MSGBUFSIZE,0, 
       (struct sockaddr *) &addr,&addrlen)) < 0) { 
      perror("recvfrom"); 
      exit(1); 
     } 
     puts(msgbuf); 
    } 
}