IdHTTP->ConnectTimeout works in Windows 7, does not work on XP - windows-xp

Using Embarcadero C++ Builder 2010, I'm trying to detect specific web server devices connected to a network.
I'm interrogating those devices by calling a CGI function using TIdHTTP and analyzing the answer on a range of IP address.
I am using IdHTTP->ConnectTimeout and IdHTTP->ReadTimeout parameters to throws an exception if there's no connection by the time the timeout elapses. This should happen when TIdHTTP is interrogating an unexpected devices, in this case I release IdHTTP by calling IdHTTP->Free().
It works fine on Windows 7, but on Windows XP the timeout doesn't apply, so it can take up to 10 minutes before IdHTTP.get() stop.
By removing those two parameters the app work a bit faster on Windows XP but still take to long compare to the timeout than I am expecting.
I found this related subject without real solutions: Indy 10 + SSL = works in Windows 7, does not work on XP
This is a part of the source code:
#include "winsock2.h"
String url = "http://" + anIpAddress + "/myCGIFunction.cgi";
TMemoryStream *XML = new TMemoryStream;
AnsiString answer="";
p_IdHTTP = new TIdHTTP(NULL);
try
{
p_IdHTTP->ConnectTimeout = 2000;
p_IdHTTP->Get(url,XML);
XML->Position = 0;
answer=ReadStringFromStream(XML);
p_IdHTTP->Free();
}
catch (...)
{
p_IdHTTP->Free();
}
My questions are:
Why does IdHTTP->ConnectTimeout isn't working on Windows XP?
And do you have any idea to replace this parameter to release/destroyed the IdHTTP after a specific time?
Update:
void __fastcall Func::MyFunc()
{
AnsiString anIpAddress= "20.20.20.11";
String url = "http://" + anIpAddress + "/myCGIFunction.cgi";
TMemoryStream *XML = new TMemoryStream;
AnsiString answer="";
p_IdHTTP = new TIdHTTP(NULL);
try
{
p_SSLHandler=new TIdSSLIOHandlerSocketOpenSSL(p_IdHTTP);
p_SSLHandler->SSLOptions->Method= sslvSSLv23;
p_IdHTTP->ConnectTimeout = 2000;
p_IdHTTP->ReadTimeout=400;
p_IdHTTP->IOHandler=p_SSLHandler;
p_IdHTTP->OnConnected= IdHTTPConnected;
p_IdHTTP->OnStatus= IdHTTPStatus;
p_IdHTTP->Get(url,XML);
XML->Position = 0;
answer=ReadStringFromStream(XML);
p_IdHTTP->Free();
}
catch (...)
{
p_IdHTTP->Free();
}
}
void __fastcall Func::IdHTTPStatus(TObject *Sender, TIdStatus const AStatus, String const AStatusText){
String msgtest = ipAddress ;
switch (AStatus){
case (hsResolving):
msgtest+= " resolving...";
break;
case (hsConnecting):
msgtest+= " connecting...";
break;
case (hsConnected):
msgtest+= " connected...";
break;
case (hsDisconnecting):
msgtest+= " disconnecting...";
break;
case (hsDisconnected):
msgtest+= " disconnected...";
break;
case (hsStatusText):
msgtest+= " hsStatusText: " + AStatusText;
break;
default:
msgtest+= " Other status ";
break;
}
aListBox->Items->Add(msgtest);
Application->ProcessMessages();
}
void __fastcall Func::IdHTTPConnected(TObject *Sender){
struct timeval timeout;
timeout.tv_sec = 2;
timeout.tv_usec = 0;
setsockopt((unsigned int) p_IdHTTP->Socket->Binding, SOL_SOCKET,
SO_RCVTIMEO, (char *)&timeout, sizeof(timeout) );
setsockopt ((unsigned int) p_IdHTTP->Socket->Binding, SOL_SOCKET, SO_SNDTIMEO,
(char *)&timeout, sizeof(timeout));
}

Related

Plc4x library Modbus serial (RTU) get is not retrieving data

