Teltonika FMB965 continues sending same records – Ack Problem? - php

Im trying to build a small GPS-tracking software.
To parse the data sent through TCP/IP from the device to my server I am using this package: https://github.com/uro/teltonika-fm-parser
I already receive all necessary information and store it to the database successfully.
But unfortunately, the FMB965 sends the same records again and again. So, after I've formatted the tracker, it start's with one record. Next connection two records, etc. etc. Seems like the ACK doesn't get back to the tracker?
$ip = env('SOCKET_SERVER_IP');
$port = env('SOCKET_SERVER_PORT');
$parser = new FmParser('tcp');
$socket = stream_socket_server("tcp://$ip:$port", $errno, $errstr);
$this->info("Listening to tcp://{$ip}:{$port}...");
if (!$socket) {
throw new \Exception("$errstr ($errno)");
} else {
while ($conn = stream_socket_accept($socket)) {
// Read IMEI
$payload = fread($conn, 1024);
$imei = $parser->decodeImei($payload);
// Accept packet
fwrite($conn, Reply::accept());
// Read Data
$payload="";
while( !feof( $conn ) ) {
$payload .= fread( $conn, 1024 ) ;
}
$packet = $parser->decodeData($payload);
fwrite($conn, $parser->encodeAcknowledge($packet));
foreach ($packet->getAvlDataCollection()->getAvlData() as $avlData) {
$gps = $avlData->getGpsElement();
// Create it in DB
$this->info('Record created');
}
fclose($conn);
}
fclose($socket);
}

Related

Cannot get required headers from some IPs and ports to parse song title using ShoutCast protocol

I'm trying to extract song title from live mp3 streams using SC protocol. The php script works fine with some IPs and ports, however with some IPs and ports I cannot get required headers from the response to determine the meta-block frequency, therefore I cannot find the location of the song title in the stream. Here's my code:
<?php
while(true)
{
//close warning messages (re-open for debugging)
error_reporting(E_ERROR | E_PARSE);
//create and connect socket with the parameters entered by the user
$sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
echo "Establishing connection to the given adress...\n";
$fp = fsockopen($argv[1], $argv[2], $errno, $errstr, 10);
if($fp)
{
echo "Connection established.\n";
$result = socket_connect($sock, $argv[1], $argv[2]);
//prepare request
$request = "GET / HTTP/1.1\r\n";
$request .= "Icy-MetaData: 1\r\n\r\n";
//send request
socket_write($sock,$request,strlen($request));
//set sentinel boolean value's initial value
$headers = true;
//put the segment to be parsed into a string variable
$l = socket_read($sock,2048);
$meta = "";
$streamurl = "";
$checkContentType = false;
//Parsing metadata frequency and streamurl from response's headers.
foreach(preg_split("/((\r?\n)|(\r\n?))/", $l) as $line)
{
if(!(strpos($line, "metaint:") === false))
{
$meta = $line;
}
if(!(strpos($line, "icy-url:") === false))
{
$streamurl = $line;
}
if(!strpos($line, "audio/mpeg") === false)
{
$checkContentType = true;
}
}
echo $l;
//Checking if the content of the stream is mpeg or not
if($checkContentType)
{
$pos = strpos($meta, ":");
$interval = intval(substr($meta,$pos+1));
$pos = strpos($streamurl, ":");
$streamurl = substr($streamurl, $pos+1);
$flag = false;
//initialize bytecount to 0
$bytecount = 0;
//Extracting song title using SC protocol
while($headers)
{
$l = socket_read($sock,PHP_NORMAL_READ);
$bytecount++;
if($bytecount == $interval )
{
$headers = false;
$flag = true;
}
if($flag)
{
$len = ord($l);
}
}
//Determining length variable
$len = $len * 16;
$string = socket_read($sock,$len);
$pos2 = strpos($string, "'") + 1;
$pos3 = strpos($string, ";",$pos2) -1;
$songtitle = substr($string, $pos2, ($pos3-$pos2));
//Formatting the log entry
$finalstr = "[".date("c")."]"."[".$streamurl."]".$songtitle."\n";
echo "logged".$finalstr;
//finalize connection
socket_close($sock);
//Writing the requested info to a log file
file_put_contents("log.txt", $finalstr,FILE_APPEND | LOCK_EX);
//waiting 5 minutes
echo "Logging next entry in five minutes. \n";
sleep(300);
}
else
{
echo "Content of the stream is not suitable.\n";
exit;
}
}
else
{
echo "Unable to connect to the given ip and port.\n Exiting...\n";
socket_close($sock);
exit;
}
}
?>
I've never tried to access shoutcast programatically but I've run streaming audio servers in the past. There are actually two different flavours of shoutcast server and I would guess your program is trying to talk to one and these broken servers are the other type.
From the post READING SHOUTCAST METADATA FROM A STREAM:
Turns out that SHOUTcast and Icecast (two of the most popular server
applications for streaming radio) are supposed to be compatible, but
the response message from each server is slightly different.
Full details about the shoutcast protocol: Shoutcast Metadata Protocol

