Optimal IP subnet matching - scala

The following code appears to be the hottest spot in my program.
JAVA_OPTS=-Xprof output:
Compiled + native Method
5.7% 173 + 0 scala.collection.IndexedSeqOptimized$class.slice
5.1% 156 + 0 scala.collection.IndexedSeqOptimized$class.foreach
2.9% 87 + 0 java.util.regex.Pattern$BmpCharProperty.match
2.5% 76 + 0 scala.collection.IndexedSeqOptimized$class.sameElements
2.4% 73 + 0 trafacct.SubNet.contains
Slice, sameElements and even foreach calls seem to be most used from here too. Can someone give an advice or two on how to optimize contains() method? Maybe some techniques allowing Bytes analysis without converting them to integers? Or solid whole-sequence approach without slice?
Function SubNet.contains() matches an IP address against subnet.
object SubNet {
def toInts(bytes: Seq[Byte]): Seq[Int] = bytes.map(_.toInt & 0xFF)
}
case class SubNet(ip:InetAddress, maskLength:Int) extends HostCategory {
import SubNet.toInts
private val bytes: Int = maskLength / 8
private val subnet = toInts(ip.getAddress)
private val bits = bytes * 8 - maskLength
def contains(host: Host) = {
if (host.ip == null && ip == null) {
true
} else if (this.ip == null) {
false
} else {
val address = toInts(host.ip.getAddress)
if (address.length != subnet.length) {
false
} else {
if (address.slice(0, bytes) != subnet.slice(0, bytes)) {
false
} else {
((address(bytes) >> (8-bits) ^ subnet(bytes) >> (8-bits)) & 0xFF) == 0
}
}
}
}
}
I understand, that this optimization won't give me much better throughput, I just feel that I'm doing something wrong spending so much time inside this simple function.
This code should be IPv6 (16 bytes) compatible, and I don't like the idea of handling IPv4 case separately.

You're not doing anything wrong per se; you're just using collections that are meant for ease of use not performance when handling primitives.
If you want to speed this up, you'll get the largest boost by switching to using arrays and while loops. It's not entirely clear to me that the code you wrote even works for IPv6 except for IPv4 addresses stored in IPv6 format, since you could have a subnet with more than 256 items. Also, by testing lengths you're assuming no mixed IPv6/IPv4 representations of the same address.
I'd forget the whole "toInts" thing and just store byte arrays; then do something like (warning, untested)
def contains(host: Host): Boolean = {
//...
if (address.length != subnet.length) false
else {
var i = 0
while (i<address.length-1) {
if (address(i) != subnet(i)) return false
i += 1
}
(address(i)&0xFF) >> (8-bits) ^ (subnet(i)&0xFF) >> (8-bits) == 0
}
}
It's really not any more complicated than your original solution, and should run ~10x faster.

With this code, it does not validate correctly.
For example:
scala> val ip = java.net.InetAddress.getByName("::ffff:1.2.176.0")
ip: java.net.InetAddress = /1.2.176.0
scala> val prefix = new InetPrefix(ip, 20)
prefix: InetPrefix = InetPrefix#6febf6f9
scala> prefix.contains(java.net.InetAddress.getByName("::ffff:1.2.176.20"))
res11: Boolean = true
scala> prefix.contains(java.net.InetAddress.getByName("::ffff:1.2.191.20"))
res12: Boolean = false
But if you calculate that network: (1.2.176.0/20)
$ sipcalc 1.2.176.0/20
-[ipv4 : 1.2.176.0/20] - 0
[CIDR]
Host address - 1.2.176.0
Host address (decimal) - 16953344
Host address (hex) - 102B000
Network address - 1.2.176.0
Network mask - 255.255.240.0
Network mask (bits) - 20
Network mask (hex) - FFFFF000
Broadcast address - 1.2.191.255
Cisco wildcard - 0.0.15.255
Addresses in network - 4096
Network range - 1.2.176.0 - 1.2.191.255
Usable range - 1.2.176.1 - 1.2.191.254
-
I rewrote both (IPv4 and IPv6) in Scala put it for everyone on GitHub. It now also validates within ranges (so /20 etc will be regarded, which the old one did not do.)
You can find the code (i separated it into IPv4 and IPv6) at https://github.com/wasted/scala-util/blob/master/src/main/scala/io/wasted/util/InetPrefix.scala
I also created a blogpost about this.

