redefinition in h files - c++

i solved couple of my redefinition problems but still have one:
Error 2 error LNK2005: "class ConsoleCommandHandler commandHandler" (?commandHandler##3VConsoleCommandHandler##A) already defined in IRC.obj C:\Users\Łukasz\Desktop\IRCClient-master\Magic.obj
Here are the .h files
magic.h
#ifndef Magic_h
#define Magic_h
#include <iostream>
#include <signal.h>
#include <cstdlib>
#include <map>
#include <algorithm>
#include "src\Thread.h"
#include "src\IRCClient.h"
void signalHandler(int signal);
class ConsoleCommandHandler
{
public:
bool AddCommand(std::string name, int argCount, void(*handler)(std::string /*params*/, IRCClient* /*client*/));
void ParseCommand(std::string command, IRCClient* client);
private:
struct CommandEntry
{
int argCount;
void(*handler)(std::string /*arguments*/, IRCClient* /*client*/);
};
std::map<std::string, CommandEntry> _commands;
};
ConsoleCommandHandler commandHandler;
void msgCommand(std::string arguments, IRCClient* client);
void joinCommand(std::string channel, IRCClient* client);
void partCommand(std::string channel, IRCClient* client);
void ctcpCommand(std::string arguments, IRCClient* client);
ThreadReturn inputThread(void* client);
#endif
magic.cpp
#include "Magic.h"
void signalHandler(int signal)
{
volatile bool running;
running = false;
};
bool ConsoleCommandHandler::AddCommand(std::string name, int argCount, void(*handler)(std::string /*params*/, IRCClient* /*client*/))
{
CommandEntry entry;
entry.argCount = argCount;
entry.handler = handler;
std::transform(name.begin(), name.end(), name.begin(), towlower);
_commands.insert(std::pair<std::string, CommandEntry>(name, entry));
return true;
}
void ConsoleCommandHandler::ParseCommand(std::string command, IRCClient* client)
{
if (_commands.empty())
{
std::cout << "No commands available." << std::endl;
return;
}
if (command[0] == '/')
command = command.substr(1); // Remove the slash
std::string name = command.substr(0, command.find(" "));
std::string args = command.substr(command.find(" ") + 1);
int argCount = std::count(args.begin(), args.end(), ' ');
std::transform(name.begin(), name.end(), name.begin(), towlower);
std::map<std::string, CommandEntry>::const_iterator itr = _commands.find(name);
if (itr == _commands.end())
{
std::cout << "Command not found." << std::endl;
return;
}
if (++argCount < itr->second.argCount)
{
std::cout << "Insuficient arguments." << std::endl;
return;
}
(*(itr->second.handler))(args, client);
}
struct CommandEntry
{
int argCount;
void(*handler)(std::string /*arguments*/, IRCClient* /*client*/);
};
std::map<std::string, CommandEntry> _commands;
void msgCommand(std::string arguments, IRCClient* client)
{
std::string to = arguments.substr(0, arguments.find(" "));
std::string text = arguments.substr(arguments.find(" ") + 1);
std::cout << "To " + to + ": " + text << std::endl;
client->SendIRC("PRIVMSG " + to + " :" + text);
};
void joinCommand(std::string channel, IRCClient* client)
{
if (channel[0] != '#')
channel = "#" + channel;
client->SendIRC("JOIN " + channel);
}
void partCommand(std::string channel, IRCClient* client)
{
if (channel[0] != '#')
channel = "#" + channel;
client->SendIRC("PART " + channel);
}
void ctcpCommand(std::string arguments, IRCClient* client)
{
std::string to = arguments.substr(0, arguments.find(" "));
std::string text = arguments.substr(arguments.find(" ") + 1);
std::transform(text.begin(), text.end(), text.begin(), towupper);
client->SendIRC("PRIVMSG " + to + " :\001" + text + "\001");
}
ThreadReturn inputThread(void* client)
{
std::string command;
commandHandler.AddCommand("msg", 2, &msgCommand);
commandHandler.AddCommand("join", 1, &joinCommand);
commandHandler.AddCommand("part", 1, &partCommand);
commandHandler.AddCommand("ctcp", 2, &ctcpCommand);
while (true)
{
getline(std::cin, command);
if (command == "")
continue;
if (command[0] == '/')
commandHandler.ParseCommand(command, (IRCClient*)client);
else
((IRCClient*)client)->SendIRC(command);
if (command == "quit")
break;
}
#ifdef _WIN32
_endthread();
#else
pthread_exit(NULL);
#endif
}
irc.h
#pragma once
#include <iostream>
#include <signal.h>
#include <cstdlib>
#include <map>
#include <algorithm>
#include "Magic.h"
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
#using <mscorlib.dll>
namespace IRCclient {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::IO;
using namespace System::Runtime::InteropServices;
using namespace msclr::interop;
/// <summary>
/// Summary for MyForm
/// </summary>
private: System::Void connect_button_Click(System::Object^ sender, System::EventArgs^ e)
{
if ((server_box->Text == "") || (port_box->Text == "") || (username_box->Text == "") || (channel_box->Text == ""))
{
MessageBox::Show("Wypełnij wszystkie pola", "Puste pola", MessageBoxButtons::OK, MessageBoxIcon::Warning);
server_box->Focus();
}
else
{
String^ host_string = server_box->Text;
char* host = (char*)(void*)Marshal::StringToHGlobalAnsi(host_string);
String^ port_string = port_box->Text;
int port;
//String^ port_string = port.ToString();
String^ nick_string = username_box->Text;
std::string nick(marshal_as<std::string>(nick_string));
std::string user = "test";
IRCClient client;
volatile bool running;
Thread thread;
thread.Start(&inputThread, &client);
if (client.InitSocket())
{
content_box->Text = "Socket initialized. Connecting..." + "\r\n";
if (client.Connect(host, port))
{
content_box->Text = "Connected. Loggin in..." + "\r\n";
if (client.Login(nick, user))
{
content_box->Text = "Logged." + "\r\n";
running = true;
signal(SIGINT, signalHandler);
while (client.Connected() && running)
client.ReceiveData();
}
if (client.Connected())
client.Disconnect();
content_box->Text = "Disconnected." + "\r\n";
}
}
}
};
};
};

In the Magic.h file make this change:
extern ConsoleCommandHandler commandHandler;
Then in the Magic.cpp file add this code:
ConsoleCommandHandler commandHandler;
Otherwise both Magic.obj and IRC.obj will end up with ConsoleCommandHandler commandHandler because the header will reserve it twice, once in each obj file.

Related

Boost asio crashing when used with 60 parallel TCP/TLS client doing IO

