Added dynamic loading of libpcap on *nix platforms.

This commit is contained in:
Mark Pizzolato 2011-11-17 09:51:58 -08:00
parent 8b01b90008
commit 3b7492d6be
4 changed files with 122 additions and 45 deletions

View file

@ -378,6 +378,7 @@ Dave
Change Log Change Log
=============================================================================== ===============================================================================
17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and

View file

@ -15,6 +15,10 @@
# In general, the logic below will detect and build with the available # In general, the logic below will detect and build with the available
# features which the host build environment provides. # features which the host build environment provides.
# #
# Dynamic loading of libpcap is the default behavior if pcap.h is
# available at build time. Direct calls to libpcap can be enabled
# if GNU make is invoked with USE_NETWORK on the command line.
#
# Internal ROM support can be disabled if GNU make is invoked with # Internal ROM support can be disabled if GNU make is invoked with
# DONT_USE_ROMS=1 on the command line. # DONT_USE_ROMS=1 on the command line.
# #
@ -105,11 +109,19 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin)
endif endif
endif endif
endif endif
ifneq (,$(call find_lib,pcap)) ifneq (,$(call find_include,pcap))
ifneq (,$(call find_include,pcap)) ifneq (,$(call find_lib,pcap))
NETWORK_CCDEFS = -DUSE_NETWORK ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line
NETWORK_LDFLAGS = -lpcap NETWORK_CCDEFS = -DUSE_NETWORK
$(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap)) NETWORK_LDFLAGS = -lpcap
$(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap))
else # default build uses dynamic libpcap
NETWORK_CCDEFS = -DUSE_SHARED
$(info using libpcap: $$(call find_include,pcap))
endif
else
NETWORK_CCDEFS = -DUSE_SHARED
$(info using libpcap: $$(call find_include,pcap))
endif endif
endif endif
ifneq (,$(call find_lib,vdeplug)) ifneq (,$(call find_lib,vdeplug))

View file