Related

Can OMNET with INET4.4 be used for large-scale simulations?

everybody!
I want to simulate a large-scale (more than thousand nodes) satellite network,e.g.,starlink_p1 constellation with 1584 satellites.
We model satellite as router, and each router connects to a standhost for generating traffic. We use the up-to-date version of OMNET with INET4.4 in Ubuntu20.04, and the topology file (NED) and config file(ini) are complete as the following.
However, when we run the simulation by the means of Cmdenv, the simulation has been initializing for more than a day. I wonder if there's something wrong with my setting, or if omnet does not support large-scale simulation with 1584 nodes.
I look forward to your reply, thanks.
NED.file:
package inet.examples.inet.MegaCons;
import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator;
import inet.node.inet.Router;
import inet.node.inet.StandardHost;
network Starlink_p1_grid_topo
{
parameters:
int n = 1584;
types:
channel Intra_channel extends ned.DatarateChannel
{
delay = 2.2ms;
datarate = 1Gbps;
ber = 1e-7;
}
channel Ref_channel extends ned.DatarateChannel
{
datarate = 1Gbps;
ber = 1e-7;
}
submodules:
sat[n]: Router {
gates:
pppg[4];
ethg[1];
}
H1: StandardHost {
gates:
ethg[1];
}
H2: StandardHost {
gates:
ethg[1];
}
configurator: Ipv4NetworkConfigurator {
#display("p=66,93");
}
connections allowunconnected:
sat[125].ethg++ <--> Ref_channel <--> H1.ethg++;
sat[853].ethg++ <--> Ref_channel <--> H2.ethg++;
//------intra-plane ISLs----------------
for orb = 0..23,for orb_sat = 0..65 {
sat[24*orb + orb_sat].pppg++ <--> Ref_channel <--> sat[24*orb + orb_sat + 1].pppg++ if (24*orb + orb_sat < 66*(orb + 1) - 1);
sat[24*orb + orb_sat].pppg++ <--> Ref_channel <--> sat[24*orb + orb_sat - 65].pppg++ if (24*orb + orb_sat == 66*(orb + 1) - 1);
}
//------inter-plane ISLs----------------
for orb_sat = 0..65,for orb = 0..23 {
sat[orb_sat + 24*orb].pppg++ <--> Ref_channel <--> sat[orb_sat + 66*(orb + 1)].pppg++ if (orb < 23);
sat[orb_sat + 24*orb].pppg++ <--> Ref_channel <--> sat[orb_sat + 66*(orb - 23)].pppg++ if (orb == 23);
}
}
INI file :
[General]
network = Starlink_p1_grid_topo
sim-time-limit = 30s
**.module-eventlog-recording = false
**.sndNxt.statistic-recording = true
**.sndTime.statistic-recording = true
**.rcvSeq.statistic-recording = true
**.rcvTime.statistic-recording = true
**.packetSent.statistic-recording = true
**.packetReceived.statistic-recording = true
**.endToEndDelay.statistic-recording = true
**.throughput.statistic-recording = true
**.**.statistic-recording = false
**.**.bin-recording = false
[Config test]
**.H*.numApps = 2
**.app[0].typename = "UdpBasicApp"
**.app[0].destPort = 1234
**.app[0].messageLength = 128B
**.app[0].sendInterval = 0.1s
**.app[0].startTime = 10s
**.app[0].stopTime = 20s
**.H2.app[0].destAddresses = "H1"
**.H1.app[0].destAddresses = "H2"
**.app[1].typename = "UdpEchoApp"
**.app[1].localPort = 1234
And Cmdenv config is as following:
First, a few comments on your network:
if you use the ++ operator on gates, you do NOT have to specify the gate sizes (for ethg and pppg) in your hosts. The simulation kernel will allocate new gates as needed when the ++ operator is used.
It seems that you want to create a 'torus' topology in your network. Your code is sub-omptimal as it tests some conditions unnecessary in the loop and in some places it has definitely bugs (e.g. orb_sat + 24*orb seems definitely wrong to me. isn't that orb_sat + 66*orb ?).
But after correcting these issues, you will still face heavy initialization times (that are non-linear with the size of the network). The reason is the usage of the Ipv4NetworkConfigurator module. That module is very powerful, but if does NOT scale easily with the number of network, because it has to find the shortest path between ALL subnets in the network and configure optimize ALL routing tables everywhere. This is OK if you have a lot of nodes placed in a few subnets, but here you have 1584 routers with 1584 subnets. That is not something the Ipv4NetworkConfigurator can handle in a reasonable time. You MUST remove the Ipv4NetworkConfigurator module from your network and create your own configurator that set's up the routing tables correctly. I'm not sure how you intend to set up the routing at all. Probably, that's the main point of your study. I suggest to remove the network configurator and as a first step, use HostAutoConfigurator in each roiter by placing this in your INI file:
**.configurator.typename = "HostAutoConfigurator"
This just assigns an IP address to the nodes, but it does NOT set up the routing tables, so you won't be able to route packets until you properly set up all the routing tables. Probably static routing tables are not suitable at all and you would need to implement your own routing algorithm (some kind of geographic routing, where the routing is not done based on destination IP addresses, but rather on the desination's geographic location). I'm not even sure that the whole thing should be simulated at network level. Maybe it should work on link layer level? A bit modified version of your code:
network Starlink_p1_grid_topo
{
parameters:
int noOfSats = 66; // satellites per orbital plane
int noOfPlanes = 24; // number of orbital planes
types:
...
submodules:
sat[noOfSats * noOfPlanes]: Router {
#display("p=,,m,$noOfSats");
}
H1: StandardHost {
}
H2: StandardHost {
}
connections allowunconnected:
...
// connect all sat modules in a torus topology
for p = 0..noOfPlanes-1,for s = 0..noOfSats-1 {
sat[p*noOfSats + s].pppg++ <--> Ref_channel <--> sat[p*noOfSats + ((s+1) % noOfSats)].pppg++; // intra-plane link
sat[p*noOfSats + s].pppg++ <--> Ref_channel <--> sat[((p+1) % noOfPlanes)*noOfSats + s].pppg++; // inter plane-link
}
}

