Receiving multicast RTP stream (containing multiple subsessions) from a recorded RTSP session (pcap) using Live555 - h.264

I have to implement an RTSP Client which connects to an existing RTSP session without being able to send commands to the RTSP Server (recvonly).
To simulate such an environment, I have recorded a RTSP/RTP stream between testH264VideoStreamer and testRTSPClient examples from Live555 with Wireshark, and played it back using tcpreplay while trying to receive stream data with a modified version of testRTSPClient.
I've also stored the SDP information provided by the testH264VideoStreamer as an SDP file.
v=0
o=- 1606317166144671 1 IN IP4 192.168.3.92
s=Session streamed by "testH264VideoStreamer"
i=test.264
t=0 0
a=tool:LIVE555 Streaming Media v2020.10.16
a=type:broadcast
a=control:*
a=source-filter: incl IN IP4 * 192.168.3.92
a=rtcp-unicast: reflection
a=range:npt=0-
a=x-qt-text-nam:Session streamed by "testH264VideoStreamer"
a=x-qt-text-inf:test.264
m=video 18888 RTP/AVP 96
c=IN IP4 232.42.39.62/255
b=AS:500
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-$
a=control:track1
^#
I've modified the testRTSPClient example so that it connects to the RTP stream only by using the data from the SDP File.
Here are two functions which I use to initialise.
void openSDP(UsageEnvironment& env, char const* sdpFile)
{
const char * rtspURL = "rtsp://192.168.3.92:8554/testStream/";
RTSPClient* rtspClient = ourRTSPClient::createNew(env, rtspURL, RTSP_CLIENT_VERBOSITY_LEVEL);
if(rtspClient == NULL)
{
env << "Failed to create a RTSP client for URL \"" << rtspURL << "\": " << env.getResultMsg();
return;
}
else
{
env << "Connecting to the stream at " << rtspURL;
}
StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
std::vector<char> sdpBuffer;
std::ifstream file(sdpFile, std::ios_base::in | std::ios_base::binary);
file.unsetf(std::ios::skipws);
std::streampos fileSize;
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
sdpBuffer.reserve(fileSize);
sdpBuffer.insert(sdpBuffer.begin(),
std::istream_iterator<unsigned char>(file),
std::istream_iterator<unsigned char>());
char* const sdpDescription = sdpBuffer.data();
// Create a media session object from this SDP description:
scs.session = MediaSession::createNew(env, sdpDescription);
if(scs.session == NULL)
{
env << *rtspClient << "Failed to create a MediaSession object from the SDP description: " << env.getResultMsg() << "\n";
}
else
if(!scs.session->hasSubsessions())
{
env << *rtspClient << "This session has no media subsessions (i.e., no \"m=\" lines)\n";
}
scs.iter = new MediaSubsessionIterator(*scs.session);
setupNextSubsession(rtspClient);
return;
}
void setupNextSubsession(RTSPClient* rtspClient)
{
UsageEnvironment& env = rtspClient->envir(); // alias
StreamClientState& scs = ((ourRTSPClient*)rtspClient)->scs; // alias
scs.subsession = scs.iter->next();
if(scs.subsession != NULL)
{
if(!scs.subsession->initiate())
{
env << "Failed to initiate the subsession: " << env.getResultMsg();
setupNextSubsession(rtspClient); // give up on this subsession; go to the next one
}
else
{
env << "Initiated the subsession:";
if(scs.subsession->rtcpIsMuxed())
{
env << "client port " << scs.subsession->clientPortNum();
}
else
{
env << "client ports " << scs.subsession->clientPortNum() << "-" << scs.subsession->clientPortNum()+1;
}
scs.subsession->sink = DummySink::createNew(env,
*scs.subsession,
rtspClient->url());
// perhaps use your own custom "MediaSink" subclass instead
if(scs.subsession->sink == NULL)
{
env << "Failed to create a data sink for the subsession: " << env.getResultMsg();
}
env << "Created a data sink for the subsession";
scs.subsession->miscPtr = rtspClient; // a hack to let subsession handler functions get the "RTSPClient" from the subsession
scs.subsession->sink->startPlaying(*(scs.subsession->readSource()),
subsessionAfterPlaying, scs.subsession);
// Also set a handler to be called if a RTCP "BYE" arrives for this subsession:
if(scs.subsession->rtcpInstance() != NULL)
{
scs.subsession->rtcpInstance()->setByeWithReasonHandler(subsessionByeHandler, scs.subsession);
}
// Set up the next subsession, if any:
setupNextSubsession(rtspClient);
}
}
}
Everything initialises without errors, but DummySink receives no data. Any ideas?

