ring_tx: handle EINTR from sendto
[netsniff-ng.git] / pcap_mm.c
blob75ee0afbbb3526a9ced652b68ad1dbcb6c9ca499
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * Copyright 2011 - 2013 Daniel Borkmann.
4 * Subject to the GPL, version 2.
5 */
7 #define _GNU_SOURCE
8 #include <stdio.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <stdbool.h>
14 #include <sys/mman.h>
16 #include "pcap_io.h"
17 #include "built_in.h"
18 #include "ioops.h"
19 #include "iosched.h"
21 static size_t map_size = 0;
22 static char *ptr_va_start, *ptr_va_curr;
24 static void __pcap_mmap_write_need_remap(int fd)
26 int ret;
27 off_t pos, map_size_old = map_size;
28 off_t offset = ptr_va_curr - ptr_va_start;
30 map_size = PAGE_ALIGN(map_size_old * 10 / 8);
32 pos = lseek(fd, map_size, SEEK_SET);
33 if (pos < 0)
34 panic("Cannot lseek pcap file!\n");
36 ret = write_or_die(fd, "", 1);
37 if (ret != 1)
38 panic("Cannot write file!\n");
40 ptr_va_start = mremap(ptr_va_start, map_size_old, map_size, MREMAP_MAYMOVE);
41 if (ptr_va_start == MAP_FAILED)
42 panic("mmap of file failed!");
44 ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL);
45 if (ret < 0)
46 panic("Failed to give kernel mmap advise!\n");
48 ptr_va_curr = ptr_va_start + offset;
51 static ssize_t pcap_mm_write(int fd, pcap_pkthdr_t *phdr, enum pcap_type type,
52 const uint8_t *packet, size_t len)
54 size_t hdrsize = pcap_get_hdr_length(phdr, type);
56 if ((off_t) (ptr_va_curr - ptr_va_start) + hdrsize + len > map_size)
57 __pcap_mmap_write_need_remap(fd);
59 memcpy(ptr_va_curr, &phdr->raw, hdrsize);
60 ptr_va_curr += hdrsize;
61 memcpy(ptr_va_curr, packet, len);
62 ptr_va_curr += len;
64 return hdrsize + len;
67 static ssize_t pcap_mm_read(int fd __maybe_unused, pcap_pkthdr_t *phdr,
68 enum pcap_type type, uint8_t *packet, size_t len)
70 size_t hdrsize = pcap_get_hdr_length(phdr, type), hdrlen;
72 if (unlikely((off_t) (ptr_va_curr + hdrsize - ptr_va_start) > (off_t) map_size))
73 return -EIO;
75 memcpy(&phdr->raw, ptr_va_curr, hdrsize);
76 ptr_va_curr += hdrsize;
77 hdrlen = pcap_get_length(phdr, type);
79 if (unlikely((off_t) (ptr_va_curr + hdrlen - ptr_va_start) > (off_t) map_size))
80 return -EIO;
81 if (unlikely(hdrlen == 0 || hdrlen > len))
82 return -EINVAL;
84 memcpy(packet, ptr_va_curr, hdrlen);
85 ptr_va_curr += hdrlen;
87 return hdrsize + hdrlen;
90 static inline off_t ____get_map_size(bool jumbo)
92 int allocsz = jumbo ? 16 : 3;
94 return PAGE_ALIGN(sizeof(struct pcap_filehdr) + (RUNTIME_PAGE_SIZE * allocsz) * 1024);
97 static void __pcap_mm_prepare_access_wr(int fd, bool jumbo)
99 int ret;
100 off_t pos;
101 struct stat sb;
103 map_size = ____get_map_size(jumbo);
105 ret = fstat(fd, &sb);
106 if (ret < 0)
107 panic("Cannot fstat pcap file!\n");
108 if (!S_ISREG (sb.st_mode))
109 panic("pcap dump file is not a regular file!\n");
111 pos = lseek(fd, map_size, SEEK_SET);
112 if (pos < 0)
113 panic("Cannot lseek pcap file!\n");
115 ret = write_or_die(fd, "", 1);
116 if (ret != 1)
117 panic("Cannot write file!\n");
119 ptr_va_start = mmap(NULL, map_size, PROT_WRITE, MAP_SHARED, fd, 0);
120 if (ptr_va_start == MAP_FAILED)
121 panic("mmap of file failed!");
122 ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL);
123 if (ret < 0)
124 panic("Failed to give kernel mmap advise!\n");
126 ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr);
129 static void __pcap_mm_prepare_access_rd(int fd)
131 int ret;
132 struct stat sb;
134 ret = fstat(fd, &sb);
135 if (ret < 0)
136 panic("Cannot fstat pcap file!\n");
137 if (!S_ISREG (sb.st_mode))
138 panic("pcap dump file is not a regular file!\n");
140 map_size = sb.st_size;
141 ptr_va_start = mmap(NULL, map_size, PROT_READ, MAP_SHARED | MAP_LOCKED, fd, 0);
142 if (ptr_va_start == MAP_FAILED)
143 panic("mmap of file failed!");
144 ret = madvise(ptr_va_start, map_size, MADV_SEQUENTIAL);
145 if (ret < 0)
146 panic("Failed to give kernel mmap advise!\n");
148 ptr_va_curr = ptr_va_start + sizeof(struct pcap_filehdr);
151 static void pcap_mm_init_once(bool enforce_prio)
153 if (enforce_prio)
154 set_ioprio_be();
157 static int pcap_mm_prepare_access(int fd, enum pcap_mode mode, bool jumbo)
159 switch (mode) {
160 case PCAP_MODE_RD:
161 __pcap_mm_prepare_access_rd(fd);
162 break;
163 case PCAP_MODE_WR:
164 __pcap_mm_prepare_access_wr(fd, jumbo);
165 break;
166 default:
167 bug();
170 return 0;
173 static void pcap_mm_fsync(int fd __maybe_unused)
175 msync(ptr_va_start, (off_t) (ptr_va_curr - ptr_va_start), MS_ASYNC);
178 static void pcap_mm_prepare_close(int fd, enum pcap_mode mode)
180 int ret;
182 ret = munmap(ptr_va_start, map_size);
183 if (ret < 0)
184 panic("Cannot unmap the pcap file!\n");
186 if (mode == PCAP_MODE_WR) {
187 ret = ftruncate(fd, (off_t) (ptr_va_curr - ptr_va_start));
188 if (ret)
189 panic("Cannot truncate the pcap file!\n");
193 const struct pcap_file_ops pcap_mm_ops = {
194 .init_once_pcap = pcap_mm_init_once,
195 .pull_fhdr_pcap = pcap_generic_pull_fhdr,
196 .push_fhdr_pcap = pcap_generic_push_fhdr,
197 .prepare_access_pcap = pcap_mm_prepare_access,
198 .prepare_close_pcap = pcap_mm_prepare_close,
199 .read_pcap = pcap_mm_read,
200 .write_pcap = pcap_mm_write,
201 .fsync_pcap = pcap_mm_fsync,