I am trying to write a sample program to retrieve temperature data from SHT20 temperature sensor using serial port with apache plc4x library.
private void plcRtuReader() {
String connectionString =
"modbus:serial://COM5?unit-identifier=1&baudRate=19200&stopBits=" + SerialPort.ONE_STOP_BIT + "&parityBits=" + SerialPort.NO_PARITY + "&dataBits=8";
try (PlcConnection plcConnection = new PlcDriverManager().getConnection(connectionString)) {
if (!plcConnection.getMetadata().canRead()) {
System.out.println("This connection doesn't support reading.");
return;
}
PlcReadRequest.Builder builder = plcConnection.readRequestBuilder();
builder.addItem("value-1", "holding-register:258[2]");
PlcReadRequest readRequest = builder.build();
PlcReadResponse response = readRequest.execute().get();
for (String fieldName : response.getFieldNames()) {
if (response.getResponseCode(fieldName) == PlcResponseCode.OK) {
int numValues = response.getNumberOfValues(fieldName);
// If it's just one element, output just one single line.
if (numValues == 1) {
System.out.println("Value[" + fieldName + "]: " + response.getObject(fieldName));
}
// If it's more than one element, output each in a single row.
else {
System.out.println("Value[" + fieldName + "]:");
for (int i = 0; i < numValues; i++) {
System.out.println(" - " + response.getObject(fieldName, i));
}
}
}
// Something went wrong, to output an error message instead.
else {
System.out.println(
"Error[" + fieldName + "]: " + response.getResponseCode(fieldName).name());
}
}
System.exit(0);
} catch (PlcConnectionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
Connection is established with the device using serial communication. But it fails to get data and instead prints the below warning messages continously.
debugger hangs at below line:
PlcReadResponse response = readRequest.execute().get();
with below logs printing continuously.
2021-06-03-17:41:48.425 [nioEventLoopGroup-2-1] WARN io.netty.channel.nio.NioEventLoop - Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector#131f8986.
2021-06-03-17:41:55.080 [nioEventLoopGroup-2-1] WARN io.netty.channel.nio.NioEventLoop - Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector#48c328c5.
With same URL data (i.e baudrate,stopBits etc..) using modpoll.exe it works and returns the data over RTU. I am not sure what is missing here.
Kindly shed some light here.

How I do an ESP8266 HTTPupdate via private Github repository?

I try to do an update firmeware via Git repo from an ESP8266. But I don't know how. The repo is private, that mean I need a password, I read that I can use HTTPclient library for authentication. How Github's authentication works?
Also, do I need some extra code for Update library? HTTPclient supports HTTPS?
EDIT: Here some example of my code, but is for a public repo:
update.cpp (I have it in a separate header file)
//#define repo "https://github.com/username/reponame/branch/path/to/file?raw=true"
#define repo "https://raw.githubusercontent.com/username/reponame/branch/path/to/file"
t_httpUpdate_return ret = ESPhttpUpdate.update(client, repo);
// Or:
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin");
I have configured httpUpdate error message, it show the next error:
CALLBACK: HTTP update fatal error code -5
HTTP_UPDATE_FAILD Error (-5): HTTP error: connection lost
There is a different way to do an update from GitHub, first GitHub use a HTTPS connection, that mean you need configure before a TLS/SSL setting, Also, port 80 is for insecure connections, 443 is designed for secure connections.
Public repository (insecure)
This is the easier way, just add .setInsecure() to the wifi client from WiFiClientSecure.h library, this allow you to stablish a connection ignoring all alerts from http connection.
WiFiClientSecure client;
client.setInsecure();
Is insecure, only do this for testing, not for production.
You must use https://raw.githubusercontent.com, this is for download raw data from GitHub's public repos, just the file. Your full link to the file must be:
#define repo "https://raw.githubusercontent.com/<user>/<repo>/master/<path to the .bin>"
t_httpUpdate_return ret = ESPhttpUpdate.update(client, repo);
Replace <user> with your user name, and <repo> with your repository's name. <path to the .bin> is something like "folder/folder/firmware.bin"
Public repository (secure):
There is an example in the official GitHub repository of ESP8266/Arduino.
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266httpUpdate/examples/httpUpdateSecure/httpUpdateSecure.ino
You can follow this example for a secure connection with httpUpdate. Also you will need to download the certs, this can do by executing the next script in the same folder of your project:
https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py
If you are using windows, to run this script, you will need add "OpenSSL.exe" to the path, Git comes with it, you add the Git's bin folder to the path. Also, you will need one more file "ar.exe", this come with the ESP8266 core. You can also put this two .exe files in the same folder of the script.
For Arduino IDE is something like:
%userprofile%\AppData\Local\Arduino15\packages\esp8266\tools\xtensa-lx106-elf-gcc\2.5.0-4-b40a506\xtensa-lx106-elf\bin
For PlaformIO is:
%userprofile%\.platformio\packages\toolchain-xtensa\xtensa-lx106-elf\bin
When the script finish, this will create a folder named data with certs.ar inside. Upload this file system image to ESP8266 with LittleFS.
Private repository:
This is the same as the previous one, just couple of things to change, and we will make change to the ESP8266httpUpdate library. We use the same example to httpupdatesecure and you will need to configure a token in your GitHub account.
Follow the instructions of the help page of GitHub for create a token:
https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line
You only need this option selected
Copy the token and save it, you only able see one time.
You can't use raw.githubusercontent.com, will give you error 404, this only work for public repos. You need: api.github.com. You full link looks like:
https://api.github.com/repos/<user>/<repo>/contents/<path to the .bin>
And you need to add the headers to the http request, in the ESP8266httpUpdate.cpp, you must put it in the function HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate in the part where start add headers:
http.addHeader(F("Accept"), "application/vnd.github.v3.raw");
http.addHeader(F("authorization"), "Bearer <your token>");
Replace <your token> with the one that you created and saved before.
Remember, edit this library will affect all your future projects, so, when you are done revert or comment the two headers that you added to the library.
NOTE: Using a token will allow your application access to all your
repos, even if your token is read-only. Currently, is not possible generate a token for a specific repo on GitHub. Be careful if you share your
code. Better use a dummy account with only one repo for this.
[Edit] - It's wokring now, it was an arduino core bug, installed 2.7.4 and now it works(come form 3.0.2-dev)
Doesn't work here "Verify Bin Header Failed", tryied hosting bin on github, 000webhosting, surge, not seens anything related to web server problem :(
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
//#include <WiFiClientSecure.h>
#include <CertStoreBearSSL.h>
BearSSL::CertStore certStore;
#include <time.h>
#include <FS.h>
#include <LittleFS.h>
const String FirmwareVer={"1"};
//#define URL_fw_Version "/teste/key/version.txt"
//#define URL_fw_Bin "https://pacauiot.surge.sh/teste/key/firmware.bin"
//const char* host = "pacauiot.surge.sh";
#define URL_fw_Bin "https://fourieristic-prison.000webhostapp.com/meucu.php"
const char* host = "fourieristic-prison.000webhostapp.com";
const int httpsPort = 443;
const char* ssid = "wifi";
const char* password = "wifipass";
#define RTC_UTC_TEST 1510592825
void setClock()
// *******************************************************************************************
{
// see https://github.com/esp8266/Arduino/issues/4637
time_t now;
now = time(nullptr); // if there's no time, this will have a value of 28800; Thu Jan 1 08:00:00 1970
Serial.print("Initial time:"); Serial.println(now);
Serial.println(ctime(&now));
int myTimezone = -7;
int dst = 0;
int SecondsPerHour = 3600;
int MAX_TIME_RETRY = 60;
int i = 0;
// it is unlikely that the time is already set since we have no battery;
// if no time is avalable, then try to set time from the network
if (now <= 1500000000) {
// try to set network time via ntp packets
configTime(0, 0, "pool.ntp.org", "time.nist.gov"); // see https://github.com/esp8266/Arduino/issues/4749#issuecomment-390822737
// Starting in 2007, most of the United States and Canada observe DST from
// the second Sunday in March to the first Sunday in November.
// example setting Pacific Time:
setenv("TZ", "EST4EDT", 1); // see https://users.pja.edu.pl/~jms/qnx/help/watcom/clibref/global_data.html
// | month 3, second sunday at 2:00AM
// | Month 11 - firsst Sunday, at 2:00am
// Mm.n.d
// The dth day(0 <= d <= 6) of week n of month m of the year(1 <= n <= 5, 1 <= m <= 12, where
// week 5 means "the last d day in month m", which may occur in the fourth or fifth week).
// Week 1 is the first week in which the dth day occurs.Day zero is Sunday.
tzset();
Serial.print("Waiting for time(nullptr).");
i = 0;
while (!time(nullptr)) {
Serial.print(".");
delay(1000);
i++;
if (i > MAX_TIME_RETRY) {
Serial.println("Gave up waiting for time(nullptr) to have a valid value.");
break;
}
}
}
Serial.println("");
// wait and determine if we have a valid time from the network.
now = time(nullptr);
i = 0;
Serial.print("Waiting for network time.");
while (now <= 1500000000) {
Serial.print(".");
delay(1000); // allow a few seconds to connect to network time.
i++;
now = time(nullptr);
if (i > MAX_TIME_RETRY) {
Serial.println("Gave up waiting for network time(nullptr) to have a valid value.");
break;
}
}
Serial.println("ok");
// get the time from the system
char *tzvalue;
tzvalue = getenv("TZ");
Serial.print("Network time:"); Serial.println(now);
Serial.println(ctime(&now));
Serial.print("tzvalue for timezone = "); Serial.println(tzvalue);
// TODO - implement a web service that returns current epoch time to use when NTP unavailable (insecure SSL due to cert date validation)
// some networks may not allow ntp protocol (e.g. guest networks) so we may need to fudge the time
if (now <= 1500000000) {
Serial.println("Unable to get network time. Setting to fixed value. \n");
// set to RTC text value
// see https://www.systutorials.com/docs/linux/man/2-settimeofday/
//
//struct timeval {
// time_t tv_sec; /* seconds */
// suseconds_t tv_usec; /* microseconds */
//};
timeval tv = { RTC_UTC_TEST, 0 };
//
//struct timezone {
// int tz_minuteswest; /* minutes west of Greenwich */
// int tz_dsttime; /* type of DST correction */
//};
timezone tz = { myTimezone * 60 , 0 };
// int settimeofday(const struct timeval *tv, const struct timezone *tz);
settimeofday(&tv, &tz);
}
now = time(nullptr);
Serial.println("Final time:"); Serial.println(now);
Serial.println(ctime(&now));
}
void FirmwareUpdate()
{
//WiFiClientSecure client;
BearSSL::WiFiClientSecure client;
bool mfln = client.probeMaxFragmentLength(host, 443, 1024); // server must be the same as in ESPhttpUpdate.update()
Serial.printf("MFLN supported: %s\n", mfln ? "yes" : "no");
if (mfln) {
client.setBufferSizes(1024, 1024);
}
client.setCertStore(&certStore);
//client.setTrustAnchors(&cert);
// if (!client.connect(host, httpsPort)) {
// Serial.println("Connection failed");
// return;
// }
// client.print(String("GET ") + URL_fw_Version + " HTTP/1.1\r\n" +
// "Host: " + host + "\r\n" +
// "User-Agent: BuildFailureDetectorESP8266\r\n" +
// "Connection: close\r\n\r\n");
// while (client.connected()) {
// String line = client.readStringUntil('\n');
// if (line == "\r") {
// //Serial.println("Headers received");
// break;
// }
// }
// String payload = client.readStringUntil('\n');
//
// payload.trim();
// if(payload.equals(FirmwareVer) )
// {
// Serial.println("Device already on latest firmware version");
// }
if(1==2){
}
else
{
Serial.println("New firmware detected");
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
t_httpUpdate_return ret = ESPhttpUpdate.update(client, URL_fw_Bin);
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILD Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("HTTP_UPDATE_OK");
break;
}
}
}
void connect_wifi();
unsigned long previousMillis_2 = 0;
unsigned long previousMillis = 0; // will store last time LED was updated
const long interval = 10000;
const long mini_interval = 5000;
void repeatedCall(){
unsigned long currentMillis = millis();
if ((currentMillis - previousMillis) >= interval)
{
// save the last time you blinked the LED
previousMillis = currentMillis;
setClock();
FirmwareUpdate();
}
if ((currentMillis - previousMillis_2) >= mini_interval) {
static int idle_counter=0;
previousMillis_2 = currentMillis;
Serial.print(" Active fw version:");
Serial.println(FirmwareVer);
Serial.print("Idle Loop(5s)...");
//Serial.println(idle_counter++);
if(idle_counter%2==0)
digitalWrite(LED_BUILTIN, HIGH);
else
digitalWrite(LED_BUILTIN, LOW);
if(WiFi.status() == !WL_CONNECTED)
connect_wifi();
}
}
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
Serial.println("Start Xuxu");
WiFi.mode(WIFI_STA);
connect_wifi();
setClock();
pinMode(LED_BUILTIN, OUTPUT);
LittleFS.begin();
int numCerts = certStore.initCertStore(LittleFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
Serial.print(F("Number of CA certs read: "));
Serial.println(numCerts);
if (numCerts == 0) {
Serial.println(F("No certs found. Did you run certs-from-mozill.py and upload the LittleFS directory before running?"));
return; // Can't connect to anything w/o certs!
}
//repeatedCall();
FirmwareUpdate();
}
void loop()
{
}
void connect_wifi()
{
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print("O");
}
Serial.println("Connected to WiFi");
}