eBPF packet monitor losing some packets when 'ping -f'ed

I wrote this program to capture all the packets that come into my network interface.
It seems to work fine with things like ping [IP].
It also works fine with ping -f [IP] -c 10.
However, when the number of packets that are pinged goes up to like 200, the program sees to lost some packets.
Is this a natural limit of eBPF or am I doing something wrong?
Here's the code :
Also, when I ping -f [IP] -c 500, it also outputs : "Possibly lost 10 samples" or "Possibly lost 34 samples"
from bcc import BPF
# Network interface to be monoitored
INTERFACE = "my_interface"
bpf_text = """
#include <uapi/linux/ptrace.h>
#include <net/sock.h>
#include <bcc/proto.h>
#include <linux/bpf.h>
#define IP_TCP 6
#define IP_UDP 17
#define IP_ICMP 1
#define ETH_HLEN 14
BPF_PERF_OUTPUT(skb_events); // has to be delcared outside any function
BPF_ARRAY(black_list, u64, 5);
int packet_monitor(struct __sk_buff *skb) {
u8 *cursor = 0;
u32 saddr;
u32 daddr;
u32 ttl;
u32 hchecksum;
u64 magic = 111;
u64 magic2 = 111;
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
if (!(ethernet -> type == 0x0800)) {
return 0; // drop
}
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
/*
if (ip->nextp != IP_TCP)
{
if (ip -> nextp != IP_UDP)
{
if (ip -> nextp != IP_ICMP)
return 0;
}
}
*/
skb_events.perf_submit_skb(skb, skb -> len, &magic, sizeof(magic));
saddr = ip -> src;
daddr = ip -> dst;
ttl = ip -> ttl;
hchecksum = ip -> hchecksum;
magic = ip -> src;
magic2 = ip -> dst;
skb_events.perf_submit_skb(skb, skb->len, &magic, sizeof(magic)); // this one parses number as a hex to the user space
skb_events.perf_submit_skb(skb, skb->len, &magic2, sizeof(magic2)); // can send multiple values like this
bpf_trace_printk("saddr = %llu, daddr = %llu, ttl = %llu", saddr, daddr, ttl);
// bpf_trace_printk("Incoming packet!!\\n");
return -1;
}
"""
from ctypes import *
import ctypes as ct
import sys
import socket
import os
import struct
def print_skb_event(cpu, data, size):
class SkbEvent(ct.Structure):
_fields_ = [ ("magic", ct.c_uint32), ("magic2", ct.c_uint32)]
skb_event = ct.cast(data, ct.POINTER(SkbEvent)).contents
print("- : ")
print("%d" % (skb_event.magic))
bpf = BPF(text=bpf_text)
function_skb_matching = bpf.load_func("packet_monitor", BPF.SOCKET_FILTER)
BPF.attach_raw_socket(function_skb_matching, INTERFACE)
bpf["skb_events"].open_perf_buffer(print_skb_event)
black_list = bpf.get_table("black_list") # retrieve blacklist list
try:
while True :
bpf.perf_buffer_poll() # value = bpf.perf_buffer_poll() function does not return any function and therefore, doesn't work
except KeyboardInterrupt:
pass
Yes, that's a limitation of the perf ring buffer. If the BPF program produce events on the ring buffer faster than the userspace (Python) process can consume them, some events will be lost (overwritten since it's a ring). The Possibly lost XX samples message is a notification of this happening.
I would first recommend that you try to group your multiple skb_events.perf_submit_skb calls into a single one on the BPF side. That may help. Otherwise, you can try to aggregate data on the BPF side to have less information sent to the Python side.

