1/*
2Copyright (c) 2015-2015 Cisco Systems, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16#include "captureFile.h"
17#include "pcap.h"
18#include "erf.h"
19#include "basic_utils.h"
20#include <stdlib.h>
21#include <errno.h>
22#include <string.h>
23#include <math.h>
24
25
26void CPktNsecTimeStamp::Dump(FILE *fd){
27    fprintf(fd,"%.6f [%x:%x]",getNsec(),m_time_sec,m_time_nsec );
28}
29
30
31void * CAlignMalloc::malloc(uint16_t size,uint8_t align){
32    assert(m_p==0);
33    m_p=(char *)::malloc(size+align);
34    uintptr_t v =(uintptr_t)m_p;
35    char *p=(char *)my_utl_align_up( v,align);
36    return  (void *)p;
37}
38
39void CAlignMalloc::free(){
40    ::free(m_p);
41    m_p=0;
42}
43
44#define PKT_ALIGN 128
45
46
47CCapPktRaw::CCapPktRaw(CCapPktRaw  *obj){
48    flags =0;
49    pkt_cnt=obj->pkt_cnt;
50    pkt_len=obj->pkt_len;
51    time_sec=obj->time_sec;
52    time_nsec=obj->time_nsec;
53    assert ((pkt_len>0) && (pkt_len<MAX_PKT_SIZE) );
54    raw = (char *)m_handle.malloc(pkt_len,PKT_ALIGN);
55    // copy the packet
56    memcpy(raw,obj->raw,pkt_len);
57}
58
59
60CCapPktRaw::CCapPktRaw(int size){
61    pkt_cnt=0;
62    flags =0;
63    pkt_len=size;
64    time_sec=0;
65    time_nsec=0;
66    if (size==0) {
67        raw =0;
68    }else{
69        raw = (char *)m_handle.malloc(size,PKT_ALIGN);
70        memset(raw,0xee,size);
71    }
72
73}
74
75CCapPktRaw::CCapPktRaw(){
76    flags =0;
77	pkt_cnt=0;
78	pkt_len=0;
79	time_sec=0;
80	time_nsec=0;
81	raw = (char *)m_handle.malloc((uint16_t)MAX_PKT_SIZE,PKT_ALIGN);
82    memset(raw,0xee,MAX_PKT_SIZE);
83}
84
85CCapPktRaw::~CCapPktRaw(){
86	if (raw && (getDoNotFree()==false) ) {
87		m_handle.free();
88	}
89}
90
91char * CCapPktRaw::append(uint16_t len){
92    CAlignMalloc h;
93    char * p;
94    char * new_raw = (char *)h.malloc(pkt_len+len,PKT_ALIGN);
95    memcpy(new_raw,raw,pkt_len);
96    m_handle.free();
97    raw=new_raw;
98    p= raw+pkt_len;
99    pkt_len+=len;
100    m_handle.m_p =h.m_p;
101    /* new pointer */
102    return(p);
103}
104
105
106void CCapPktRaw::CloneShalow(CCapPktRaw  *obj){
107    pkt_len=obj->pkt_len;
108    raw = obj->raw;
109    setDoNotFree(true);
110}
111
112void CCapPktRaw::Dump(FILE *fd,int verbose){
113	fprintf(fd," =>pkt (%p) %llu , len %d, time [%x:%x] \n",raw, (unsigned long long)pkt_cnt,pkt_len,time_sec,time_nsec);
114	if (verbose) {
115		utl_DumpBuffer(fd,raw,pkt_len,0);
116	}
117}
118
119
120bool CCapPktRaw::Compare(CCapPktRaw * obj,int dump,double dsec){
121
122    if (pkt_len != obj->pkt_len) {
123        if ( dump ){
124            printf(" ERROR: len is not eq. First len is %d, second is %d \n", pkt_len, obj->pkt_len);
125        }
126        return (false);
127    }
128
129    if ( getInterface() != obj->getInterface() ){
130        printf(" ERROR: original packet from if=%d and cur packet from if=%d \n",getInterface(),obj->getInterface());
131        return (false);
132    }
133
134    CPktNsecTimeStamp t1(time_sec,time_nsec);
135    CPktNsecTimeStamp t2(obj->time_sec,obj->time_nsec);
136    if ( t1.diff(t2) > dsec ){
137        if ( dump ){
138            printf(" ERROR: diff of %lf seconds while only %lf allowed\n", t1.diff(t2), dsec);
139        }
140        return (false);
141    }
142
143    if ( memcmp(raw,obj->raw,pkt_len) == 0 ){
144        return (true);
145    }else{
146        if ( dump ){
147            fprintf(stdout," ERROR: buffers not the same \n");
148            fprintf(stdout," B1 \n");
149            fprintf(stdout," ---------------\n");
150            utl_DumpBuffer(stdout,raw,pkt_len,0);
151            fprintf(stdout," B2 \n");
152            fprintf(stdout," ---------------\n");
153
154            utl_DumpBuffer(stdout,obj->raw,obj->pkt_len,0);
155        }
156        return (false);
157    }
158}
159
160#define  CPY_BUFSIZE 1024
161
162bool CErfCmp::cpy(std::string src,std::string dst){
163
164    char mybuf[CPY_BUFSIZE] ;
165    FILE *ifd = NULL;
166    FILE *ofd = NULL;
167    ifd = fopen( src.c_str(), "rb" );
168    ofd = fopen( dst.c_str(), "w+");
169    assert(ifd!=NULL);
170    assert(ofd!=NULL);
171
172    int n;
173    while ( true){
174        n = fread(mybuf, sizeof(char), CPY_BUFSIZE ,ifd);
175        if (n>0) {
176            fwrite(mybuf, sizeof(char),n,ofd);
177        }else{
178            break;
179        }
180    }
181
182    fclose(ifd);
183    fclose(ofd);
184    return true;
185}
186
187
188bool CErfCmp::compare(std::string f1, std::string f2 ){
189
190    if ( dump ){
191        printf(" compare %s %s \n",f1.c_str(),f2.c_str());
192    }
193    bool res=true;
194    CCapReaderBase * lp1=CCapReaderFactory::CreateReader((char *)f1.c_str(),0);
195    if (lp1 == 0) {
196        if ( dump ){
197            printf(" ERROR file %s does not exits or not supported \n",(char *)f1.c_str());
198        }
199        return (false);
200    }
201
202    CCapReaderBase * lp2=CCapReaderFactory::CreateReader((char *)f2.c_str(),0);
203    if (lp2 == 0) {
204        delete lp1;
205        if ( dump ){
206            printf(" ERROR file %s does not exits or not supported \n",(char *)f2.c_str());
207        }
208        return (false);
209    }
210
211    CCapPktRaw raw_packet1;
212    bool has_pkt1;
213    CCapPktRaw raw_packet2;
214    bool has_pkt2;
215
216    int pkt_cnt=1;
217    while ( true ) {
218        /* read packet */
219         has_pkt1 = lp1->ReadPacket(&raw_packet1) ;
220         has_pkt2 = lp2->ReadPacket(&raw_packet2) ;
221
222         /* one has finished */
223         if ( !has_pkt1  || !has_pkt2 ) {
224             if (has_pkt1 != has_pkt2 ) {
225                 if ( dump ){
226                     printf(" ERROR not the same number of packets  \n");
227                 }
228                 res=false;
229             }
230             break;
231         }
232        if (!raw_packet1.Compare(&raw_packet2,true,d_sec)  ){
233            res=false;
234            printf(" ERROR in pkt %d \n",pkt_cnt);
235            break;
236        }
237
238
239        pkt_cnt++;
240    }
241
242    delete lp1;
243    delete lp2;
244    return (res);
245}
246
247/**
248 * try to create type by type
249 * @param name
250 *
251 * @return CCapReaderBase*
252 */
253CCapReaderBase * CCapReaderFactory::CreateReader(char * name, int loops, std::ostream &err)
254{
255    assert(name);
256
257    /* make sure we have a file */
258    FILE * f = CAP_FOPEN_64(name, "rb");
259    if (f == NULL) {
260        if (errno == ENOENT) {
261            err << "CAP file '" << name << "' not found";
262        } else {
263            err << "failed to open CAP file '" << name << "' with errno " << errno;
264        }
265        return NULL;
266    }
267    // close the file
268    fclose(f);
269
270    for (capture_type_e i = LIBPCAP ; i<LAST_TYPE ; i = (capture_type_e(i+1)) )
271	{
272		CCapReaderBase * next = CCapReaderFactory::CreateReaderInstace(i);
273		if (next == NULL || next->Create(name,loops)) {
274			return next;
275		}
276		delete next;
277	}
278
279    err << "unsupported CAP format (not PCAP or ERF): " << name << "\n";
280
281	return NULL;
282}
283
284CCapReaderBase * CCapReaderFactory::CreateReaderInstace(capture_type_e type)
285{
286	switch(type)
287	{
288	case  ERF:
289		return new CErfFileReader();
290	case LIBPCAP:
291		return new LibPCapReader();
292	default:
293		printf("Got unsupported file type\n");
294		return NULL;
295	}
296
297}
298
299
300
301/**
302 * The factory function will create the matching reader instance
303 * according to the type.
304 *
305 * @param type - the foramt
306 * @param name - new file name
307 *
308 * @return CCapWriter* - return pointer to the writer instance
309 *         or NULL if failed from some reason. Instance user
310 *         should relase memory when instance not needed
311 *         anymore.
312 */
313CFileWriterBase  * CCapWriterFactory::CreateWriter(capture_type_e type ,char * name)
314{
315	if (name == NULL) {
316		return NULL;
317	}
318
319	CFileWriterBase  * toRet = CCapWriterFactory::createWriterInsance(type);
320
321	if (toRet) {
322		if (!toRet->Create(name)) {
323            delete toRet;
324			toRet = NULL;
325		}
326	}
327
328	return toRet;
329}
330
331/**
332 * Create instance for writer if type is supported.
333 * @param type
334 *
335 * @return CFileWriterBase*
336 */
337CFileWriterBase  * CCapWriterFactory::createWriterInsance(capture_type_e type )
338{
339	switch(type) {
340	case LIBPCAP:
341		return new LibPCapWriter();
342	case ERF:
343		return new CErfFileWriter();
344		// other is not supported yet.
345	default:
346		return NULL;
347	}
348}
349
350