Initial commit
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
*.o
|
||||||
|
.*.swp
|
||||||
|
AlarmServer
|
||||||
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string base64_encode(unsigned char const* , unsigned int len);
|
||||||
|
std::string base64_decode(std::string const& s);
|
||||||
|
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user