PCM5122 DAC with Android Things

I have a Raspberry Pi 3B and Suptronics X920 Expansion Board which uses PCM5122 DAC. So I'm having trouble playing sounds through that board.
The config file is default except for the display configuration part:
kernel=u-boot-dtok.bin
framebuffer_depth=16
# Prevent the firmware from loading HAT overlays now that we handle pin muxing.
# ourselves. See:
# https://www.raspberrypi.org/documentation/configuration/device-tree.md#part3.4
dtoverlay=
dtparam=i2c_arm=on
dtparam=spi=on
dtparam=audio=on
# pwm and I2S are mutually-exclusive since they share hardware clocks.
dtoverlay=pwm-2chan-with-clk,pin=18,func=2,pin2=13,func2=4
dtoverlay=generic-i2s
start_x=1
# Tell U-boot to always use the "serial0" interface for the console, which is
# set to whichever uart (uart0 or uart1) is set to the header pins. This doesn't
# interfere with the uart selected for Bluetooth.
dtoverlay=chosen-serial0
# Enable skip-init on the UART interfaces, so U-Boot doesn't attempt to
# re-initialize them.
dtoverlay=rpi-uart-skip-init
# Add pin devices to the system for use by the runtime pin configuration driver.
dtoverlay=runtimepinconfig
dtoverlay=uart1
dtoverlay=bcm2710-rpi-3-b-spi0-pin-reorder
# Tell the I2S driver to use the cprman clock.
dtoverlay=bcm2710-rpi-3-b-i2s-use-cprman
# Uncomment to disable serial port on headers, use GPIO14 and GPIO15
# as gpios and to allow the core_freq to change at runtime.
enable_uart=1
core_freq=400
# Support official RPi display.
dtoverlay=i2c-rtc,ds3231
dtoverlay=rpi-ft5406
hdmi_force_hotplug=1
# Set framebuffer to support RGBA colors.
framebuffer_swap=0
# Waveshare display settings
max_usb_current=1
hdmi_group=2
hdmi_mode=87
hdmi_cvt 1024 600 60 6 0 0 0
hdmi_drive=1
This is the code for playing a sound file:
fun playSound(file: File) {
val audioEncoding = AudioFormat.ENCODING_PCM_16BIT
val sampleRate = 16000
val audioOutputFormat = AudioFormat.Builder()
.setChannelMask(AudioFormat.CHANNEL_OUT_MONO)
.setEncoding(audioEncoding)
.setSampleRate(16000)
.build()
val audioOutputBufferSize = AudioTrack.getMinBufferSize(sampleRate, audioOutputFormat.channelMask, audioEncoding)
val audioOutputDevice = findAudioDevice(AudioManager.GET_DEVICES_OUTPUTS, AudioDeviceInfo.TYPE_BUS)
val audioTrack = AudioTrack.Builder()
.setAudioFormat(audioOutputFormat)
.setBufferSizeInBytes(audioOutputBufferSize)
.setTransferMode(AudioTrack.MODE_STREAM)
.build()
audioTrack.preferredDevice = audioOutputDevice
val buffer = ByteArray(audioOutputBufferSize)
audioTrack.play()
audioTrack.setVolume(1f)
val stream = file.inputStream().buffered()
try {
while (stream.read(buffer) > 0) {
val out = audioTrack.write(buffer, 0, buffer.size, AudioTrack.WRITE_BLOCKING)
d { "audioTrack.write = $out" }
}
} catch (error: Throwable) {
e(error) { "Error playing audio $file" }
} finally {
stream.close()
}
audioTrack.stop()
audioTrack.release()
}
private fun findAudioDevice(deviceFlag: Int, deviceType: Int): AudioDeviceInfo? {
val manager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
val adis = manager.getDevices(deviceFlag)
for (adi in adis) {
if (adi.type == deviceType) {
return adi
}
}
return null
}
I've tested the code with a regular Raspberry Pi audio output (which is AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) and it works ok. But with AudioDeviceInfo.TYPE_BUS it just produces no sound without any errors.
I tried various config options like dtoverlay=hifiberry or dtoverlay=hifiberry-dacplus with no luck.
Please help.
It looks like you might be using some of the code for the Google Assistant sample, and you are correct to assume that TYPE_BUS is what you need to enable the audio routes to use the I2S bus instead of the built-in audio jack.
However, that is likely not the whole story. The DAC likely requires additional configuration commands and/or external triggers. Looking at a similar HAT with the same DAC, for example, there is an I2C bus connection as well for DAC setup commands. Our Assistant sample uses the VoiceHAT driver to accomplish the additional triggering required by the DAC on that peripheral.
In Raspbian, the driver you enable via dtoverlay likely takes care of both pieces. Here, your code will need to manage the setup bits manually. Look at how the VoiceHAT driver is used in the Assistant sample as an example of this.
Also, make sure you are not enabling any of the I2S pins as either GPIO or PWM, as this will disable the audio route per the documentation.
Side Note: Android Things does not support making kernel changes via config.txt, so adding drivers there is expected not to have any effect.
It's been awhile since I figured this out, so I'm posting the code that working for me so that others spend less time buried in manuals.
After I've spent a few hours reading through the manual and frowning on the board's schematic, I figured out that the PCM5122 chip needs some preconfiguration.
It turns out that this chip has a complex clocking scheme. From the datasheet:
The serial audio interface typically has 4 connections: SCK (system master clock), BCK (bit clock), LRCK (left
right word clock), and DIN (data). The device has an internal PLL that is used to take either SCK or BCK and
create the higher rate clocks required by the interpolating processor and the DAC clock. This allows the device to
operate with or without an external SCK.
So, long story short, the chip's PLL operation depends on what pin is physically wired to the Raspberry board - SCK, BCK or both:
In my case it was BCK. We need to select PLL clock source with 13th register:
With all that explained, I'll post the full driver I've used with some additional configuration. All the information you can find in the linked manual. Hope it helps.
class SuptronicsX920AudioDevice private constructor(
private val busDevice: AudioDeviceInfo,
private val i2cDevice: I2cDevice) : AudioDevice {
private var audioTrack: AudioTrack? = null
private var leftVolume = 1f
private var rightVolume = 1f
companion object {
private const val ERROR_DETECT_REG = 37
private const val ERROR_DETECT_IDCM_BIT = 3
private const val PLL_SOURCE_REG = 13
private const val PLL_SOURCE_BCK_BIT = 4
private const val AUTO_MUTE_REG = 65
private const val DIGITAL_VOLUME_LEFT_REG = 61
private const val DIGITAL_VOLUME_RIGHT_REG = 62
fun create(busDevice: AudioDeviceInfo, i2cDevice: I2cDevice): Either<IOException, SuptronicsX920AudioDevice> {
return try {
// Ignore BCK\SCK missing errors as they turn device into Power down mode
riseRegBit(i2cDevice, ERROR_DETECT_REG, ERROR_DETECT_IDCM_BIT)
// Select BCK as the source for PLL
riseRegBit(i2cDevice, PLL_SOURCE_REG, PLL_SOURCE_BCK_BIT)
// Disable auto mute for both channels
i2cDevice.writeRegByte(AUTO_MUTE_REG, 0)
// Set the maximum gain for both channels
i2cDevice.writeRegByte(DIGITAL_VOLUME_LEFT_REG, 0)
i2cDevice.writeRegByte(DIGITAL_VOLUME_RIGHT_REG, 0)
SuptronicsX920AudioDevice(busDevice, i2cDevice).right()
} catch (ioe: IOException) {
e(ioe) { "Unable to configure PCM512x for Suptronics x920" }
ioe.left()
}
}
private fun riseRegBit(i2cDevice: I2cDevice, regAddress: Int, bitAddress: Int) {
val value = i2cDevice.readRegByte(regAddress)
i2cDevice.writeRegByte(regAddress, value or (1 shl bitAddress).toByte())
}
}
override fun play(stream: InputStream, audioFormat: AudioFormat) {
val audioOutputBufferSize = AudioTrack.getMinBufferSize(
audioFormat.sampleRate,
audioFormat.channelMask,
audioFormat.encoding)
val buffer = ByteArray(audioOutputBufferSize)
audioTrack = AudioTrack.Builder()
.setAudioFormat(audioFormat)
.setBufferSizeInBytes(audioOutputBufferSize)
.setTransferMode(AudioTrack.MODE_STREAM)
.build()
audioTrack?.apply {
preferredDevice = busDevice
setStereoVolume(leftVolume, rightVolume)
play()
var bytes = 0
try {
while (stream.read(buffer) > 0) {
bytes += write(buffer, 0, buffer.size, AudioTrack.WRITE_BLOCKING)
}
} catch (error: Throwable) {
e(error) { "Error playing audio" }
}
d { "$bytes of audio track written" }
}
stop()
audioTrack = null
}
override fun stop() {
audioTrack?.apply {
if (state != AudioTrack.STATE_UNINITIALIZED) {
try {
pause()
flush()
release()
d { "Audio stopped" }
} catch (error: Throwable) {
e(error) { "Can't stop track properly" }
}
}
}
}
override fun setVolume(leftVolume: Float, rightVolume: Float) {
this.leftVolume = leftVolume
this.rightVolume = rightVolume
audioTrack?.apply { setStereoVolume(leftVolume, rightVolume) }
}
override fun close() {
stop()
i2cDevice.close()
}
}

