/* * Copyright (c) 2014 Netflix, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "DialDiscovery.h" #include "DialConformance.h" #include #include #include #include #include #include #include #include #include #include using namespace std; static DialDiscovery* gpDiscovery; static bool gUseMenu = true; // TODO: Make it possible to pass applications from the command line static vector gAppList; static string gOutputFile; static string gInputFile; // IP address of the DIAL server static string gIpAddress; static void printServerList( vector list ) { int i; vector::iterator it; for( i = 0, it = list.begin(); it < list.end(); it++, i++ ) { string uuid, name, macAddr; int wolTimeOut; (*it)->getFriendlyName( name ); (*it)->getUuid( uuid ); 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(), uuid.c_str(), name.c_str(), macAddr.c_str(), wolTimeOut); } } static DialServer* getServerFromUser( vector list ) { DialServer* pServer; // show a list to the user char buf[80] = {0,}; vector::iterator it; printf("Found Multiple servers\n"); printf("0: Rescan and list DIAL servers\n"); printServerList(list); printf("Enter server: "); scanf("%s", buf); unsigned int server = atoi(buf); if( server > 0 && server <= list.size()){ pServer = list[server-1]; }else{ pServer = NULL; } return pServer; } static void runConformance() { vector list; gpDiscovery->getServerList(list); if( list.size() ) { DialServer *pServer = NULL; if( !gIpAddress.empty() ) { pServer = NULL; vector::iterator it; for( it = list.begin(); it < list.end(); it ++ ) { if( gIpAddress.compare((*it)->getIpAddress()) == 0 ) { ATRACE("Found server %s in the list of servers\n", gIpAddress.c_str() ); pServer = (*it); break; } } } else { pServer = getServerFromUser( list ); } if( pServer ) { string name; bool serverExists = pServer->getFriendlyName(name); assert( serverExists ); string uuid; pServer->getUuid( uuid ); printf("\nRunning conformance against: IP[%s] UUID[%s] FriendlyName[%s] \n", pServer->getIpAddress().c_str(), uuid.c_str(), name.c_str() ); DialConformance::instance()->run( pServer, gAppList, gInputFile, gOutputFile ); } else { printf("DIAL server not found\n"); printf("%Zu available server(s): \n", list.size()); printServerList(list); } } else { printf("No servers available\n"); } } 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 processInputOuter = 1; char buf[80]; vector list; while (processInputOuter){ pDial->getServerList(list); if( list.size() == 0 ){ printf("No servers available\n"); return 1; } DialServer* pServer = getServerFromUser( list ); if (pServer==NULL){ pDial->send_mcast(); continue; } int processInput = 1; while(processInput){ string responseHeaders, responseBody, payload; string netflix = "Netflix"; string youtube = "YouTube"; memset(buf, 0, 80); printf("0. Rescan and list DIAL servers\n"); printf("1. Launch Netflix\n"); printf("2. Hide Netflix\n"); printf("3. Stop Netflix\n"); printf("4. Netflix status\n"); printf("5. Launch YouTube\n"); printf("6. Hide YouTube\n"); printf("7. Stop YouTube\n"); printf("8. YouTube status\n"); printf("9. Run conformance tests\n"); printf("10. Wake up on lan/wlan\n"); printf("11. QUIT\n"); printf("Command (0:1:2:3:4:5:6:7:8:9:10:11): "); scanf("%s", buf); switch( atoi(buf) ) { case 0: { pDial->send_mcast(); processInput=0; }break; case 1: printf("Launch Netflix\n"); pServer->launchApplication( netflix, payload, responseHeaders, responseBody ); break; case 2: printf("Hide Netflix\n"); pServer->hideApplication( netflix, responseHeaders, responseBody ); break; case 3: printf("Stop Netflix\n"); pServer->stopApplication( netflix, responseHeaders ); break; case 4: printf("Netflix Status: \n"); pServer->getStatus( netflix, responseHeaders, responseBody ); printf("RESPONSE: \n%s\n", responseBody.c_str()); break; case 5: printf("Launch YouTube\n"); pServer->launchApplication( youtube, payload, responseHeaders, responseBody ); break; case 6: printf("Hide YouTube\n"); pServer->hideApplication( youtube, responseHeaders, responseBody ); break; case 7: printf("Stop YouTube\n"); pServer->stopApplication( youtube, responseHeaders ); break; case 8: printf("YouTube Status: \n"); pServer->getStatus( youtube, responseHeaders, responseBody ); break; case 9: runConformance(); break; case 10: printf("Sending the magic packet\n"); sendMagic(pServer->getMacAddress()); break; case 11: processInput = 0; processInputOuter = 0; break; default: printf("Invalid, try again\n"); } } } return 0; } static const char usage[] = "\n" " If no option is specified, the program will run a conformance test.\n" "\n" "usage: dialclient