1 /*
2 * Copyright 2007 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-pcapparse
22 * @title: pcapparse
23 *
24 * Extracts payloads from Ethernet-encapsulated IP packets.
25 * Use #GstPcapParse:src-ip, #GstPcapParse:dst-ip,
26 * #GstPcapParse:src-port and #GstPcapParse:dst-port to restrict which packets
27 * should be included.
28 *
29 * The supported data format is the classical
30 * [libpcap file format](https://wiki.wireshark.org/Development/LibpcapFileFormat)
31 *
32 * ## Example pipelines
33 * |[
34 * gst-launch-1.0 filesrc location=h264crasher.pcap ! pcapparse ! rtph264depay
35 * ! ffdec_h264 ! fakesink
36 * ]| Read from a pcap dump file using filesrc, extract the raw UDP packets,
37 * depayload and decode them.
38 *
39 */
40
41 /* TODO:
42 * - Implement support for timestamping the buffers.
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48
49 #include "gstpcapparse.h"
50
51 #include <string.h>
52
53 #ifndef G_OS_WIN32
54 #include <arpa/inet.h>
55 #include <netinet/in.h>
56 #include <string.h>
57 #else
58 #include <winsock2.h>
59 #endif
60
61
62 const guint GST_PCAPPARSE_MAGIC_MILLISECOND_NO_SWAP_ENDIAN = 0xa1b2c3d4;
63 const guint GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN = 0xa1b23c4d;
64 const guint GST_PCAPPARSE_MAGIC_MILLISECOND_SWAP_ENDIAN = 0xd4c3b2a1;
65 const guint GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN = 0x4d3cb2a1;
66
67
68 enum
69 {
70 PROP_0,
71 PROP_SRC_IP,
72 PROP_DST_IP,
73 PROP_SRC_PORT,
74 PROP_DST_PORT,
75 PROP_CAPS,
76 PROP_TS_OFFSET
77 };
78
79 GST_DEBUG_CATEGORY_STATIC (gst_pcap_parse_debug);
80 #define GST_CAT_DEFAULT gst_pcap_parse_debug
81
82 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
83 GST_PAD_SINK,
84 GST_PAD_ALWAYS,
85 GST_STATIC_CAPS ("raw/x-pcap"));
86
87 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
88 GST_PAD_SRC,
89 GST_PAD_ALWAYS,
90 GST_STATIC_CAPS_ANY);
91
92 static void gst_pcap_parse_finalize (GObject * object);
93 static void gst_pcap_parse_get_property (GObject * object, guint prop_id,
94 GValue * value, GParamSpec * pspec);
95 static void gst_pcap_parse_set_property (GObject * object, guint prop_id,
96 const GValue * value, GParamSpec * pspec);
97 static GstStateChangeReturn
98 gst_pcap_parse_change_state (GstElement * element, GstStateChange transition);
99
100 static void gst_pcap_parse_reset (GstPcapParse * self);
101
102 static GstFlowReturn gst_pcap_parse_chain (GstPad * pad,
103 GstObject * parent, GstBuffer * buffer);
104 static gboolean gst_pcap_sink_event (GstPad * pad,
105 GstObject * parent, GstEvent * event);
106
107
108 #define parent_class gst_pcap_parse_parent_class
109 G_DEFINE_TYPE (GstPcapParse, gst_pcap_parse, GST_TYPE_ELEMENT);
110 GST_ELEMENT_REGISTER_DEFINE (pcapparse, "pcapparse", GST_RANK_NONE,
111 GST_TYPE_PCAP_PARSE);
112
113 static void
gst_pcap_parse_class_init(GstPcapParseClass * klass)114 gst_pcap_parse_class_init (GstPcapParseClass * klass)
115 {
116 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
117 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118
119 gobject_class->finalize = gst_pcap_parse_finalize;
120 gobject_class->get_property = gst_pcap_parse_get_property;
121 gobject_class->set_property = gst_pcap_parse_set_property;
122
123 g_object_class_install_property (gobject_class,
124 PROP_SRC_IP, g_param_spec_string ("src-ip", "Source IP",
125 "Source IP to restrict to", "",
126 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
127
128 g_object_class_install_property (gobject_class,
129 PROP_DST_IP, g_param_spec_string ("dst-ip", "Destination IP",
130 "Destination IP to restrict to", "",
131 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
132
133 g_object_class_install_property (gobject_class,
134 PROP_SRC_PORT, g_param_spec_int ("src-port", "Source port",
135 "Source port to restrict to", -1, G_MAXUINT16, -1,
136 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
137
138 g_object_class_install_property (gobject_class,
139 PROP_DST_PORT, g_param_spec_int ("dst-port", "Destination port",
140 "Destination port to restrict to", -1, G_MAXUINT16, -1,
141 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
142
143 g_object_class_install_property (gobject_class, PROP_CAPS,
144 g_param_spec_boxed ("caps", "Caps",
145 "The caps of the source pad", GST_TYPE_CAPS,
146 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
147
148 g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
149 g_param_spec_int64 ("ts-offset", "Timestamp Offset",
150 "Relative timestamp offset (ns) to apply (-1 = use absolute packet time)",
151 -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152
153 gst_element_class_add_static_pad_template (element_class, &sink_template);
154 gst_element_class_add_static_pad_template (element_class, &src_template);
155
156 element_class->change_state = gst_pcap_parse_change_state;
157
158 gst_element_class_set_static_metadata (element_class, "PCapParse",
159 "Raw/Parser",
160 "Parses a raw pcap stream",
161 "Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com>");
162
163 GST_DEBUG_CATEGORY_INIT (gst_pcap_parse_debug, "pcapparse", 0, "pcap parser");
164 }
165
166 static void
gst_pcap_parse_init(GstPcapParse * self)167 gst_pcap_parse_init (GstPcapParse * self)
168 {
169 self->sink_pad = gst_pad_new_from_static_template (&sink_template, "sink");
170 gst_pad_set_chain_function (self->sink_pad,
171 GST_DEBUG_FUNCPTR (gst_pcap_parse_chain));
172 gst_pad_use_fixed_caps (self->sink_pad);
173 gst_pad_set_event_function (self->sink_pad,
174 GST_DEBUG_FUNCPTR (gst_pcap_sink_event));
175 gst_element_add_pad (GST_ELEMENT (self), self->sink_pad);
176
177 self->src_pad = gst_pad_new_from_static_template (&src_template, "src");
178 gst_pad_use_fixed_caps (self->src_pad);
179 gst_element_add_pad (GST_ELEMENT (self), self->src_pad);
180
181 self->src_ip = -1;
182 self->dst_ip = -1;
183 self->src_port = -1;
184 self->dst_port = -1;
185 self->offset = -1;
186
187 self->adapter = gst_adapter_new ();
188
189 gst_pcap_parse_reset (self);
190 }
191
192 static void
gst_pcap_parse_finalize(GObject * object)193 gst_pcap_parse_finalize (GObject * object)
194 {
195 GstPcapParse *self = GST_PCAP_PARSE (object);
196
197 g_object_unref (self->adapter);
198 if (self->caps)
199 gst_caps_unref (self->caps);
200
201 G_OBJECT_CLASS (parent_class)->finalize (object);
202 }
203
204 static const gchar *
get_ip_address_as_string(gint64 ip_addr)205 get_ip_address_as_string (gint64 ip_addr)
206 {
207 if (ip_addr >= 0) {
208 struct in_addr addr;
209 addr.s_addr = ip_addr;
210 return inet_ntoa (addr);
211 } else {
212 return "";
213 }
214 }
215
216 static void
set_ip_address_from_string(gint64 * ip_addr,const gchar * ip_str)217 set_ip_address_from_string (gint64 * ip_addr, const gchar * ip_str)
218 {
219 if (ip_str[0] != '\0') {
220 gulong addr = inet_addr (ip_str);
221 if (addr != INADDR_NONE)
222 *ip_addr = addr;
223 } else {
224 *ip_addr = -1;
225 }
226 }
227
228 static void
gst_pcap_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)229 gst_pcap_parse_get_property (GObject * object, guint prop_id,
230 GValue * value, GParamSpec * pspec)
231 {
232 GstPcapParse *self = GST_PCAP_PARSE (object);
233
234 switch (prop_id) {
235 case PROP_SRC_IP:
236 g_value_set_string (value, get_ip_address_as_string (self->src_ip));
237 break;
238
239 case PROP_DST_IP:
240 g_value_set_string (value, get_ip_address_as_string (self->dst_ip));
241 break;
242
243 case PROP_SRC_PORT:
244 g_value_set_int (value, self->src_port);
245 break;
246
247 case PROP_DST_PORT:
248 g_value_set_int (value, self->dst_port);
249 break;
250
251 case PROP_CAPS:
252 gst_value_set_caps (value, self->caps);
253 break;
254
255 case PROP_TS_OFFSET:
256 g_value_set_int64 (value, self->offset);
257 break;
258
259 default:
260 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261 break;
262 }
263 }
264
265 static void
gst_pcap_parse_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)266 gst_pcap_parse_set_property (GObject * object, guint prop_id,
267 const GValue * value, GParamSpec * pspec)
268 {
269 GstPcapParse *self = GST_PCAP_PARSE (object);
270
271 switch (prop_id) {
272 case PROP_SRC_IP:
273 set_ip_address_from_string (&self->src_ip, g_value_get_string (value));
274 break;
275
276 case PROP_DST_IP:
277 set_ip_address_from_string (&self->dst_ip, g_value_get_string (value));
278 break;
279
280 case PROP_SRC_PORT:
281 self->src_port = g_value_get_int (value);
282 break;
283
284 case PROP_DST_PORT:
285 self->dst_port = g_value_get_int (value);
286 break;
287
288 case PROP_CAPS:
289 {
290 const GstCaps *new_caps_val;
291 GstCaps *new_caps, *old_caps;
292
293 new_caps_val = gst_value_get_caps (value);
294 if (new_caps_val == NULL) {
295 new_caps = gst_caps_new_any ();
296 } else {
297 new_caps = gst_caps_copy (new_caps_val);
298 }
299
300 old_caps = self->caps;
301 self->caps = new_caps;
302 if (old_caps)
303 gst_caps_unref (old_caps);
304
305 gst_pad_set_caps (self->src_pad, new_caps);
306 break;
307 }
308
309 case PROP_TS_OFFSET:
310 self->offset = g_value_get_int64 (value);
311 break;
312
313 default:
314 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315 break;
316 }
317 }
318
319 static void
gst_pcap_parse_reset(GstPcapParse * self)320 gst_pcap_parse_reset (GstPcapParse * self)
321 {
322 self->initialized = FALSE;
323 self->swap_endian = FALSE;
324 self->nanosecond_timestamp = FALSE;
325 self->cur_packet_size = -1;
326 self->cur_ts = GST_CLOCK_TIME_NONE;
327 self->base_ts = GST_CLOCK_TIME_NONE;
328 self->newsegment_sent = FALSE;
329 self->first_packet = TRUE;
330
331 gst_adapter_clear (self->adapter);
332 }
333
334 static guint32
gst_pcap_parse_read_uint32(GstPcapParse * self,const guint8 * p)335 gst_pcap_parse_read_uint32 (GstPcapParse * self, const guint8 * p)
336 {
337 guint32 val = *((guint32 *) p);
338
339 if (self->swap_endian) {
340 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
341 return GUINT32_FROM_BE (val);
342 #else
343 return GUINT32_FROM_LE (val);
344 #endif
345 } else {
346 return val;
347 }
348 }
349
350 #define ETH_MAC_ADDRESSES_LEN 12
351 #define ETH_HEADER_LEN 14
352 #define ETH_VLAN_HEADER_LEN 4
353 #define SLL_HEADER_LEN 16
354 #define IP_HEADER_MIN_LEN 20
355 #define UDP_HEADER_LEN 8
356
357 #define IP_PROTO_UDP 17
358 #define IP_PROTO_TCP 6
359
360
361 static gboolean
gst_pcap_parse_scan_frame(GstPcapParse * self,const guint8 * buf,gint buf_size,const guint8 ** payload,gint * payload_size)362 gst_pcap_parse_scan_frame (GstPcapParse * self,
363 const guint8 * buf,
364 gint buf_size, const guint8 ** payload, gint * payload_size)
365 {
366 const guint8 *buf_ip = 0;
367 const guint8 *buf_proto;
368 guint16 eth_type;
369 guint8 b;
370 guint8 ip_header_size;
371 guint8 flags;
372 guint16 fragment_offset;
373 guint8 ip_protocol;
374 guint32 ip_src_addr;
375 guint32 ip_dst_addr;
376 guint16 src_port;
377 guint16 dst_port;
378 guint16 len;
379 guint16 ip_packet_len;
380
381 switch (self->linktype) {
382 case LINKTYPE_ETHER:
383 if (buf_size < ETH_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
384 return FALSE;
385 eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + ETH_MAC_ADDRESSES_LEN)));
386 /* check for vlan 802.1q header (4 bytes, with first two bytes equal to 0x8100) */
387 if (eth_type == 0x8100) {
388 if (buf_size <
389 ETH_HEADER_LEN + ETH_VLAN_HEADER_LEN + IP_HEADER_MIN_LEN +
390 UDP_HEADER_LEN)
391 return FALSE;
392 eth_type =
393 GUINT16_FROM_BE (*((guint16 *) (buf + ETH_MAC_ADDRESSES_LEN +
394 ETH_VLAN_HEADER_LEN)));
395 buf_ip = buf + ETH_HEADER_LEN + ETH_VLAN_HEADER_LEN;
396 } else {
397 buf_ip = buf + ETH_HEADER_LEN;
398 }
399 break;
400 case LINKTYPE_SLL:
401 if (buf_size < SLL_HEADER_LEN + IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
402 return FALSE;
403
404 eth_type = GUINT16_FROM_BE (*((guint16 *) (buf + 14)));
405 buf_ip = buf + SLL_HEADER_LEN;
406 break;
407 case LINKTYPE_RAW:
408 if (buf_size < IP_HEADER_MIN_LEN + UDP_HEADER_LEN)
409 return FALSE;
410
411 eth_type = 0x800; /* This is fine since IPv4/IPv6 is parse elsewhere */
412 buf_ip = buf;
413 break;
414
415 default:
416 return FALSE;
417 }
418
419 if (eth_type != 0x800) {
420 GST_ERROR_OBJECT (self,
421 "Link type %d: Ethernet type %d is not supported; only type 0x800",
422 (gint) self->linktype, (gint) eth_type);
423 return FALSE;
424 }
425
426 b = *buf_ip;
427
428 /* Check that the packet is IPv4 */
429 if (((b >> 4) & 0x0f) != 4)
430 return FALSE;
431
432 ip_header_size = (b & 0x0f) * 4;
433 if (buf_ip + ip_header_size > buf + buf_size)
434 return FALSE;
435
436 flags = buf_ip[6] >> 5;
437 fragment_offset =
438 (GUINT16_FROM_BE (*((guint16 *) (buf_ip + 6))) & 0x1fff) * 8;
439 if (flags & 0x1 || fragment_offset > 0) {
440 GST_ERROR_OBJECT (self, "Fragmented packets are not supported");
441 return FALSE;
442 }
443
444 ip_protocol = *(buf_ip + 9);
445 GST_LOG_OBJECT (self, "ip proto %d", (gint) ip_protocol);
446
447 if (ip_protocol != IP_PROTO_UDP && ip_protocol != IP_PROTO_TCP)
448 return FALSE;
449
450 /* ip info */
451 ip_src_addr = *((guint32 *) (buf_ip + 12));
452 ip_dst_addr = *((guint32 *) (buf_ip + 16));
453 buf_proto = buf_ip + ip_header_size;
454 ip_packet_len = GUINT16_FROM_BE (*(guint16 *) (buf_ip + 2));
455
456 /* ok for tcp and udp */
457 src_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 0)));
458 dst_port = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 2)));
459
460 /* extract some params and data according to protocol */
461 if (ip_protocol == IP_PROTO_UDP) {
462 len = GUINT16_FROM_BE (*((guint16 *) (buf_proto + 4)));
463 if (len < UDP_HEADER_LEN || buf_proto + len > buf + buf_size)
464 return FALSE;
465
466 *payload = buf_proto + UDP_HEADER_LEN;
467 *payload_size = len - UDP_HEADER_LEN;
468 } else {
469 if (buf_proto + 12 >= buf + buf_size)
470 return FALSE;
471 len = (buf_proto[12] >> 4) * 4;
472 if (buf_proto + len > buf + buf_size)
473 return FALSE;
474
475 /* all remaining data following tcp header is payload */
476 *payload = buf_proto + len;
477 *payload_size = ip_packet_len - ip_header_size - len;
478 }
479
480 /* but still filter as configured */
481 if (self->src_ip >= 0 && ip_src_addr != self->src_ip)
482 return FALSE;
483
484 if (self->dst_ip >= 0 && ip_dst_addr != self->dst_ip)
485 return FALSE;
486
487 if (self->src_port >= 0 && src_port != self->src_port)
488 return FALSE;
489
490 if (self->dst_port >= 0 && dst_port != self->dst_port)
491 return FALSE;
492
493 return TRUE;
494 }
495
496 static GstFlowReturn
gst_pcap_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buffer)497 gst_pcap_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
498 {
499 GstPcapParse *self = GST_PCAP_PARSE (parent);
500 GstFlowReturn ret = GST_FLOW_OK;
501 GstBufferList *list = NULL;
502
503 gst_adapter_push (self->adapter, buffer);
504
505 while (ret == GST_FLOW_OK) {
506 gint avail;
507 const guint8 *data;
508
509 avail = gst_adapter_available (self->adapter);
510
511 if (self->initialized) {
512 if (self->cur_packet_size >= 0) {
513 /* Parse the Packet Data */
514 if (avail < self->cur_packet_size)
515 break;
516
517 if (self->cur_packet_size > 0) {
518 const guint8 *payload_data;
519 gint payload_size;
520
521 data = gst_adapter_map (self->adapter, self->cur_packet_size);
522
523 GST_LOG_OBJECT (self, "examining packet size %" G_GINT64_FORMAT,
524 self->cur_packet_size);
525
526 if (gst_pcap_parse_scan_frame (self, data, self->cur_packet_size,
527 &payload_data, &payload_size)) {
528 GstBuffer *out_buf;
529 guintptr offset = payload_data - data;
530
531 gst_adapter_unmap (self->adapter);
532 gst_adapter_flush (self->adapter, offset);
533 /* we don't use _take_buffer_fast() on purpose here, we need a
534 * buffer with a single memory, since the RTP depayloaders expect
535 * the complete RTP header to be in the first memory if there are
536 * multiple ones and we can't guarantee that with _fast() */
537 if (payload_size > 0) {
538 out_buf = gst_adapter_take_buffer (self->adapter, payload_size);
539 } else {
540 out_buf = gst_buffer_new ();
541 }
542
543 /* only first packet should have DISCONT flag */
544 if (G_LIKELY (!self->first_packet)) {
545 GST_BUFFER_FLAG_UNSET (out_buf, GST_BUFFER_FLAG_DISCONT);
546 } else {
547 GST_BUFFER_FLAG_SET (out_buf, GST_BUFFER_FLAG_DISCONT);
548 self->first_packet = FALSE;
549 }
550
551 gst_adapter_flush (self->adapter,
552 self->cur_packet_size - offset - payload_size);
553
554 if (GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
555 if (!GST_CLOCK_TIME_IS_VALID (self->base_ts))
556 self->base_ts = self->cur_ts;
557 if (self->offset >= 0) {
558 self->cur_ts -= self->base_ts;
559 self->cur_ts += self->offset;
560 }
561 }
562 GST_BUFFER_DTS (out_buf) = self->cur_ts;
563
564
565 if (list == NULL)
566 list = gst_buffer_list_new ();
567 gst_buffer_list_add (list, out_buf);
568 } else {
569 gst_adapter_unmap (self->adapter);
570 gst_adapter_flush (self->adapter, self->cur_packet_size);
571 }
572 }
573
574 self->cur_packet_size = -1;
575 } else {
576 /* Parse the Record (Packet) Header */
577 guint32 ts_sec;
578 guint32 ts_usec;
579 guint32 incl_len;
580
581 /* sizeof(pcaprec_hdr_t) == 16 */
582 if (avail < 16)
583 break;
584
585 data = gst_adapter_map (self->adapter, 16);
586
587 ts_sec = gst_pcap_parse_read_uint32 (self, data + 0);
588 ts_usec = gst_pcap_parse_read_uint32 (self, data + 4);
589 incl_len = gst_pcap_parse_read_uint32 (self, data + 8);
590 /* orig_len = gst_pcap_parse_read_uint32 (self, data + 12); */
591
592 gst_adapter_unmap (self->adapter);
593 gst_adapter_flush (self->adapter, 16);
594
595 self->cur_ts =
596 ts_sec * GST_SECOND +
597 ts_usec * (self->nanosecond_timestamp ? 1 : GST_USECOND);
598 self->cur_packet_size = incl_len;
599 }
600 } else {
601 /* Parse the Global Header */
602 guint32 magic;
603 guint32 linktype;
604 guint16 major_version;
605
606 /* sizeof(pcap_hdr_t) == 24 */
607 if (avail < 24)
608 break;
609
610 data = gst_adapter_map (self->adapter, 24);
611
612 magic = *((guint32 *) data);
613 major_version = *((guint16 *) (data + 4));
614 linktype = *((guint32 *) (data + 20));
615 gst_adapter_unmap (self->adapter);
616
617 if (magic == GST_PCAPPARSE_MAGIC_MILLISECOND_NO_SWAP_ENDIAN ||
618 magic == GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN) {
619 self->swap_endian = FALSE;
620 if (magic == GST_PCAPPARSE_MAGIC_NANOSECOND_NO_SWAP_ENDIAN)
621 self->nanosecond_timestamp = TRUE;
622 } else if (magic == GST_PCAPPARSE_MAGIC_MILLISECOND_SWAP_ENDIAN ||
623 magic == GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN) {
624 self->swap_endian = TRUE;
625 if (magic == GST_PCAPPARSE_MAGIC_NANOSECOND_SWAP_ENDIAN)
626 self->nanosecond_timestamp = TRUE;
627 major_version = GUINT16_SWAP_LE_BE (major_version);
628 linktype = GUINT32_SWAP_LE_BE (linktype);
629 } else {
630 GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
631 ("File is not a libpcap file, magic is %X", magic));
632 ret = GST_FLOW_ERROR;
633 goto out;
634 }
635
636 if (major_version != 2) {
637 GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
638 ("File is not a libpcap major version 2, but %u", major_version));
639 ret = GST_FLOW_ERROR;
640 goto out;
641 }
642
643 if (linktype != LINKTYPE_ETHER && linktype != LINKTYPE_SLL &&
644 linktype != LINKTYPE_RAW) {
645 GST_ELEMENT_ERROR (self, STREAM, WRONG_TYPE, (NULL),
646 ("Only dumps of type Ethernet, raw IP or Linux Cooked (SLL) "
647 "understood; type %d unknown", linktype));
648 ret = GST_FLOW_ERROR;
649 goto out;
650 }
651
652 GST_DEBUG_OBJECT (self, "linktype %u", linktype);
653 self->linktype = linktype;
654
655 gst_adapter_flush (self->adapter, 24);
656 self->initialized = TRUE;
657 }
658 }
659
660 if (list) {
661 if (!self->newsegment_sent && GST_CLOCK_TIME_IS_VALID (self->cur_ts)) {
662 GstSegment segment;
663
664 if (self->caps)
665 gst_pad_set_caps (self->src_pad, self->caps);
666 gst_segment_init (&segment, GST_FORMAT_TIME);
667 segment.start = self->base_ts;
668 gst_pad_push_event (self->src_pad, gst_event_new_segment (&segment));
669 self->newsegment_sent = TRUE;
670 }
671
672 ret = gst_pad_push_list (self->src_pad, list);
673 list = NULL;
674 }
675
676 out:
677
678 if (list)
679 gst_buffer_list_unref (list);
680
681 return ret;
682 }
683
684 static gboolean
gst_pcap_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)685 gst_pcap_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
686 {
687 gboolean ret = TRUE;
688 GstPcapParse *self = GST_PCAP_PARSE (parent);
689
690 switch (GST_EVENT_TYPE (event)) {
691 case GST_EVENT_SEGMENT:
692 /* Drop it, we'll replace it with our own */
693 gst_event_unref (event);
694 break;
695 case GST_EVENT_FLUSH_STOP:
696 gst_pcap_parse_reset (self);
697 /* Push event down the pipeline so that other elements stop flushing */
698 /* fall through */
699 default:
700 ret = gst_pad_push_event (self->src_pad, event);
701 break;
702 }
703
704 return ret;
705 }
706
707 static GstStateChangeReturn
gst_pcap_parse_change_state(GstElement * element,GstStateChange transition)708 gst_pcap_parse_change_state (GstElement * element, GstStateChange transition)
709 {
710 GstPcapParse *self = GST_PCAP_PARSE (element);
711 GstStateChangeReturn ret;
712
713 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
714
715 switch (transition) {
716 case GST_STATE_CHANGE_PAUSED_TO_READY:
717 gst_pcap_parse_reset (self);
718 break;
719 default:
720 break;
721 }
722
723
724 return ret;
725 }
726