#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define SERVER_PORT 5000
typedef void (*callback_type)(void *callback_data);
char *PROGNAME;
void usage(int exitval) {
fprintf(stderr, "Usage: %s <port> <mac>\n", PROGNAME);
exit(exitval);
}
void fatal(const char *message, int exitval) {
fprintf(stderr, "%s: FATAL: %s\n", PROGNAME, message);
exit(exitval);
}
void error(const char *msg) {
fprintf(stderr, "%s: ERROR: %s\n", PROGNAME, msg);
}
void debug(const char *msg) {
fprintf(stderr, "%s: DEBUG: %s\n", PROGNAME, msg);
}
void send_wol(char *ethaddr) {
struct sockaddr_in sap;
int optval = 1;
int packet;
if ((packet = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
error("socket failed");
return;
}
struct in_addr interface_addr;
interface_addr.s_addr = inet_addr("192.168.1.1");
if (setsockopt(packet, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr)) < 0) {
error("setsocket failed"); error(strerror(errno));
close(packet);
return;
}
if (setsockopt(packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) {
error("setsocket failed"); error(strerror(errno));
close(packet);
return;
}
sap.sin_family = AF_INET;
// sap.sin_addr.s_addr = htonl(0xffffffff); // broadcast address
// sap.sin_addr.s_addr = htonl(0xc0a800ff); // broadcast address
sap.sin_addr.s_addr = inet_addr("192.168.1.255");
sap.sin_port = htons(60000);
// Build the message to send - 6 x 0xff then 16 x MAC address
unsigned char buf[128], *ptr = buf;
int i, j;
for (i = 0; i < 6; i++)
*ptr++ = 0xff;
for (j = 0; j < 16; j++)
for (i = 0; i < 6; i++)
*ptr++ = ethaddr[i];
if (sendto(packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof(sap)) < 0) {
error("sendto failed"); error(strerror(errno));
close(packet);
return;
}
debug("WOL sent");
close(packet);
}
void wait_for_event(int port, callback_type callback, void *callback_data) {
char message[1024];
int sock;
struct sockaddr_in name;
struct hostent *hp, *gethostbyname();
int bytes;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
fatal("Opening datagram socket", 11);
memset((char *)&name, 0, sizeof(name));
name.sin_family = AF_INET;
name.sin_addr.s_addr = htonl(INADDR_ANY);
name.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &name, sizeof(name)))
fatal("binding datagram socket", 12);
struct timespec lasttime, mytime;
clock_gettime(CLOCK_MONOTONIC, &lasttime);
unsigned total_bytes = 0;
while ((bytes = read(sock, message, 1024)) > 0) {
clock_gettime(CLOCK_MONOTONIC, &mytime);
if ((mytime.tv_sec - lasttime.tv_sec) * 1000000000 + mytime.tv_nsec - lasttime.tv_nsec < 200000000)
total_bytes += bytes;
else
total_bytes = bytes;
if (total_bytes >= 180) {
debug("callback triggered");
callback(callback_data);
total_bytes = 0;
}
lasttime = mytime;
}
close(sock);
}
void main(int argc, char *argv[]) {
PROGNAME = argv[0];
if (argc < 3)
usage(1);
int port = atoi(argv[1]);
if (port < 1)
fatal("bad port number", 1);
unsigned char mac[8];
if (sscanf(argv[2], "%hhx%*c%hhx%*c%hhx%*c%hhx%*c%hhx%*c%hhx", mac, mac+1, mac+2, mac+3, mac+4, mac+5) !=6)
if (sscanf(argv[2], "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", mac, mac+1, mac+2, mac+3, mac+4, mac+5) !=6)
fatal("bad mac address", 2);
mac[7] = mac[8] = 0;
while(1)
wait_for_event(port, (callback_type)&send_wol, mac);
}