Interpreting keypresses sent to raspberry-pi through uv4l-webrtc datachannel

I apologize if this doesn't make sense since I'm still a newbie with using a raspberry pi and this is my first time posting on StackOverflow.
I am making a web app that lets me stream video to and from a raspberry pi while also letting me send keycodes. The sent keycodes would ultimately let me control servos on a drone. After scouring the internet, I figured that the simplest way to stream 2-way video is by using uv4l so I have it installed along with uv4l-webrtc on my raspberry pi. I hooked up some GPIO pins to a flight controller and I am using pigpio to send PWM signals to it, which I then monitor using CleanFlight.
Right now, I can manipulate with keypresses the roll, pitch, etc. of the flight controller using a python script if I access the pi remotely using VNC, but I would like to ultimately be able to do this through my custom web page that is being served by the uv4l-server. I am trying to use the WebRTC Data Channels, but I'm having some trouble understanding what I would need to do to recognize the messages sent through the data channels. I know that the data channels are opened when a video call is initiated and I've tried the test in this link to see if I can indeed send keycodes to the pi (and I can).
My problem right now is that I have no idea where those sent messages go or how I can get them so I can incorporate them into my python script. Would I need to make a server that would listen for the keycodes being sent to the pi?
tl;dr I have a python script on a raspberry pi to control servos on a flight controller using keypresses and a separate webpage that streams video using WebRTC, but I have no idea how to combine them together using WebRTC data channels.
Thanks to #adminkiam for the solution. Here's a version of the python script that now listens to the socket. It's essentially a variation of this code by the person who made pigpio:
import socket
import time
import pigpio
socket_path = '/tmp/uv4l.socket'
try:
os.unlink(socket_path)
except OSError:
if os.path.exists(socket_path):
raise
s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
ROLL_PIN = 13
PITCH_PIN = 14
YAW_PIN = 15
MIN_PW = 1000
MID_PW = 1500
MAX_PW = 2000
NONE = 0
LEFT_ARROW = 1
RIGHT_ARROW = 2
UP_ARROW = 3
DOWN_ARROW = 4
LESS_BTN = 5
GREATER_BTN = 6
print 'socket_path: %s' % socket_path
s.bind(socket_path)
s.listen(1)
def getch(keyCode):
key = NONE
if keyCode == 188:
key = LESS_BTN
elif keyCode == 190:
key = GREATER_BTN
elif keyCode == 37:
key = LEFT_ARROW
elif keyCode == 39:
key = RIGHT_ARROW
elif keyCode == 38:
key = UP_ARROW
elif keyCode == 40:
key = DOWN_ARROW
return key
def cleanup():
pi.set_servo_pulsewidth(ROLL_PIN, 0)
pi.set_servo_pulsewidth(PITCH_PIN, 0)
pi.set_servo_pulsewidth(YAW_PIN, 0)
pi.stop()
while True:
print 'awaiting connection...'
connection, client_address = s.accept()
print 'client_address %s' % client_address
try:
print 'established connection with', client_address
pi = pigpio.pi()
rollPulsewidth = MID_PW
pitchPulsewidth = MID_PW
yawPulsewidth = MID_PW
pi.set_servo_pulsewidth(ROLL_PIN, rollPulsewidth)
pi.set_servo_pulsewidth(PITCH_PIN, pitchPulsewidth)
pi.set_servo_pulsewidth(YAW_PIN, yawPulsewidth)
while True:
data = connection.recv(16)
print 'received message"%s"' % data
time.sleep(0.01)
key = getch(int(data))
rollPW = rollPulsewidth
pitchPW = pitchPulsewidth
yawPW = yawPulsewidth
if key == UP_ARROW:
pitchPW = pitchPW + 10
if pitchPW > MAX_PW:
pitchPW = MAX_PW
elif key == DOWN_ARROW:
pitchPW = pitchPW - 10
if pitchPW < MIN_PW:
pitchPW = MIN_PW
elif key == LEFT_ARROW:
rollPW = rollPW - 10
if rollPW < MIN_PW:
rollPW = MIN_PW
elif key == RIGHT_ARROW:
rollPW = rollPW + 10
if rollPW > MAX_PW:
rollPW = MAX_PW
elif key == GREATER_BTN:
yawPW = yawPW + 10
if yawPW > MAX_PW:
yawPW = MAX_PW
elif key == LESS_BTN:
yawPW = yawPW - 10
if yawPW < MIN_PW:
yawPW = MIN_PW
if rollPW != rollPulsewidth:
rollPulsewidth = rollPW
pi.set_servo_pulsewidth(ROLL_PIN, rollPulsewidth)
if pitchPW != pitchPulsewidth:
pitchPulsewidth = pitchPW
pi.set_servo_pulsewidth(PITCH_PIN, pitchPulsewidth)
if yawPW != yawPulsewidth:
yawPulsewidth = yawPW
pi.set_servo_pulsewidth(YAW_PIN, yawPulsewidth)
if data:
print 'echo data to client'
connection.sendall(data)
else:
print 'no more data from', client_address
break
finally:
# Clean up the connection
cleanup()
connection.close()
When a WebRTC data channel is created between UV4L and the other WebRTC peer (i.e. a browser, Janus Gateway, etc...), UV4L creates a full-duplex Unix Domain Socket (/tmp/uv4l.socket by default) from/to which you can receive/send messages on the Raspberry Pi. Your python script should just open, listen and read to the socket for the incoming messages from the e.g. web application and/or write the messages to the same socket for the web app to receive them. An example doing this in C++ is under the link to the tutorial you pointed out in your question:
/*
Copyright (c) 2016 info#linux-projects.org
All rights reserved.
Redistribution and use in source and binary forms are permitted
provided that the above copyright notice and this paragraph are
duplicated in all such forms and that any documentation,
advertising materials, and other materials related to such
distribution and use acknowledge that the software was developed
by the linux-projects.org. The name of the
linux-projects.org may not be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* This is a simple echo server.
* It creates to a unix domain socket of type SOCK_SEQPACKET specified by
* command line, listens to it waiting for incoming messages from clients
* (e.g. UV4L) and replies the received messages back to the senders.
*
* Example:
* $ ./datachannel_server /tmp/uv4l.socket
*
* To compile this program you need boost v1.60 or greater, for example:
* g++ -Wall -I/path/to/boost/include/ -std=c++11 datachannel_server.cpp -L/path/to/boost/lib -l:libboost_coroutine.a -l:libboost_context.a -l:libboost_system.a -l:libboost_thread.a -pthread -o datachannel_server
*/
#include <boost/asio/io_service.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio.hpp>
#include <memory>
#include <cstdio>
#include <array>
#include <functional>
#include <iostream>
#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS)
#error Local sockets not available on this platform.
#endif
constexpr std::size_t MAX_PACKET_SIZE = 1024 * 16;
namespace seqpacket {
struct seqpacket_protocol {
int type() const {
return SOCK_SEQPACKET;
}
int protocol() const {
return 0;
}
int family() const {
return AF_UNIX;
}
using endpoint = boost::asio::local::basic_endpoint<seqpacket_protocol>;
using socket = boost::asio::generic::seq_packet_protocol::socket;
using acceptor = boost::asio::basic_socket_acceptor<seqpacket_protocol>;
#if !defined(BOOST_ASIO_NO_IOSTREAM)
/// The UNIX domain iostream type.
using iostream = boost::asio::basic_socket_iostream<seqpacket_protocol>;
#endif
};
}
using seqpacket::seqpacket_protocol;
struct session : public std::enable_shared_from_this<session> {
explicit session(seqpacket_protocol::socket socket) : socket_(std::move(socket)) {}
~session() {
//std::cerr << "session closed\n";
}
void echo(boost::asio::yield_context yield) {
auto self = shared_from_this();
try {
for (;;) {
seqpacket_protocol::socket::message_flags in_flags = MSG_WAITALL, out_flags = MSG_WAITALL;
// Wait for the message from the client
auto bytes_transferred = socket_.async_receive(boost::asio::buffer(data_), in_flags, yield);
// Write the same message back to the client
socket_.async_send(boost::asio::buffer(data_, bytes_transferred), out_flags, yield);
}
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
socket_.close();
}
}
void go() {
boost::asio::spawn(socket_.get_io_service(), std::bind(&session::echo, this, std::placeholders::_1));
}
private:
seqpacket_protocol::socket socket_;
std::array<char, MAX_PACKET_SIZE> data_;
};
int main(int argc, char* argv[]) {
try {
if (argc != 2) {
std::cerr << "Usage: datachannel_server <file> (e.g. /tmp/uv4l.socket)\n";
std::cerr << "*** WARNING: existing file is removed ***\n";
return EXIT_FAILURE;
}
boost::asio::io_service io_service;
std::remove(argv[1]);
boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) {
seqpacket_protocol::acceptor acceptor_(io_service, seqpacket_protocol::endpoint(argv[1]));
for (;;) {
boost::system::error_code ec;
seqpacket_protocol::socket socket_(io_service);
acceptor_.async_accept(socket_, yield[ec]);
if (!ec)
std::make_shared<session>(std::move(socket_))->go();
}
});
io_service.run();
} catch (std::exception& e) {
std::cerr << "Exception: " << e.what() << "\n";
return EXIT_FAILURE;
}
}

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.

