mirror of
https://github.com/ntop/n2n.git
synced 2024-09-19 16:41:11 +02:00
added Windows support to n2n-route tool (#1023)
* added Windows support to n2n-route tool * fixed includes * more include fixes * one more include addition * more compile fixes * wish I had a working Windows VM * fixed some more Windows compile errors * considered Windows-specific lib linkage * promised to never code OS specific tools again * removed invisible invalid characters * where to get if_idx from * retrieving interface index for route * bracket... * one more bracket... * added optional gateway parameter to user-defined routes * clarification * clarification * Windows needs special network init * adapted waiting-for-key
This commit is contained in:
parent
24c1569c88
commit
2ee7dfdb98
|
@ -206,7 +206,7 @@ add_library(n2n STATIC
|
|||
if(DEFINED WIN32)
|
||||
add_library(edge_utils_win32 src/edge_utils_win32.c)
|
||||
add_subdirectory(win32)
|
||||
target_link_libraries(n2n edge_utils_win32 n2n_win32 iphlpapi)
|
||||
target_link_libraries(n2n edge_utils_win32 n2n_win32 iphlpapi netapi32)
|
||||
endif(DEFINED WIN32)
|
||||
|
||||
add_executable(edge src/edge.c)
|
||||
|
|
|
@ -24,7 +24,7 @@ This C tool sets new routes for all the traffic to be routed via a VPN gateway
|
|||
appropriate routes to supernodes and peers via the original default gateway.
|
||||
|
||||
The tool can auto-detect the default gateway and also has options to only route
|
||||
traffic to specified networks through the VPN gateway.
|
||||
traffic to some specified networks through the VPN gateway.
|
||||
|
||||
Make sure to run with sufficient rights to let the tool add and delete routes.
|
||||
|
||||
|
@ -34,7 +34,7 @@ including hints how to setup the remote edge (IP routing, masquerading).
|
|||
Example:
|
||||
- `tools/n2n-route <remote edge address>`
|
||||
- `tools/n2n-route -n 10.10.10.0/24 <remote edge address>`
|
||||
- `tools/n2n-route -n 8.8.8.8/32 <remote edge address>`
|
||||
- `tools/n2n-route -n 8.8.8.8/32:192.168.0.5 <some (other) remote edge address>`
|
||||
|
||||
### `n2n-portfwd`
|
||||
|
||||
|
|
|
@ -92,8 +92,7 @@
|
|||
#include <net/if_arp.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/route.h>
|
||||
#endif /* #ifdef __linux__ */
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
|
@ -108,7 +107,6 @@
|
|||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
@ -137,6 +135,9 @@
|
|||
#include "n2n_typedefs.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h> /* for privilege check in tools/n2n-route */
|
||||
#include <lmaccess.h> /* for privilege check in tools/n2n-route */
|
||||
#include <lmapibuf.h> /* for privilege check in tools/n2n-route */
|
||||
#include <winsock2.h> /* for tcp */
|
||||
#define SHUT_RDWR SD_BOTH /* for tcp */
|
||||
#include "wintap.h"
|
||||
|
|
|
@ -8,6 +8,7 @@ HEADERS=$(wildcard include/*.h)
|
|||
CFLAGS+=-I../include
|
||||
ifeq ($(CONFIG_TARGET),mingw)
|
||||
CFLAGS+=-I../win32
|
||||
LDLIBS+=-lnetapi32
|
||||
endif
|
||||
CFLAGS+=$(DEBUG)
|
||||
LDFLAGS+=-L..
|
||||
|
|
|
@ -20,10 +20,7 @@
|
|||
#include "n2n.h"
|
||||
|
||||
|
||||
#ifdef __linux__ /* currently, Linux only */
|
||||
|
||||
|
||||
#include <net/route.h>
|
||||
#if defined (__linux__) || defined(WIN32) /* currently, Linux and Windows only */
|
||||
|
||||
|
||||
#define WITH_ADDRESS 1
|
||||
|
@ -45,6 +42,11 @@
|
|||
#define NO_DETECT 0
|
||||
#define AUTO_DETECT 1
|
||||
|
||||
// REVISIT: may become obsolete
|
||||
#ifdef WIN32
|
||||
#define STDIN_FILENO _fileno(stdin)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct n2n_route {
|
||||
struct in_addr net_addr; /* network address to be routed, also key for hash table*/
|
||||
|
@ -74,12 +76,32 @@ static int keep_running = 1; /* for main loop, handled by signals *
|
|||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
// taken from https://stackoverflow.com/questions/4159910/check-if-user-is-root-in-c
|
||||
int is_privileged (void) {
|
||||
|
||||
#if defined(__linux__)
|
||||
// taken from https://stackoverflow.com/questions/4159910/check-if-user-is-root-in-c
|
||||
uid_t euid = geteuid();
|
||||
|
||||
return euid == 0;
|
||||
|
||||
#elif defined(WIN32)
|
||||
// taken from https://stackoverflow.com/a/10553065
|
||||
int result;
|
||||
DWORD rc;
|
||||
wchar_t user_name[256];
|
||||
USER_INFO_1 *info;
|
||||
DWORD size = sizeof(user_name);
|
||||
|
||||
GetUserNameW(user_name, &size);
|
||||
rc = NetUserGetInfo(NULL, user_name, 1, (unsigned char**)&info);
|
||||
if (rc) {
|
||||
return 0;
|
||||
}
|
||||
result = (info->usri1_priv == USER_PRIV_ADMIN);
|
||||
NetApiBufferFree(info);
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -89,21 +111,20 @@ int is_privileged (void) {
|
|||
|
||||
void set_term_handler(const void *handler) {
|
||||
|
||||
#ifdef __linux__
|
||||
#if defined(__linux__)
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGTERM, handler);
|
||||
signal(SIGINT, handler);
|
||||
#endif
|
||||
#ifdef WIN32 /* the beginning of Windows support ...? */
|
||||
#elif defined(WIN32)
|
||||
SetConsoleCtrlHandler(handler, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32 /* the beginning of Windows support ...? */
|
||||
BOOL WINAPI term_handler (DWORD sig) {
|
||||
#else
|
||||
#if !defined(WIN32)
|
||||
static void term_handler (int sig) {
|
||||
#else
|
||||
BOOL WINAPI term_handler (DWORD sig) {
|
||||
#endif
|
||||
|
||||
static int called = 0;
|
||||
|
@ -117,7 +138,7 @@ static void term_handler (int sig) {
|
|||
}
|
||||
|
||||
keep_running = 0;
|
||||
#ifdef WIN32 /* the beginning of Windows support ...? */
|
||||
#if defined(WIN32)
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
@ -127,14 +148,16 @@ static void term_handler (int sig) {
|
|||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
// taken from https://gist.github.com/javiermon/6272065
|
||||
// with modifications
|
||||
// originally licensed under GPLV2, Apache, and/or MIT
|
||||
|
||||
#define RTLINK_BUFFER_SIZE 8192
|
||||
|
||||
int find_default_gateway (struct in_addr *gateway_addr, struct in_addr *exclude) {
|
||||
|
||||
#if defined(__linux__)
|
||||
// taken from https://gist.github.com/javiermon/6272065
|
||||
// with modifications
|
||||
// originally licensed under GPLV2, Apache, and/or MIT
|
||||
|
||||
int ret = 0;
|
||||
int received_bytes = 0, msg_len = 0, route_attribute_len = 0;
|
||||
SOCKET sock = -1;
|
||||
|
@ -260,6 +283,59 @@ find_default_gateway_end:
|
|||
|
||||
closesocket(sock);
|
||||
return ret;
|
||||
|
||||
#elif defined(WIN32)
|
||||
// taken from (and modified)
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-createipforwardentry
|
||||
|
||||
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
|
||||
DWORD dwSize = 0;
|
||||
BOOL bOrder = FALSE;
|
||||
DWORD dwStatus = 0;
|
||||
unsigned int i;
|
||||
ipstr_t gateway_address;
|
||||
|
||||
// find out how big our buffer needs to be
|
||||
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
if(dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// allocate the memory for the table
|
||||
if(!(pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(dwSize))) {
|
||||
traceEvent(TRACE_DEBUG, "malloc failed, out of memory\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// now get the table
|
||||
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
}
|
||||
|
||||
if (dwStatus != ERROR_SUCCESS) {
|
||||
traceEvent(TRACE_DEBUG, "getIpForwardTable failed\n");
|
||||
if(pIpForwardTable)
|
||||
free(pIpForwardTable);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dwStatus = EXIT_FAILURE;
|
||||
// search for the row in the table we want. The default gateway has a destination of 0.0.0.0
|
||||
for(i = 0; i < pIpForwardTable->dwNumEntries; i++) {
|
||||
if(pIpForwardTable->table[i].dwForwardDest == 0) {
|
||||
// we have found a default route
|
||||
// do not use if the gateway is the one to be excluded
|
||||
if(pIpForwardTable->table[i].dwForwardNextHop == exclude->S_un.S_addr)
|
||||
continue;
|
||||
dwStatus = 0;
|
||||
gateway_addr->S_un.S_addr = pIpForwardTable->table[i].dwForwardNextHop;
|
||||
traceEvent(TRACE_DEBUG, "assuming default gateway %s",
|
||||
inaddrtoa(gateway_address, *gateway_addr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pIpForwardTable) {
|
||||
free(pIpForwardTable);
|
||||
}
|
||||
|
||||
return dwStatus;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -267,9 +343,75 @@ find_default_gateway_end:
|
|||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
DWORD get_interface_index (struct in_addr addr) {
|
||||
// taken from (and modified)
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-createipforwardentry
|
||||
|
||||
PMIB_IPFORWARDTABLE pIpForwardTable = NULL;
|
||||
DWORD dwSize = 0;
|
||||
BOOL bOrder = FALSE;
|
||||
DWORD dwStatus = 0;
|
||||
DWORD mask_addr = 0;
|
||||
DWORD max_idx = 0;
|
||||
uint8_t bitlen, max_bitlen = 0;
|
||||
unsigned int i;
|
||||
ipstr_t gateway_address;
|
||||
|
||||
// find out how big our buffer needs to be
|
||||
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
if(dwStatus == ERROR_INSUFFICIENT_BUFFER) {
|
||||
// allocate the memory for the table
|
||||
if(!(pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(dwSize))) {
|
||||
traceEvent(TRACE_DEBUG, "malloc failed, out of memory\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// now get the table
|
||||
dwStatus = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
|
||||
}
|
||||
|
||||
if (dwStatus != ERROR_SUCCESS) {
|
||||
traceEvent(TRACE_DEBUG, "getIpForwardTable failed\n");
|
||||
if(pIpForwardTable)
|
||||
free(pIpForwardTable);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// search for the row in the table we want. The default gateway has a destination of 0.0.0.0
|
||||
for(i = 0; i < pIpForwardTable->dwNumEntries; i++) {
|
||||
mask_addr = pIpForwardTable->table[i].dwForwardMask;
|
||||
// if same subnet ...
|
||||
if((mask_addr & addr.S_un.S_addr) == (mask_addr & pIpForwardTable->table[i].dwForwardDest)) {
|
||||
mask_addr = ntohl(mask_addr);
|
||||
for(bitlen = 0; (int)mask_addr < 0; mask_addr <<= 1)
|
||||
bitlen++;
|
||||
if(bitlen > max_bitlen) {
|
||||
max_bitlen = bitlen;
|
||||
max_idx = pIpForwardTable->table[i].dwForwardIfIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
traceEvent(TRACE_DEBUG, "found interface index %u for gateway %s",
|
||||
max_idx, inaddrtoa(gateway_address, addr));
|
||||
|
||||
if(pIpForwardTable) {
|
||||
free(pIpForwardTable);
|
||||
}
|
||||
|
||||
return max_idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
/* adds (verb == ROUTE_ADD) or deletes (verb == ROUTE_DEL) a route */
|
||||
void handle_route (n2n_route_t* in_route, int verb) {
|
||||
|
||||
#if defined(__linux__)
|
||||
struct sockaddr_in *addr_tmp;
|
||||
struct rtentry route;
|
||||
SOCKET sock;
|
||||
|
@ -320,6 +462,34 @@ void handle_route (n2n_route_t* in_route, int verb) {
|
|||
}
|
||||
|
||||
closesocket(sock);
|
||||
|
||||
#elif defined(WIN32)
|
||||
// REVISIT: use 'CreateIpForwardEntry()' and 'DeleteIpForwardEntry()' [iphlpapi.h]
|
||||
struct in_addr net_addr, gateway;
|
||||
char c_net_addr[32];
|
||||
char c_gateway[32];
|
||||
char c_interface[32];
|
||||
char c_verb[32];
|
||||
uint32_t mask;
|
||||
uint8_t bitlen;
|
||||
DWORD if_idx;
|
||||
char cmd[256];
|
||||
|
||||
// assemble route command components
|
||||
_snprintf(c_net_addr, sizeof(c_net_addr), inet_ntoa(in_route->net_addr));
|
||||
_snprintf(c_gateway, sizeof(c_gateway), inet_ntoa(in_route->gateway));
|
||||
mask = ntohl(in_route->net_mask.S_un.S_addr);
|
||||
for(bitlen = 0; (int)mask < 0; mask <<= 1)
|
||||
bitlen++;
|
||||
if_idx = get_interface_index(in_route->gateway);
|
||||
_snprintf(c_interface, sizeof(c_interface), "if %u", if_idx);
|
||||
_snprintf(c_verb, sizeof(c_verb), (verb == ROUTE_ADD) ? "add" : "delete");
|
||||
_snprintf(cmd, sizeof(cmd), "route %s %s/%d %s %s > nul", c_verb, c_net_addr, bitlen, c_gateway, c_interface);
|
||||
traceEvent(TRACE_INFO, "ROUTE CMD = '%s'\n", cmd);
|
||||
|
||||
// issue the route command
|
||||
system(cmd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -363,6 +533,7 @@ int same_subnet (struct in_addr addr0, struct in_addr addr1, struct in_addr subn
|
|||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
SOCKET connect_to_management_port (n2n_route_conf_t *rrr) {
|
||||
|
@ -370,6 +541,23 @@ SOCKET connect_to_management_port (n2n_route_conf_t *rrr) {
|
|||
SOCKET ret;
|
||||
struct sockaddr_in sock_addr;
|
||||
|
||||
#if defined(WIN32)
|
||||
// Windows requires a call to WSAStartup() before it can work with sockets
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
int err;
|
||||
|
||||
// Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h
|
||||
wVersionRequested = MAKEWORD(2, 2);
|
||||
|
||||
err = WSAStartup(wVersionRequested, &wsaData);
|
||||
if (err != 0) {
|
||||
// tell the user that we could not find a usable Winsock DLL
|
||||
traceEvent(TRACE_ERROR, "WSAStartup failed with error: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = socket (PF_INET, SOCK_DGRAM, 0);
|
||||
if((int)ret < 0)
|
||||
return -1;
|
||||
|
@ -420,10 +608,12 @@ int get_addr_from_json (struct in_addr *addr, json_object_t *json, char *key, in
|
|||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// PLATFORM-DEPENDANT CODE
|
||||
|
||||
|
||||
#if !defined(WIN32)
|
||||
// taken from https://web.archive.org/web/20170407122137/http://cc.byexamples.com/2007/04/08/non-blocking-user-input-in-loop-without-ncurses/
|
||||
int kbhit () {
|
||||
int _kbhit () {
|
||||
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
|
@ -436,6 +626,7 @@ int kbhit () {
|
|||
|
||||
return FD_ISSET(STDIN_FILENO, &fds);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
|
@ -446,7 +637,8 @@ static void help (int level) {
|
|||
if(level == 0) return; /* no help required */
|
||||
|
||||
printf(" n2n-route [-t <manangement_port>] [-p <management_port_password>] [-v] [-V]"
|
||||
"\n [-g <default gateway>] [-n <network address>/bitlen] <vpn gateway>"
|
||||
"\n [-g <default gateway>] [-n <network address>/bitlen[:gateway]]"
|
||||
"\n <vpn gateway>"
|
||||
"\n"
|
||||
"\n This tool sets new routes for all the traffic to be routed via the"
|
||||
"\n <vpn gateway> and polls the management port of a local n2n edge for"
|
||||
|
@ -454,7 +646,7 @@ static void help (int level) {
|
|||
"\n gateway. Adapt port (default: %d) and password (default: '%s')"
|
||||
"\n to match your edge's configuration."
|
||||
"\n\n If no <default gateway> provided, the tool will try to auto-detect."
|
||||
"\n\n To not route all traffic through vpn, inidicate the networks to be"
|
||||
"\n\n To only route some traffic through vpn, inidicate the networks to be"
|
||||
"\n routed with '-n' option and use as many as required."
|
||||
"\n\n Verbosity can be increased or decreased with -v or -V , repeat as"
|
||||
"\n as needed."
|
||||
|
@ -495,14 +687,18 @@ static int set_option (n2n_route_conf_t *rrr, int optkey, char *optargument) {
|
|||
}
|
||||
|
||||
case 'n': /* user-provided network to be routed */ {
|
||||
char cidr_net[64], bitlen;
|
||||
char cidr_net[64], bitlen, gateway[64];
|
||||
n2n_route_t *route;
|
||||
struct in_addr mask;
|
||||
int ret;
|
||||
|
||||
if(sscanf(optargument, "%63[^/]/%hhd", cidr_net, &bitlen) != 2) {
|
||||
traceEvent(TRACE_WARNING, "bad cidr network format '%d'", optargument);
|
||||
gateway[0] = '\0'; // optional parameter
|
||||
ret = sscanf(optargument, "%63[^/]/%hhd:%63s", cidr_net, &bitlen, gateway);
|
||||
if((ret < 2) || (ret > 3)) {
|
||||
traceEvent(TRACE_WARNING, "bad cidr network format '%s'", optargument);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if((bitlen < 0) || (bitlen > 32)) {
|
||||
traceEvent(TRACE_WARNING, "bad prefix '%d' in '%s'", bitlen, optargument);
|
||||
return 1;
|
||||
|
@ -511,14 +707,19 @@ static int set_option (n2n_route_conf_t *rrr, int optkey, char *optargument) {
|
|||
traceEvent(TRACE_WARNING, "bad network '%s' in '%s'", cidr_net, optargument);
|
||||
return 1;
|
||||
}
|
||||
|
||||
traceEvent(TRACE_NORMAL, "routing %s/%d", cidr_net, bitlen);
|
||||
if(gateway[0]) {
|
||||
if(!inet_address_valid(inet_address(gateway))) {
|
||||
traceEvent(TRACE_WARNING, "bad gateway '%s' in '%s'", gateway, optargument);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
traceEvent(TRACE_NORMAL, "routing %s/%d via %s", cidr_net, bitlen, gateway[0] ? gateway : "vpn gateway");
|
||||
|
||||
route = calloc(1, sizeof(*route));
|
||||
if(route) {
|
||||
mask.s_addr = htonl(bitlen2mask(bitlen));
|
||||
// gateway is unknown at this point, will be rectified later
|
||||
fill_route(route, inet_address(cidr_net), mask, inet_address(""));
|
||||
// gateway might be unknown at this point, will be rectified later
|
||||
fill_route(route, inet_address(cidr_net), mask, inet_address(gateway));
|
||||
HASH_ADD(hh, rrr->routes, net_addr, sizeof(route->net_addr), route);
|
||||
// will be added to system table later
|
||||
}
|
||||
|
@ -617,11 +818,15 @@ int main (int argc, char* argv[]) {
|
|||
fill_route(route, inet_address(UPPER_HALF), inet_address(MASK_HALF), rrr.gateway_vpn);
|
||||
HASH_ADD(hh, rrr.routes, net_addr, sizeof(route->net_addr), route);
|
||||
}
|
||||
} else {
|
||||
traceEvent(TRACE_WARNING, "only user-supplied networks will be routed, not the complete traffic");
|
||||
}
|
||||
// set gateway for all so far present routes as '-n'-provided do not have it yet,
|
||||
// set gateway for all so far present routes if '-n'-provided do not have it yet,
|
||||
// make them UNPURGEABLE and add them to system table
|
||||
HASH_ITER(hh, rrr.routes, route, tmp_route) {
|
||||
if(!inet_address_valid(route->gateway)) {
|
||||
route->gateway = rrr.gateway_vpn;
|
||||
}
|
||||
route->purgeable = UNPURGEABLE;
|
||||
handle_route(route, ROUTE_ADD);
|
||||
}
|
||||
|
@ -658,7 +863,7 @@ reset_main_loop:
|
|||
// read answer packet by packet which are only accepted if a corresponding request was sent before
|
||||
// of which we know about by having set the related tag, tag_info or tag_route_ip resp.
|
||||
// a valid edge ip address indicates that we have seen a valid answer to the info request
|
||||
while(keep_running && !kbhit()) {
|
||||
while(keep_running && !_kbhit()) {
|
||||
// current time
|
||||
now = time(NULL);
|
||||
|
||||
|
@ -846,16 +1051,16 @@ end_route_tool:
|
|||
}
|
||||
|
||||
|
||||
#else /* ifdef __linux__ -- currently, Linux only */
|
||||
#else /* if defined(__linux__) || defined(WIN32) -- currently, Linux and Windows only */
|
||||
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
|
||||
traceEvent(TRACE_WARNING, "currently, only Linux is supported");
|
||||
traceEvent(TRACE_WARNING, "currently, only Linux and Windows are supported");
|
||||
traceEvent(TRACE_WARNING, "if you want to port to other OS, please find the source code having clearly marked the platform-dependant portions");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ifdef __linux__ -- currently, Linux only */
|
||||
#endif /* if defined (__linux__) || defined(WIN32) -- currently, Linux and Windows only */
|
||||
|
|
Loading…
Reference in New Issue
Block a user