I am using boost 1.55, openssl- 1.0.2k-fips; on a linux (RHEL7) host with 32 CPU/520 GB RAM and 20 Gbits/s network bandwidth.
While running 60 parallel TLS-1.2 client trying to connect over port 12666 to IO data the TCP server seems to crash. I have a feeling that the sendreceive method is crasing somewhere. Any pointer on efficient debugging would be really helpful!
UPDATE:
Right before the crash I also observe the network in on the host crosses 3.5Gbits/s spike; and the tcpdump on the port 12666 stops.
Here is the client code using boost asio:
#include <iostream>
#include <sstream>
#include <exception>
#include <boost/algorithm/string.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/bind.hpp>
#include <boost/system/error_code.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/asio/error.hpp>
#include <boost/random.hpp>
#include <boost/generator_iterator.hpp>
#include "log.h"
#include "CacheMgrClient.h"
using namespace std;
using namespace boost;
using namespace asio;
using namespace boost::system;
using namespace cache;
using asio::ip::tcp;
#if (defined(WIN32) || defined(WIN64))
CacheMgrClient::CacheMgrClient(const string& host_, string& port_)
: host(host_), port(port_), sock(NULL),
nothrow(false), lastpid(0) {}
#else
#include <openssl/ssl.h>
typedef ssl::stream<tcp::socket> SSLsocket;
CacheMgrClient::CacheMgrClient(const string& host_, string& port_, ssl::context *ctx_)
: host(host_), port(port_), ctx(ctx_), sock(NULL), ssl_sock(NULL),
nothrow(false), lastpid(0) {}
#endif
void CacheMgrClient::connectTCP(tcp::resolver::iterator &endpoint_iterator) {
tcp::resolver::iterator end;
sock = new tcp::socket(io_service);
boost::system::error_code error = boost::asio::error::host_not_found;
while(error && endpoint_iterator != end) {
sock -> close();
sock -> connect(*endpoint_iterator++, error)
}
if (error) {
delete sock;
sock = NULL;
if (!notthrow)
throw error.message();
}
}
void CacheMgrClient::disconnectTCP() {
try {
if (sock)
sock -> close();
}
catch (...) {
if (notthrow)
return;
delete sock;
sock = NULL;
throw;
}
delete sock;
sock = NULL;
}
void CacheMgrClient::connect() {
tcp::resolver resolver(io_sercice);
tcp::resolver::query query(tcp::v4(), host, port);
tcp::resover::iterator endpoint_iterator = resolver.resolve(query);
#if !(defined(WIN32) || defined(WIN64))
if (ssl_sock)
/* this part works fine */
connectSSL(endpoint_iterator);
else
#endif
/* i am looking for some assistance here */
connectTCP(endpoint_iterator);
}
void CacheMgrClient::disconnect() {
#if !(defined(WIN32) || defined(WIN64))
if (ssl_sock)
disconnectSSL();
else
#endif
disconnectTCP();
}
void CacheMgrClient::sendReceive(const vector<char>& req) {
pid_t curpid = getpid();
if (lastpid && lastpid != curpid)
disconnect()
lastpid = curpid;
boost::asio::streambuf responseBuf;
string responseString, errorMsg;
bool success = false;
int tries = 0;
while(!success) {
istream responseStream(&responseBuf);
try {
connect();
size_t count = 0;
if (sock)
count = boost::asio::write(*sock::asio::buffer(&req[0], req.size()));
#if !(defined(WIN32) || defined(WIN64))
else if (ssl_sock)
count = boost::asio::write(*ssl_sock::asio::buffer(&req[0], req.size()));
#endif
if (count <= 0 && req.size() > 0)
throw "Failed to wrote to the Cache Manager socket";
boost::system::error_code ec;
count = 0;
if (sock)
count = boost::asio::read_until(*sock, responseBuf, "\n", ec);
#if !(defined(WIN32) || defined(WIN64))
else if (ssl_sock)
count = boost::asio::read_until(*ssl_sock, responseBuf, "\n", ec);
#endif
if (count <=0 ) {
stringstream errorMsg;
errorMsg << "Failed to read Cache Manager respoinse. Error code =" << ec;
throw errorMsg.str();
}
if(!responseStream)
throw "Empty response from Cache Manager";
std::getline(responseStream, responseString);
if (responseString.substring(0,2) != "ok" %% responseString.substring(0,4) != "fail")
throw "Invalid reponse from Cache Manager, response=" + responseString;
log4::debug("Success: "+ responseString);
success = true;
}
catch(string errorMsg_) {
errorMsg = errorMsg_;
log4::error(errorMsg_);
}
catch(...) {
stringstream errorMsg;
errorMsg << "Failed to read response: " << boost::current_exception_diagnostic_information();
log4::error(errorMsg.str());
}
if (!success) {
#if (defined(WIN32) || defined(WIN64))
bool wasConnected = sock ? true : false;
#else
bool wasConnected = sock || ssl_sock ? true : false;
#endif
disconnect();
if (wasConnected && nothrow) {
log4.warn("Exception from Cache Manager while existing");
return "";
}
if (++tries >= max_connection_tries) {
stringstream msg
msg << "Giving up connecting ot Cahce Manager after " << tries << " tries";
log4::error(msg.str());
throw msg.str();
}
stringstream errorMsg;
int retry_delay = chooseRetryDelay(tries); /* usually 10 seconds */
/* This is the error that i am getting in my run*/
errorMsg << "Unable to connect to cache manager at " << host << ":" << port
<< ". Sleeping for " << retry_delay << " seconds and retrying."
<< " Will try " << max_connect_tries - tries -1 << " more times.";
log4::warn(errorMsg.str());
if (tries) {
#if (defined(WIN32) || defined(WIN64))
Sleep(retry_delay);
#else
sleep(retry_delay);
#endif
}
}
}
if (responseString.substring(0,2) != "ok") {
string errorMsg = "Exception from Cache Manager. See Cache Manager log in parent task "
"for traceback. \nResponse=" + responseString;
log4::error(errorMsg);
throw errorMsg;
}
return trim_left_copy(responseString.substring(2m resonseString.size() -2));
}

C++ decode e-mail's subject