@ -50,7 +50,7 @@
Define one of the two macros below to enable networking: Define one of the two macros below to enable networking:
USE_NETWORK - Create statically linked network code USE_NETWORK - Create statically linked network code
USE_SHARED - Create dynamically linked network code (_WIN32 only) USE_SHARED - Create dynamically linked network code
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -160,6 +160,7 @@
Modification history: Modification history:
17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX
12-Aug-11 MP Cleaned up payload length determination 12-Aug-11 MP Cleaned up payload length determination
@ -752,7 +753,7 @@ void ethq_insert(ETH_QUE* que, int32 type, ETH_PACK* pack, int32 status)
/* Non-implemented versions */ /* Non-implemented versions */
/*============================================================================*/ /*============================================================================*/
#if !defined (USE_NETWORK) && (!defined (_WIN32) || !defined (USE_SHARED)) #if !defined (USE_NETWORK) && !defined (USE_SHARED)
t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit) t_stat eth_open(ETH_DEV* dev, char* name, DEVICE* dptr, uint32 dbit)
{return SCPE_NOFNC;} {return SCPE_NOFNC;}
t_stat eth_close (ETH_DEV* dev) t_stat eth_close (ETH_DEV* dev)
@ -816,14 +817,35 @@ void eth_show_dev (FILE* st, ETH_DEV* dev)
#include <winreg.h> #include <winreg.h>
#endif #endif
#if defined(_WIN32) && defined(USE_SHARED) #if defined(USE_SHARED) && (defined(_WIN32) || defined(HAVE_DLOPEN))
/* Dynamic DLL loading technique and modified source comes from /* Dynamic DLL loading technique and modified source comes from
Etherial/WireShark capture_pcap.c */ Etherial/WireShark capture_pcap.c */
#ifdef HAVE_DLOPEN
#include <dlfcn.h>
#endif
/* Dynamic DLL load variables */ /* Dynamic DLL load variables */
static HINSTANCE hDll = 0; /* handle to DLL */ #ifdef _WIN32
static int dll_loaded = 0; /* 0=not loaded, 1=loaded, 2=DLL load failed, 3=Func load failed */ static HINSTANCE hLib = 0; /* handle to DLL */
static char* no_wpcap = "wpcap load failure"; #else
static void *hLib = 0; /* handle to Library */
#endif
static int lib_loaded = 0; /* 0=not loaded, 1=loaded, 2=library load failed, 3=Func load failed */
static char* lib_name =
#ifdef _WIN32
"wpcap.dll";
#else
#define __STR_QUOTE(tok) #tok
#define __STR(tok) __STR_QUOTE(tok)
"libpcap." __STR(HAVE_DLOPEN);
#endif
static char* no_pcap =
#ifdef _WIN32
"wpcap load failure";
#else
"libpcap load failure";
#endif
/* define pointers to pcap functions needed */ /* define pointers to pcap functions needed */
static void (*p_pcap_close) (pcap_t *); static void (*p_pcap_close) (pcap_t *);
@ -836,46 +858,63 @@ static void (*p_pcap_freecode) (struct bpf_program *);
static char* (*p_pcap_geterr) (pcap_t *); static char* (*p_pcap_geterr) (pcap_t *);
static int (*p_pcap_lookupnet) (const char *, bpf_u_int32 *, bpf_u_int32 *, char *); static int (*p_pcap_lookupnet) (const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *); static pcap_t* (*p_pcap_open_live) (const char *, int, int, int, char *);
#ifdef _WIN32
static int (*p_pcap_setmintocopy) (pcap_t* handle, int); static int (*p_pcap_setmintocopy) (pcap_t* handle, int);
static HANDLE (*p_pcap_getevent) (pcap_t *); static HANDLE (*p_pcap_getevent) (pcap_t *);
#else
static int (*p_pcap_get_selectable_fd) (pcap_t *);
#endif
static int (*p_pcap_sendpacket) (pcap_t* handle, const u_char* msg, int len); static int (*p_pcap_sendpacket) (pcap_t* handle, const u_char* msg, int len);
static int (*p_pcap_setfilter) (pcap_t *, struct bpf_program *); static int (*p_pcap_setfilter) (pcap_t *, struct bpf_program *);
static char* (*p_pcap_lib_version) (void); static char* (*p_pcap_lib_version) (void);
/* load function pointer from DLL */ /* load function pointer from DLL */
void load_function(char* function, void** func_ptr) { void load_function(char* function, void** func_ptr) {
*func_ptr = GetProcAddress(hDll, function); #ifdef _WIN32
if (*func_ptr == 0) { *func_ptr = GetProcAddress(hLib, function);
char* msg = "Eth: Failed to find function '%s' in wpcap.dll\r\n"; #else
*func_ptr = dlsym(hLib, function);
#endif
if (*func_ptr == 0) {
char* msg = "Eth: Failed to find function '%s' in %s\r\n";
printf (msg, function); printf (msg, function, lib_name);
if (sim_log) fprintf (sim_log, msg, function); if (sim_log) fprintf (sim_log, msg, function, lib_name);
dll_loaded = 3; lib_loaded = 3;
} }
} }
/* load wpcap.dll as required */ /* load wpcap.dll as required */
int load_wpcap(void) { int load_pcap(void) {
switch(dll_loaded) { switch(lib_loaded) {
case 0: /* not loaded */ case 0: /* not loaded */
/* attempt to load DLL */ /* attempt to load DLL */
hDll = LoadLibrary(TEXT("wpcap.dll")); #ifdef _WIN32
if (hDll == 0) { hLib = LoadLibraryA(lib_name);
#else
hLib = dlopen(lib_name, RTLD_NOW);
#endif
if (hLib == 0) {
/* failed to load DLL */ /* failed to load DLL */
char* msg = "Eth: Failed to load wpcap.dll\r\n"; char* msg = "Eth: Failed to load %s\r\n";
char* msg2 = "Eth: You must install WinPcap 4.x to use networking\r\n"; char* msg2 =
#ifdef _WIN32
"Eth: You must install WinPcap 4.x to use networking\r\n";
#else
"Eth: You must install libpcap to use networking\r\n";
#endif
printf (msg); printf (msg, lib_name);
printf (msg2); printf (msg2);
if (sim_log) { if (sim_log) {
fprintf (sim_log, msg); fprintf (sim_log, msg, lib_name);
fprintf (sim_log, msg2); fprintf (sim_log, msg2);
} }
dll_loaded = 2; lib_loaded = 2;
break; break;
} else { } else {
/* DLL loaded OK */ /* library loaded OK */
dll_loaded = 1; lib_loaded = 1;
} }
/* load required functions; sets dll_load=3 on error */ /* load required functions; sets dll_load=3 on error */
@ -889,13 +928,17 @@ int load_wpcap(void) {
load_function("pcap_geterr", (void**) &p_pcap_geterr); load_function("pcap_geterr", (void**) &p_pcap_geterr);
load_function("pcap_lookupnet", (void**) &p_pcap_lookupnet); load_function("pcap_lookupnet", (void**) &p_pcap_lookupnet);
load_function("pcap_open_live", (void**) &p_pcap_open_live); load_function("pcap_open_live", (void**) &p_pcap_open_live);
#ifdef _WIN32
load_function("pcap_setmintocopy", (void**) &p_pcap_setmintocopy); load_function("pcap_setmintocopy", (void**) &p_pcap_setmintocopy);
load_function("pcap_getevent", (void**) &p_pcap_getevent); load_function("pcap_getevent", (void**) &p_pcap_getevent);
#else
load_function("pcap_get_selectable_fd", (void**) &p_pcap_get_selectable_fd);
#endif
load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket); load_function("pcap_sendpacket", (void**) &p_pcap_sendpacket);
load_function("pcap_setfilter", (void**) &p_pcap_setfilter); load_function("pcap_setfilter", (void**) &p_pcap_setfilter);
load_function("pcap_lib_version", (void**) &p_pcap_lib_version); load_function("pcap_lib_version", (void**) &p_pcap_lib_version);
if (dll_loaded == 1) { if (lib_loaded == 1) {
/* log successful load */ /* log successful load */
char* version = p_pcap_lib_version(); char* version = p_pcap_lib_version();
printf("%s\n", version); printf("%s\n", version);
@ -906,18 +949,18 @@ int load_wpcap(void) {
default: /* loaded or failed */ default: /* loaded or failed */
break; break;
} }
return (dll_loaded == 1) ? 1 : 0; return (lib_loaded == 1) ? 1 : 0;
} }
/* define functions with dynamic revectoring */ /* define functions with dynamic revectoring */
void pcap_close(pcap_t* a) { void pcap_close(pcap_t* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
p_pcap_close(a); p_pcap_close(a);
} }
} }
int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e) { int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_compile(a, b, c, d, e); return p_pcap_compile(a, b, c, d, e);
} else { } else {
return 0; return 0;
@ -925,7 +968,7 @@ int pcap_compile(pcap_t* a, struct bpf_program* b, char* c, int d, bpf_u_int32 e
} }
int pcap_datalink(pcap_t* a) { int pcap_datalink(pcap_t* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_datalink(a); return p_pcap_datalink(a);
} else { } else {
return 0; return 0;
@ -933,7 +976,7 @@ int pcap_datalink(pcap_t* a) {
} }
int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) { int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_dispatch(a, b, c, d); return p_pcap_dispatch(a, b, c, d);
} else { } else {
return 0; return 0;
@ -941,29 +984,29 @@ int pcap_dispatch(pcap_t* a, int b, pcap_handler c, u_char* d) {
} }
int pcap_findalldevs(pcap_if_t** a, char* b) { int pcap_findalldevs(pcap_if_t** a, char* b) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_findalldevs(a, b); return p_pcap_findalldevs(a, b);
} else { } else {
*a = 0; *a = 0;
strcpy(b, no_wpcap); strcpy(b, no_pcap);
return -1; return -1;
} }
} }
void pcap_freealldevs(pcap_if_t* a) { void pcap_freealldevs(pcap_if_t* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
p_pcap_freealldevs(a); p_pcap_freealldevs(a);
} }
} }
void pcap_freecode(struct bpf_program* a) { void pcap_freecode(struct bpf_program* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
p_pcap_freecode(a); p_pcap_freecode(a);
} }
} }
char* pcap_geterr(pcap_t* a) { char* pcap_geterr(pcap_t* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_geterr(a); return p_pcap_geterr(a);
} else { } else {
return (char*) 0; return (char*) 0;
@ -971,7 +1014,7 @@ char* pcap_geterr(pcap_t* a) {
} }
int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) { int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_lookupnet(a, b, c, d); return p_pcap_lookupnet(a, b, c, d);
} else { } else {
return 0; return 0;
@ -979,15 +1022,16 @@ int pcap_lookupnet(const char* a, bpf_u_int32* b, bpf_u_int32* c, char* d) {
} }
pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) { pcap_t* pcap_open_live(const char* a, int b, int c, int d, char* e) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_open_live(a, b, c, d, e); return p_pcap_open_live(a, b, c, d, e);
} else { } else {
return (pcap_t*) 0; return (pcap_t*) 0;
} }
} }
#ifdef _WIN32
int pcap_setmintocopy(pcap_t* a, int b) { int pcap_setmintocopy(pcap_t* a, int b) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_setmintocopy(a, b); return p_pcap_setmintocopy(a, b);
} else { } else {
return 0; return 0;
@ -995,15 +1039,25 @@ int pcap_setmintocopy(pcap_t* a, int b) {
} }
HANDLE pcap_getevent(pcap_t* a) { HANDLE pcap_getevent(pcap_t* a) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_getevent(a); return p_pcap_getevent(a);
} else { } else {
return (HANDLE) 0; return (HANDLE) 0;
} }
} }
#else
int pcap_get_selectable_fd(pcap_t* a) {
if (load_pcap() != 0) {
return p_pcap_get_selectable_fd(a);
} else {
return 0;
}
}
#endif
int pcap_sendpacket(pcap_t* a, const u_char* b, int c) { int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_sendpacket(a, b, c); return p_pcap_sendpacket(a, b, c);
} else { } else {
return 0; return 0;
@ -1011,7 +1065,7 @@ int pcap_sendpacket(pcap_t* a, const u_char* b, int c) {
} }
int pcap_setfilter(pcap_t* a, struct bpf_program* b) { int pcap_setfilter(pcap_t* a, struct bpf_program* b) {
if (load_wpcap() != 0) { if (load_pcap() != 0) {
return p_pcap_setfilter(a, b); return p_pcap_setfilter(a, b);
} else { } else {
return 0; return 0;

View file

@ -28,6 +28,7 @@
Modification history: Modification history:
17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms
30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking
18-Apr-11 MP Fixed race condition with self loopback packets in 18-Apr-11 MP Fixed race condition with self loopback packets in
multithreaded environments multithreaded environments
@ -98,6 +99,15 @@
#endif #endif
#endif /* USE_READER_THREAD */ #endif /* USE_READER_THREAD */
/* give priority to USE_NETWORK over USE_SHARED */
#if defined(USE_NETWORK) && defined(USE_SHARED)
#undef USE_SHARED
#endif
/* USE_SHARED only works on Windows or if HAVE_DLOPEN */
#if defined(USE_SHARED) && !defined(_WIN32) && !defined(HAVE_DLOPEN)
#undef USE_SHARED
#endif
/* /*
USE_BPF is defined to let this code leverage the libpcap/OS kernel provided USE_BPF is defined to let this code leverage the libpcap/OS kernel provided
BPF packet filtering. This generally will enhance performance. It may not BPF packet filtering. This generally will enhance performance. It may not