mirror of
https://github.com/Netflix/dial-reference.git
synced 2026-06-08 10:59:59 +00:00
dial spec 2.0
This commit is contained in:
@@ -1,3 +1,9 @@
|
|||||||
|
---------------------------------------------------------------------
|
||||||
|
Version 1.0.6 (72ab437)
|
||||||
|
---------------------------------------------------------------------
|
||||||
|
Server changes:
|
||||||
|
- Update to DIAL specificiation 2.0
|
||||||
|
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
Version 1.0.5 (06edbce)
|
Version 1.0.5 (06edbce)
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include "DialDiscovery.h"
|
#include "DialDiscovery.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
#define SSDP_TIMEOUT 30
|
#define SSDP_TIMEOUT 30
|
||||||
#define SSDP_RESPONSE_TIMEOUT 3
|
#define SSDP_RESPONSE_TIMEOUT 3
|
||||||
@@ -97,6 +98,45 @@ static string getLocation(char *pResponse)
|
|||||||
return retUrl;
|
return retUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string getMac(char *pResponse)
|
||||||
|
{
|
||||||
|
string response(pResponse);
|
||||||
|
string mac("");
|
||||||
|
size_t index = response.find("WAKEUP:");
|
||||||
|
|
||||||
|
if (index==string::npos){
|
||||||
|
return mac;
|
||||||
|
}else{
|
||||||
|
size_t start = response.find("MAC=", index);
|
||||||
|
if (start==string::npos) return mac;
|
||||||
|
start+=4;
|
||||||
|
size_t end = response.find(";", start);
|
||||||
|
if (end==string::npos) return mac;
|
||||||
|
mac = response.substr(start, end-start);
|
||||||
|
return mac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getTimeout(char *pResponse)
|
||||||
|
{
|
||||||
|
string response(pResponse);
|
||||||
|
int timeOut=0;
|
||||||
|
string timeOutStr;
|
||||||
|
size_t index = response.find("WAKEUP:");
|
||||||
|
if (index==string::npos){
|
||||||
|
return timeOut;
|
||||||
|
}else{
|
||||||
|
size_t start = response.find("Timeout=", index);
|
||||||
|
if (start==string::npos) return timeOut;
|
||||||
|
start+=8;
|
||||||
|
size_t end = response.find("\r\n", start);
|
||||||
|
if (end==string::npos) return timeOut;
|
||||||
|
timeOutStr = response.substr(start, end-start);
|
||||||
|
timeOut = (int)(strtol(timeOutStr.c_str(), NULL, 10));
|
||||||
|
return timeOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static size_t header_cb(void* ptr, size_t size, size_t nmemb, void* userdata)
|
static size_t header_cb(void* ptr, size_t size, size_t nmemb, void* userdata)
|
||||||
{
|
{
|
||||||
if ((size * nmemb) != 0) {
|
if ((size * nmemb) != 0) {
|
||||||
@@ -132,7 +172,6 @@ static void getServerInfo( const string &server, string& appsUrl, string& ddxml
|
|||||||
{
|
{
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
CURLcode res = CURLE_OK;
|
CURLcode res = CURLE_OK;
|
||||||
|
|
||||||
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
|
||||||
fprintf(stderr, "curl_global_init() failed\n");
|
fprintf(stderr, "curl_global_init() failed\n");
|
||||||
return;
|
return;
|
||||||
@@ -146,6 +185,7 @@ static void getServerInfo( const string &server, string& appsUrl, string& ddxml
|
|||||||
|
|
||||||
ATRACE("Sending ##%s##\n", server.c_str());
|
ATRACE("Sending ##%s##\n", server.c_str());
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, server.c_str());
|
curl_easy_setopt(curl, CURLOPT_URL, server.c_str());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);
|
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_cb);
|
||||||
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &appsUrl);
|
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &appsUrl);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveData);
|
||||||
@@ -157,7 +197,7 @@ static void getServerInfo( const string &server, string& appsUrl, string& ddxml
|
|||||||
//curl_global_cleanup();
|
//curl_global_cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialDiscovery::updateServerList(string& server)
|
void DialDiscovery::updateServerList(string& server, string mac, int timeOut)
|
||||||
{
|
{
|
||||||
ServerMap::const_iterator it;
|
ServerMap::const_iterator it;
|
||||||
it = mServerMap.find(server);
|
it = mServerMap.find(server);
|
||||||
@@ -165,7 +205,7 @@ void DialDiscovery::updateServerList(string& server)
|
|||||||
// not found, add it
|
// not found, add it
|
||||||
string appsUrl, ddxml;
|
string appsUrl, ddxml;
|
||||||
getServerInfo(server, appsUrl, ddxml);
|
getServerInfo(server, appsUrl, ddxml);
|
||||||
mServerMap[server] = new DialServer(server, appsUrl, ddxml);
|
mServerMap[server] = new DialServer(server, appsUrl, ddxml, mac, timeOut);
|
||||||
} else {
|
} else {
|
||||||
// just mark that we found it
|
// just mark that we found it
|
||||||
(*it).second->setFound(true);
|
(*it).second->setFound(true);
|
||||||
@@ -182,8 +222,11 @@ void DialDiscovery::processServer(char *pResponse)
|
|||||||
server = getLocation(pResponse);
|
server = getLocation(pResponse);
|
||||||
ATRACE("FOUND server: %s\n", server.c_str());
|
ATRACE("FOUND server: %s\n", server.c_str());
|
||||||
|
|
||||||
|
string mac=getMac(pResponse);
|
||||||
|
int timeOut=getTimeout(pResponse);
|
||||||
|
|
||||||
// save the appURL in the server
|
// save the appURL in the server
|
||||||
updateServerList(server);
|
updateServerList(server, mac, timeOut);
|
||||||
#ifndef DEBUG
|
#ifndef DEBUG
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -196,9 +239,30 @@ void DialDiscovery::processServer(char *pResponse)
|
|||||||
void *DialDiscovery::receiveResponses(void *p)
|
void *DialDiscovery::receiveResponses(void *p)
|
||||||
{
|
{
|
||||||
search_conn *pConn = (search_conn*)p;
|
search_conn *pConn = (search_conn*)p;
|
||||||
|
|
||||||
|
fd_set readfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int selectRt;
|
||||||
|
// clear the set ahead of time
|
||||||
|
FD_ZERO(&readfds);
|
||||||
|
// add our descriptors to the set
|
||||||
|
FD_SET(pConn->sock, &readfds);
|
||||||
|
// wait until either socket has data ready to be recv()d (timeout 1.5 secs)
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 500000;
|
||||||
|
|
||||||
int bytes;
|
int bytes;
|
||||||
char buf[4096] = {0,};
|
char buf[4096] = {0,};
|
||||||
while (1) {
|
time_t start=std::time(NULL);
|
||||||
|
while (std::time(NULL)-start<RESPONSE_TIMEOUT) {
|
||||||
|
// printf("beat %ld %ld %ld\n", std::time(NULL), start, std::time(NULL)-start);
|
||||||
|
selectRt=select(pConn->sock+1, &readfds, NULL, NULL, &tv);
|
||||||
|
if (selectRt==-1){
|
||||||
|
perror("select"); // error occurred in select()
|
||||||
|
break;
|
||||||
|
}else if (selectRt == 0){
|
||||||
|
// printf("Timeout occurred! No data after 1.5 seconds.\n");
|
||||||
|
}else{
|
||||||
if (-1 == (bytes = recvfrom(pConn->sock, buf, sizeof(buf) - 1, 0,
|
if (-1 == (bytes = recvfrom(pConn->sock, buf, sizeof(buf) - 1, 0,
|
||||||
(struct sockaddr *)&pConn->saddr, &pConn->addrlen))) {
|
(struct sockaddr *)&pConn->saddr, &pConn->addrlen))) {
|
||||||
perror("recvfrom");
|
perror("recvfrom");
|
||||||
@@ -208,6 +272,7 @@ void *DialDiscovery::receiveResponses(void *p)
|
|||||||
ATRACE("Received [%s:%d] %s\n", __FUNCTION__, __LINE__, buf);
|
ATRACE("Received [%s:%d] %s\n", __FUNCTION__, __LINE__, buf);
|
||||||
DialDiscovery::instance()->processServer(buf);
|
DialDiscovery::instance()->processServer(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,17 +309,17 @@ void DialDiscovery::resetDiscovery(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void * DialDiscovery::send_mcast(void *p)
|
void *DialDiscovery::send_mcast()
|
||||||
{
|
{
|
||||||
int one = 1, my_sock;
|
int one = 1, my_sock;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
//struct ip_mreq mreq;
|
//struct ip_mreq mreq;
|
||||||
char send_buf[strlen((char*)ssdp_msearch) + INET_ADDRSTRLEN + 256] = {0,};
|
char send_buf[strlen((char*)ssdp_msearch) + INET_ADDRSTRLEN + 256] = {0,};
|
||||||
int send_size;
|
int send_size;
|
||||||
pthread_attr_t attr;
|
|
||||||
search_conn connection;
|
search_conn connection;
|
||||||
|
|
||||||
// send_size = snprintf(send_buf, sizeof(send_buf), ssdp_msearch, ip_addr, my_port);
|
printf("Sending mcast for discovery. Please wait for %d seconds for the response.\n", RESPONSE_TIMEOUT);
|
||||||
|
|
||||||
send_size = snprintf(send_buf, sizeof(send_buf), ssdp_msearch);
|
send_size = snprintf(send_buf, sizeof(send_buf), ssdp_msearch);
|
||||||
ATRACE("[%s:%d] %s\n", __FUNCTION__, __LINE__, send_buf);
|
ATRACE("[%s:%d] %s\n", __FUNCTION__, __LINE__, send_buf);
|
||||||
|
|
||||||
@@ -270,45 +335,38 @@ void * DialDiscovery::send_mcast(void *p)
|
|||||||
saddr.sin_addr.s_addr = inet_addr("239.255.255.250");
|
saddr.sin_addr.s_addr = inet_addr("239.255.255.250");
|
||||||
saddr.sin_port = htons(1900);
|
saddr.sin_port = htons(1900);
|
||||||
|
|
||||||
while (1) {
|
|
||||||
addrlen = sizeof(saddr);
|
addrlen = sizeof(saddr);
|
||||||
ATRACE("Sending SSDP M-SEARCH to %s:%d\n",
|
ATRACE("Sending SSDP M-SEARCH to %s:%d\n",
|
||||||
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
|
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
|
||||||
if (-1 == sendto(my_sock, send_buf, send_size, 0, (struct sockaddr *)&saddr, addrlen)) {
|
if (-1 == sendto(my_sock, send_buf, send_size, 0, (struct sockaddr *)&saddr, addrlen)) {
|
||||||
perror("sendto");
|
perror("sendto");
|
||||||
continue;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set all servers to not found
|
// set all servers to not found
|
||||||
DialDiscovery::instance()->resetDiscovery();
|
DialDiscovery::instance()->resetDiscovery();
|
||||||
|
|
||||||
// spawn a response thread
|
|
||||||
connection.saddr = saddr;
|
connection.saddr = saddr;
|
||||||
connection.sock = my_sock;
|
connection.sock = my_sock;
|
||||||
connection.addrlen = addrlen;
|
connection.addrlen = addrlen;
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
|
||||||
pthread_create(&DialDiscovery::instance()->_responseThread, &attr, DialDiscovery::receiveResponses, &connection);
|
|
||||||
|
|
||||||
// sleep SSDP_RESPONSE_TIMEOUT seconds to allow clients to response
|
receiveResponses(&connection);
|
||||||
sleep(SSDP_RESPONSE_TIMEOUT);
|
|
||||||
|
// // sleep SSDP_RESPONSE_TIMEOUT seconds to allow clients to response
|
||||||
|
// sleep(SSDP_RESPONSE_TIMEOUT);
|
||||||
DialDiscovery::instance()->cleanServerList();
|
DialDiscovery::instance()->cleanServerList();
|
||||||
|
|
||||||
sleep(SSDP_TIMEOUT-SSDP_RESPONSE_TIMEOUT);
|
return 0;
|
||||||
pthread_cancel(DialDiscovery::instance()->_responseThread);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialDiscovery::init()
|
void DialDiscovery::init()
|
||||||
{
|
{
|
||||||
pthread_attr_t attr;
|
send_mcast();
|
||||||
pthread_attr_init(&attr);
|
|
||||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
|
||||||
pthread_create(&_mcastThread, &attr, DialDiscovery::send_mcast, (void*)ssdp_msearch );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DialDiscovery::getServerList( vector<DialServer*>& list )
|
void DialDiscovery::getServerList( vector<DialServer*>& list )
|
||||||
{
|
{
|
||||||
|
list.clear();
|
||||||
for( ServerMap::iterator it = mServerMap.begin(); it != mServerMap.end(); ++it ) {
|
for( ServerMap::iterator it = mServerMap.begin(); it != mServerMap.end(); ++it ) {
|
||||||
list.push_back( it->second );
|
list.push_back( it->second );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,11 @@ public:
|
|||||||
const string& friendlyName,
|
const string& friendlyName,
|
||||||
DialServer &server );
|
DialServer &server );
|
||||||
|
|
||||||
|
void *send_mcast();
|
||||||
private:
|
private:
|
||||||
DialDiscovery();
|
DialDiscovery();
|
||||||
void updateServerList(string& server);
|
void updateServerList(string& server, string mac, int timeOut);
|
||||||
static void *receiveResponses(void *p);
|
static void *receiveResponses(void *p);
|
||||||
static void *send_mcast(void *p);
|
|
||||||
void processServer(char *pResponse);
|
void processServer(char *pResponse);
|
||||||
void cleanServerList();
|
void cleanServerList();
|
||||||
void resetDiscovery();
|
void resetDiscovery();
|
||||||
@@ -89,6 +89,7 @@ private:
|
|||||||
ServerMap mServerMap;
|
ServerMap mServerMap;
|
||||||
|
|
||||||
static DialDiscovery* sDiscovery;
|
static DialDiscovery* sDiscovery;
|
||||||
|
static const int RESPONSE_TIMEOUT = 5;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DIALDISCOVERY_H
|
#endif // DIALDISCOVERY_H
|
||||||
|
|||||||
@@ -185,6 +185,16 @@ bool DialServer::getUuid( string& uuid )
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string DialServer::getMacAddress()
|
||||||
|
{
|
||||||
|
return m_macAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DialServer::getWakeOnLanTimeout()
|
||||||
|
{
|
||||||
|
return m_wakeUpTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
int DialServer::launchApplication(
|
int DialServer::launchApplication(
|
||||||
string &application,
|
string &application,
|
||||||
string &payload,
|
string &payload,
|
||||||
@@ -193,8 +203,8 @@ int DialServer::launchApplication(
|
|||||||
{
|
{
|
||||||
ATRACE("%s: Launch %s\n", __FUNCTION__, application.c_str());
|
ATRACE("%s: Launch %s\n", __FUNCTION__, application.c_str());
|
||||||
string appUrl = m_appsUrl;
|
string appUrl = m_appsUrl;
|
||||||
sendCommand( appUrl.append(application), COMMAND_LAUNCH, payload, responseHeaders, responseBody);
|
int status = sendCommand( appUrl.append(application), COMMAND_LAUNCH, payload, responseHeaders, responseBody);
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DialServer::getStatus(
|
int DialServer::getStatus(
|
||||||
@@ -205,8 +215,9 @@ int DialServer::getStatus(
|
|||||||
ATRACE("%s: GetStatus %s\n", __FUNCTION__, application.c_str());
|
ATRACE("%s: GetStatus %s\n", __FUNCTION__, application.c_str());
|
||||||
string emptyPayload;
|
string emptyPayload;
|
||||||
string appUrl = m_appsUrl;
|
string appUrl = m_appsUrl;
|
||||||
sendCommand( appUrl.append(application), COMMAND_STATUS, emptyPayload, responseHeaders, responseBody );
|
int status = sendCommand( appUrl.append(application), COMMAND_STATUS, emptyPayload, responseHeaders, responseBody );
|
||||||
|
|
||||||
|
if (!status) return 0;
|
||||||
ATRACE("Body: %s\n", responseBody.c_str());
|
ATRACE("Body: %s\n", responseBody.c_str());
|
||||||
unsigned found = responseBody.find("href=");
|
unsigned found = responseBody.find("href=");
|
||||||
if( found != string::npos )
|
if( found != string::npos )
|
||||||
@@ -234,10 +245,10 @@ int DialServer::stopApplication(
|
|||||||
// just call status to update the run endpoint
|
// just call status to update the run endpoint
|
||||||
getStatus( application, responseHeaders, responseBody );
|
getStatus( application, responseHeaders, responseBody );
|
||||||
|
|
||||||
sendCommand(
|
int status = sendCommand(
|
||||||
(appUrl.append(application)).append("/"+m_stopEndPoint),
|
(appUrl.append(application)).append("/"+m_stopEndPoint),
|
||||||
COMMAND_KILL, emptyPayload, responseHeaders, responseBody );
|
COMMAND_KILL, emptyPayload, responseHeaders, responseBody );
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DialServer::getHttpResponseHeader(
|
int DialServer::getHttpResponseHeader(
|
||||||
|
|||||||
@@ -50,11 +50,13 @@ public:
|
|||||||
* empty string to find any server
|
* empty string to find any server
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
DialServer( string location, string appsUrl, string dd_xml ) :
|
DialServer( string location, string appsUrl, string dd_xml, string macAddr, int wakeUpTimeout) :
|
||||||
m_location(location),
|
m_location(location),
|
||||||
m_appsUrl(appsUrl),
|
m_appsUrl(appsUrl),
|
||||||
found(true),
|
found(true),
|
||||||
m_ddxml(dd_xml)
|
m_ddxml(dd_xml),
|
||||||
|
m_macAddr(macAddr),
|
||||||
|
m_wakeUpTimeout(wakeUpTimeout)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~DialServer() { ATRACE("%s\n", __FUNCTION__); }
|
~DialServer() { ATRACE("%s\n", __FUNCTION__); }
|
||||||
@@ -94,6 +96,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool getUuid( string& uuid );
|
bool getUuid( string& uuid );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the dial server mac address
|
||||||
|
*
|
||||||
|
* @return mac address if avaliable, '' if not.
|
||||||
|
*/
|
||||||
|
string getMacAddress();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the wake on lan timeout in seconds
|
||||||
|
*
|
||||||
|
* @return timeout value if avaliable, zero if not.
|
||||||
|
*/
|
||||||
|
int getWakeOnLanTimeout();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch a DIAL application
|
* Launch a DIAL application
|
||||||
*
|
*
|
||||||
@@ -176,6 +192,9 @@ private:
|
|||||||
bool found;
|
bool found;
|
||||||
string m_ddxml; // information about the device
|
string m_ddxml; // information about the device
|
||||||
string m_stopEndPoint;
|
string m_stopEndPoint;
|
||||||
|
string m_macAddr;
|
||||||
|
int m_wakeUpTimeout;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DIALSERVER_H
|
#endif // DIALSERVER_H
|
||||||
|
|||||||
112
client/main.cpp
112
client/main.cpp
@@ -31,6 +31,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@@ -51,12 +56,15 @@ static void printServerList( vector<DialServer*> list )
|
|||||||
vector<DialServer*>::iterator it;
|
vector<DialServer*>::iterator it;
|
||||||
for( i = 0, it = list.begin(); it < list.end(); it++, i++ )
|
for( i = 0, it = list.begin(); it < list.end(); it++, i++ )
|
||||||
{
|
{
|
||||||
string uuid, name;
|
string uuid, name, macAddr;
|
||||||
|
int wolTimeOut;
|
||||||
(*it)->getFriendlyName( name );
|
(*it)->getFriendlyName( name );
|
||||||
(*it)->getUuid( uuid );
|
(*it)->getUuid( uuid );
|
||||||
printf("%Zu: Server IP[%s] UUID[%s] FriendlyName[%s] \n",
|
macAddr =(*it)->getMacAddress();
|
||||||
|
wolTimeOut =(*it)->getWakeOnLanTimeout();
|
||||||
|
printf("%Zu: Server IP[%s] UUID[%s] FriendlyName[%s] MacAddress[%s] WakeOnLanTimeout[%d]\n",
|
||||||
i+1, (*it)->getIpAddress().c_str(),
|
i+1, (*it)->getIpAddress().c_str(),
|
||||||
uuid.c_str(), name.c_str() );
|
uuid.c_str(), name.c_str(), macAddr.c_str(), wolTimeOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,22 +72,19 @@ static DialServer* getServerFromUser( vector<DialServer*> list )
|
|||||||
{
|
{
|
||||||
DialServer* pServer;
|
DialServer* pServer;
|
||||||
// show a list to the user
|
// show a list to the user
|
||||||
if( list.size() > 1 )
|
|
||||||
{
|
|
||||||
char buf[80] = {0,};
|
char buf[80] = {0,};
|
||||||
vector<DialServer*>::iterator it;
|
vector<DialServer*>::iterator it;
|
||||||
|
|
||||||
printf("Found Multiple servers\n");
|
printf("Found Multiple servers\n");
|
||||||
|
printf("0: Rescan and list DIAL servers\n");
|
||||||
printServerList(list);
|
printServerList(list);
|
||||||
printf("Enter server: ");
|
printf("Enter server: ");
|
||||||
scanf("%s", buf);
|
scanf("%s", buf);
|
||||||
unsigned int server = atoi(buf);
|
unsigned int server = atoi(buf);
|
||||||
assert( server > 0 && server <= list.size() );
|
if( server > 0 && server <= list.size()){
|
||||||
pServer = list[server-1];
|
pServer = list[server-1];
|
||||||
}
|
}else{
|
||||||
else
|
pServer = NULL;
|
||||||
{
|
|
||||||
pServer = list.front();
|
|
||||||
}
|
}
|
||||||
return pServer;
|
return pServer;
|
||||||
}
|
}
|
||||||
@@ -141,27 +146,81 @@ static void runConformance()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sendMagic(string macAddr)
|
||||||
|
{
|
||||||
|
unsigned char tosend[102];
|
||||||
|
unsigned char mac[6];
|
||||||
|
|
||||||
|
/** first 6 bytes of 255 **/
|
||||||
|
for(int i = 0; i < 6; i++) {
|
||||||
|
tosend[i] = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** store mac address **/
|
||||||
|
printf("sending magic packet to: ");
|
||||||
|
for (int i=0; i<6; i++){
|
||||||
|
mac[i]=(unsigned char)(strtoul(macAddr.substr(i*3, 2).c_str(), NULL, 16));
|
||||||
|
printf("%02x:", mac[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/** append it 16 times to packet **/
|
||||||
|
for(int i = 1; i <= 16; i++) {
|
||||||
|
memcpy(&tosend[i * 6], &mac, 6 * sizeof(unsigned char));
|
||||||
|
}
|
||||||
|
|
||||||
|
int udpSocket;
|
||||||
|
struct sockaddr_in udpClient, udpServer;
|
||||||
|
int broadcast = 1;
|
||||||
|
|
||||||
|
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
/** you need to set this so you can broadcast **/
|
||||||
|
if (setsockopt(udpSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast) == -1) {
|
||||||
|
perror("setsockopt (SO_BROADCAST)");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
udpClient.sin_family = AF_INET;
|
||||||
|
udpClient.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
udpClient.sin_port = 0;
|
||||||
|
|
||||||
|
bind(udpSocket, (struct sockaddr*)&udpClient, sizeof(udpClient));
|
||||||
|
|
||||||
|
/** set server end point (the broadcast addres)**/
|
||||||
|
udpServer.sin_family = AF_INET;
|
||||||
|
udpServer.sin_addr.s_addr = inet_addr("255.255.255.255");
|
||||||
|
udpServer.sin_port = htons(9);
|
||||||
|
|
||||||
|
/** send the packet **/
|
||||||
|
sendto(udpSocket, &tosend, sizeof(unsigned char) * 102, 0, (struct sockaddr*)&udpServer, sizeof(udpServer));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int handleUser(DialDiscovery *pDial) {
|
int handleUser(DialDiscovery *pDial) {
|
||||||
int processInput = 1;
|
int processInputOuter = 1;
|
||||||
char buf[80];
|
char buf[80];
|
||||||
vector<DialServer*> list;
|
vector<DialServer*> list;
|
||||||
|
|
||||||
|
while (processInputOuter){
|
||||||
pDial->getServerList(list);
|
pDial->getServerList(list);
|
||||||
if( list.size() == 0 )
|
if( list.size() == 0 ){
|
||||||
{
|
|
||||||
printf("No servers available\n");
|
printf("No servers available\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
DialServer* pServer = getServerFromUser( list );
|
DialServer* pServer = getServerFromUser( list );
|
||||||
|
if (pServer==NULL){
|
||||||
|
pDial->send_mcast();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
while(processInput)
|
int processInput = 1;
|
||||||
{
|
while(processInput){
|
||||||
string responseHeaders, responseBody, payload;
|
string responseHeaders, responseBody, payload;
|
||||||
string netflix = "Netflix";
|
string netflix = "Netflix";
|
||||||
string youtube = "YouTube";
|
string youtube = "YouTube";
|
||||||
|
|
||||||
memset(buf, 0, 80);
|
memset(buf, 0, 80);
|
||||||
printf("0. List DIAL servers\n");
|
printf("0. Rescan and list DIAL servers\n");
|
||||||
printf("1. Launch Netflix\n");
|
printf("1. Launch Netflix\n");
|
||||||
printf("2. Kill Netflix\n");
|
printf("2. Kill Netflix\n");
|
||||||
printf("3. Netflix status\n");
|
printf("3. Netflix status\n");
|
||||||
@@ -169,21 +228,16 @@ int handleUser(DialDiscovery *pDial) {
|
|||||||
printf("5. Kill YouTube\n");
|
printf("5. Kill YouTube\n");
|
||||||
printf("6. YouTube status\n");
|
printf("6. YouTube status\n");
|
||||||
printf("7. Run conformance tests\n");
|
printf("7. Run conformance tests\n");
|
||||||
printf("8. QUIT\n");
|
printf("8. Wake up on lan/wlan\n");
|
||||||
printf("Command (0:1:2:3:4:5:6:7:8): ");
|
printf("9. QUIT\n");
|
||||||
|
printf("Command (0:1:2:3:4:5:6:7:8:9): ");
|
||||||
scanf("%s", buf);
|
scanf("%s", buf);
|
||||||
switch( atoi(buf) )
|
switch( atoi(buf) )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
printf("\n\n******** %Zu servers found ********\n\n", list.size());
|
pDial->send_mcast();
|
||||||
for( unsigned int i = 0; i < list.size(); i++ )
|
processInput=0;
|
||||||
{
|
|
||||||
string name;
|
|
||||||
list[i]->getFriendlyName(name);
|
|
||||||
printf("Server %Zu: %s\n", i+1, name.c_str());
|
|
||||||
}
|
|
||||||
printf("\n*********************************\n\n");
|
|
||||||
}break;
|
}break;
|
||||||
case 1:
|
case 1:
|
||||||
printf("Launch Netflix\n");
|
printf("Launch Netflix\n");
|
||||||
@@ -214,12 +268,18 @@ int handleUser(DialDiscovery *pDial) {
|
|||||||
runConformance();
|
runConformance();
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
|
printf("Sending the magic packet\n");
|
||||||
|
sendMagic(pServer->getMacAddress());
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
processInput = 0;
|
processInput = 0;
|
||||||
|
processInputOuter = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Invalid, try again\n");
|
printf("Invalid, try again\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
79
server/LinuxInterfaces.c
Normal file
79
server/LinuxInterfaces.c
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#include "LinuxInterfaces.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Fetch the MACAddress of a network interface */
|
||||||
|
int getMACAddress(char* ifname, char* macBuf, unsigned int macBufSize)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
int sock;
|
||||||
|
unsigned char chMAC[6];
|
||||||
|
|
||||||
|
sock=socket(AF_INET,SOCK_DGRAM,0);
|
||||||
|
strcpy( ifr.ifr_name, ifname );
|
||||||
|
ifr.ifr_addr.sa_family = AF_INET;
|
||||||
|
if (ioctl( sock, SIOCGIFHWADDR, &ifr ) < 0) {
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(chMAC, ifr.ifr_hwaddr.sa_data, 6);
|
||||||
|
if (macBufSize<32){
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}else{
|
||||||
|
sprintf(macBuf,"%02X:%02X:%02X:%02X:%02X:%02X",chMAC[0],chMAC[1],chMAC[2],chMAC[3],chMAC[4],chMAC[5]);
|
||||||
|
}
|
||||||
|
close(sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasRoute(const char *nf, int flag)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
const char* fileName = "/proc/net/route";
|
||||||
|
int r;
|
||||||
|
FILE* fp = fopen(fileName, "r");
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
char line[1024];
|
||||||
|
int nfBegin = 0, nfEnd = 0, nfFlag = 0;
|
||||||
|
const int nfLen = strlen(nf);
|
||||||
|
while (!feof(fp)) {
|
||||||
|
if (!fgets(line, sizeof(line), fp))
|
||||||
|
break;
|
||||||
|
r = sscanf(line, "%n%*s%n %*s %*s %d %*s %*s %*s %*s %*s %*s %*s", &nfBegin, &nfEnd, &nfFlag);
|
||||||
|
if (r == 1 && nfBegin == 0 && nfEnd == nfLen && !strncmp(nf, line, nfLen) && (flag == -1 || nfFlag == flag)) {
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDefault(char *nf)
|
||||||
|
{
|
||||||
|
return hasRoute(nf, 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetInterface getDefaultNetworkInterfaces()
|
||||||
|
{
|
||||||
|
DIR *d;
|
||||||
|
struct dirent *dir;
|
||||||
|
d = opendir("/sys/class/net/");
|
||||||
|
NetInterface defaultNet;
|
||||||
|
if (d){
|
||||||
|
while ((dir = readdir(d)) != NULL){
|
||||||
|
if(strcmp(dir->d_name,".") && strcmp(dir->d_name,"..")){
|
||||||
|
if (hasRoute(dir->d_name, -1) && isDefault(dir->d_name)){
|
||||||
|
getMACAddress(dir->d_name, defaultNet.macAddress, MACBUFSIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(d);
|
||||||
|
}
|
||||||
|
return defaultNet;
|
||||||
|
}
|
||||||
26
server/LinuxInterfaces.h
Normal file
26
server/LinuxInterfaces.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef LINUXINTERFACES_H_
|
||||||
|
#define LINUXINTERFACES_H_
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
#include <linux/wireless.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* Fetch the MACAddress of a network interface */
|
||||||
|
#define MACBUFSIZE 32
|
||||||
|
#define WAKEUPTIMEOUT 15
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char macAddress[MACBUFSIZE];
|
||||||
|
}NetInterface;
|
||||||
|
|
||||||
|
NetInterface getDefaultNetworkInterfaces();
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
export TARGET=/usr/local/i686-netflix-linux-gnu-4.2/bin/i686-netflix-linux-gnu-
|
export TARGET=/usr/local/i686-netflix-linux-gnu-4.3/bin/i686-netflix-linux-gnu-
|
||||||
make
|
make
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
#define UUID_OPTION_LONG "--uuid-name"
|
#define UUID_OPTION_LONG "--uuid-name"
|
||||||
#define UUID_DESCRIPTION "UUID of the device"
|
#define UUID_DESCRIPTION "UUID of the device"
|
||||||
|
|
||||||
|
#define WAKE_OPTION "-W"
|
||||||
|
#define WAKE_OPTION_LONG "--wake-on-wifi-len"
|
||||||
|
#define WAKE_DESCRIPTION "Enable wake on wifi/len. Value: on/off. Default (on)"
|
||||||
|
|
||||||
struct dial_options
|
struct dial_options
|
||||||
{
|
{
|
||||||
const char * pOption;
|
const char * pOption;
|
||||||
@@ -79,6 +83,11 @@ struct dial_options gDialOptions[] =
|
|||||||
UUID_OPTION,
|
UUID_OPTION,
|
||||||
UUID_OPTION_LONG,
|
UUID_OPTION_LONG,
|
||||||
UUID_DESCRIPTION
|
UUID_DESCRIPTION
|
||||||
|
},
|
||||||
|
{
|
||||||
|
WAKE_OPTION,
|
||||||
|
WAKE_OPTION_LONG,
|
||||||
|
WAKE_DESCRIPTION
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
#include "url_lib.h"
|
#include "url_lib.h"
|
||||||
|
#include "LinuxInterfaces.h"
|
||||||
|
|
||||||
// TODO: Partners should define this port
|
// TODO: Partners should define this port
|
||||||
#define DIAL_PORT (56789)
|
#define DIAL_PORT (56789)
|
||||||
@@ -213,6 +214,7 @@ static void handle_app_status(struct mg_connection *conn,
|
|||||||
free(encoded_key);
|
free(encoded_key);
|
||||||
free(encoded_value);
|
free(encoded_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
app->state = app->callbacks.status_cb(ds, app_name, app->run_id, &canStop,
|
app->state = app->callbacks.status_cb(ds, app_name, app->run_id, &canStop,
|
||||||
app->callback_data);
|
app->callback_data);
|
||||||
mg_printf(
|
mg_printf(
|
||||||
@@ -510,7 +512,6 @@ static void *request_handler(enum mg_event event, struct mg_connection *conn,
|
|||||||
free(app_name);
|
free(app_name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int use_payload =
|
int use_payload =
|
||||||
strcmp(request_info->request_method, "POST") ? 0 : 1;
|
strcmp(request_info->request_method, "POST") ? 0 : 1;
|
||||||
handle_dial_data(conn, request_info, app_name, origin_header,
|
handle_dial_data(conn, request_info, app_name, origin_header,
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ typedef enum {
|
|||||||
/*
|
/*
|
||||||
* DIAL version that is reported via in the status response.
|
* DIAL version that is reported via in the status response.
|
||||||
*/
|
*/
|
||||||
#define DIAL_VERSION ("\"1.7\"")
|
#define DIAL_VERSION ("\"2.0\"")
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The maximum DIAL payload accepted per the DIAL 1.6.1 specification.
|
* The maximum DIAL payload accepted per the DIAL 1.6.1 specification.
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "dial_server.h"
|
#include "dial_server.h"
|
||||||
#include "dial_options.h"
|
#include "dial_options.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define BUFSIZE 256
|
#define BUFSIZE 256
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ static char spNetflix[BUFSIZE];
|
|||||||
static char spFriendlyName[BUFSIZE];
|
static char spFriendlyName[BUFSIZE];
|
||||||
static char spModelName[BUFSIZE];
|
static char spModelName[BUFSIZE];
|
||||||
static char spUuid[BUFSIZE];
|
static char spUuid[BUFSIZE];
|
||||||
|
extern bool wakeOnWifiLan;
|
||||||
static int gDialPort;
|
static int gDialPort;
|
||||||
|
|
||||||
static char *spAppYouTube = "chrome";
|
static char *spAppYouTube = "chrome";
|
||||||
@@ -409,6 +411,17 @@ static void processOption( int index, char * pOption )
|
|||||||
case 4: // UUID
|
case 4: // UUID
|
||||||
setValue( pOption, spUuid );
|
setValue( pOption, spUuid );
|
||||||
break;
|
break;
|
||||||
|
case 5:
|
||||||
|
if (strcmp(pOption, "on")==0){
|
||||||
|
wakeOnWifiLan=true;
|
||||||
|
}else if (strcmp(pOption, "off")==0){
|
||||||
|
wakeOnWifiLan=false;
|
||||||
|
}else{
|
||||||
|
fprintf(stderr, "Option %s is not valid for %s",
|
||||||
|
pOption, WAKE_OPTION_LONG);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// Should not get here
|
// Should not get here
|
||||||
fprintf( stderr, "Option %d not valid\n", index);
|
fprintf( stderr, "Option %d not valid\n", index);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ CC=$(TARGET)gcc
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
.DEFAULT_GOAL=all
|
.DEFAULT_GOAL=all
|
||||||
|
|
||||||
OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o
|
OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o LinuxInterfaces.o
|
||||||
HEADERS := $(wildcard *.h)
|
HEADERS := $(wildcard *.h)
|
||||||
|
|
||||||
%.c: $(HEADERS)
|
%.c: $(HEADERS)
|
||||||
|
|||||||
@@ -32,19 +32,11 @@
|
|||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "mongoose.h"
|
#include "mongoose.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
// TODO: Partners should define this port
|
// TODO: Partners should define this port
|
||||||
#define SSDP_PORT (56790)
|
#define SSDP_PORT (56790)
|
||||||
|
|
||||||
static int exit_ssdp = 0;
|
|
||||||
void stop_ssdp()
|
|
||||||
{
|
|
||||||
exit_ssdp = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
static char gBuf[4096];
|
static char gBuf[4096];
|
||||||
|
|
||||||
// TODO: Partners should get the friendlyName from the system and insert here.
|
// TODO: Partners should get the friendlyName from the system and insert here.
|
||||||
@@ -67,6 +59,9 @@ static const char ddxml[] = ""
|
|||||||
" </device>"
|
" </device>"
|
||||||
"</root>";
|
"</root>";
|
||||||
|
|
||||||
|
// TODO: Partners should use appropriate timeout (in seconds) if hardware supports WoL.
|
||||||
|
static const short wakeup_timeout = 10;
|
||||||
|
|
||||||
// TODO: Partners should get the UUID from the system and insert here.
|
// TODO: Partners should get the UUID from the system and insert here.
|
||||||
static const char ssdp_reply[] = "HTTP/1.1 200 OK\r\n"
|
static const char ssdp_reply[] = "HTTP/1.1 200 OK\r\n"
|
||||||
"LOCATION: http://%s:%d/dd.xml\r\n"
|
"LOCATION: http://%s:%d/dd.xml\r\n"
|
||||||
@@ -76,10 +71,15 @@ static const char ssdp_reply[] = "HTTP/1.1 200 OK\r\n"
|
|||||||
"SERVER: Linux/2.6 UPnP/1.0 quick_ssdp/1.0\r\n"
|
"SERVER: Linux/2.6 UPnP/1.0 quick_ssdp/1.0\r\n"
|
||||||
"ST: urn:dial-multiscreen-org:service:dial:1\r\n"
|
"ST: urn:dial-multiscreen-org:service:dial:1\r\n"
|
||||||
"USN: uuid:%s::"
|
"USN: uuid:%s::"
|
||||||
"urn:dial-multiscreen-org:service:dial:1\r\n\r\n";
|
"urn:dial-multiscreen-org:service:dial:1\r\n"
|
||||||
|
"%s"
|
||||||
|
"\r\n";
|
||||||
|
|
||||||
|
static const char wakeup_header[] = "WAKEUP: MAC=%s;Timeout=%d\r\n";
|
||||||
|
#define STR_TIMEOUTLEN 6 /* Longest is 32767 */
|
||||||
|
#define HW_ADDRSTRLEN 18
|
||||||
static char ip_addr[INET_ADDRSTRLEN] = "127.0.0.1";
|
static char ip_addr[INET_ADDRSTRLEN] = "127.0.0.1";
|
||||||
|
static char hw_addr[HW_ADDRSTRLEN] = "00:00:00:00:00:00";
|
||||||
static int dial_port = 0;
|
static int dial_port = 0;
|
||||||
static int my_port = 0;
|
static int my_port = 0;
|
||||||
static char friendly_name[256];
|
static char friendly_name[256];
|
||||||
@@ -87,6 +87,8 @@ static char uuid[256];
|
|||||||
static char model_name[256];
|
static char model_name[256];
|
||||||
static struct mg_context *ctx;
|
static struct mg_context *ctx;
|
||||||
|
|
||||||
|
bool wakeOnWifiLan=true;
|
||||||
|
|
||||||
static void *request_handler(enum mg_event event,
|
static void *request_handler(enum mg_event event,
|
||||||
struct mg_connection *conn,
|
struct mg_connection *conn,
|
||||||
const struct mg_request_info *request_info) {
|
const struct mg_request_info *request_info) {
|
||||||
@@ -124,15 +126,31 @@ static void get_local_address() {
|
|||||||
fprintf(stderr, "SIOCGIFCONF output too long");
|
fprintf(stderr, "SIOCGIFCONF output too long");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
close(s);
|
|
||||||
for (i = 0; i < ifc.ifc_len/sizeof(ifc.ifc_req[0]); i++) {
|
for (i = 0; i < ifc.ifc_len/sizeof(ifc.ifc_req[0]); i++) {
|
||||||
strcpy(ip_addr,
|
strcpy(ip_addr,
|
||||||
inet_ntoa(((struct sockaddr_in *)(&ifc.ifc_req[i].ifr_addr))->sin_addr));
|
inet_ntoa(((struct sockaddr_in *)(&ifc.ifc_req[i].ifr_addr))->sin_addr));
|
||||||
// exit if we found a non-loopback address
|
if (0 > ioctl(s, SIOCGIFFLAGS, &ifc.ifc_req[i])) {
|
||||||
if (strcmp("127.0.0.1", ip_addr)) {
|
perror("SIOCGIFFLAGS");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ifc.ifc_req[i].ifr_flags & IFF_LOOPBACK) {
|
||||||
|
// don't use loopback interfaces
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (0 > ioctl(s, SIOCGIFHWADDR, &ifc.ifc_req[i])) {
|
||||||
|
perror("SIOCGIFHWADDR");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
sprintf(hw_addr, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[0],
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[1],
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[2],
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[3],
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[4],
|
||||||
|
(unsigned char)ifc.ifc_req[i].ifr_hwaddr.sa_data[5]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
close(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_mcast() {
|
static void handle_mcast() {
|
||||||
@@ -140,11 +158,13 @@ static void handle_mcast() {
|
|||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
struct ip_mreq mreq;
|
struct ip_mreq mreq;
|
||||||
char send_buf[sizeof(ssdp_reply) + INET_ADDRSTRLEN + 256 + 256] = {0,};
|
char wakeup_buf[sizeof(wakeup_header) + HW_ADDRSTRLEN + STR_TIMEOUTLEN] = {0, };
|
||||||
|
char send_buf[sizeof(ssdp_reply) + INET_ADDRSTRLEN + 256 + 256 + sizeof(wakeup_buf)] = {0,};
|
||||||
int send_size;
|
int send_size;
|
||||||
|
if (-1 < wakeup_timeout && wakeOnWifiLan) {
|
||||||
send_size = snprintf(send_buf, sizeof(send_buf), ssdp_reply, ip_addr, my_port, uuid);
|
snprintf(wakeup_buf, sizeof(wakeup_buf), wakeup_header, hw_addr, wakeup_timeout);
|
||||||
|
}
|
||||||
|
send_size = snprintf(send_buf, sizeof(send_buf), ssdp_reply, ip_addr, my_port, uuid, wakeup_buf);
|
||||||
if (-1 == (s = socket(AF_INET, SOCK_DGRAM, 0))) {
|
if (-1 == (s = socket(AF_INET, SOCK_DGRAM, 0))) {
|
||||||
perror("socket");
|
perror("socket");
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -168,7 +188,7 @@ static void handle_mcast() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
//printf("Starting Multicast handling on 239.255.255.250\n");
|
//printf("Starting Multicast handling on 239.255.255.250\n");
|
||||||
while (!exit_ssdp) {
|
while (1) {
|
||||||
addrlen = sizeof(saddr);
|
addrlen = sizeof(saddr);
|
||||||
if (-1 == (bytes = recvfrom(s, gBuf, sizeof(gBuf) - 1, 0,
|
if (-1 == (bytes = recvfrom(s, gBuf, sizeof(gBuf) - 1, 0,
|
||||||
(struct sockaddr *)&saddr, &addrlen))) {
|
(struct sockaddr *)&saddr, &addrlen))) {
|
||||||
@@ -176,7 +196,6 @@ static void handle_mcast() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
gBuf[bytes] = 0;
|
gBuf[bytes] = 0;
|
||||||
|
|
||||||
// sophisticated SSDP parsing algorithm
|
// sophisticated SSDP parsing algorithm
|
||||||
if (!strstr(gBuf, "urn:dial-multiscreen-org:service:dial:1"))
|
if (!strstr(gBuf, "urn:dial-multiscreen-org:service:dial:1"))
|
||||||
{
|
{
|
||||||
@@ -200,15 +219,11 @@ static void handle_mcast() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(s);
|
|
||||||
exit_ssdp = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_ssdp(int port, const char *pFriendlyName, const char * pModelName, const char *pUuid) {
|
void run_ssdp(int port, const char *pFriendlyName, const char * pModelName, const char *pUuid) {
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
socklen_t len = sizeof(sa);
|
socklen_t len = sizeof(sa);
|
||||||
|
|
||||||
if(pFriendlyName) {
|
if(pFriendlyName) {
|
||||||
strncpy(friendly_name, pFriendlyName, sizeof(friendly_name));
|
strncpy(friendly_name, pFriendlyName, sizeof(friendly_name));
|
||||||
friendly_name[255] = '\0';
|
friendly_name[255] = '\0';
|
||||||
@@ -227,16 +242,12 @@ void run_ssdp(int port, const char *pFriendlyName, const char * pModelName, cons
|
|||||||
} else {
|
} else {
|
||||||
strcpy(uuid, "deadbeef-dead-beef-dead-beefdeadbeef");
|
strcpy(uuid, "deadbeef-dead-beef-dead-beefdeadbeef");
|
||||||
}
|
}
|
||||||
|
|
||||||
dial_port = port;
|
dial_port = port;
|
||||||
get_local_address();
|
get_local_address();
|
||||||
ctx = mg_start(&request_handler, NULL, SSDP_PORT);
|
ctx = mg_start(&request_handler, NULL, SSDP_PORT);
|
||||||
|
|
||||||
if (mg_get_listen_addr(ctx, &sa, &len)) {
|
if (mg_get_listen_addr(ctx, &sa, &len)) {
|
||||||
my_port = ntohs(((struct sockaddr_in *)&sa)->sin_port);
|
my_port = ntohs(((struct sockaddr_in *)&sa)->sin_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("SSDP listening on %s:%d\n", ip_addr, my_port);
|
printf("SSDP listening on %s:%d\n", ip_addr, my_port);
|
||||||
handle_mcast();
|
handle_mcast();
|
||||||
mg_stop(ctx);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user