I've downloaded mails with Poco/Net/POP3ClientSession, I wanted to convert e-mail subject into human readable, so I tried to use neagoegab's solution from here:
https://stackoverflow.com/a/8104496/1350091
unfortunately it doesn't work:
#include <Poco/Net/POP3ClientSession.h>
#include <Poco/Net/MailMessage.h>
#include <iostream>
#include <string>
using namespace std;
using namespace Poco::Net;
#include <iconv.h>
const size_t BUF_SIZE=1024;
class IConv {
iconv_t ic_;
public:
IConv(const char* to, const char* from)
: ic_(iconv_open(to,from)) { }
~IConv() { iconv_close(ic_); }
bool convert(char* input, char* output, size_t& out_size) {
size_t inbufsize = strlen(input)+1;
return iconv(ic_, &input, &inbufsize, &output, &out_size);
}
};
int main()
{
POP3ClientSession session("poczta.o2.pl");
session.login("my mail", "my password");
POP3ClientSession::MessageInfoVec messages;
session.listMessages(messages);
cout << "id: " << messages[0].id << " size: " << messages[0].size << endl;
MailMessage message;
session.retrieveMessage(messages[0].id, message);
const string subject = message.getSubject();
cout << "Original subject: " << subject << endl;
IConv iconv_("UTF8","ISO-8859-2");
char from[BUF_SIZE];// "=?ISO-8859-2?Q?Re: M=F3j sen o JP II?=";
subject.copy(from, sizeof(from));
char to[BUF_SIZE] = "bye";
size_t outsize = BUF_SIZE;//you will need it
iconv_.convert(from, to, outsize);
cout << "converted: " << to << endl;
}
The output is:
id: 1 size: 2792
Original subject: =?ISO-8859-2?Q?Re: M=F3j sen o JP II?=
converted: =?ISO-8859-2?Q?Re: M=F3j sen o JP II?=
The interesting thing is that when I try to convert the subject with POCO it fails:
cout << "Encoded with POCO: " << MailMessage::encodeWord("Re: Mój sen o JP II", "ISO-8859-2") << endl; // output: Encoded with POCO: =?ISO-8859-2?q?Re=3A_M=C3=B3j_sen_o_JP_II?=
But the subject I want to receive is:
"Re: Mój sen o JP II"
The only succesfull way I found to convert the subject is:
https://docs.python.org/2/library/email.header.html#email.header.decode_header
So my question is -how to convert e-mail's subject in C++ into some format like UTF-8?
The relevant RFC to your situation is RFC 2047. That RFC specifies how non-ASCII data should be encoded in mail messages. The basic gist is that all bytes besides printable ASCII characters are escaped as an '=' character followed by two hexadecimal digits. Since "ó" is represented by the byte 0xF3 in ISO-8859-2, and 0xF3 is not a printable ASCII character, it is encoded as "=F3". You'll need to decode all of the encoded characters in your message.
I found out how to solve the problem (I'm not sure that it is 100% correct solution), but it looks like it is enough to use:
Poco::UTF8Encoding::convert to convert from characterCode to utf8:
#include <Poco/Net/POP3ClientSession.h>
#include <Poco/Net/MessageHeader.h>
#include <Poco/Net/MailMessage.h>
#include <Poco/UTF8Encoding.h>
#include <iostream>
#include <string>
using namespace std;
using namespace Poco::Net;
class EncoderLatin2
{
public:
EncoderLatin2(const string& encodedSubject)
{
/// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
int charsetBeginPosition = strlen("=?");
int charsetEndPosition = encodedSubject.find("?", charsetBeginPosition);
charset = encodedSubject.substr(charsetBeginPosition, charsetEndPosition-charsetBeginPosition);
int encodingPosition = charsetEndPosition + strlen("?");
encoding = encodedSubject[encodingPosition];
if ("ISO-8859-2" != charset)
throw std::invalid_argument("Invalid encoding!");
const int lenghtOfEncodedText = encodedSubject.length() - encodingPosition-strlen("?=")-2;
extractedEncodedSubjectToConvert = encodedSubject.substr(encodingPosition+2, lenghtOfEncodedText);
}
string convert()
{
size_t positionOfAssignment = -1;
while (true)
{
positionOfAssignment = extractedEncodedSubjectToConvert.find('=', positionOfAssignment+1);
if (string::npos != positionOfAssignment)
{
const string& charHexCode = extractedEncodedSubjectToConvert.substr(positionOfAssignment + 1, 2);
replaceAllSubstringsWithUnicode(extractedEncodedSubjectToConvert, charHexCode);
}
else
break;
}
return extractedEncodedSubjectToConvert;
}
void replaceAllSubstringsWithUnicode(string& s, const string& charHexCode)
{
const int charCode = stoi(charHexCode, nullptr, 16);
char buffer[10] = {};
encodingConverter.convert(charCode, (unsigned char*)buffer, sizeof(buffer));
replaceAll(s, '=' + charHexCode, buffer);
}
void replaceAll(string& s, const string& replaceFrom, const string& replaceTo)
{
size_t needlePosition = -1;
while (true)
{
needlePosition = s.find(replaceFrom, needlePosition + 1);
if (string::npos == needlePosition)
break;
s.replace(needlePosition, replaceFrom.length(), replaceTo);
}
}
private:
string charset;
char encoding;
Poco::UTF8Encoding encodingConverter;
string extractedEncodedSubjectToConvert;
};
int main()
{
POP3ClientSession session("poczta.o2.pl");
session.login("my mail", "my password");
POP3ClientSession::MessageInfoVec messages;
session.listMessages(messages);
MessageHeader header;
MailMessage message;
auto currentMessage = messages[0];
session.retrieveHeader(currentMessage.id, header);
session.retrieveMessage(currentMessage.id, message);
const string subject = message.getSubject();
EncoderLatin2 encoder(subject);
cout << "Original subject: " << subject << endl;
cout << "Encoded: " << encoder.convert() << endl;
}
I found another solution, better than before.
Some e-mails subjects has different encodings, I noticed:
Latin2, encoded like: =?ISO-8859-2?Q?...?=
UTF-8 Base64 like:
=?utf-8?B?Wm9iYWN6Y2llIGNvIGRsYSBXYXMgcHJ6eWdvdG93YWxpxZtteSAvIHN0eWN6ZcWEIHcgTGFzZXJwYXJrdQ==?=
UTF-8 quoted printable like:
=?utf-8?Q?...?=
No encoding (if only ASCII characters) like: ...
So with POCO (Base64Decoder, Latin2Encoding, UTF8Encoding, QuotedPrintableDecoder) I managed to convert all the cases:
#include <iostream>
#include <string>
#include <sstream>
#include <Poco/Net/POP3ClientSession.h>
#include <Poco/Net/MessageHeader.h>
#include <Poco/Net/MailMessage.h>
#include <Poco/Base64Decoder.h>
#include <Poco/Latin2Encoding.h>
#include <Poco/UTF8Encoding.h>
#include <Poco/Net/QuotedPrintableDecoder.h>
using namespace std;
class Encoder
{
public:
Encoder(const string& encodedText)
{
isStringEncoded = isEncoded(encodedText);
if (!isStringEncoded)
{
extractedEncodedSubjectToConvert = encodedText;
return;
}
splitEncodedText(encodedText);
}
string convert()
{
if (isStringEncoded)
{
if (Poco::Latin2Encoding().isA(charset))
return decodeFromLatin2();
if (Poco::UTF8Encoding().isA(charset))
return decodeFromUtf8();
}
return extractedEncodedSubjectToConvert;
}
private:
void splitEncodedText(const string& encodedText)
{
/// encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
const int charsetBeginPosition = strlen(sequenceBeginEncodedText);
const int charsetEndPosition = encodedText.find("?", charsetBeginPosition);
charset = encodedText.substr(charsetBeginPosition, charsetEndPosition-charsetBeginPosition);
const int encodingPosition = charsetEndPosition + strlen("?");
encoding = encodedText[encodingPosition];
const int lenghtOfEncodedText = encodedText.length() - encodingPosition-strlen(sequenceBeginEncodedText)-strlen(sequenceEndEncodedText);
extractedEncodedSubjectToConvert = encodedText.substr(encodingPosition+2, lenghtOfEncodedText);
}
bool isEncoded(const string& encodedSubject)
{
if (encodedSubject.size() < 4)
return false;
if (0 != encodedSubject.find(sequenceBeginEncodedText))
return false;
const unsigned positionOfLastTwoCharacters = encodedSubject.size() - strlen(sequenceEndEncodedText);
return positionOfLastTwoCharacters == encodedSubject.rfind(sequenceEndEncodedText);
}
string decodeFromLatin2()
{
size_t positionOfAssignment = -1;
while (true)
{
positionOfAssignment = extractedEncodedSubjectToConvert.find('=', positionOfAssignment+1);
if (string::npos != positionOfAssignment)
{
const string& charHexCode = extractedEncodedSubjectToConvert.substr(positionOfAssignment + 1, 2);
replaceAllSubstringsWithUnicode(extractedEncodedSubjectToConvert, charHexCode);
}
else
break;
}
return extractedEncodedSubjectToConvert;
}
void replaceAllSubstringsWithUnicode(string& s, const string& charHexCode)
{
static Poco::UTF8Encoding encodingConverter;
const int charCode = stoi(charHexCode, nullptr, 16);
char buffer[10] = {};
encodingConverter.convert(charCode, (unsigned char*)buffer, sizeof(buffer));
replaceAll(s, '=' + charHexCode, buffer);
}
void replaceAll(string& s, const string& replaceFrom, const string& replaceTo)
{
size_t needlePosition = -1;
while (true)
{
needlePosition = s.find(replaceFrom, needlePosition + 1);
if (string::npos == needlePosition)
break;
s.replace(needlePosition, replaceFrom.length(), replaceTo);
}
}
string decodeFromUtf8()
{
if('B' == toupper(encoding))
{
return decodeFromBase64();
}
else // if Q:
{
return decodeFromQuatedPrintable();
}
}
string decodeFromBase64()
{
istringstream is(extractedEncodedSubjectToConvert);
Poco::Base64Decoder e64(is);
extractedEncodedSubjectToConvert.clear();
string buffer;
while(getline(e64, buffer))
extractedEncodedSubjectToConvert += buffer;
return extractedEncodedSubjectToConvert;
}
string decodeFromQuatedPrintable()
{
replaceAll(extractedEncodedSubjectToConvert, "_", " ");
istringstream is(extractedEncodedSubjectToConvert);
Poco::Net::QuotedPrintableDecoder qp(is);
extractedEncodedSubjectToConvert.clear();
string buffer;
while(getline(qp, buffer))
extractedEncodedSubjectToConvert += buffer;
return extractedEncodedSubjectToConvert;
}
private:
string charset;
char encoding;
string extractedEncodedSubjectToConvert;
bool isStringEncoded;
static constexpr const char* sequenceBeginEncodedText = "=?";
static constexpr const char* sequenceEndEncodedText = "?=";
};
int main()
{
Poco::Net::POP3ClientSession session("poczta.o2.pl");
session.login("my mail", "my password");
Poco::Net::POP3ClientSession::MessageInfoVec messages;
session.listMessages(messages);
Poco::Net::MessageHeader header;
Poco::Net::MailMessage message;
auto currentMessage = messages[0];
session.retrieveHeader(currentMessage.id, header);
session.retrieveMessage(currentMessage.id, message);
const string subject = message.getSubject();
Encoder encoder(subject);
cout << "Original subject: " << subject << endl;
cout << "Encoded: " << encoder.convert() << endl;
}

How to set the configuration properties for Mosquitto in c++?

I am writing mosquitto code for consuming the message after subscribing to a particular topic. Now I want to set different configuration for mosquitto like
autosave_interval 100
persistence true
persistence_location /var/lib/mosquitto/
persistence_file mosquitto.db
But I have no idea how to set this configuration in c++. I tried to google it but could not found any result. Plz, help. Below is c++ code for mosquito
myMosq.h
/*
* myMosq.h
*
* Created on: Jul 28, 2016
* Author: nilav
*/
#include <iostream>
#ifndef MYMOSQ_H_
#define MYMOSQ_H_
#include <mosquittopp.h>
#include <mosquitto.h>
using namespace std;
class myMosq : public mosqpp::mosquittopp
{
private:
const char * host;
const char * id;
const char * topic;
int port;
int keepalive;
void on_connect(int rc);
void on_message(const struct mosquitto_message *message);
void on_disconnect(int rc);
void on_subscribe(int mid, int qos_count, const int *granted_qos);
void on_publish(int mid);
void on_unsubscribe(int mid);
public:
myMosq(const char *id, const char * _topic, const char *host, int port);
~myMosq();
bool send_message(string responseMessage);
bool receive_message();
void writeToDatabase(string query);
};
#endif
myMosq.cpp
#include <cstdio>
#include <cstring>
#include <iostream>
#include "myMosq.h"
#include <mosquittopp.h>
#include "Configuration.h"
#include "Databases.h"
using namespace std;
Configuration configuration;
myMosq::myMosq(const char * _id,const char * _topic, const char * _host, int _port) : mosquittopp(_id)
{
mosqpp::lib_init(); // Mandatory initialization for mosquitto library
this->keepalive = 60; // Basic configuration setup for myMosq class
this->id = _id;
this->port = _port;
this->host = _host;
this->topic = _topic;
connect_async(host, // non blocking connection to broker request
port,
keepalive);
loop_start(); // Start thread managing connection / publish / subscribe
};
myMosq::~myMosq() {
loop_stop(); // Kill the thread
mosqpp::lib_cleanup(); // Mosquitto library cleanup
}
bool myMosq::receive_message()
{
int set = subscribe(NULL, configuration.subscriptionTopic.c_str(),2);
return set;
}
bool myMosq::send_message(string responseMessage) {
int ret = publish(NULL,configuration.producerTopic.c_str(),strlen(responseMessage.c_str()),responseMessage.c_str(),1,false);
return (ret = MOSQ_ERR_SUCCESS);
}
void myMosq::on_disconnect(int rc) {
std::cout << ">> myMosq - disconnection(" << rc << ")" << std::endl;
}
void myMosq::on_connect(int rc)
{
if ( rc == 0 ) {
std::cout << ">> myMosq - connected with server" << std::endl;
} else {
std::cout << ">> myMosq - Impossible to connect with server(" << rc << ")" << std::endl;
}
}
void myMosq::on_message(const struct mosquitto_message *message) {
char * pchar = (char*)(message->payload);
string str(pchar);
writeToDatabase(str);
}
void myMosq::on_subscribe(int mid, int qos_count, const int *granted_qos)
{
std::cout << ">> subscription succeeded (" << mid << ") " << std::endl;
}
void myMosq::on_publish(int mid) {
std::cout << ">> myMosq - Message (" << mid << ") succeed to be published " << std::endl;
}
void myMosq::writeToDatabase(string query) {
Databases* database = new Databases(configuration.db,
configuration.dbPort, configuration.username, configuration.password,
configuration.schema);
database->writeDatabase(query);
if(database->responseMessage == "") {
database->responseMessage = "SUCCESS";
}
this->send_message(database->responseMessage);
}
void myMosq::on_unsubscribe(int mid) {
cout<<"unscubscribed";
};
The options you are seeing are for mosquitto broker which acts almost like a server.
Mosquitto C++ library is a client library and those options(e.g. autosave_interval) are not valid for a client. Regarding persistance, mosquitto C/C++ client library doesn't offer file persistance currently.

How to use boost.Asio with MJPEG?

I want to broadcast OpenCV images (coming from a camera) to a distant computer in real time, it has to be done via Ethernet. The images are continuously received in standard OpenCV Mat objects. The final code has to be integrated into a C++ (Qt) application.
I have found this Python script that does the job very well.
Now I'm trying to get a C++ equivalent of that code, I managed to create an HTTP server using Boost Asio and the Simple-Web-Server project. I am able to display a static blue image/webcam camera image (not refreshed).
I have written a code but it's not working. My guess is that the data are sent only at the return of the function (which never returns).
How can I force sending the data after each iteration of the while loop?
#include "server_http.hpp"
#include <thread>
#include <boost/chrono.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>
#include <opencv2/opencv.hpp>
//#include <opencv/cv.h>
using namespace boost::posix_time;
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;
cv::Mat image;
cv::VideoCapture cap;
int main()
{
cap.open(0);
if (!cap.isOpened ())
{
std::cerr << "Could not initialize capturing" << std::endl;
return (-1);
}
cap >> image;
HttpServer server(8080, 2);
// Image resource is requested
server.resource["^/cam.mjpg"]["GET"] =
[=](HttpServer::Response& response, std::shared_ptr<HttpServer::Request> request)
{
time_facet *facet = new time_facet("%d-%b-%Y %H:%M:%S");
std::cout.imbue(std::locale(std::cout.getloc(), facet));
std::cout << second_clock::local_time() << " | " << "Camera image requested!" << std::endl;
response <<
"HTTP/1.1 200 OK\r\n"
"Content-type: multipart/x-mixed-replace; boundary=--jpgboundary";
//TODO: Send header
while (1) // TODO: Allow exiting this
{
std::cout << "Send image" << std::endl;
cap >> image;
// Encode mat to jpg and copy it to content
std::vector<uchar> buf;
cv::imencode(".jpg", image, buf, std::vector<int>());
std::string img_content(buf.begin(), buf.end());
response << "--jpgboundary\r\n" << // Signal we start a new image
"Content-type: image/jpeg" <<
"Content-Length: " << img_content.length() << "\r\n" <<
"\r\n" << img_content << "\r\n";
std::this_thread::sleep_for(std::chrono::milliseconds(400));
}
};
// Anything else is requested
server.default_resource["GET"] = [](HttpServer::Response& response, std::shared_ptr<HttpServer::Request> request)
{
time_facet *facet = new time_facet("%d-%b-%Y %H:%M:%S");
std::cout.imbue(std::locale(std::cout.getloc(), facet));
std::cout << second_clock::local_time() << " | " << request->path << std::endl;
std::string content =
"<html><head></head><body>"
"<img src=\"cam.mjpg\"/>"
"</body></html>";
response <<
"HTTP/1.1 200 OK\r\n"
"Content-Length: " << content.length() << "\r\n"
"\r\n" << content;
};
std::thread server_thread([&server]()
{
server.start();
});
std::this_thread::sleep_for(std::chrono::seconds(1));
server_thread.join();
return 0;
}
EDIT 1
Based on Technik Empire comment I went back to boost examples;
In the HTTP server example the response in sent when the callback returns so I modified the callback to allow do_write() operations on the socket.
The HTML page is correctly displayed but the image is not displayed (the broken image icon is shown instead), I tried to see what happens with Wireshark but I don't know what is wrong.
Here is my handle_request function: (request_handler.cpp):
void request_handler::handle_request(const request& req, reply& rep, connection &con)
{
// Decode url to path.
std::string request_path;
if (!url_decode(req.uri, request_path))
{
rep = reply::stock_reply(reply::bad_request);
return;
}
// Request path must be absolute and not contain "..".
if (request_path.empty() || request_path[0] != '/'
|| request_path.find("..") != std::string::npos)
{
rep = reply::stock_reply(reply::bad_request);
return;
}
// Determine the file extension.
std::size_t last_slash_pos = request_path.find_last_of("/");
std::string filename;
if (last_slash_pos != std::string::npos)
filename = request_path.substr(last_slash_pos + 1);
if (filename == "cam.mjpg") // Image is requested
{
rep.status = reply::ok;
rep.headers.resize(1);
rep.headers[0].name = "Content-Type";
rep.headers[0].value = "multipart/x-mixed-replace; boundary=--jpgboundary";
rep.content.empty();
con.do_write();
rep.status = reply::none;
while (true) // FIXME: How do I handle disconnection from the client?
{
cv::Mat image(200, 300, CV_8UC3);
int random = rand() % 255 + 1;
image = cv::Scalar(random, 0, 0); // Fill image with blue
std::vector<uchar> buf;
cv::imencode(".jpg", image, buf, std::vector<int>());
std::string img_content(buf.begin(), buf.end());
rep.headers.clear();
rep.content.clear();
rep.content.append("--jpgboundary\r\n");
con.do_write();
rep.content.clear();
rep.headers.resize(2);
rep.headers[0].name = "Content-Type";
rep.headers[0].value = mime_types::extension_to_type("jpg");
rep.headers[1].name = "Content-length";
rep.headers[1].value = img_content.size();
rep.content.append(img_content);
rep.content.append("\r\n");
con.do_write();
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
}
}
else // Anything but the image is requested
{
std::string content =
"<html><head></head><body>"
"Hello :)<br>"
"<img src=\"cam.mjpg\"/>"
"</body></html>";
rep.status = reply::ok;
rep.headers.resize(2);
rep.headers[0].name = "Content-Length";
rep.headers[0].value = content.length();
rep.headers[1].name = "Content-Type";
rep.headers[1].value = mime_types::extension_to_type("html");
rep.content.append(content);
con.do_write();
return;
}
}
I got it working by analyzing the packets thanks to the Firefox network analyzer, I replicated the Python headers/content answer and it works fine:
I added a reply::none reply type and made sure that if this reply was provided, no HTTP status is being sent. So in the reply::to_buffers() function I added this:
if (status != none) // Don't add status to buffer if status is "none"
buffers.push_back(status_strings::to_buffer(status));
The request_handler.cpp code looks like this:
if (filename == "cam.mjpg") // Image is requested
{
rep.status = reply::ok;
rep.headers.resize(1);
rep.headers[0].name = "Content-Type";
rep.headers[0].value = "multipart/x-mixed-replace; boundary=--jpgboundary\r\n";
con.do_write();
while (true) // FIXME: How do I handle disconnection from the client?
{
cv::Mat image(200, 300, CV_8UC3);
int random = rand() % 255 + 1;
image = cv::Scalar(random, 0, 0); // Fill image with blue
std::vector<uchar> buf;
cv::imencode(".jpg", image, buf, std::vector<int>());
std::string img_content(buf.begin(), buf.end());
rep.status = reply::none;
rep.headers.resize(0);
rep.content.clear();
rep.content.append("--jpgboundary");
rep.content.append("\r\n");
rep.content.append("Content-Type: image/jpeg");
rep.content.append("\r\n");
rep.content.append("Content-length: "+boost::lexical_cast<std::string>(img_content.length()));
rep.content.append("\r\n");
rep.content.append("\r\n");
rep.content.append(img_content);
rep.content.append("\r\n");
con.do_write();
boost::this_thread::sleep(boost::posix_time::milliseconds(100));
}
}
else // Anything but the image is requested
{
std::string content =
"<html><head></head><body>"
"<img src=\"cam.mjpg\"/>"
"</body></html>";
rep.status = reply::ok;
rep.headers.resize(2);
rep.headers[0].name = "Content-Length";
rep.headers[0].value = content.length();
rep.headers[1].name = "Content-Type";
rep.headers[1].value = mime_types::extension_to_type("html");
rep.content.append(content);
con.do_write();
return;
}
Improvements suggestions are welcome in the comments. I don't know how to handle a disconnection from the client (exiting the while loop) so at the moment the server will only work with 1 request; after that it's stucked in the while loop.
Http_server.hpp
#ifndef HTTPSERVER_HPP_INCLUDED
#define HTTPSERVER_HPP_INCLUDED
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <opencv2/core/core.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
typedef boost::shared_ptr<tcp::socket> socket_ptr;
class HttpServer
{
public:
std::map<std::string, std::string> winnames;
std::map<std::string,int> requestcounts;
std::map<std::string,std::vector<unsigned char> > jpegbuffers;
short port;
HttpServer();
void run(int portno);
boost::shared_mutex mut;
boost::condition_variable_any cond;
int httpdelay;
void IMSHOW(std::string win, cv::Mat mat);
int compression;
bool is_debug;
private:
int it;
void server(int port);
void session(socket_ptr sock);
void handleinfo(socket_ptr sock);
void handlewindows(socket_ptr sock);
void handlemjpeg(socket_ptr sock,std::string winname);
void handlejpg(socket_ptr sock,std::string winname);
void handle404(socket_ptr sock);
};
#endif
Http_server.cpp
#include "http_server.hpp"
#include <fstream>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <opencv2/opencv.hpp>
#include <boost/lexical_cast.hpp>
namespace bfs= boost::filesystem;
using namespace std;
using boost::lexical_cast;
// Helper functions
#if defined(unix) || defined(__unix) || defined(__unix__) \
|| defined(linux) || defined(__linux) || defined(__linux__) \
|| defined(sun) || defined(__sun) \
|| defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__FreeBSD__) || defined __DragonFly__ \
|| defined(sgi) || defined(__sgi) \
|| defined(__MACOSX__) || defined(__APPLE__) \
|| defined(__CYGWIN__)
#define is_nix
#endif
#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
|| defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
#define is_win
#endif
#ifdef is_win
#include <windows.h>
#define SLEEP(ms) Sleep(ms)
#endif
#ifdef is_nix
#define SLEEP(ms) usleep(ms*1000)
#endif
std::vector<std::string> &dssplit(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> dssplit(const std::string &s, char delim) {
std::vector<std::string> elems;
return dssplit(s, delim, elems);
}
void removeEmptyStrings(std::vector<std::string>& strings)
{
std::vector<std::string>::iterator it = remove_if(strings.begin(), strings.end(), mem_fun_ref(&std::string::empty));
strings.erase(it, strings.end());
}
bool hasEnding(std::string const &fullString, std::string const &ending)
{
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending));
}
else {
return false;
}
}
bool startswith(std::string const &src, std::string const &start)
{
if (src.compare(0, start.length(), start) == 0)
{
return true;
}
return false;
}
std::string urldecode(std::string &src) {
std::string ret;
char ch;
int ii;
for (size_t i = 0; i<src.length(); i++) {
if (int(src[i]) == 37) {
sscanf(src.substr(i + 1, 2).c_str(), "%x", &ii);
ch = static_cast<char>(ii);
ret += ch;
i = i + 2;
}
else {
ret += src[i];
}
}
return (ret);
}
// Server implementation
HttpServer::HttpServer() :compression(70), is_debug(true), httpdelay(100)
{
}
void HttpServer::IMSHOW(std::string win, cv::Mat mat)
{
winnames[win] = lexical_cast<string>(mat.cols) + "," + lexical_cast<string>(mat.rows);
if (is_debug)
{
cv::imshow(win, mat);
}
else
{
//cvDestroyWindow(win.c_str());
}
if (requestcounts[win] > 0)
{
cv::Mat towrite;
if (mat.type() == CV_8UC1)
{
cvtColor(mat, towrite, CV_GRAY2BGR);
}
else if (mat.type() == CV_32FC3)
{
double minVal, maxVal;
minMaxLoc(mat, &minVal, &maxVal);
mat.convertTo(towrite, CV_8U, 255.0 / (maxVal - minVal), -minVal * 255.0 / (maxVal - minVal));
}
else{
towrite = mat;
}
std::vector<uchar> buffer;
std::vector<int> param(2);
param[0] = CV_IMWRITE_JPEG_QUALITY;
param[1] = compression;
imencode(".jpg", towrite, buffer, param);
jpegbuffers[win].swap(buffer);
}
}
void HttpServer::run(int portno)
{
port=portno;
boost::thread t(boost::bind(&HttpServer::server,this,port));
}
void HttpServer::server(int port)
{
try
{
boost::asio::io_service io_service;
io_service.run();
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
socket_ptr sock(new tcp::socket(io_service));
a.accept(*sock);
boost::thread t(boost::bind(&HttpServer::session, this, sock));
}
}
catch (boost::exception & e)
{
std::cout << "OMG!" << boost::diagnostic_information(e)<<endl;
}
}
void HttpServer::session(socket_ptr sock)
{
try
{
boost::system::error_code ec;
boost::asio::streambuf sbuffer;
boost::asio::read_until(* sock, sbuffer, "\0", ec );
const char* header=boost::asio::buffer_cast<const char*>(sbuffer.data());
std::string reqStr(header,header+sbuffer.size());
sbuffer.consume(sbuffer.size());
std::vector<std::string> strs;
strs = dssplit(reqStr,' ');
if(strs.size()>1)
{
std::string requesturl = urldecode(strs[1]);
std::vector<std::string> splited=dssplit(requesturl,'/');
removeEmptyStrings(splited);
if(splited.size()==1)
{
if(startswith(splited[0],"windows"))
{
handlewindows(sock);
}else if(startswith(splited[0],"info"))
{
handleinfo(sock);
}else if(hasEnding(splited[0],".mjpg"))
{
handlemjpeg(sock,splited[0].substr(0,splited[0].size()-5));
}else if(hasEnding(splited[0],".jpg") || splited[0].find(".jpg?")!=string::npos)
{
handlejpg(sock,splited[0]);
}else
{
handle404(sock);
}
}else
{
handle404(sock);
}
sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
}
}catch(const std::exception& ex)
{
boost::system::error_code ec;
boost::asio::ip::tcp::endpoint endpoint = sock->remote_endpoint(ec);
if(!ec)
{
sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
//DPRINTERR(ex.what());
}catch(const std::string& ex)
{
boost::system::error_code ec;
boost::asio::ip::tcp::endpoint endpoint = sock->remote_endpoint(ec);
if(!ec)
{
sock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
}
}
void HttpServer::handleinfo(socket_ptr sock)
{
boost::system::error_code error;
boost::asio::streambuf sbuffer;
std::ostream response_stream(&sbuffer);
string retstr;
for (std::map<std::string,std::string>::iterator it=winnames.begin(); it!=winnames.end(); ++it)
{
string wname =it->first;
int rcnt = 0;
if(requestcounts.find(wname)!=requestcounts.end())
{
rcnt=requestcounts[wname];
}
retstr+=boost::str(boost::format("{"
"\"name\":\"%s\","
"\"reqCnt\":%d,"
"\"size\":\"%s\""
"},"
)
%wname
%rcnt
%it->second
);
}
if(retstr.size()>0) retstr.resize(retstr.size()-1);
retstr=boost::str(boost::format("{"
"\"windows\":[%s],"
"\"version\":\"%s\","
"\"fps\":%s"
"}"
)
%retstr
%"0.0"
% to_string(0.)
);
response_stream << "HTTP/1.1 200 OK\r\n";
response_stream << "Access-Control-Allow-Origin: *\r\n";
response_stream << "Content-Type: text/plain\r\n\r\n";
response_stream << retstr << "\r\n\r\n";
boost::asio::write(*sock, sbuffer);
}
void HttpServer::handlewindows(socket_ptr sock)
{
boost::system::error_code error;
boost::asio::streambuf sbuffer;
std::ostream response_stream(&sbuffer);
string retstr;
for (std::map<std::string,std::string>::iterator it=winnames.begin(); it!=winnames.end(); ++it)
{
string wname =it->first;
int rcnt = 0;
if(requestcounts.find(wname)!=requestcounts.end())
{
rcnt=requestcounts[wname];
}
retstr+=boost::str(boost::format("{"
"\"name\":\"%s\","
"\"reqCnt\":%d,"
"\"size\":\"%s\""
"},"
)
%wname
%rcnt
%it->second
);
}
if(retstr.size()>0) retstr.resize(retstr.size()-1);
retstr="{\"windows\":["+retstr+"]}";
response_stream<<"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n\r\n"<<
retstr<<"\r\n\r\n";
boost::asio::write(*sock, sbuffer);
}
void HttpServer::handlemjpeg(socket_ptr sock,std::string winname)
{
if(requestcounts.find(winname)==requestcounts.end())
{
handle404(sock);
return;
}
std::string frame=winname;
//boost::shared_lock<boost::shared_mutex> lock(mut);
//lock.lock();
requestcounts[frame]++;
//lock.unlock();
boost::system::error_code error;
boost::asio::streambuf sbuffer;
std::ostream response_stream(&sbuffer);
response_stream<<"HTTP/1.1 200 OK\r\n";
response_stream<<"Content-Type: multipart/mixed;boundary=b\r\n";
response_stream<<"Cache-Control: no-store\r\n";
response_stream<<"Pragma: no-cache\r\n";
response_stream<<"Audio Mode : None\r\n";
response_stream<<"Connection: close\r\n";
response_stream<<"\r\n";
boost::asio::write(*sock, sbuffer);
for(;;)
{
try
{
if( (jpegbuffers.count(frame)<0 ||
jpegbuffers[frame].size()<4) ||
(jpegbuffers[frame][0]!=0xff && jpegbuffers[frame][1]!=0xd8 &&
jpegbuffers[frame][jpegbuffers[frame].size()-2]!=0xff && jpegbuffers[frame][jpegbuffers[frame]. size()-1]!=0xd9))
{
SLEEP(10);
continue;
}
//boost::shared_lock<boost::shared_mutex> lock(mut);
response_stream<<"--b\r\n";
response_stream<<"Content-Type: image/jpeg\r\n";
response_stream<<"Content-length: "<<jpegbuffers[frame].size()<<"\r\n";
response_stream<<"\r\n";
boost::asio::write(*sock, sbuffer);
boost::asio::write(*sock,boost::asio::buffer(jpegbuffers[frame], jpegbuffers[frame].size()));
//lock.unlock();
SLEEP(httpdelay);
}
catch (std::exception& e)
{
SLEEP(50);
//lock.lock();
requestcounts[frame]--;
//lock.unlock();
return;
}
}
//lock.lock();
requestcounts[frame]--;
//lock.unlock();
}
void HttpServer::handlejpg(socket_ptr sock,std::string winname)
{
if(winname.find("?")!=string::npos)
{
winname = winname.substr(0,winname.find("?"));
}
winname =winname.substr(0,winname.size()-4);
std::string frame=winname;
requestcounts[frame]++;
boost::system::error_code error;
boost::asio::streambuf sbuffer;
std::ostream response_stream(&sbuffer);
jpegbuffers[frame].clear();
for(;;)
{
try
{
if( (jpegbuffers.count(frame)<0 ||
jpegbuffers[frame].size()<4) ||
(jpegbuffers[frame][0]!=0xff && jpegbuffers[frame][1]!=0xd8 &&
jpegbuffers[frame][jpegbuffers[frame].size()-2]!=0xff && jpegbuffers[frame][jpegbuffers[frame]. size()-1]!=0xd9))
{
SLEEP(10);
continue;
}
response_stream<<"HTTP/1.1 200 OK\r\n";
response_stream<<"Content-Type: image/jpeg\r\n";
response_stream<<"Cache-Control: no-store\r\n";
response_stream<<"Access-Control-Allow-Origin: *\r\n";
response_stream<<"Pragma: no-cache\r\n";
response_stream<<"Content-length: "<<jpegbuffers[frame].size()<<"\r\n";
response_stream<<"Connection: close\r\n";
response_stream<<"\r\n";
boost::asio::write(*sock, sbuffer);
boost::asio::write(*sock,boost::asio::buffer(jpegbuffers[frame], jpegbuffers[frame].size()));
break;
}
catch (std::exception& e)
{
//DPRINTERR( "net exceptoin:"+std::string(e.what()));
SLEEP(50);
requestcounts[frame]--;
return;
}
}
requestcounts[frame]--;
}
void HttpServer::handle404(socket_ptr sock)
{
boost::system::error_code error;
boost::asio::streambuf sbuffer;
std::ostream response_stream(&sbuffer);
response_stream<<"HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"Content-Length: 132\r\n\r\n"
"<html>\r\n"
"<head><title>404 Not Found</title></head>\r\n"
"<body bgcolor=\"white\">\r\n"
"<center><h1>404 Not Found</h1></center>\r\n"
"</body>\r\n"
"</html>\r\n";
boost::asio::write(*sock, sbuffer);
}
Main.cpp
#include <opencv2/opencv.hpp>
#include "http_server.hpp"
#include <iostream>
#include <fstream>
using namespace cv;
#define MJPGFILE_BUFFER_SIZE 10240
class MjpgFileCapture{
public:
static double lastframeseen;
MjpgFileCapture() {};
MjpgFileCapture(std::string filepath)
{
filepath_ = filepath;
is_inited_ = false;
skip_ = true;
imgready_ = false;
ff_ = false;
readbytes_ = -2;
i_ = 0;
};
void init();
MjpgFileCapture& operator >>(cv::Mat& out);
private:
std::string filepath_;
bool is_inited_;
std::ifstream ifstream_;
std::vector<char> data_;
bool skip_;
bool imgready_;
bool ff_;//have we seen ff byte?
long long readbytes_;
char ca_[MJPGFILE_BUFFER_SIZE];
int i_;//loop index
};
void MjpgFileCapture::init()
{
is_inited_ = true;
ifstream_ = std::ifstream(filepath_.c_str(), std::ios::binary);
}
MjpgFileCapture& MjpgFileCapture::operator >> (cv::Mat& out)
{
out = Mat();
if (!is_inited_)
{
init();
}
while (1)
{
uchar c;
if (readbytes_ != 0 && readbytes_ != -1)
{
if (i_ >= readbytes_)
{
ifstream_.read(ca_, MJPGFILE_BUFFER_SIZE);
readbytes_ = ifstream_.gcount();
i_ = 0;
}
for (; i_ < readbytes_; i_++)
{
c = ca_[i_];
if (ff_ && c == 0xd8)
{
skip_ = false;
data_.push_back((uchar)0xff);
}
if (ff_ && c == 0xd9)
{
imgready_ = true;
data_.push_back((uchar)0xd9);
skip_ = true;
}
ff_ = c == 0xff;
if (!skip_)
{
data_.push_back(c);
}
if (imgready_)
{
if (data_.size() != 0)
{
cv::Mat data_mat(data_);
cv::Mat frame(imdecode(data_mat, 1));
out = frame;
}
else
{
printf("warning:image is ready and data is empty. Likely bug.");
}
imgready_ = false;
skip_ = true;
data_.clear();
return *this;
}
}
}
else
{
//own exception class
throw std::string("zero byte read:probably end of file.");
}
}
return *this;
}
HttpServer* server = 0;
void file_loop()
{
MjpgFileCapture cap("C:/v/frame.mjpg");
while (true)
{
Mat im;
cap >> im;
server->IMSHOW("im", im);
imshow("im", im);
if (waitKey(1) == 27)
exit(0);
}
}
int main(int argc, char** argv)
{
server = new HttpServer;
//server->port = 8080;
server->run(8080);
while (true)
{
try{
file_loop();
}
catch (...)
{
}
}
return 0;
}
Usage
server->IMSHOW("im",mat);//register mat as window name im in server, accessible from browser as http://localhost:8080/im.jpg or http://localhost:8080/im.mjpg
http://localhost:8080/windows (show all registered windows)

XMPP Handshake Flow using Gloox C/C++

I am trying to perform XMPP Handshake Flow mentioned at https://developers.google.com/cloud-print/docs/rawxmpp.
This allows the device to subscribe and receive notifications.
As of now, I have explored the following options:
1) libcurl
2) Gloox C/C++
3) TXMPP
4) Libjingle
Which option would be a good choice to start with? I would like to consider support for and maintenance of the library as a major factor.
Following is my solution using Gloox C/C++ library to perform XMPP Handshake Flow:
#include <cassert>
#include <iostream>
#include <boost/make_shared.hpp>
#include <iq.h>
#include <parser.h>
#include <base64.h>
#include <connectiontcpclient.h>
#include <connectiontls.h>
#include <connectiondatahandler.h>
#include <connectionhttpproxy.h>
#include <logsink.h>
#include <client.h>
#include <connectionsocks5proxy.h>
using namespace gloox;
using namespace std;
const string proxyHost = ""; //specify proxy server name
const int proxyPort = 0; //specify proxy port number
const string xmppHost = "talk.google.com";
const int xmppPort = 5222;
Client *c;
ConnectionBase *client_ ;
ConnectionTCPClient* conn0;
ConnectionHTTPProxy* conn2;
class Bot: public ConnectionDataHandler, TagHandler, TLSHandler{
public:
Bot(): parser_(this)
{
conn0 = new ConnectionTCPClient(this, log_, proxyHost, proxyPort);
ConnectionHTTPProxy* conn2 = new ConnectionHTTPProxy( this, conn0, log_, xmppHost, xmppPort);
client_ = conn0;
ConnectionError ce = ConnNoError;
ce = conn2->connect();
assert(ce == ConnNoError);
conn2->receive();
}
virtual void handleConnect(const ConnectionBase* con) {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
virtual void handleReceivedData(const ConnectionBase* con, const string& data) {
cerr << "[recv] " << data << endl;
string copied = data;
int pos = parser_.feed(copied);
assert(pos < 0);
}
virtual void handleTag(Tag* tag) {
if (tag->name() == "stream" && tag->xmlns() == "http://etherx.jabber.org/streams") {
sid_ = tag->findAttribute("id");
} else{
if (tag->name() == "features") {
if (tag->hasChild("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls")) {
send(Tag("starttls", "xmlns", "urn:ietf:params:xml:ns:xmpp-tls").xml());
}
else if (tag->hasChild("mechanisms", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl") && tag->findChild("mechanisms")->hasChildWithCData(
"mechanism", "X-OAUTH2"))
{
Tag a("auth", "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
a.addAttribute("mechanism", "X-OAUTH2");
a.addAttribute("service", "chromiumsync");
a.addAttribute("allow-generated-jid", "true");
a.addAttribute("client-uses-full-bind-result", "true");
a.addAttribute("auth", "http://www.google.com/talk/protocol/auth");
string credential;
credential.append("\0", 1);
credential.append(""); //Specify Bare JID
credential.append("\0", 1);
credential.append(""); //Specify Access Token
a.setCData(Base64::encode64(credential));
send(a.xml());
}
else if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
Tag iq("iq", "xmlns", "jabber:client");
iq.addAttribute("type", "set");
iq.addAttribute("id", "0");
Tag *bind = new Tag("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind");
Tag *resource = new Tag("resource");
resource->setCData("GCPResource");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
else if (tag->name() == "proceed" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-tls") {
ConnectionTLS* encryption_client = new ConnectionTLS(this, conn0, log_);
encryption_client->registerTLSHandler(this);
client_ = encryption_client;
ConnectionError ret = encryption_client->connect();
assert(ret == ConnNoError);
}
else if (tag->name() == "success" && tag->xmlns() == "urn:ietf:params:xml:ns:xmpp-sasl") {
send("<stream:stream to=\"gmail.com\" xml:lang=\"en\" version=\"1.0\" xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"jabber:client\">\r\n");
}
else if (tag->name() == "iq") {
if (tag->hasChild("bind", "xmlns", "urn:ietf:params:xml:ns:xmpp-bind")) {
resource_ = tag->findChild("bind")->findChild("jid")->cdata();
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("id", "1");
iq.addChild(new Tag("session", "xmlns", "urn:ietf:params:xml:ns:xmpp-session"));
send(iq.xml());
//Step 2: Subscribing for notifications
if (tag->hasAttribute("type", "result")) {
Tag iq("iq");
iq.addAttribute("type", "set");
iq.addAttribute("to", ""); //Specify Bare JID
iq.addAttribute("id", "3");
Tag *bind = new Tag("subscribe", "xmlns", "google:push");
Tag *resource = new Tag("item");
resource->addAttribute("channel", "cloudprint.google.com");
resource->addAttribute("from", "cloudprint.google.com");
bind->addChild(resource);
iq.addChild(bind);
send(iq.xml());
}
}
}
}
}
virtual void handleEncryptedData(const TLSBase* tls,
const string& data) {
cout << "handleEncryptedData" << endl;
}
virtual void handleDecryptedData(const TLSBase* tls,
const string& data) {
cout << "handleDecryptedData" << endl;
}
virtual void handleHandshakeResult(const TLSBase* tls, bool,
CertInfo& cert) {
cout << "handleHandshakeResult" << endl;
}
virtual void handleDisconnect(const ConnectionBase* con, ConnectionError) {
cout << "handleDisconnect" << endl;
}
private:
LogSink log_;
string sid_;
string resource_;
Parser parser_;
ConnectionBase *client_;
void send(const string &data) {
cerr << "[send] " << data << endl;
client_->send(data);
}
};
int main() {
Bot bot;
}