/* * Copyright (C) 2012,2013 Scuola Superiore Sant'Anna (http://www.sssup.it) * and Consorzio Nazionale Interuniversitario per le Telecomunicazioni * (http://www.cnit.it). * * This file is part of Sniffer 15.4, an IEEE 802.15.4 packet sniffer for * Android devices. * * Sniffer 15.4 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Sniffer 15.4 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Sniffer 15.4. If not, see <http://www.gnu.org/licenses/>. */ package it.sssup.rtn.sniffer154.storage; import it.sssup.rtn.sniffer154.AppSniffer154; import it.sssup.rtn.sniffer154.R; import it.sssup.rtn.sniffer154.dissecting.Packet80215; import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.Activity; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.text.Editable; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class PcapExporter extends Activity { // private final static int LINKTYPE_IEEE802_15_4 = 195; // TODO add an option for FCS packets private final static int LINKTYPE_IEEE802_15_4_NOFCS = 230; private static final String TAG = "PCAPFILEMANAGER"; private static final String PCAPEXT = ".pcap"; private static Uri sessionUri = Uri.EMPTY; private int sessionDateBase; public Cursor cursor; private class GlobalHeader { static final int magic_number = 0xa1b2c3d4; /* magic number */ static final short version_major = 2; static final short version_minor = 4; static final int thiszone = 0; /* GMT to local correction */ static final int sigfigs = 0; /* accuracy of timestamps */ static final int snaplen = 65535; /* * max length of captured packets, in * octets */ } @Override protected void onCreate(Bundle savedInstanceState) { // Be sure to call the super class. super.onCreate(savedInstanceState); Log.d(TAG, "onCreate()"); setContentView(R.layout.exporter); final Button saveButton = (Button) findViewById(R.id.buttonExport); AppSniffer154 app = (AppSniffer154) getApplication(); sessionUri = app.getSessionUri(); Cursor sessionC = getContentResolver().query(sessionUri, null, null, null, null); if (sessionC == null || !sessionC.moveToFirst()) { toastMessage("Error, Cannot find the session date"); saveButton.setEnabled(false); return; } long sessionDate = sessionC.getLong(sessionC .getColumnIndex(SessionTable.C_SESSION_DATE)); sessionDateBase = (int) (sessionDate / 1000); Uri uri = Uri.withAppendedPath(sessionUri, PacketContentProvider.BASE_PATH_PACKETS + "/" + PacketContentProvider.BASE_PATH_FILTERED); cursor = getContentResolver().query(uri, null, null, null, null); if (cursor == null) { saveButton.setEnabled(false); } saveButton.setEnabled(true); saveButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { saveClicked(v); } }); } private void saveClicked(View v) { Log.d(TAG, "exportListButton()"); exportList(); } private void writeGlobalHeader(DataOutputStream dos, int LINKTYPE) throws IOException { dos.writeInt(GlobalHeader.magic_number); dos.writeShort(GlobalHeader.version_major); dos.writeShort(GlobalHeader.version_minor); dos.writeInt(GlobalHeader.thiszone); dos.writeInt(GlobalHeader.sigfigs); dos.writeInt(GlobalHeader.snaplen); dos.writeInt(LINKTYPE); } private void writeRecord(DataOutputStream dos, Packet80215 pack, long ts) throws IOException { int secOffset = (int) (ts / 1000); int us = ((int) (ts % 1000)) * 1000; dos.writeInt(secOffset + sessionDateBase); dos.writeInt(us); dos.writeInt(pack.getRaw().length); dos.writeInt(pack.getRaw().length); dos.write(pack.getRaw()); } private void toastMessage(String mess) { Toast toast = Toast.makeText(getApplicationContext(), mess, Toast.LENGTH_LONG); toast.show(); } private void exportList() { Log.d(TAG, "ExportList"); if (!cursor.moveToFirst()) { // empty list toastMessage("Empty list"); return; } EditText e = (EditText) findViewById(R.id.editText1); long sessionID = cursor.getLong(cursor .getColumnIndex(PacketTable.C_PACKET_SESSION)); String fileName = "Session" + Long.toString(sessionID); Editable s = e.getText(); if (!s.toString().equals("")) { fileName = s.toString(); } String fullFileName = fileName + PCAPEXT; File dir = new File(Environment.getExternalStorageDirectory() + "/sniffer154/"); dir.mkdirs(); File file = new File(dir, fullFileName); try { file.createNewFile(); if (!file.canWrite()) { Log.d(TAG, "cannot write"); toastMessage("Error writing to file"); return; } if (!file.exists()) { Log.d(TAG, "not exists"); toastMessage("Unable to create file"); return; } FileOutputStream fos; fos = new FileOutputStream(file); DataOutputStream dos = new DataOutputStream(fos); int linktype = LINKTYPE_IEEE802_15_4_NOFCS; writeGlobalHeader(dos, linktype); do { byte[] packet = cursor.getBlob(cursor .getColumnIndex(PacketTable.C_PACKET_PAYLOAD)); Packet80215 pack = Packet80215.create(packet); long tsOffset = cursor.getLong(cursor .getColumnIndex(PacketTable.C_PACKET_DATE)); if (pack == null) { toastMessage("Error parsing packet"); return; } Log.d(TAG, "Exporting " + pack.getType()); writeRecord(dos, pack, tsOffset); } while (cursor.moveToNext()); dos.close(); toastMessage("File " + fullFileName + " saved"); } catch (FileNotFoundException e1) { Log.d(TAG, "FileNotFound"); toastMessage("File not found"); e1.printStackTrace(); return; } catch (IOException e2) { Log.d(TAG, "IOException"); toastMessage("Error writing to file"); e2.printStackTrace(); } } }