Skip to content

Commit 24b6193

Browse files
authored
Make a singleton and use FFI::scope or FFI::load when possible (#3)
1 parent 0ffddc1 commit 24b6193

File tree

2 files changed

+52
-33
lines changed

2 files changed

+52
-33
lines changed

src/PcapFFI.php

+49-33
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,42 @@ class PcapFFI
1515
{
1616
public const LIBPCAP_NAME = 'libpcap.so.1';
1717

18-
private FFI $ffi;
18+
static private $ffi = NULL;
1919

2020
private ?string $error = null;
2121

2222
public function __construct()
2323
{
24-
$env = getenv('LIBPCAP_NAME');
25-
$lib = ($env !== false) ? $env : self::LIBPCAP_NAME;
26-
$code = file_get_contents(__DIR__ . '/pcap.h');
27-
28-
if ($code === false) {
29-
throw new Exception('Cannot load pcap C definitions');
24+
if (self::$ffi) {
25+
return;
3026
}
3127

32-
$this->ffi = FFI::cdef($code, $lib);
28+
$lib = getenv('LIBPCAP_NAME');
29+
if ($lib) {
30+
// old way
31+
$code = file_get_contents(__DIR__ . '/pcap.h');
32+
33+
if ($code === false) {
34+
throw new Exception('Cannot load pcap C definitions');
35+
}
36+
self::$ffi = FFI::cdef($code, $lib);
37+
} else {
38+
try {
39+
// Try preload
40+
self::$ffi = \FFI::scope("_RTCKIT_PCAP_FFI_");
41+
} catch (\FFI\Exception $e) {
42+
// Try direct load
43+
self::$ffi = \FFI::load(__DIR__ . '/pcap.h');
44+
}
45+
}
46+
if (!self::$ffi) {
47+
throw new \RuntimeException("FFI parse fails");
48+
}
3349
}
3450

3551
public function lib_version(): string
3652
{
37-
return $this->ffi->pcap_lib_version();
53+
return self::$ffi->pcap_lib_version();
3854
}
3955

4056
/**
@@ -47,11 +63,11 @@ public function findalldevs(): ?array
4763
{
4864
$this->resetLastError();
4965

50-
$devs = $this->ffi->new('pcap_if_t *');
51-
$dev = $this->ffi->new('pcap_if_t *');
52-
$err = $this->ffi->new('char[257]');
66+
$devs = self::$ffi->new('pcap_if_t *');
67+
$dev = self::$ffi->new('pcap_if_t *');
68+
$err = self::$ffi->new('char[257]');
5369

54-
if ($this->ffi->pcap_findalldevs(FFI::addr($devs), $err) < 0) {
70+
if (self::$ffi->pcap_findalldevs(FFI::addr($devs), $err) < 0) {
5571
$this->setLastError(FFI::string($err));
5672

5773
return null;
@@ -68,7 +84,7 @@ public function findalldevs(): ?array
6884
$dev = $dev->next;
6985
}
7086

71-
$this->ffi->pcap_freealldevs($devs);
87+
self::$ffi->pcap_freealldevs($devs);
7288

7389
return $ret;
7490
}
@@ -77,8 +93,8 @@ public function create(string $dev): ?CData
7793
{
7894
$this->resetLastError();
7995

80-
$err = $this->ffi->new('char[257]');
81-
$ret = $this->ffi->pcap_create($dev, $err);
96+
$err = self::$ffi->new('char[257]');
97+
$ret = self::$ffi->pcap_create($dev, $err);
8298

8399
if (is_null($ret)) {
84100
$this->setLastError(FFI::string($err));
@@ -93,7 +109,7 @@ public function set_snaplen(CData $pcap, int $snaplen): int
93109
{
94110
$this->resetLastError();
95111

96-
$ret = $this->ffi->pcap_set_snaplen($pcap, $snaplen);
112+
$ret = self::$ffi->pcap_set_snaplen($pcap, $snaplen);
97113

98114
if ($ret < 0) {
99115
$this->setLastPcapError($pcap);
@@ -106,7 +122,7 @@ public function set_promisc(CData $pcap, int $promisc): int
106122
{
107123
$this->resetLastError();
108124

109-
$ret = $this->ffi->pcap_set_promisc($pcap, $promisc);
125+
$ret = self::$ffi->pcap_set_promisc($pcap, $promisc);
110126

111127
if ($ret < 0) {
112128
$this->setLastPcapError($pcap);
@@ -119,7 +135,7 @@ public function set_immediate_mode(CData $pcap, int $immediate_mode): int
119135
{
120136
$this->resetLastError();
121137

122-
$ret = $this->ffi->pcap_set_immediate_mode($pcap, $immediate_mode);
138+
$ret = self::$ffi->pcap_set_immediate_mode($pcap, $immediate_mode);
123139

124140
if ($ret < 0) {
125141
$this->setLastPcapError($pcap);
@@ -132,7 +148,7 @@ public function set_timeout(CData $pcap, int $to_ms): int
132148
{
133149
$this->resetLastError();
134150

135-
$ret = $this->ffi->pcap_set_timeout($pcap, $to_ms);
151+
$ret = self::$ffi->pcap_set_timeout($pcap, $to_ms);
136152

137153
if ($ret < 0) {
138154
$this->setLastPcapError($pcap);
@@ -145,8 +161,8 @@ public function setnonblock(CData $pcap, int $nonblock): int
145161
{
146162
$this->resetLastError();
147163

148-
$err = $this->ffi->new('char[257]');
149-
$ret = $this->ffi->pcap_setnonblock($pcap, $nonblock, $err);
164+
$err = self::$ffi->new('char[257]');
165+
$ret = self::$ffi->pcap_setnonblock($pcap, $nonblock, $err);
150166

151167
if ($ret < 0) {
152168
$this->setLastError(FFI::string($err));
@@ -159,7 +175,7 @@ public function activate(CData $pcap): int
159175
{
160176
$this->resetLastError();
161177

162-
$ret = $this->ffi->pcap_activate($pcap);
178+
$ret = self::$ffi->pcap_activate($pcap);
163179

164180
if ($ret < 0) {
165181
$this->setLastPcapError($pcap);
@@ -170,21 +186,21 @@ public function activate(CData $pcap): int
170186

171187
public function get_selectable_fd(CData $pcap): int
172188
{
173-
return $this->ffi->pcap_get_selectable_fd($pcap);
189+
return self::$ffi->pcap_get_selectable_fd($pcap);
174190
}
175191

176192
public function inject(CData $pcap, string $data): int
177193
{
178-
return $this->ffi->pcap_inject($pcap, $data, strlen($data));
194+
return self::$ffi->pcap_inject($pcap, $data, strlen($data));
179195
}
180196

181197
public function next_ex(CData $pcap): string
182198
{
183199
$this->resetLastError();
184200

185-
$header = $this->ffi->new('struct pcap_pkthdr *');
186-
$data = $this->ffi->new('const u_char *');
187-
$next = $this->ffi->pcap_next_ex($pcap, FFI::addr($header), FFI::addr($data));
201+
$header = self::$ffi->new('struct pcap_pkthdr *');
202+
$data = self::$ffi->new('const u_char *');
203+
$next = self::$ffi->pcap_next_ex($pcap, FFI::addr($header), FFI::addr($data));
188204

189205
if ($next < 0) {
190206
$this->setLastPcapError($pcap);
@@ -203,13 +219,13 @@ public function compile_setfilter(CData $pcap, string $filter): int
203219
{
204220
$this->resetLastError();
205221

206-
$fp = $this->ffi->new('struct bpf_program');
207-
$ret = $this->ffi->pcap_compile($pcap, FFI::addr($fp), $filter, 0, 0);
222+
$fp = self::$ffi->new('struct bpf_program');
223+
$ret = self::$ffi->pcap_compile($pcap, FFI::addr($fp), $filter, 0, 0);
208224

209225
if ($ret < 0) {
210226
$this->setLastPcapError($pcap);
211227
} else {
212-
$ret = $this->ffi->pcap_setfilter($pcap, FFI::addr($fp));
228+
$ret = self::$ffi->pcap_setfilter($pcap, FFI::addr($fp));
213229

214230
if ($ret < 0) {
215231
$this->setLastPcapError($pcap);
@@ -221,7 +237,7 @@ public function compile_setfilter(CData $pcap, string $filter): int
221237

222238
public function close(CData $pcap): void
223239
{
224-
$this->ffi->pcap_close($pcap);
240+
self::$ffi->pcap_close($pcap);
225241
}
226242

227243
public function getLastError(): string
@@ -236,7 +252,7 @@ private function setLastError(string $error): void
236252

237253
private function setLastPcapError(CData $pcap): void
238254
{
239-
$err = $this->ffi->pcap_geterr($pcap);
255+
$err = self::$ffi->pcap_geterr($pcap);
240256

241257
if (!is_null($err)) {
242258
$this->setLastError(FFI::string($err));

src/pcap.h

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
#define FFI_SCOPE "_RTCKIT_PCAP_FFI_"
2+
#define FFI_LIB "libpcap.so.1"
3+
14
typedef unsigned long int time_t;
25
typedef unsigned long int suseconds_t;
36

0 commit comments

Comments
 (0)