How to send Protocol Buffer object using Winsock2?

I am creating a client server app using a simple socket to transfer Protocol Buffer objects between C++ and Java. I have it created on the Java side both as the client and receiver. I even got the Java to send to C++ but I am having trouble with sending from C++ to Java. Not sure how to write it. First I am sending the size and then reading the proto object.
I am using Visual Studio C++ 2008. DataGram and Bookmartlet are my proto objects.
Here is my C++ Sender Client
int loopt = 99;
do {
DataGram dataGram;
dataGram.set_state("ACK");
time ( &rawtime );
dataGram.set_status(ctime(&rawtime));
Bookmarklet* bookmarklet = dataGram.mutable_bookmarklet();
bookmarklet->set_name("TEST");
bookmarklet->set_utl("TEST");
dataGram.SerializeToArray(recvbuf,recvbuflen);
dataGram.ByteSize();
//Trouble SPOT
send(ConnectSocket,size,1,0);
send(ConnectSocket,recvbuf,recvbuflen,0);
} while (loopt > 0);
This is what I am trying to replicate from Java.
OutputStream output = socket.getOutputStream();
try {
int testtimes = 99;
while (socket.isConnected() && testtimes > 0) {
Thread.sleep(1000); // do nothing for 1000 miliseconds (1
// second)
DataGram dataGram = null;
Bookmarklet bookmarklet = Bookmarklet.newBuilder()
.setName("TEST").setUtl("TEST").build();
if (testtimes % 2 == 0) {
dataGram = DataGram.newBuilder().setState("ACK")
.setBookmarklet(bookmarklet)
.setStatus(new Date().toGMTString()).build();
} else {
dataGram = DataGram.newBuilder().setState("ACK")
.setStatus(new Date().toGMTString()).build();
}
output.write(dataGram.getSerializedSize());
output.write(dataGram.toByteArray());
testtimes--;
}
} catch (Exception e) {
e.printStackTrace();
}
Any help would be great. Thanks.
Client in Java for Reference:
InputStream input = socket.getInputStream();
int count = input.read();
int counter = 0;
while (count > 0) {
byte[] buffer = new byte[count];
count = input.read(buffer);
DataGram dataGram = DataGram.parseFrom(buffer);
Bookmarklet bookmarklet = null;
if ((bookmarklet = dataGram.getBookmarklet()) != null) {
System.out.println(bookmarklet.toString());
}
System.out.println(dataGram.getState() + " "
+ dataGram.getStatus());
count = input.read();
System.out.println(++counter);
}