From 3b7492d6bee69bfa23c0a91cf895e2528f210dc0 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Thu, 17 Nov 2011 09:51:58 -0800 Subject: [PATCH] Added dynamic loading of libpcap on *nix platforms. --- 0readme_ethernet.txt | 1 + makefile | 22 +++++-- sim_ether.c | 134 ++++++++++++++++++++++++++++++------------- sim_ether.h | 10 ++++ 4 files changed, 122 insertions(+), 45 deletions(-) diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt index eb1c66f0..225f5be0 100644 --- a/0readme_ethernet.txt +++ b/0readme_ethernet.txt @@ -378,6 +378,7 @@ Dave 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 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 diff --git a/makefile b/makefile index b7499af5..6d4c357f 100644 --- a/makefile +++ b/makefile @@ -14,6 +14,10 @@ # # In general, the logic below will detect and build with the available # 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 # DONT_USE_ROMS=1 on the command line. @@ -105,11 +109,19 @@ ifeq ($(WIN32),) #*nix Environments (&& cygwin) endif endif endif - ifneq (,$(call find_lib,pcap)) - ifneq (,$(call find_include,pcap)) - NETWORK_CCDEFS = -DUSE_NETWORK - NETWORK_LDFLAGS = -lpcap - $(info using libpcap: $(call find_lib,pcap) $(call find_include,pcap)) + ifneq (,$(call find_include,pcap)) + ifneq (,$(call find_lib,pcap)) + ifneq ($(USE_NETWORK),) # Network support specified on the GNU make command line + NETWORK_CCDEFS = -DUSE_NETWORK + 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 ifneq (,$(call find_lib,vdeplug)) diff --git a/sim_ether.c b/sim_ether.c index 3ca7eefa..08abbad9 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -50,7 +50,7 @@ Define one of the two macros below to enable networking: 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: + 17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms 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 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 */ /*============================================================================*/ -#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) {return SCPE_NOFNC;} t_stat eth_close (ETH_DEV* dev) @@ -816,14 +817,35 @@ void eth_show_dev (FILE* st, ETH_DEV* dev) #include #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 Etherial/WireShark capture_pcap.c */ +#ifdef HAVE_DLOPEN +#include +#endif + /* Dynamic DLL load variables */ -static HINSTANCE hDll = 0; /* handle to DLL */ -static int dll_loaded = 0; /* 0=not loaded, 1=loaded, 2=DLL load failed, 3=Func load failed */ -static char* no_wpcap = "wpcap load failure"; +#ifdef _WIN32 +static HINSTANCE hLib = 0; /* handle to DLL */ +#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 */ 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 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 *); +#ifdef _WIN32 static int (*p_pcap_setmintocopy) (pcap_t* handle, int); 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_setfilter) (pcap_t *, struct bpf_program *); static char* (*p_pcap_lib_version) (void); /* load function pointer from DLL */ void load_function(char* function, void** func_ptr) { - *func_ptr = GetProcAddress(hDll, function); - if (*func_ptr == 0) { - char* msg = "Eth: Failed to find function '%s' in wpcap.dll\r\n"; +#ifdef _WIN32 + *func_ptr = GetProcAddress(hLib, function); +#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); - if (sim_log) fprintf (sim_log, msg, function); - dll_loaded = 3; + printf (msg, function, lib_name); + if (sim_log) fprintf (sim_log, msg, function, lib_name); + lib_loaded = 3; } } /* load wpcap.dll as required */ -int load_wpcap(void) { - switch(dll_loaded) { +int load_pcap(void) { + switch(lib_loaded) { case 0: /* not loaded */ /* attempt to load DLL */ - hDll = LoadLibrary(TEXT("wpcap.dll")); - if (hDll == 0) { +#ifdef _WIN32 + hLib = LoadLibraryA(lib_name); +#else + hLib = dlopen(lib_name, RTLD_NOW); +#endif + if (hLib == 0) { /* failed to load DLL */ - char* msg = "Eth: Failed to load wpcap.dll\r\n"; - char* msg2 = "Eth: You must install WinPcap 4.x to use networking\r\n"; + char* msg = "Eth: Failed to load %s\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); if (sim_log) { - fprintf (sim_log, msg); + fprintf (sim_log, msg, lib_name); fprintf (sim_log, msg2); } - dll_loaded = 2; + lib_loaded = 2; break; } else { - /* DLL loaded OK */ - dll_loaded = 1; + /* library loaded OK */ + lib_loaded = 1; } /* 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_lookupnet", (void**) &p_pcap_lookupnet); load_function("pcap_open_live", (void**) &p_pcap_open_live); +#ifdef _WIN32 load_function("pcap_setmintocopy", (void**) &p_pcap_setmintocopy); 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_setfilter", (void**) &p_pcap_setfilter); load_function("pcap_lib_version", (void**) &p_pcap_lib_version); - if (dll_loaded == 1) { + if (lib_loaded == 1) { /* log successful load */ char* version = p_pcap_lib_version(); printf("%s\n", version); @@ -906,18 +949,18 @@ int load_wpcap(void) { default: /* loaded or failed */ break; } - return (dll_loaded == 1) ? 1 : 0; + return (lib_loaded == 1) ? 1 : 0; } /* define functions with dynamic revectoring */ void pcap_close(pcap_t* a) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { p_pcap_close(a); } } 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); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_datalink(a); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_dispatch(a, b, c, d); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_findalldevs(a, b); } else { *a = 0; - strcpy(b, no_wpcap); + strcpy(b, no_pcap); return -1; } } void pcap_freealldevs(pcap_if_t* a) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { p_pcap_freealldevs(a); } } void pcap_freecode(struct bpf_program* a) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { p_pcap_freecode(a); } } char* pcap_geterr(pcap_t* a) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_geterr(a); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_lookupnet(a, b, c, d); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_open_live(a, b, c, d, e); } else { return (pcap_t*) 0; } } +#ifdef _WIN32 int pcap_setmintocopy(pcap_t* a, int b) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_setmintocopy(a, b); } else { return 0; @@ -995,15 +1039,25 @@ int pcap_setmintocopy(pcap_t* a, int b) { } HANDLE pcap_getevent(pcap_t* a) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_getevent(a); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_sendpacket(a, b, c); } else { 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) { - if (load_wpcap() != 0) { + if (load_pcap() != 0) { return p_pcap_setfilter(a, b); } else { return 0; diff --git a/sim_ether.h b/sim_ether.h index 1478c40c..2314e835 100644 --- a/sim_ether.h +++ b/sim_ether.h @@ -28,6 +28,7 @@ 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 18-Apr-11 MP Fixed race condition with self loopback packets in multithreaded environments @@ -98,6 +99,15 @@ #endif #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 BPF packet filtering. This generally will enhance performance. It may not