mirror of
https://github.com/xcat2/xNBA.git
synced 2024-11-25 19:08:35 +00:00
375 lines
11 KiB
C
375 lines
11 KiB
C
/*****************************************************************************
|
|
*
|
|
* wol.c - Wake-On-LAN utility to wake a networked PC
|
|
*
|
|
* by R. Edwards (bob@cs.anu.edu.au), January 2000
|
|
* (in_ether routine adapted from net-tools-1.51/lib/ether.c by
|
|
* Fred N. van Kempen)
|
|
* added file input, some minor changes for compiling for NetWare
|
|
* added switches -q and -d=<ms>, added Win32 target support
|
|
* by G. Knauf (gk@gknw.de), 30-Jan-2001
|
|
* added switches -b=<bcast> and -p=<port>
|
|
* by G. Knauf (gk@gknw.de), 10-Okt-2001
|
|
* added OS/2 target support
|
|
* by G. Knauf (gk@gknw.de), 24-May-2002
|
|
*
|
|
* This utility allows a PC with WOL configured to be powered on by
|
|
* sending a "Magic Packet" to it's network adaptor (see:
|
|
* http://www.amd.com/products/npd/overview/20212.html).
|
|
* Only the ethernet dest address needs to be given to make this work.
|
|
* Current version uses a UDP broadcast to send out the Magic Packet.
|
|
*
|
|
* compile with: gcc -Wall -o wol wol.c
|
|
* with Solaris: (g)cc -o wol wol.c -lsocket -lnsl
|
|
* with MingW32: gcc -Wall -o wol wol.c -lwsock32
|
|
*
|
|
* usage: wol <dest address>
|
|
* where <dest address> is in [ddd.ddd.ddd.ddd-]xx:xx:xx:xx:xx:xx format.
|
|
* or: wol [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<File name>
|
|
* where <File name> is a file containing one dest address per line,
|
|
* optional followed by a hostname or ip separated by a blank.
|
|
* -b sets optional broadcast address, -p sets optional port,
|
|
* -q supresses output, -d=<ms> delays ms milliseconds between sending.
|
|
*
|
|
* Released under GNU Public License January, 2000.
|
|
*/
|
|
|
|
#define VERSION "1.12.2 (c) G.Knauf http://www.gknw.de/"
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#ifdef WATTCP
|
|
#define strncasecmp strnicmp
|
|
#include <ctype.h>
|
|
#include <dos.h>
|
|
#include <tcp.h>
|
|
#else
|
|
#ifdef WIN32 /* Win32 platform */
|
|
#define USE_WINSOCKAPI
|
|
#define delay Sleep
|
|
#if (defined(__LCC__) || defined(__BORLANDC__))
|
|
#define strncasecmp strnicmp
|
|
#else
|
|
#define strncasecmp _strnicmp
|
|
#endif
|
|
#elif defined(N_PLAT_NLM) /* NetWare platform */
|
|
#ifdef __NOVELL_LIBC__
|
|
#include <ctype.h>
|
|
#else
|
|
extern int isdigit(int c); /* no ctype.h for NW3.x */
|
|
#include <nwthread.h>
|
|
#define strncasecmp strnicmp
|
|
#endif
|
|
#elif defined(__OS2__) /* OS/2 platform */
|
|
#ifdef __EMX__
|
|
#define strncasecmp strnicmp
|
|
#endif
|
|
extern int DosSleep(long t);
|
|
#define delay DosSleep
|
|
#else /* all other platforms */
|
|
#define delay(t) usleep(t*1000)
|
|
#endif
|
|
#ifndef N_PLAT_NLM /* ! NetWare platform */
|
|
#include <ctype.h>
|
|
#endif
|
|
#ifndef WIN32 /* ! Win32 platform */
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef USE_WINSOCKAPI /* Winsock2 platforms */
|
|
#ifdef N_PLAT_NLM /* NetWare platform */
|
|
#include <ws2nlm.h>
|
|
#else
|
|
#include <winsock.h>
|
|
#endif
|
|
#define close(s) { \
|
|
closesocket(s); \
|
|
WSACleanup(); \
|
|
}
|
|
#else /* Socket platforms */
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#if defined(__OS2__) && !defined(__EMX__)
|
|
#include <utils.h>
|
|
#else
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#endif
|
|
|
|
#endif
|
|
|
|
static int read_file (char *destfile);
|
|
static int in_ether (char *bufp, unsigned char *addr);
|
|
static int send_wol (char *dest, char *host);
|
|
|
|
|
|
char *progname;
|
|
int quiet = 0;
|
|
int twait = 0;
|
|
unsigned int port = 60000;
|
|
unsigned long bcast = 0xffffffff;
|
|
|
|
int main (int argc, char *argv[]) {
|
|
|
|
int cmdindx = 0;
|
|
progname = argv[0];
|
|
|
|
if (argc > 1) {
|
|
/* parse input parameters */
|
|
for (argc--, argv++; *argv; argc--, argv++) {
|
|
char *bp;
|
|
char *ep;
|
|
|
|
if (strncasecmp (*argv, "-", 1) == 0) {
|
|
if (strncasecmp (*argv, "-F=", 3) == 0) {
|
|
bp = *argv + 3;
|
|
read_file (bp);
|
|
} else if (strncasecmp (*argv, "-B=", 3) == 0) {
|
|
bp = *argv + 3;
|
|
bcast = inet_addr(bp);
|
|
if (bcast == -1) {
|
|
fprintf (stderr, "%s: expected address argument at %s\n", progname, *argv);
|
|
exit (1);
|
|
}
|
|
} else if (strncasecmp (*argv, "-D=", 3) == 0) {
|
|
bp = *argv + 3;
|
|
twait = strtol (bp, &ep, 0);
|
|
if (ep == bp || *ep != '\0') {
|
|
fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
|
|
exit (1);
|
|
}
|
|
} else if (strncasecmp (*argv, "-P=", 3) == 0) {
|
|
bp = *argv + 3;
|
|
port = strtol (bp, &ep, 0);
|
|
if (ep == bp || *ep != '\0') {
|
|
fprintf (stderr, "%s: expected integer argument at %s\n", progname, *argv);
|
|
exit (1);
|
|
}
|
|
} else if (strncasecmp (*argv, "-Q", 2) == 0) {
|
|
quiet = 1;
|
|
} else if (strncasecmp (*argv, "-V", 2) == 0) {
|
|
fprintf (stderr, "\r%s Version %s\n", progname, VERSION);
|
|
exit (0);
|
|
} else {
|
|
fprintf (stderr, "\r%s: invalid or unknown option %s\n", progname, *argv);
|
|
exit (1);
|
|
}
|
|
} else {
|
|
send_wol (*argv, "");
|
|
}
|
|
cmdindx++;
|
|
}
|
|
return (0);
|
|
} else {
|
|
/* No arguments given -> usage message */
|
|
fprintf (stderr, "\rUsage: %s [-q] [-b=<bcast>] [-p=<port>] [-d=<ms>] -f=<file> | <dest>\n", progname);
|
|
fprintf (stderr, " need at least hardware address or file option\n");
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int in_ether (char *bufp, unsigned char *addr) {
|
|
|
|
char c, *orig;
|
|
int i;
|
|
unsigned char *ptr = addr;
|
|
unsigned val;
|
|
|
|
i = 0;
|
|
orig = bufp;
|
|
while ((*bufp != '\0') && (i < 6)) {
|
|
val = 0;
|
|
c = *bufp++;
|
|
if (isdigit(c))
|
|
val = c - '0';
|
|
else if (c >= 'a' && c <= 'f')
|
|
val = c - 'a' + 10;
|
|
else if (c >= 'A' && c <= 'F')
|
|
val = c - 'A' + 10;
|
|
else {
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
|
|
#endif
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
val <<= 4;
|
|
c = *bufp;
|
|
if (isdigit(c))
|
|
val |= c - '0';
|
|
else if (c >= 'a' && c <= 'f')
|
|
val |= c - 'a' + 10;
|
|
else if (c >= 'A' && c <= 'F')
|
|
val |= c - 'A' + 10;
|
|
else if (c == ':' || c == 0)
|
|
val >>= 4;
|
|
else {
|
|
#ifdef DEBUG
|
|
fprintf (stderr, "\rin_ether(%s): invalid ether address!\n", orig);
|
|
#endif
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
if (c != 0)
|
|
bufp++;
|
|
*ptr++ = (unsigned char) (val & 0377);
|
|
i++;
|
|
|
|
/* We might get a semicolon here - not required. */
|
|
if (*bufp == ':') {
|
|
if (i == 6) {
|
|
; /* nothing */
|
|
}
|
|
bufp++;
|
|
}
|
|
}
|
|
if (bufp - orig != 17) {
|
|
return (-1);
|
|
} else {
|
|
return (0);
|
|
}
|
|
} /* in_ether */
|
|
|
|
|
|
static int read_file (char *destfile) {
|
|
|
|
FILE *pfile = NULL;
|
|
char dest[64];
|
|
char host[32];
|
|
char buffer[512];
|
|
|
|
pfile = fopen (destfile, "r+");
|
|
|
|
if (pfile) {
|
|
while (fgets (buffer, 511, pfile) != NULL) {
|
|
if (buffer[0] != '#' && buffer[0] != ';') {
|
|
dest[0] = host[0] = '\0';
|
|
sscanf (buffer, "%s %s", dest, host);
|
|
send_wol (dest, host);
|
|
}
|
|
}
|
|
fclose (pfile);
|
|
return (0);
|
|
} else {
|
|
fprintf (stderr, "\r%s: destfile '%s' not found\n", progname, destfile);
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
|
|
static int send_wol (char *dest, char *host) {
|
|
|
|
int i, j;
|
|
int packet;
|
|
struct sockaddr_in sap;
|
|
unsigned char ethaddr[8];
|
|
unsigned char *ptr;
|
|
unsigned char buf [128];
|
|
unsigned long bc;
|
|
char mask[32];
|
|
char *tmp;
|
|
#ifdef USE_WINSOCKAPI
|
|
WORD wVersionRequested;
|
|
WSADATA wsaData;
|
|
int err;
|
|
#endif
|
|
#ifdef WATTCP
|
|
static udp_Socket sock;
|
|
udp_Socket *s;
|
|
#else
|
|
int optval = 1;
|
|
#endif
|
|
|
|
/* Fetch the broascast address if present. */
|
|
if ((tmp = strstr(dest,"-"))) {
|
|
printf("found: %s\n", tmp);
|
|
tmp[0] = 32;
|
|
sscanf (dest, "%s %s", mask, dest);
|
|
bc = inet_addr(mask);
|
|
printf("bc: string %s address %08lX\n", mask, bc);
|
|
if (bc == -1) {
|
|
fprintf (stderr, "\r%s: expected address argument at %s\n", progname, mask);
|
|
return (-1);
|
|
}
|
|
} else
|
|
bc = bcast;
|
|
|
|
/* Fetch the hardware address. */
|
|
if (in_ether (dest, ethaddr) < 0) {
|
|
fprintf (stderr, "\r%s: invalid hardware address\n", progname);
|
|
return (-1);
|
|
}
|
|
|
|
#ifdef USE_WINSOCKAPI
|
|
/* I would like to have Socket Vers. 1.1 */
|
|
wVersionRequested = MAKEWORD(1, 1);
|
|
err = WSAStartup (wVersionRequested, &wsaData);
|
|
if (err != 0) {
|
|
fprintf (stderr, "\r%s: couldn't init Winsock Version 1.1\n", progname);
|
|
WSACleanup ();
|
|
return (-1);
|
|
}
|
|
#endif
|
|
|
|
/* setup the packet socket */
|
|
#ifdef WATTCP
|
|
sock_init();
|
|
s = &sock;
|
|
if (!udp_open( s, 0, bc, port, NULL )) {
|
|
#else
|
|
if ((packet = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
|
|
#endif
|
|
fprintf (stderr, "\r%s: socket failed\n", progname);
|
|
#ifdef USE_WINSOCKAPI
|
|
WSACleanup ();
|
|
#endif
|
|
return (-1);
|
|
}
|
|
|
|
#ifndef WATTCP
|
|
/* Set socket options */
|
|
if (setsockopt (packet, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof (optval)) < 0) {
|
|
fprintf (stderr, "\r%s: setsocket failed %s\n", progname, strerror (errno));
|
|
close (packet);
|
|
return (-1);
|
|
}
|
|
|
|
/* Set up broadcast address */
|
|
sap.sin_family = AF_INET;
|
|
sap.sin_addr.s_addr = bc; /* broadcast address */
|
|
sap.sin_port = htons(port);
|
|
#endif
|
|
|
|
/* Build the message to send - 6 x 0xff then 16 x dest address */
|
|
ptr = buf;
|
|
for (i = 0; i < 6; i++)
|
|
*ptr++ = 0xff;
|
|
for (j = 0; j < 16; j++)
|
|
for (i = 0; i < 6; i++)
|
|
*ptr++ = ethaddr [i];
|
|
|
|
/* Send the packet out */
|
|
#ifdef WATTCP
|
|
sock_write( s, buf, 102 );
|
|
sock_close( s );
|
|
#else
|
|
if (sendto (packet, (char *)buf, 102, 0, (struct sockaddr *)&sap, sizeof (sap)) < 0) {
|
|
fprintf (stderr, "\r%s: sendto failed, %s\n", progname, strerror(errno));
|
|
close (packet);
|
|
return (-1);
|
|
}
|
|
close (packet);
|
|
#endif
|
|
if (!quiet) fprintf (stderr, "\r%s: packet sent to %04X:%08lX-%s %s\n",
|
|
progname, port, (unsigned long)htonl(bc), dest, host);
|
|
if (twait > 0 ) {
|
|
delay (twait);
|
|
}
|
|
return (0);
|
|
}
|
|
|