I've found out that although wireshark was showing me the incoming packets with valid checksums, udp port received no packets.
I've tried following commands (as sudo) to avoid kernel discarding the packets but they simply don't help on Debian Buster.
sysctl net.ipv4.conf.eth0.rp_filter=0
sysctl net.ipv4.conf.all.rp_filter=0
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter
sysctl -a | grep "\.rp_filter" | awk '{print $1 "=0"}' | xargs sysctl
Basically I've ended up streaming the pcap file from another computer, now I'm able to receive NALUs.

Related

How to connect to a web service that returns JSON in LUA

I am beginner in LUA. I have written the following code in lua file that mysql proxy run with it.
function read_query(packet)
if string.byte(packet) == proxy.COM_QUERY then
local command = string.lower(packet)
if string.find(command, "select") ~= nil and string.find(string.lower(packet), "from") ~= nil then
local socket = require('socket')
local conn, err = socket.connect('localhost', 5050)
print(conn, err)
proxy.response.type = proxy.MYSQLD_PACKET_OK
//proxy.response.resultset get json from web service (url)
proxy.response.resultset = {
fields = {
{ type = proxy.MYSQL_TYPE_INT, name = "id", },
},
rows = {
{ 9001 }
}
}
return proxy.PROXY_SEND_RESULT
end
end
end
I want to connect to the web service on Port 5050 that return the JSON file and save the json that it returns in the proxy.response.resultset.
Another question, How can i add socket module. I paste files like following image
socket module files
but give an error : can not find /socket/core.lua.
local socket = require('socket')
You are using luasocket and it comes as a mix of lua (socket.lua) and binary (socket/core.so) files. You need to set (if it's not set already) to point to .so files; something like this may work: package.cpath=package.cpath..';./?.so'

Remove extra characters from thread script

I've got a ruby script which check microservices version from each microservice API. I try to run this with bamboo and return the result as a html table.
...
h = {}
threads = []
service = data_hash.keys
service.each do |microservice|
threads << Thread.new do
thread_id = Thread.current.object_id.to_s(36)
begin
h[thread_id] = ""
port = data_hash["#{microservice}"]['port']
nodes = "knife search 'chef_environment:#{env} AND recipe:#
{microservice}' -i 2>&1 | tail -n 2"
node = %x[ #{nodes} ].split
node.each do |n|
h[thread_id] << "\n<html><body><h4> Node: #{n} </h4></body></html>\n"
uri = URI("http://#{n}:#{port}/service-version")
res = Net::HTTP.get_response(uri)
status = Net::HTTP.get(uri)
data_hash = JSON.parse(status)
name = data_hash['name']
version = data_hash['version']
h[thread_id] << "<table><tr><th> #{name}:#{version} </th></tr></table>"
end
rescue => e
h[thread_id] << "ReadTimeout Error"
next
end
end
end
threads.each do |thread|
thread.join
end
ThreadsWait.all_waits(*threads)
puts h.to_a
The issue is that I want to output name and version into a html table and if I put threads it generates some random characters between each line:
<table><tr><th> microservice1:2.10.3 </th></tr></table>
bjfsw
<table><tr><th> microservice2:2.10.8 </th></tr></table>
The random characters are the keys of the hash generated with to_s(36).
Replace the puts h.to_a with something like
puts h.values.join("\n")
And you will only see the data and not the keys.
You can use kernel#p h or puts h.inspect to see this.

IRC bot pong doesn't work

I've created bot, using code from this page.
Everything was good, when I was trying to reach irc.rizon.net. But problem arrives, when I've changed server to irc.alphachat.net.
#!/usr/bin/env python3
import socket
server = 'irc.alphachat.net'
channel = '#somechannel'
NICK = 'somenick'
IDENT = 'somenick'
REALNAME = 'somenick'
port = 6667
def joinchan(chan):
ircsock.send(bytes('JOIN %s\r\n' % chan, 'UTF-8'))
def ping(): # This is our first function! It will respond to server Pings.
ircsock.send(bytes("QUOTE PONG \r\n", 'UTF-8'))
def send_message(chan, msg):
ircsock.send(bytes('PRIVMSG %s :%s\r\n' % (chan, msg), 'UTF-8'))
ircsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ircsock.connect((server, port)) # Here we connect to the server using the port 6667
ircsock.send(bytes("USER "+ NICK +" "+ NICK +" "+ NICK +" :This bot\n", 'UTF-8')) # user authentication
ircsock.send(bytes("NICK "+ NICK +"\n", 'UTF-8')) # here we actually assign the nick to the bot
joinchan(channel) # Join the channel using the functions we previously defined
while 1: # Be careful with these! it might send you to an infinite loop
ircmsg = ircsock.recv(2048).decode() # receive data from the server
ircmsg = ircmsg.strip('\n\r') # removing any unnecessary linebreaks.
print(ircmsg) # Here we print what's coming from the server
if ircmsg.find(' PRIVMSG ')!=-1:
nick=ircmsg.split('!')[0][1:]
if ircmsg.find("PING :") != -1: # if the server pings us then we've got to respond!
ping()
if ircmsg.find(":Hello "+ NICK) != -1: # If we can find "Hello Mybot" it will call the function hello()
hello()
Problem is with ping command because I don't know how to answer to server:
:irc-us2.alphachat.net NOTICE * :*** Looking up your hostname...
:irc-us2.alphachat.net NOTICE * :*** Checking Ident
:irc-us2.alphachat.net NOTICE * :*** Found your hostname
:irc-us2.alphachat.net NOTICE * :*** No Ident response
PING :CE661578
:irc-us2.alphachat.net 451 * :You have not registered
With IRC, you should really split each line up by ' ' (space) into chunks to process it - something like this should work after your print (untested)
The reason it's not working is because you're not replying to PINGs properly
chunk = ircmsg.split(' ')
if chunk[0] == 'PING': # This is a ping
ircsock.send(bytes('PONG :%s\r\n' % (chunk[1]), 'UTF-8')) # Send a pong!
if chunk[1] == 'PRIVMSG': # This is a message
if chunk[3] == ':Hello': # Hey, someone said hello!
send_message(chunk[2], "Hi there!") # chunk[2] is channel / private!
if chunk[1] == '001': # We've logged on
joinchannel(channel) # Let's join!
send_message(channel, "I've arrived! :-)") # Announce to the channel
Normally the command / numeric is found in the second parameter (chunk[1]) - The only exception I can think of is PING which is found in the first (chunk[0])
Also note that I moved joinchannel() - you should only be doing this after you're logged on.
Edit: Didn't realise the age of this post. Sorry!
I believe you just need to make a small change to the string you send in response to the ping request.
try using:
ircsock.send(bytes("PONG pingis\n", "UTF-8"))
This ping response works for me on freenode.

How do I connect to my web domain's mySQL database using Qt?

I have a web domain and had already mySql database in it. I wish to connect and retrieve data from the database to my Qt Application. Here is my attempt and my result. (The host name, database name, username and password were just edited).
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setHostName("www.mydomain.com");
db.setDatabaseName("myDatabase");
db.setUserName("myName");
db.setPassword("myPass");
if(!db.open()){
QSqlError err = db.lastError();
qDebug() << err.text();
}
else {
QSqlQuery qry;
qDebug() << "Connected to SQL Database!";
if (qry.exec("select * from dataTable;")){
while(qry.next()){
qDebug() << qry.value(1).toString();
}
}
else {
qDebug() << "ERROR QUERY";
}
qDebug() << "Closing...";
db.close();
}
return a.exec();
}
It shows that it got connected but upon executing a query. It returns an error. Furthermore, I tried changing to an invalid hostname and/or username and it still got connected.
1) Try w/o the semi-colon.
"For SQLite, the query string can contain only one statement at a time." (http://qt-project.org/doc/qt-4.8/qsqlquery.html#exec)
However this is one statement, the interpreter may get confused because of the semi-colon.
2) "Note that the last error for this query is reset when exec() is called." (http://qt-project.org/doc/qt-4.8/qsqlquery.html#exec)
Because this is not a prepared statement, try avoiding exec() so information about the last error is available:
QSqlQuery qry("select * from dataTable");
if(qry.lastError()) {
// ...
}
while(qry.next()) {
qDebug() << qry.value(1).toString();
}

c# console application backup mysql

I try to use this code as a console application so that I can back up mydatabase automatics
I am not sure what wrong with it
static void Main(string[] args)
{
try
{
DateTime backupTime = DateTime.Now;
int year = backupTime.Year;
int month = backupTime.Month;
int day = backupTime.Day;
int hour = backupTime.Hour;
int minute = backupTime.Minute;
int second = backupTime.Second;
int ms = backupTime.Millisecond;
String tmestr = backupTime.ToString();
tmestr = "C:\\" + year + "-" + month + "-" + day + "-" + hour + "-" + minute + ".sql";
StreamWriter file = new StreamWriter(tmestr);
ProcessStartInfo proc = new ProcessStartInfo();
string cmd = string.Format(#"-u{0} -p{1} -h{2} {3} > {4};", "root", "", "localhost", "dbfile", "backup.sql");
proc.FileName = "mysqldump";
proc.RedirectStandardInput = false;
proc.RedirectStandardOutput = true;
proc.Arguments = cmd;//"-u root -p smartdb > testdb.sql";
proc.UseShellExecute = false;
Process p = Process.Start(proc);
string res;
res = p.StandardOutput.ReadToEnd();
file.WriteLine(res);
p.WaitForExit();
file.Close();
}
catch (IOException ex)
{
MessageBox.Show("Disk full or other IO error , unable to backup!");
}
}
Since I'm not sure what kind of error you're geting, atleast this could be changed.
string cmd = string.Format(#"-u{0} -p{1} -h{2} {3} > {4};", "root", "", "localhost", "dbfile", "backup.sql");
Later you commented it should be -u root -p smartdb > testdb.sql";
except the above, is missing the space after the -u so I'd change it to:
string cmd = string.Format(#"-u {0} -p {1} -h {2} {3} > {4};", "root", "", "localhost", "dbfile", "backup.sql");
Why are you creating a StreamWriter and trying to get the output of mysqldump, Why not just tell mysqldump to write to the backup file itself?
string cmd = string.Format(#"-u{0} -p{1} -h{2} {3} > ""{4}"";",
"root", "", "localhost", "dbfile", tmestr);
for starters i would change how you're outputting the information. You're essentially opening a file so you can redirect the backup utility's output to that file. The > in your process call is for that very purpose. Just change your "backup.sql" parameter to tmestr.
Also, because the output is already being redirected to a file, your process won't have anything to return. But because we're now having it dump to the correct path, this should be irrelevant.
One final change, add a space between your -u{0} so it's -u {0}. And the same with -h{2}.
In summary:
remove StreamWriter and all variables associated to it
modify the String.Format in your process arguments to use `tmestr
add spaces in your cmd variable for -u&-h
And you should be good-to-go (assuming it's not a problem with locating the mysqldump executable.