pcapdotnet in windows7 how to sniffer a port without specify a device or with the ip 0.0.0.0?

I have 2 software working together through the port 8888 in one computer, I want to know how they works. It's really nice if I can get another way, like software to do this job:)
I download the pcapdotnet and try the sample code on http://pcapdotnet.codeplex.com/wikipage?title=Pcap.Net%20User%20Guide&referringTitle=Home
It can got all messages on the local network but not for me.
I use netstat -a get this " TCP 0.0.0.0:8888 ZC01N00278:0 LISTENING"
I'm really confusing about this 0.0.0.0.
so I disable all my network device(this cause my pcap can't work, cause it need at least one device), but it still there. I suppose the 2 software communication each other without a Ethernet, is it true?
I am a newbie in socket, in which way I can get the packet in this port?
Here's the code, it mostly from the tutorial sample.
using System;
using System.Collections.Generic;
using PcapDotNet.Core;
using PcapDotNet.Packets;
using PcapDotNet.Packets.IpV4;
using PcapDotNet.Packets.Transport;
using System.IO;
namespace pcap_test1
{
class Program
{
static StreamWriter sw;
static void Main(string[] args)
{
sw = new StreamWriter(#"C:\sunxin\pcap.txt");
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
if (allDevices.Count == 0)
{
Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
return;
}
// Print the list
for (int i = 0; i != allDevices.Count; ++i)
{
LivePacketDevice device = allDevices[i];
Console.Write((i + 1) + ". " + device.Name);
if (device.Description != null)
Console.WriteLine(" (" + device.Description + ")");
else
Console.WriteLine(" (No description available)");
}
int deviceIndex = 0;
do
{
Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
string deviceIndexString = Console.ReadLine();
if (!int.TryParse(deviceIndexString, out deviceIndex) ||
deviceIndex < 1 || deviceIndex > allDevices.Count)
{
deviceIndex = 0;
}
} while (deviceIndex == 0);
// Take the selected adapter
PacketDevice selectedDevice = allDevices[deviceIndex - 1];
// Open the device
using (PacketCommunicator communicator =
selectedDevice.Open(65536, // portion of the packet to capture
// 65536 guarantees that the whole packet will be captured on all the link layers
PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
1000)) // read timeout
{
// Check the link layer. We support only Ethernet for simplicity.
if (communicator.DataLink.Kind != DataLinkKind.Ethernet)
{
Console.WriteLine("This program works only on Ethernet networks.");
return;
}
// Compile the filter
using (BerkeleyPacketFilter filter = communicator.CreateFilter("port 8888"))
{
// Set the filter
communicator.SetFilter(filter);
}
Console.WriteLine("Listening on " + selectedDevice.Description + "...");
// start the capture
communicator.ReceivePackets(0, PacketHandler);
}
}
// Callback function invoked by libpcap for every incoming packet
private static void PacketHandler(Packet packet)
{
// print timestamp and length of the packet
Console.WriteLine(packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Ethernet);
sw.WriteLine(packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + packet.Ethernet);
IpV4Datagram ip = packet.Ethernet.IpV4;
UdpDatagram udp = ip.Udp;
for (int i = ip.HeaderLength; i < packet.Length; ++i)
{
Console.Write(Convert.ToChar(packet.Buffer[i]));
sw.Write(Convert.ToChar(packet.Buffer[i]));
}
Console.WriteLine();
sw.WriteLine();
// print ip addresses and udp ports
//Console.WriteLine(ip.Source + ":" + udp.SourcePort + " -> " + ip.Destination + ":" + udp.DestinationPort);
//sw.WriteLine(ip.Source + ":" + udp.SourcePort + " -> " + ip.Destination + ":" + udp.DestinationPort);
sw.Flush();
}
}
}
Wireshark's wiki tells that WinPcap cannot capture packets between endpoints on the same computer in Windows (Pcap.Net uses WinPcap). It recommends to use RawCap.

java.nio.BufferUnderflowException when processing files in Scala

I got a similar problem to this guy while processing 4MB log file. Actually I'm processing multiple files simultaneously but since I keep getting this exception, I decide to just test it for a single file:
val temp = Source.fromFile("./datasource/input.txt")
val dummy = new PrintWriter("test.txt")
var itr = 0
println("Default Buffer size: " + Source.DefaultBufSize)
try {
for( chr <- temp) {
dummy.print(chr.toChar)
itr += 1
if(itr == 75703) println("Passed line 85")
if(itr % 256 == 0){ print("..." + itr); temp.reset; System.gc; }
if(itr == 75703) println("Passed line 87")
if(itr % 2048 == 0) println("")
if(itr == 75703) println("Passed line 89")
}
} finally {
println("\nFalied at itr = " + itr)
}
What I always get is that it will fails at itr = 75703, while my output file will always be 64KB (65536 Bytes exact). No matter where I put temp.reset or System.gc, all experiments ends up the same.
It seems like the problem relies on some memory allocation but I cannot find any useful information on this problem. Any idea on how to solve this one?
All your helps are greatly appreciated
EDIT: Actually I want to process it as binary files, so this technique is not a good solution, many had recommend me to use BufferedInputStream instead.
Why are you calling reset on the Source before it has finished iterating thru the file?
val temp = Source.fromFile("./datasource/input.txt")
try {
for (line <- tem p.getLines) {
//whatever
}
finally temp.reset
Should work just fine with no underflows. See also this question