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