Initial commit

This commit is contained in:
2017-04-28 18:45:26 +02:00
commit 37fe983738
23 changed files with 1319 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
*.o
.*.swp
AlarmServer
+51
View File
@@ -0,0 +1,51 @@
CC := g++
CFLAGS := -O3
LFLAGS := -L/opt/lib -lpthread -lcrypto -lcurl -lboost_regex -lboost_filesystem -lboost_system -ljpeg
ifeq ($(BUILD),debug)
# Debug flags
CFLAGS += -O0 -g
endif
ifeq ($(BUILD),release)
# Optimization flags valid for Intel Atom (DS1813+)
CFLAGS += -march=prescott -mtune=pentium -mfpmath=sse -O3 -s -DNDEBUG
endif
%.o: %.cpp
$(CC) -c $(CFLAGS) $< -o $@
AlarmServer: main.cpp server.o connection.o protocol.o message.o mimeImage.o outputImage.o inputImage.o util.o httpClient.o base64.o
g++ -o AlarmServer main.cpp server.o connection.o protocol.o message.o mimeImage.o outputImage.o inputImage.o util.o httpClient.o base64.o $(LFLAGS) $(LDFLAGS) $(CFLAGS)
server.o: server.cpp server.h connection.h protocol.h util.h httpClient.h
connection.o: connection.cpp connection.h protocol.h util.h httpClient.h
protocol.o: protocol.cpp protocol.h util.h httpClient.h
message.o: message.cpp message.h mimeImage.h outputImage.h inputImage.h util.h httpClient.h base64.h
mimeImage.o: mimeImage.cpp mimeImage.h outputImage.h inputImage.h base64.h
outputImage.o: outputImage.cpp outputImage.h inputImage.h
inputImage.o: inputImage.cpp inputImage.h
util.o: util.cpp util.h httpClient.h
httpClient.o: httpClient.cpp httpClient.h
base64.o: base64.cpp base64.h
all: AlarmServer
debug:
make "BUILD=debug"
release:
make "BUILD=release"
clean:
-rm *.o AlarmServer
+123
View File
@@ -0,0 +1,123 @@
/*
base64.cpp and base64.h
Copyright (C) 2004-2008 René Nyffenegger
This source code is provided 'as-is', without any express or implied
warranty. In no event will the author be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this source code must not be misrepresented; you must not
claim that you wrote the original source code. If you use this source code
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original source code.
3. This notice may not be removed or altered from any source distribution.
René Nyffenegger rene.nyffenegger@adp-gmbh.ch
*/
#include "base64.h"
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(std::string const& encoded_string) {
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
+5
View File
@@ -0,0 +1,5 @@
#include <string>
std::string base64_encode(unsigned char const* , unsigned int len);
std::string base64_decode(std::string const& s);
+59
View File
@@ -0,0 +1,59 @@
#include <boost/asio/write.hpp>
#include <boost/bind.hpp>
#include "connection.h"
connection::connection(boost::asio::io_service& ioService, const context& context) :
m_ioService(ioService),
m_socket(ioService),
m_protocol(context)
{
}
boost::asio::ip::tcp::socket& connection::socket()
{
return m_socket;
}
void connection::start()
{
start_write(m_protocol.openConnection(m_socket.remote_endpoint().address().to_string()).second);
}
void connection::start_read()
{
m_socket.async_read_some(boost::asio::buffer(m_data), boost::bind(&connection::handle_read, this, _1, _2));
}
void connection::handle_read(const boost::system::error_code& ec, std::size_t length)
{
if (!ec)
{
protocol::result result = m_protocol.processMessage(std::string(m_data.begin(), m_data.begin() + length));
if (result.second.size() > 0)
start_write(result.second);
else
start_read();
if (result.first == protocol::state::disconnected)
m_socket.close();
}
}
void connection::start_write(const std::string& message)
{
std::copy(message.begin(), message.end(), m_data.data());
size_t length = message.size() + 1;
m_data[message.size()] = '\n';
boost::asio::async_write(m_socket, boost::asio::buffer(m_data, length), boost::bind(&connection::handle_write, this, _1));
}
void connection::handle_write(const boost::system::error_code& ec)
{
if (!ec)
start_read();
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef CONNECTION_H
#define CONNECTION_H
#include <string>
#include <boost/noncopyable.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/array.hpp>
#include "protocol.h"
#include "util.h"
class connection : private boost::noncopyable
{
public:
connection(boost::asio::io_service& ioService, const context& context);
boost::asio::ip::tcp::socket& socket();
void start();
private:
void start_read();
void handle_read(const boost::system::error_code& ec, std::size_t length);
void start_write(const std::string& message);
void handle_write(const boost::system::error_code& ec);
boost::asio::io_service& m_ioService;
boost::asio::ip::tcp::socket m_socket;
boost::array<char, 1024> m_data;
protocol m_protocol;
};
#endif // CONNECTION_H
+57
View File
@@ -0,0 +1,57 @@
#include "httpClient.h"
httpClient::httpClient()
{
curl_global_init(CURL_GLOBAL_ALL);
m_userAgents.push_back("Opera/9.80 (X11; Linux i686; U; en) Presto/2.7.62 Version/11.00");
initialize_locks();
}
httpClient::~httpClient()
{
free_locks();
curl_global_cleanup();
}
std::string httpClient::GetUrlContents(const std::string& url) const
{
std::string buffer;
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_USERAGENT, m_userAgents[rand() % m_userAgents.size()].c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
int code = 0;
curl_easy_perform(curl);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
curl_easy_cleanup(curl);
if (code != 200)
{
std::stringstream error;
error << "Error encountered while retrieving " << url;
throw std::runtime_error(error.str());
}
return buffer;
}
size_t httpClient::WriteCallback(char* data, size_t size, size_t nmemb, std::string* writerData)
{
if (writerData == NULL)
return 0;
writerData->append(data, size * nmemb);
return size * nmemb;
}
+59
View File
@@ -0,0 +1,59 @@
#ifndef HTTPCLIENT_H
#define HTTPCLIENT_H
#include <string>
#include <vector>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <curl/curl.h>
static std::vector<boost::shared_ptr<boost::mutex> > g_mutexes;
static void lock_callback(int mode, int type, const char *file, int line)
{
if (mode & CRYPTO_LOCK)
g_mutexes[type]->lock();
else
g_mutexes[type]->unlock();
}
static unsigned long thread_id(void)
{
return (unsigned long)pthread_self();
}
static void initialize_locks(void)
{
g_mutexes.resize(CRYPTO_num_locks());
for (int i = 0; i < CRYPTO_num_locks(); ++i)
g_mutexes[i] = boost::shared_ptr<boost::mutex>(new boost::mutex());
CRYPTO_set_id_callback(thread_id);
CRYPTO_set_locking_callback(lock_callback);
}
static void free_locks(void)
{
CRYPTO_set_locking_callback(NULL);
}
class httpClient : boost::noncopyable
{
public:
httpClient();
~httpClient();
std::string GetUrlContents(const std::string& url) const;
private:
static size_t WriteCallback(char* data, size_t size, size_t nmemb, std::string* writerData);
private:
std::vector<std::string> m_userAgents;
};
#endif // HTTPCLIENT_H
+120
View File
@@ -0,0 +1,120 @@
#include "inputImage.h"
const static JOCTET EOI_BUFFER[1] = { JPEG_EOI };
inputImage::inputImage()
{
}
void inputImage::setImageData(const std::string& data)
{
decompressImage(data.c_str(), data.size());
}
unsigned int inputImage::width() const
{
return m_width;
}
unsigned int inputImage::height() const
{
return m_height;
}
unsigned int inputImage::strideX() const
{
return m_strideX;
}
unsigned int inputImage::strideY() const
{
return m_strideY;
}
const std::vector<char>& inputImage::data() const
{
return m_data;
}
void inputImage::init_source(j_decompress_ptr pCinfo)
{
}
boolean inputImage::fill_input_buffer(j_decompress_ptr pCinfo)
{
source_mgr_ptr pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
pSrc->pub.next_input_byte = EOI_BUFFER;
pSrc->pub.bytes_in_buffer = 1;
return TRUE;
}
void inputImage::skip_input_data(j_decompress_ptr pCinfo, long numBytes)
{
source_mgr_ptr pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
if (pSrc->pub.bytes_in_buffer < numBytes)
{
pSrc->pub.next_input_byte = EOI_BUFFER;
pSrc->pub.bytes_in_buffer = 1;
}
else
{
pSrc->pub.next_input_byte += numBytes;
pSrc->pub.bytes_in_buffer -= numBytes;
}
}
void inputImage::term_source(j_decompress_ptr pCinfo)
{
}
void inputImage::setSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const
{
source_mgr_ptr pSrc;
if (pCinfo->src == 0)
pCinfo->src = (struct jpeg_source_mgr *)(*pCinfo->mem->alloc_small)(reinterpret_cast<j_common_ptr>(pCinfo), JPOOL_PERMANENT, sizeof(source_mgr));
pSrc = reinterpret_cast<source_mgr_ptr>(pCinfo->src);
pSrc->pub.init_source = inputImage::init_source;
pSrc->pub.fill_input_buffer = inputImage::fill_input_buffer;
pSrc->pub.skip_input_data = inputImage::skip_input_data;
pSrc->pub.resync_to_restart = jpeg_resync_to_restart;
pSrc->pub.term_source = inputImage::term_source;
pSrc->data = (const JOCTET *)pData;
pSrc->len = len;
pSrc->pub.bytes_in_buffer = len;
pSrc->pub.next_input_byte = pSrc->data;
}
void inputImage::decompressImage(const char* pData, size_t len)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
jerr.trace_level = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
setSourceMgr(&cinfo, pData, len);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
m_width = cinfo.image_width;
m_height = cinfo.image_height;
m_strideX = cinfo.num_components;
m_strideY = m_width * cinfo.num_components;
m_data.resize(m_height * m_strideY);
JSAMPROW scanlines[1];
while (cinfo.output_scanline < cinfo.image_height)
{
scanlines[0] = reinterpret_cast<JSAMPROW>(&m_data[cinfo.output_scanline * m_strideY]);
jpeg_read_scanlines(&cinfo, scanlines, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
}
+50
View File
@@ -0,0 +1,50 @@
#ifndef INPUTIMAGE_H
#define INPUTIMAGE_H
#include <string>
#include <vector>
#include <jpeglib.h>
class inputImage
{
public:
inputImage();
void setImageData(const std::string& data);
unsigned int width() const;
unsigned int height() const;
unsigned int strideX() const;
unsigned int strideY() const;
const std::vector<char>& data() const;
private:
struct source_mgr
{
struct jpeg_source_mgr pub;
const JOCTET *data;
size_t len;
};
typedef source_mgr* source_mgr_ptr;
private:
static void init_source(j_decompress_ptr pCinfo);
static boolean fill_input_buffer(j_decompress_ptr pCinfo);
static void skip_input_data(j_decompress_ptr pCinfo, long numBytes);
static void term_source(j_decompress_ptr pCinfo);
void setSourceMgr(j_decompress_ptr pCinfo, const char* pData, size_t len) const;
void decompressImage(const char* pData, size_t len);
private:
unsigned int m_width;
unsigned int m_height;
unsigned int m_strideX;
unsigned int m_strideY;
std::vector<char> m_data;
};
#endif // INPUTIMAGE_H
+49
View File
@@ -0,0 +1,49 @@
#include <iostream>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "server.h"
int main(int argc, char* argv[])
{
try
{
/* error checking elided for brevity */
int fd = ::open("/dev/null", O_WRONLY);
::dup2(fd, 2);
::close(fd);
unsigned int port;
std::string path;
std::string url;
if (argc == 3)
{
port = std::atoi(argv[1]);
path = std::string(argv[2]);
}
else if (argc == 4)
{
port = std::atoi(argv[1]);
path = std::string(argv[2]);
url = std::string(argv[3]);
}
else
{
std::cout << "Usage: AlarmServer <port> <path> [url]\n";
return 1;
}
boost::asio::io_service io_service;
server s(io_service, port, path, url);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << std::endl;
}
}
+188
View File
@@ -0,0 +1,188 @@
#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "outputImage.h"
#include "base64.h"
#include "message.h"
message::message(const std::string& address, const context& context, const std::string& message) :
m_address(address),
m_context(context),
m_mimeBoundary("-_-InvalidBoundary-_-"),
m_contentEncoding("none"),
m_currentImage(0)
{
processMessage(message);
}
std::string Decode(const std::string& data)
{
std::string result;
if (boost::istarts_with(data, "=?utf-8?"))
result = base64_decode(std::string(data.begin() + 10, data.begin() + data.find_last_of('?')));
else
result = base64_decode(data);
return result;
}
void message::processMessage(const std::string& message)
{
message::state::type state = message::state::header;
std::string line;
std::istringstream stream(message);
while (std::getline(stream, line, '\r'))
{
boost::erase_all(line, "\n");
switch (state)
{
case state::header:
state = processHeaderLine(line);
break;
case state::data:
state = processDataLine(line);
break;
case state::mimeBoundary:
state = processMimeBoundary(line);
break;
case state::image:
state = processImage(line);
break;
}
}
if (boost::algorithm::contains(m_contentEncoding, "base64"))
{
std::string decoded = Decode(m_subject);
if (decoded.size() > 0)
m_subject = decoded;
}
outputImage image(m_images);
boost::filesystem::path path(m_context.path);
path = boost::filesystem::canonical(path);
path /= m_address;
if (!boost::filesystem::exists(path))
boost::filesystem::create_directory(path);
std::string fileName(getTimeString());
fileName.append(".jpg");
path /= fileName;
image.save(path.string());
if (!m_context.url.empty())
{
std::stringstream url;
url << m_context.url << "?ip=" << m_address << "&file=" << fileName;
m_context.client.GetUrlContents(url.str());
}
}
message::state::type message::processHeaderLine(const std::string& line)
{
if (line.empty())
return message::state::data;
if (boost::istarts_with(line, "from:"))
{
m_sender = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "to:"))
{
m_receiver = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "subject:"))
{
m_subject = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "date"))
{
m_date = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
if (boost::istarts_with(line, "boundary") || boost::istarts_with(line, "\tboundary") || boost::istarts_with(line, " boundary"))
{
m_mimeBoundary = std::string("--").append(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return message::state::header;
}
if (boost::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::header;
}
return message::state::header;
}
message::state::type message::processDataLine(const std::string& line)
{
if (boost::istarts_with(line, m_mimeBoundary))
{
m_contentType = "";
return message::state::mimeBoundary;
}
return message::state::data;
}
message::state::type message::processMimeBoundary(const std::string& line)
{
if (line.empty())
{
if (boost::istarts_with(m_contentType, "image/jpeg") || boost::istarts_with(m_contentType, "image/jpg"))
{
m_mimeImages.push_back(mimeImage(m_imageName));
m_imageName = "";
return message::state::image;
}
return message::state::data;
}
if (boost::istarts_with(line, "content-type:"))
{
m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::mimeBoundary;
}
if (boost::istarts_with(line, "name") || boost::istarts_with(line, "\tname"))
{
m_imageName = "image.jpg";
//m_imageName = Decode(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
return message::state::mimeBoundary;
}
if (boost::istarts_with(line, "content-transfer-encoding:"))
{
m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
return message::state::mimeBoundary;
}
return message::state::mimeBoundary;
}
message::state::type message::processImage(const std::string& line)
{
if (boost::istarts_with(line, m_mimeBoundary))
{
m_images.push_back(m_mimeImages[m_currentImage].decodeImageData());
++m_currentImage;
m_contentType = "";
return message::state::mimeBoundary;
}
m_mimeImages[m_currentImage].appendData(line);
return message::state::image;
}
+57
View File
@@ -0,0 +1,57 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include <string>
#include <vector>
#include "mimeImage.h"
#include "inputImage.h"
#include "util.h"
class message
{
public:
message(const std::string& address, const context& context, const std::string& message);
private:
class state
{
public:
enum type
{
header,
data,
mimeBoundary,
image
};
};
private:
void processMessage(const std::string& message);
state::type processHeaderLine(const std::string& line);
state::type processDataLine(const std::string& line);
state::type processMimeBoundary(const std::string& line);
state::type processImage(const std::string& line);
private:
std::string m_address;
const context& m_context;
std::string m_sender;
std::string m_receiver;
std::string m_subject;
std::string m_date;
std::string m_mimeBoundary;
std::string m_contentType;
std::string m_contentEncoding;
size_t m_currentImage;
std::string m_imageName;
std::vector<mimeImage> m_mimeImages;
std::vector<inputImage> m_images;
};
#endif // MESSAGE_H
+30
View File
@@ -0,0 +1,30 @@
#include <fstream>
#include <boost/algorithm/string.hpp>
#include "base64.h"
#include "mimeImage.h"
mimeImage::mimeImage()
{
}
mimeImage::mimeImage(const std::string& name) :
m_name(name)
{
}
void mimeImage::appendData(const std::string& data)
{
if (data.empty())
return;
m_imageData.append(data);
}
const inputImage& mimeImage::decodeImageData()
{
boost::erase_all(m_imageData, "\r");
m_inputImage.setImageData(base64_decode(m_imageData));
return m_inputImage;
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef MIMEIMAGE_H
#define MIMEIMAGE_H
#include "inputImage.h"
class mimeImage
{
public:
mimeImage();
mimeImage(const std::string& name);
void appendData(const std::string& data);
const inputImage& decodeImageData();
private:
std::string m_name;
std::string m_imageData;
inputImage m_inputImage;
};
#endif // MIMEIMAGE_H
+64
View File
@@ -0,0 +1,64 @@
#include <stdio.h>
#include "outputImage.h"
outputImage::outputImage(const std::vector<inputImage>& images) :
m_width(0),
m_height(0),
m_strideX(0),
m_strideY(0)
{
if (images.size() == 0)
return;
m_width = images[0].width();
m_strideX = images[0].strideX();
m_strideY = images[0].strideY();
size_t height = images[0].height();
m_height = height * images.size();
m_imageData.resize(m_strideY * m_height);
std::vector<char>::iterator outIterator = m_imageData.begin();
for (std::vector<inputImage>::const_iterator it = images.begin(); it != images.end(); ++it)
outIterator = std::copy(it->data().begin(), it->data().end(), outIterator);
}
void outputImage::save(const std::string& fileName)
{
if (m_width == 0 || m_height == 0 || m_strideX == 0 || m_strideY == 0)
return;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE* outFile = fopen(fileName.c_str(), "wb");
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outFile);
cinfo.image_width = m_width;
cinfo.image_height = m_height;
cinfo.input_components = m_strideX;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults( &cinfo );
cinfo.num_components = 3;
cinfo.dct_method = JDCT_FLOAT;
jpeg_set_quality(&cinfo, 80, TRUE);
jpeg_start_compress( &cinfo, TRUE );
JSAMPROW scanlines[1];
while (cinfo.next_scanline < cinfo.image_height)
{
scanlines[0] = reinterpret_cast<JSAMPROW>(&m_imageData[cinfo.next_scanline * m_strideY]);
jpeg_write_scanlines(&cinfo, scanlines, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
fclose(outFile);
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef OUTPUTIMAGE_H
#define OUTPUTIMAGE_H
#include <string>
#include <vector>
#include "inputImage.h"
class outputImage
{
public:
outputImage(const std::vector<inputImage>& images);
void save(const std::string& fileName);
private:
size_t m_width;
size_t m_height;
size_t m_strideX;
size_t m_strideY;
std::vector<char> m_imageData;
};
#endif // OUTPUTIMAGE_H
+111
View File
@@ -0,0 +1,111 @@
#include <iostream>
#include <boost/algorithm/string/predicate.hpp>
#include "message.h"
#include "protocol.h"
protocol::protocol(const context& context) :
m_internalState(internalState::none),
m_context(context)
{
}
protocol::result protocol::openConnection(const std::string& address)
{
m_address = address;
m_internalState = internalState::connect;
//std::cout << "Connection from " << address << std::endl;
return answer(protocol::state::connected, "220 AlarmServer");
}
protocol::result protocol::processMessage(const std::string& message)
{
if (m_internalState == internalState::data)
{
appendMessage(message);
if (boost::iends_with(message, ".\r\n"))
{
::message msg(m_address, m_context, m_message);
m_internalState = internalState::helo;
return answer(protocol::state::connected, "250 Ok");
}
return answer(protocol::state::connected, "");
}
//std::cout << "-> " << message << std::endl;
if (m_internalState == internalState::auth_login_user)
{
m_internalState = internalState::auth_login_pass;
return answer(protocol::state::connected, "334 UGFzc3dvcmQ6");
}
if (m_internalState == internalState::auth_login_pass)
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "235 2.7.0 Authentication successful");
}
if (boost::iequals(message, "quit\r\n"))
{
m_internalState = internalState::disconnect;
return answer(protocol::state::disconnected, "221 Bye");
}
if (boost::istarts_with(message, "helo"))
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (boost::istarts_with(message, "ehlo"))
{
m_internalState = internalState::helo;
return answer(protocol::state::connected, "250-AlarmServer\r\n250 AUTH LOGIN");
}
if (boost::istarts_with(message, "auth login"))
{
if (m_internalState != internalState::helo)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::auth_login_user;
return answer(protocol::state::connected, "334 VXNlcm5hbWU6");
}
if (boost::istarts_with(message, "mail from:"))
{
if (m_internalState != internalState::helo)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::mail_from;
return answer(protocol::state::connected, "250 Ok");
}
if (boost::istarts_with(message, "rcpt to:"))
{
if (m_internalState != internalState::mail_from)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::rcpt_to;
return answer(protocol::state::connected, "250 Ok");
}
if (boost::iequals(message, "data\r\n"))
{
if (m_internalState != internalState::rcpt_to)
return answer(protocol::state::connected, "503 Bad sequence of commands");
m_internalState = internalState::data;
return answer(protocol::state::connected, "354 Go ahead");
}
return answer(protocol::state::connected, "502 Error");
}
protocol::result protocol::answer(protocol::state::type state, std::string answer) const
{
/*
if (answer.size() > 0)
std::cout << "<- " << answer << std::endl;
*/
return result(state, answer);
}
void protocol::appendMessage(const std::string& message)
{
m_message.append(message);
m_message.append("\n");
}
+63
View File
@@ -0,0 +1,63 @@
#ifndef PROTOCOL_H
#define PROTOCOL_H
#include <string>
#include <utility>
#include "util.h"
class protocol
{
public:
class state
{
public:
enum type
{
connected,
disconnected
};
};
typedef std::pair<state::type, std::string> result;
public:
explicit protocol(const context& context);
result openConnection(const std::string& address);
result processMessage(const std::string& message);
private:
class internalState
{
public:
enum type
{
none,
connect,
helo,
auth_login_user,
auth_login_pass,
mail_from,
rcpt_to,
data,
mime_oundary,
image_data,
disconnect
};
};
private:
result answer(state::type state, std::string answer) const;
void appendMessage(const std::string& message);
private:
internalState::type m_internalState;
std::string m_address;
std::string m_message;
const context& m_context;
};
#endif // PROTOCOL_H
+75
View File
@@ -0,0 +1,75 @@
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <sys/wait.h>
#include "server.h"
server::server(boost::asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url) :
m_ioService(ioService),
m_signal(ioService, SIGCHLD),
m_acceptor(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port)),
m_socket(ioService)
{
m_context.path = path;
m_context.url = url;
start_signal_wait();
start_accept();
}
void server::start_signal_wait()
{
m_signal.async_wait(boost::bind(&server::handle_signal_wait, this));
}
void server::handle_signal_wait()
{
// Only the parent process should check for this signal. We can determine
// whether we are in the parent by checking if the acceptor is still open.
if (m_acceptor.is_open())
{
// Reap completed child processes so that we don't end up with zombies.
int status = 0;
while (waitpid(-1, &status, WNOHANG) > 0) {}
start_signal_wait();
}
}
void server::start_accept()
{
m_connection.reset(new connection(m_ioService, m_context));
m_acceptor.async_accept(m_connection->socket(), boost::bind(&server::handle_accept, this, _1));
}
void server::handle_accept(const boost::system::error_code& ec)
{
if (!ec)
{
m_ioService.notify_fork(boost::asio::io_service::fork_prepare);
if (fork() == 0)
{
m_ioService.notify_fork(boost::asio::io_service::fork_child);
m_acceptor.close();
m_signal.cancel();
m_connection->start();
}
else
{
m_ioService.notify_fork(boost::asio::io_service::fork_parent);
m_connection.reset();
m_socket.close();
start_accept();
}
}
else
{
std::cout << "Accept error: " << ec.message() << std::endl;
start_accept();
}
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef SERVER_H
#define SERVER_H
#include <string>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/shared_ptr.hpp>
#include "connection.h"
#include "util.h"
class server
{
public:
server(boost::asio::io_service& ioService, unsigned short port, const std::string& path, const std::string& url);
private:
void start_signal_wait();
void handle_signal_wait();
void start_accept();
void handle_accept(const boost::system::error_code& ec);
boost::asio::io_service& m_ioService;
boost::asio::signal_set m_signal;
boost::asio::ip::tcp::acceptor m_acceptor;
boost::asio::ip::tcp::socket m_socket;
boost::shared_ptr<connection> m_connection;
context m_context;
};
#endif // SERVER_H
+17
View File
@@ -0,0 +1,17 @@
#include <ctime>
#include <string>
#include "util.h"
std::string getTimeString()
{
time_t rawtime;
struct tm* timeinfo;
char buffer[80];
time (&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, 80, "%Y%m%d-%H%M%S", timeinfo);
return std::string(buffer);
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef UTIL_H
#define UTIL_H
#include <string>
#include "httpClient.h"
struct context
{
public:
std::string path;
httpClient client;
std::string url;
};
std::string getTimeString();
#endif // UTIL_H