PHP - TCP/IP fsockopen

I was wondering if anyone has had any experience with this before. I'm trying to write a simple script that will continously read data from the TCP/IP stream but for some reason or another the script reads in a bunch of data, writes it out and then just stops.
$fp = fsockopen("xxxx", 3000, $errno, $errstr, 5);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
while (!feof($fp)) {
echo fgets($fp, 128)."\n";
fflush($fp);
}
fclose($fp);
}
I'd like it to have a constant flow to it, rather then echo out a bunch of data then wait 30 seconds and output a bunch more data. Anyone have any ideas?
---- EDIT ----
ZMQ Code
include 'zmsg.php';
$context = new ZMQContext();
$client = new ZMQSocket($context, ZMQ::SOCKET_DEALER);
// Generate printable identity for the client
$identity = sprintf ("%04X", rand(0, 0x10000));
$client->setSockOpt(ZMQ::SOCKOPT_IDENTITY, $identity);
$client->connect("tcp://xxxx:3000");
$read = $write = array();
$poll = new ZMQPoll();
$poll->add($client, ZMQ::POLL_IN);
$request_nbr = 0;
while (true) {
// Tick once per second, pulling in arriving messages
for ($centitick = 0; $centitick < 100; $centitick++) {
$events = $poll->poll($read, $write, 1000);
$zmsg = new Zmsg($client);
if ($events) {
$zmsg->recv();
echo $zmsg->body()."\n";
//printf ("%s: %s%s", $identity, $zmsg->body(), PHP_EOL);
}
}
$zmsg = new Zmsg($client);
//$zmsg->body_fmt("request #%d", ++$request_nbr)->send();
}
Here is how you connect to a server (as a client) if your goal is ONLY to PULL data (read).
<?php
$context = new ZMQContext();
$sock = new ZMQSocket($context, ZMQ::SOCKET_PULL);
$sock->connect("tcp://ADDRESS:3000");
while (true)
{
$request = $sock->recv(); # recv is blocking by default, no need to put timers.
printf ("Received: %s;%s", $request, PHP_EOL);
}
?>
if you want to reply, you'll need to use a pair socket (ZMQ::SOCKET_PAIR), then you can use:
$sock->send("data to send");
Also, if instead of you connecting to clients, clients connects to you, use the bind method instead of connect.
EDIT: use the PUSH socket type on the other side if you use the pull here, else, use the pair socket on both sides.

Waiting for error from apns with enhanced format in php

We're using a modified version of easy-apns for sending our push messages. With the enhanced push message format the apple server responds if an error occurs, and does nothing if everything goes well.
The problem is that we have to wait for an error a certain amount of time after each message has been sent. For example if we receive no response after 1 second, we assume everything went ok.
With 20000 push messages, this takes far too long. Is there any way I can listen for errors in a faster way? For example sending to 1000 devices and then listen for errors? What happens if the connection gets closed, can I still read the error response?
Ideal would be some kind of asynchronous writing and reading, but I think that's not possible.
Here's the corresponding code:
$fp = $this->connect();
$expiry = time()+60*60;
// construct message
$msg = chr(1).pack("N",$batchid).pack("N",$expiry).pack("n",32).pack('H*',$devicetoken).pack("n",strlen($payload)).$payload;
// send message to Apple
$fwrite = fwrite($fp, $msg);
if(!$fwrite) {
// connection has been closed
$this->disconnect();
throw new Exception("Connection closed");
} else {
// read response from Apple
// Timeout. 1 million micro seconds = 1 second
$tv_sec = 1;
$tv_usec = 0;
$r = array($fp);
$we = null; // Temporaries. "Only variables can be passed as reference."
// PROBLEM: this method waits for $tv_sec seconds for a response
$numChanged = stream_select($r, $we, $we, $tv_sec, $tv_usec);
if( $numChanged === false ) {
throw new Exception("Failed selecting stream to read.");
} elseif ( $numChanged > 0 ) {
$command = ord( fread($fp, 1) );
$status = ord( fread($fp, 1) );
$identifier = implode('', unpack("N", fread($fp, 4)));
if( $status > 0 ) {
// The socket has also been closed. Cause reopening in the loop outside.
$this->disconnect();
throw new MessageException("APNS responded with status $status: {$this->statusDesc[$status]} ($devicetoken).".microtime(), $status);
} else {
// unknown response, assume ok
}
} else {
// no response, assume ok
}
}

Speed of PHP UDP scraper is incredibly slow, how to improve?

