Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 143 lines (125 sloc) 5.448 kB
8a0b502 @ccutrer Initial commit
authored
1 // Copyright (c) 2009 - Mozy, Inc.
2
3 #include "mordor/predef.h"
4
5 #include <iostream>
6
7 #include "mordor/config.h"
8 #include "mordor/daemon.h"
9 #include "mordor/iomanager.h"
10 #include "mordor/main.h"
11 #include "mordor/socket.h"
12 #include "mordor/string.h"
13 #include "mordor/http/parser.h"
14
15 using namespace Mordor;
16
17 static ConfigVar<std::string>::ptr g_macAddress = Config::lookup("macaddress",
18 std::string(), "MAC address to send WOL to");
19 static ConfigVar<std::string>::ptr g_interface = Config::lookup("interface",
20 std::string("eth0"), "Interface to listen and send on");
e70b4ca @ccutrer Improvements
authored
21 static ConfigVar<std::string>::ptr g_blacklist = Config::lookup("blacklist",
22 std::string(), "Semicolon separate list of IP addresses to ignore");
8a0b502 @ccutrer Initial commit
authored
23
24 static void wol(Socket::ptr socket, const std::string &macAddress) {
25 MORDOR_ASSERT(macAddress.size() == 6u);
26 std::string message;
e70b4ca @ccutrer Improvements
authored
27 message.append(6u, (char)0xff);
8a0b502 @ccutrer Initial commit
authored
28 for(size_t i = 0; i < 16; ++i)
29 message.append(macAddress);
30 socket->send(message.c_str(), message.size());
31 }
32
33 static int daemonMain(int argc, char *argv[])
34 {
35 try {
36 std::string macAddressString = g_macAddress->val();
e70b4ca @ccutrer Improvements
authored
37 replace(macAddressString, "-", "");
38 if (macAddressString.size() != 12u) {
8a0b502 @ccutrer Initial commit
authored
39 std::cerr << "MAC address must be 12 characters" << std::endl;
40 return -1;
41 }
42 std::string macAddress = dataFromHexstring(macAddressString);
43
29d433d @ccutrer Bug fixes
authored
44 std::set<Address::ptr> blacklistedAddresses;
e70b4ca @ccutrer Improvements
authored
45 std::vector<std::string> blacklistedAddressesString = split(
46 g_blacklist->val(), ";, ");
47 for(std::vector<std::string>::const_iterator it(
48 blacklistedAddressesString.begin());
49 it != blacklistedAddressesString.end();
50 ++it) {
51 if(it->empty())
52 continue;
53 blacklistedAddresses.insert(IPAddress::create(it->c_str()));
54 }
55
8a0b502 @ccutrer Initial commit
authored
56 std::vector<std::pair<Address::ptr, unsigned int> > addresses =
57 Address::getInterfaceAddresses(g_interface->val(), AF_INET);
58 if (addresses.empty()) {
59 std::cerr << "Couldn't find interface " << g_interface->val()
60 << std::endl;
61 return -1;
62 }
63
e70b4ca @ccutrer Improvements
authored
64 IPAddress::ptr localAddress = boost::static_pointer_cast<IPAddress>(
65 addresses.front().first);
66 IPAddress::ptr broadcastAddress = localAddress->broadcastAddress(
67 addresses.front().second);
8a0b502 @ccutrer Initial commit
authored
68 broadcastAddress->port(9u);
69 IPv4Address multicastAddress("239.255.255.250", 1900);
70
71 IOManager ioManager;
72
73 Socket::ptr broadcastSocket(broadcastAddress->createSocket(ioManager,
74 SOCK_DGRAM));
75 broadcastSocket->setOption(SOL_SOCKET, SO_BROADCAST, 1);
76 broadcastSocket->connect(broadcastAddress);
77
78 Socket::ptr listenSocket(multicastAddress.createSocket(ioManager,
79 SOCK_DGRAM));
80 listenSocket->setOption(SOL_SOCKET, SO_REUSEADDR, 1);
29d433d @ccutrer Bug fixes
authored
81 listenSocket->bind(IPv4Address(0u, 1900u));
8a0b502 @ccutrer Initial commit
authored
82 // TODO: listenSocket->joinGroup(multicastAddress, addresses.front().first);
83 struct ip_mreq multicastGroup;
84 memcpy(&multicastGroup.imr_multiaddr, &((sockaddr_in *)multicastAddress.name())->sin_addr, sizeof(struct in_addr));
85 memcpy(&multicastGroup.imr_interface, &((sockaddr_in *)addresses.front().first->name())->sin_addr, sizeof(struct in_addr));
86 listenSocket->setOption(IPPROTO_IP, IP_ADD_MEMBERSHIP, multicastGroup);
87
88 Daemon::onTerminate.connect(boost::bind(&Socket::cancelReceive,
89 listenSocket));
90
91 try {
92 IPv4Address sender;
93 char buffer[4096];
94 size_t size;
95 while((size = listenSocket->receiveFrom(buffer, 4096, sender))) {
e70b4ca @ccutrer Improvements
authored
96 IPAddress::ptr senderDuplicate = sender.clone();
97 senderDuplicate->port(0u);
29d433d @ccutrer Bug fixes
authored
98 if (blacklistedAddresses.find(senderDuplicate) !=
e70b4ca @ccutrer Improvements
authored
99 blacklistedAddresses.end()) {
100 MORDOR_LOG_VERBOSE(Log::root())
101 << "Skipping broadcast from " << sender;
102 continue;
103 }
104
8a0b502 @ccutrer Initial commit
authored
105 HTTP::Request request;
106 HTTP::RequestParser parser(request);
107 parser.run(buffer, size);
e70b4ca @ccutrer Improvements
authored
108 if (parser.complete() && !parser.error()) {
109 if (request.requestLine.method == "M-SEARCH") {
110 MORDOR_LOG_INFO(Log::root()) << "Relaying M-SEARCH to WOL from "
111 << sender;
112 wol(broadcastSocket, macAddress);
113 }
8a0b502 @ccutrer Initial commit
authored
114 } else {
115 MORDOR_LOG_WARNING(Log::root()) << "Unable to parse HTTP request from "
116 << sender << ": " << charslice(buffer, size);
117 }
118 }
119 } catch (OperationAbortedException &) {
120 } catch (...) {
121 MORDOR_LOG_FATAL(Log::root())
122 << boost::current_exception_diagnostic_information();
123 return -1;
124 }
125 } catch (...) {
126 std::cerr << boost::current_exception_diagnostic_information() << std::endl;
127 return -1;
128 }
129 return 0;
130 }
131
132 MORDOR_MAIN(int argc, char *argv[])
133 {
134 try {
135 Config::loadFromEnvironment();
136 return Daemon::run(argc, argv, &daemonMain);
137 } catch (...) {
138 std::cerr << boost::current_exception_diagnostic_information()
139 << std::endl;
140 return -1;
141 }
142 }
Something went wrong with that request. Please try again.