I am working on a little project of mine and have built a UDP scraper that uses sockets to return data about a specific sha1 hash.
It works but is incredibly slow and wondered if any one knows how I could speed it up or improve the existing code.
The code is below;
// SCRAPE UDP
private function scrapeUDP($tracker, $hash) {
// GET TRACKER DETAILS
preg_match('%udp://([^:/]*)(?::([0-9]*))?(?:/)?%i', $tracker, $info);
// GENERATE TRANSACTION ID
$transID = mt_rand(0, 65535);
// PACKED TRANSACTION ID
$packedTransID = pack('N', $transID);
// ATTEMPT TO CREATE A SOCKET
if(!$socket = #fsockopen('udp://' . $info[1], $info[2], $errno, $errstr, 2)) {
return;
}
// SET STREAM TIMEOUT
stream_set_timeout($socket, 2);
// CONNECTION ID
$connID = "\x00\x00\x04\x17\x27\x10\x19\x80";
// BUILD CONNECTION REQUEST PACKET
$packet = $connID . pack('N', 0) . $packedTransID;
// SEND PACKET
fwrite($socket, $packet);
// CONNECTION RESPONSE
$response = fread($socket, 16);
// CHECK CONNECTION RESPONSE LENGTH
if(strlen($response) < 16) {
return;
}
// UNPACK CONNECTION RESPONSE
$returnData = unpack('Naction/NtransID', $response);
// CHECK CONNECTION RESPONSE DATA
if($returnData['action'] != 0 || $returnData['transID'] != $transID) {
return;
}
// GET CONNECTION ID
$connID = substr($response, 8, 8);
// BUILD SCRAPE PACKET
$packet = $connID . pack('N', 2) . $packedTransID . $hash;
// SEND SCRAPE PACKET
fwrite($socket, $packet);
// SCRAPE RESPONSE
$response = fread($socket, 20);
// CHECK SCRAPE RESPONSE LENGTH
if(strlen($response) < 20) {
return;
}
// UNPACK SCRAPE RESPONSE
$returnData = unpack('Naction/NtransID', $response);
// CHECK SCRAPE RESPONSE DATA
if($returnData['action'] != 2 || $returnData['transID'] != $transID) {
return;
}
// UNPACK SCRAPE INFORMATION
$returnData = unpack('Nseeders/Ncompleted/Nleechers', substr($response, 8, 12));
// RETURN TRACKER INFORMATION
return array('seeders' => $returnData['seeders'], 'leechers' => $returnData['leechers'],);
}
It is my first time I have ever created anything to do with sockets or UDP so forgive me if it is a mess!
Thanks...
You have to make parallel request using socket_select() and non-blocking sockets or forks, because you are spending a lot of time in waiting for the response. Additionally, it may be better to use low-level functions like socket_read() or similar to control connection and data transmission better.

TCP server (php)

I have a gps simulator, which sends continuous location data (nmea strings) through tcpip to 192.168.0.178:2323. How do I get that data using tcp socket and write to DB (php & mysql)?
Thanks!
This is a loaded question. First you need to read the data. Then you have to put some structure to the data for it to be usable. It doesn't do you much good to just dump lat-lon to a database. You probably want to save it as a waypoint or part of a track etc.
So I have no answer to the DB question. Here is part of the PHP program I use to read GPS data off my phone connected to a CradlePoint router. It's modified from GoogleNav code.
function read_gps() {
set_time_limit(5);
$fp = fsockopen ("192.168.0.1", 8080, $errno, $errstr, 30);
if (!$fp) {
die ("$errstr ($errno)");
}
$point=false;
$status="";
$fix=0;
while (!$point) {
$string=#fgets($fp, 4096);
switch (substr($string,0,6)) {
case "\$GPRMC" :
list($sentence, $time, $status, $latitude, $NS, $longitude, $EW, $speed, $course, $date, $magvar, $magvarEW)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
case "\$GPGGA" :
list($sentence, $time, $latitude, $NS, $longitude, $EW, $fix, $nbsat, $HDOP, $altitude,,,,,)= explode(",", trim($string));
$latd=convdec($latitude, $NS);
$lond=convdec($longitude, $EW);
break;
default :
break;
}
if ($status=="A" and $fix == 1){
$point=true;
}
}
...
?>
Start here: PHP Sockets
One of the user comments gives a helpful sample implementation of a TFTP client
<?php
function tftp_fetch($host, $filename)
{
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
// create the request packet
$packet = chr(0) . chr(1) . $filename . chr(0) . 'octet' . chr(0);
// UDP is connectionless, so we just send on it.
socket_sendto($socket, $packet, strlen($packet), 0x100, $host, 69);
$buffer = '';
$port = '';
$ret = '';
do
{
// $buffer and $port both come back with information for the ack
// 516 = 4 bytes for the header + 512 bytes of data
socket_recvfrom($socket, $buffer, 516, 0, $host, $port);
// add the block number from the data packet to the ack packet
$packet = chr(0) . chr(4) . substr($buffer, 2, 2);
// send ack
socket_sendto($socket, $packet, strlen($packet), 0, $host, $port);
// append the data to the return variable
// for large files this function should take a file handle as an arg
$ret .= substr($buffer, 4);
}
while(strlen($buffer) == 516); // the first non-full packet is the last.
return $ret;
}
?>

Categories