Browse Source

Merge pull request #1 from PurpleI2P/openssl

upstream pull
pull/544/head
MXPLRS | Kirill 9 years ago committed by GitHub
parent
commit
124f9ec44e
  1. 2
      .travis.yml
  2. 17
      Base.cpp
  3. 11
      ChangeLog
  4. 99
      HTTPProxy.cpp
  5. 25
      HTTPProxy.h
  6. 2
      HTTPServer.cpp
  7. 2
      HTTPServer.h
  8. 14
      I2CP.cpp
  9. 16
      I2CP.h
  10. 2
      Makefile.linux
  11. 13
      Makefile.mingw
  12. 3
      Streaming.cpp
  13. 78
      UPnP.cpp
  14. 6
      UPnP.h
  15. 7
      docs/build_notes_windows.md
  16. 8
      docs/configuration.md
  17. 1
      qt/i2pd_qt/.gitignore
  18. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  19. 5
      qt/i2pd_qt/i2pd.qrc
  20. 48
      qt/i2pd_qt/i2pd_qt.pro
  21. BIN
      qt/i2pd_qt/images/icon.png
  22. 120
      qt/i2pd_qt/mainwindow.cpp
  23. 34
      qt/i2pd_qt/mainwindow.h
  24. 24
      qt/i2pd_qt/mainwindow.ui

2
.travis.yml

@ -30,7 +30,7 @@ before_install:
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink boost openssl && brew link boost openssl -f ; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew unlink boost openssl && brew link boost openssl -f ; fi
env: env:
matrix: matrix:
- BUILD_TYPE=Release UPNP=ON # - BUILD_TYPE=Release UPNP=ON
- BUILD_TYPE=Release UPNP=OFF - BUILD_TYPE=Release UPNP=OFF
script: script:
- cd build && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_UPNP=${UPNP} && make - cd build && cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DWITH_UPNP=${UPNP} && make

17
Base.cpp

@ -1,5 +1,4 @@
#include <stdlib.h> #include <stdlib.h>
#include "Log.h"
#include "Base.h" #include "Base.h"
namespace i2p namespace i2p
@ -305,13 +304,10 @@ namespace data
m_Inflator.next_out = out; m_Inflator.next_out = out;
m_Inflator.avail_out = outLen; m_Inflator.avail_out = outLen;
int err; int err;
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) {
return outLen - m_Inflator.avail_out; return outLen - m_Inflator.avail_out;
else
{
LogPrint (eLogError, "Decompression error ", err);
return 0;
} }
return 0;
} }
bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s) bool GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& s)
@ -328,12 +324,10 @@ namespace data
ret = inflate (&m_Inflator, Z_NO_FLUSH); ret = inflate (&m_Inflator, Z_NO_FLUSH);
if (ret < 0) if (ret < 0)
{ {
LogPrint (eLogError, "Decompression error ", ret);
inflateEnd (&m_Inflator); inflateEnd (&m_Inflator);
s.setstate(std::ios_base::failbit); s.setstate(std::ios_base::failbit);
break; break;
} }
else
s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); s.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
} }
while (!m_Inflator.avail_out); // more data to read while (!m_Inflator.avail_out); // more data to read
@ -377,14 +371,11 @@ namespace data
m_Deflator.next_out = out; m_Deflator.next_out = out;
m_Deflator.avail_out = outLen; m_Deflator.avail_out = outLen;
int err; int err;
if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) {
return outLen - m_Deflator.avail_out; return outLen - m_Deflator.avail_out;
else } /* else */
{
LogPrint (eLogError, "Compression error ", err);
return 0; return 0;
} }
}
} }
} }

11
ChangeLog

@ -1,14 +1,23 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.8.0] - UNRELEASED ## [2.9.0] - UNRELEASED
### Changed ### Changed
- Proxy refactoring & speedup - Proxy refactoring & speedup
## [2.8.0] - 2016-06-20
### Added
- Basic Android support
- I2CP implementation
- 'doxygen' target
### Changed
- I2PControl refactoring & fixes (proper jsonrpc responses on errors) - I2PControl refactoring & fixes (proper jsonrpc responses on errors)
- boost::regex no more needed - boost::regex no more needed
### Fixed ### Fixed
- initscripts: added openrc one, in sysv-ish make I2PD_PORT optional - initscripts: added openrc one, in sysv-ish make I2PD_PORT optional
- properly close NTCP sessions (memleak)
## [2.7.0] - 2016-05-18 ## [2.7.0] - 2016-05-18
### Added ### Added

99
HTTPProxy.cpp

@ -3,6 +3,13 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <string> #include <string>
#include <atomic> #include <atomic>
#include <memory>
#include <set>
#include <boost/asio.hpp>
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
#include "HTTPProxy.h" #include "HTTPProxy.h"
#include "util.h" #include "util.h"
#include "Identity.h" #include "Identity.h"
@ -13,13 +20,12 @@
#include "I2PTunnel.h" #include "I2PTunnel.h"
#include "Config.h" #include "Config.h"
#include "HTTP.h" #include "HTTP.h"
#include "HTTPServer.h"
namespace i2p namespace i2p {
{ namespace proxy {
namespace proxy
{
static const size_t http_buffer_size = 8192; static const size_t http_buffer_size = 8192;
class HTTPProxyHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPProxyHandler> class HTTPReqHandler: public i2p::client::I2PServiceHandler, public std::enable_shared_from_this<HTTPReqHandler>
{ {
private: private:
enum state enum state
@ -36,7 +42,7 @@ namespace proxy
void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered); void HandleSockRecv(const boost::system::error_code & ecode, std::size_t bytes_transfered);
void Terminate(); void Terminate();
void AsyncSockRead(); void AsyncSockRead();
void HTTPRequestFailed(/*std::string message*/); void HTTPRequestFailed(const char *message);
void RedirectToJumpService(); void RedirectToJumpService();
void ExtractRequest(); void ExtractRequest();
bool IsI2PAddress(); bool IsI2PAddress();
@ -59,26 +65,26 @@ namespace proxy
public: public:
HTTPProxyHandler(HTTPProxyServer * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) : HTTPReqHandler(HTTPProxy * parent, std::shared_ptr<boost::asio::ip::tcp::socket> sock) :
I2PServiceHandler(parent), m_sock(sock) I2PServiceHandler(parent), m_sock(sock)
{ EnterState(GET_METHOD); } { EnterState(GET_METHOD); }
~HTTPProxyHandler() { Terminate(); } ~HTTPReqHandler() { Terminate(); }
void Handle () { AsyncSockRead(); } void Handle () { AsyncSockRead(); }
}; };
void HTTPProxyHandler::AsyncSockRead() void HTTPReqHandler::AsyncSockRead()
{ {
LogPrint(eLogDebug, "HTTPProxy: async sock read"); LogPrint(eLogDebug, "HTTPProxy: async sock read");
if(m_sock) { if(m_sock) {
m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size), m_sock->async_receive(boost::asio::buffer(m_http_buff, http_buffer_size),
std::bind(&HTTPProxyHandler::HandleSockRecv, shared_from_this(), std::bind(&HTTPReqHandler::HandleSockRecv, shared_from_this(),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} else { } else {
LogPrint(eLogError, "HTTPProxy: no socket for read"); LogPrint(eLogError, "HTTPProxy: no socket for read");
} }
} }
void HTTPProxyHandler::Terminate() { void HTTPReqHandler::Terminate() {
if (Kill()) return; if (Kill()) return;
if (m_sock) if (m_sock)
{ {
@ -91,30 +97,34 @@ namespace proxy
/* All hope is lost beyond this point */ /* All hope is lost beyond this point */
//TODO: handle this apropriately //TODO: handle this apropriately
void HTTPProxyHandler::HTTPRequestFailed(/*HTTPProxyHandler::errTypes error*/) void HTTPReqHandler::HTTPRequestFailed(const char *message)
{ {
static std::string response = "HTTP/1.0 500 Internal Server Error\r\nContent-type: text/html\r\nContent-length: 0\r\n\r\n"; std::size_t size = std::strlen(message);
boost::asio::async_write(*m_sock, boost::asio::buffer(response,response.size()), std::stringstream ss;
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1)); ss << "HTTP/1.0 500 Internal Server Error\r\n"
<< "Content-Type: text/plain\r\n";
ss << "Content-Length: " << std::to_string(size + 2) << "\r\n"
<< "\r\n"; /* end of headers */
ss << message << "\r\n";
std::string response = ss.str();
boost::asio::async_write(*m_sock, boost::asio::buffer(response),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
void HTTPProxyHandler::RedirectToJumpService(/*HTTPProxyHandler::errTypes error*/) void HTTPReqHandler::RedirectToJumpService(/*HTTPReqHandler::errTypes error*/)
{ {
std::stringstream response; std::stringstream ss;
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); i2p::http::ShowJumpServices (ss, m_address);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); boost::asio::async_write(*m_sock, boost::asio::buffer(ss.str ()),
std::bind(&HTTPReqHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
response << "HTTP/1.1 302 Found\r\nLocation: http://" << httpAddr << ":" << httpPort << "/?page=jumpservices&address=" << m_address << "\r\n\r\n";
boost::asio::async_write(*m_sock, boost::asio::buffer(response.str (),response.str ().length ()),
std::bind(&HTTPProxyHandler::SentHTTPFailed, shared_from_this(), std::placeholders::_1));
} }
void HTTPProxyHandler::EnterState(HTTPProxyHandler::state nstate) void HTTPReqHandler::EnterState(HTTPReqHandler::state nstate)
{ {
m_state = nstate; m_state = nstate;
} }
void HTTPProxyHandler::ExtractRequest() void HTTPReqHandler::ExtractRequest()
{ {
LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url); LogPrint(eLogDebug, "HTTPProxy: request: ", m_method, " ", m_url);
i2p::http::URL url; i2p::http::URL url;
@ -127,18 +137,18 @@ namespace proxy
LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path); LogPrint(eLogDebug, "HTTPProxy: server: ", m_address, ", port: ", m_port, ", path: ", m_path);
} }
bool HTTPProxyHandler::ValidateHTTPRequest() bool HTTPReqHandler::ValidateHTTPRequest()
{ {
if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" ) if ( m_version != "HTTP/1.0" && m_version != "HTTP/1.1" )
{ {
LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version); LogPrint(eLogError, "HTTPProxy: unsupported version: ", m_version);
HTTPRequestFailed(); //TODO: send right stuff HTTPRequestFailed("unsupported HTTP version");
return false; return false;
} }
return true; return true;
} }
void HTTPProxyHandler::HandleJumpServices() void HTTPReqHandler::HandleJumpServices()
{ {
static const char * helpermark1 = "?i2paddresshelper="; static const char * helpermark1 = "?i2paddresshelper=";
static const char * helpermark2 = "&i2paddresshelper="; static const char * helpermark2 = "&i2paddresshelper=";
@ -170,7 +180,7 @@ namespace proxy
m_path.erase(addressHelperPos); m_path.erase(addressHelperPos);
} }
bool HTTPProxyHandler::IsI2PAddress() bool HTTPReqHandler::IsI2PAddress()
{ {
auto pos = m_address.rfind (".i2p"); auto pos = m_address.rfind (".i2p");
if (pos != std::string::npos && (pos+4) == m_address.length ()) if (pos != std::string::npos && (pos+4) == m_address.length ())
@ -180,7 +190,7 @@ namespace proxy
return false; return false;
} }
bool HTTPProxyHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len) bool HTTPReqHandler::CreateHTTPRequest(uint8_t *http_buff, std::size_t len)
{ {
ExtractRequest(); //TODO: parse earlier ExtractRequest(); //TODO: parse earlier
if (!ValidateHTTPRequest()) return false; if (!ValidateHTTPRequest()) return false;
@ -235,7 +245,7 @@ namespace proxy
return true; return true;
} }
bool HTTPProxyHandler::HandleData(uint8_t *http_buff, std::size_t len) bool HTTPReqHandler::HandleData(uint8_t *http_buff, std::size_t len)
{ {
while (len > 0) while (len > 0)
{ {
@ -269,13 +279,13 @@ namespace proxy
case '\n': EnterState(DONE); break; case '\n': EnterState(DONE); break;
default: default:
LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff)); LogPrint(eLogError, "HTTPProxy: rejected invalid request ending with: ", ((int)*http_buff));
HTTPRequestFailed(); //TODO: add correct code HTTPRequestFailed("rejected invalid request");
return false; return false;
} }
break; break;
default: default:
LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state); LogPrint(eLogError, "HTTPProxy: invalid state: ", m_state);
HTTPRequestFailed(); //TODO: add correct code 500 HTTPRequestFailed("invalid parser state");
return false; return false;
} }
http_buff++; http_buff++;
@ -286,7 +296,7 @@ namespace proxy
return true; return true;
} }
void HTTPProxyHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len) void HTTPReqHandler::HandleSockRecv(const boost::system::error_code & ecode, std::size_t len)
{ {
LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes"); LogPrint(eLogDebug, "HTTPProxy: sock recv: ", len, " bytes");
if(ecode) if(ecode)
@ -301,7 +311,7 @@ namespace proxy
if (m_state == DONE) if (m_state == DONE)
{ {
LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url); LogPrint(eLogDebug, "HTTPProxy: requested: ", m_url);
GetOwner()->CreateStream (std::bind (&HTTPProxyHandler::HandleStreamRequestComplete, GetOwner()->CreateStream (std::bind (&HTTPReqHandler::HandleStreamRequestComplete,
shared_from_this(), std::placeholders::_1), m_address, m_port); shared_from_this(), std::placeholders::_1), m_address, m_port);
} }
else else
@ -310,14 +320,14 @@ namespace proxy
} }
void HTTPProxyHandler::SentHTTPFailed(const boost::system::error_code & ecode) void HTTPReqHandler::SentHTTPFailed(const boost::system::error_code & ecode)
{ {
if (ecode) if (ecode)
LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ()); LogPrint (eLogError, "HTTPProxy: Closing socket after sending failure because: ", ecode.message ());
Terminate(); Terminate();
} }
void HTTPProxyHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream) void HTTPReqHandler::HandleStreamRequestComplete (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {
@ -331,19 +341,18 @@ namespace proxy
else else
{ {
LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info"); LogPrint (eLogError, "HTTPProxy: error when creating the stream, check the previous warnings for more info");
HTTPRequestFailed(); // TODO: Send correct error message host unreachable HTTPRequestFailed("error when creating the stream, check logs");
} }
} }
HTTPProxyServer::HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination): HTTPProxy::HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination):
TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ()) TCPIPAcceptor(address, port, localDestination ? localDestination : i2p::client::context.GetSharedLocalDestination ())
{ {
} }
std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxyServer::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket) std::shared_ptr<i2p::client::I2PServiceHandler> HTTPProxy::CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket)
{ {
return std::make_shared<HTTPProxyHandler> (this, socket); return std::make_shared<HTTPReqHandler> (this, socket);
} }
} // http
} } // i2p
}

25
HTTPProxy.h

@ -1,32 +1,21 @@
#ifndef HTTP_PROXY_H__ #ifndef HTTP_PROXY_H__
#define HTTP_PROXY_H__ #define HTTP_PROXY_H__
#include <memory> namespace i2p {
#include <set> namespace proxy {
#include <boost/asio.hpp> class HTTPProxy: public i2p::client::TCPIPAcceptor
#include <mutex>
#include "I2PService.h"
#include "Destination.h"
namespace i2p
{
namespace proxy
{
class HTTPProxyServer: public i2p::client::TCPIPAcceptor
{ {
public: public:
HTTPProxyServer(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr); HTTPProxy(const std::string& address, int port, std::shared_ptr<i2p::client::ClientDestination> localDestination = nullptr);
~HTTPProxyServer() {}; ~HTTPProxy() {};
protected: protected:
// Implements TCPIPAcceptor // Implements TCPIPAcceptor
std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket); std::shared_ptr<i2p::client::I2PServiceHandler> CreateHandler(std::shared_ptr<boost::asio::ip::tcp::socket> socket);
const char* GetName() { return "HTTP Proxy"; } const char* GetName() { return "HTTP Proxy"; }
}; };
} // http
typedef HTTPProxyServer HTTPProxy; } // i2p
}
}
#endif #endif

2
HTTPServer.cpp

@ -612,7 +612,7 @@ namespace http {
HandleCommand (req, res, s); HandleCommand (req, res, s);
} else { } else {
ShowStatus (s); ShowStatus (s);
//res.add_header("Refresh", "5"); res.add_header("Refresh", "10");
} }
ShowPageTail (s); ShowPageTail (s);

2
HTTPServer.h

@ -61,6 +61,8 @@ namespace http {
boost::asio::io_service::work m_Work; boost::asio::io_service::work m_Work;
boost::asio::ip::tcp::acceptor m_Acceptor; boost::asio::ip::tcp::acceptor m_Acceptor;
}; };
void ShowJumpServices (std::stringstream& s, const std::string& address);
} // http } // http
} // i2p } // i2p

14
I2CP.cpp

@ -114,7 +114,7 @@ namespace client
} }
} }
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket): I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
m_Owner (owner), m_Socket (socket), m_Payload (nullptr), m_Owner (owner), m_Socket (socket), m_Payload (nullptr),
m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true) m_SessionID (0xFFFF), m_MessageID (0), m_IsSendAccepted (true)
{ {
@ -583,7 +583,12 @@ namespace client
I2CPServer::I2CPServer (const std::string& interface, int port): I2CPServer::I2CPServer (const std::string& interface, int port):
m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(interface), port)) m_Acceptor (m_Service,
#ifdef ANDROID
I2CPSession::proto::endpoint(std::string (1, '\0') + interface)) // leading 0 for abstract address
#else
I2CPSession::proto::endpoint(boost::asio::ip::address::from_string(interface), port))
#endif
{ {
memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers)); memset (m_MessagesHandlers, 0, sizeof (m_MessagesHandlers));
m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler; m_MessagesHandlers[I2CP_GET_DATE_MESSAGE] = &I2CPSession::GetDateMessageHandler;
@ -644,12 +649,13 @@ namespace client
void I2CPServer::Accept () void I2CPServer::Accept ()
{ {
auto newSocket = std::make_shared<boost::asio::ip::tcp::socket> (m_Service); auto newSocket = std::make_shared<I2CPSession::proto::socket> (m_Service);
m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this, m_Acceptor.async_accept (*newSocket, std::bind (&I2CPServer::HandleAccept, this,
std::placeholders::_1, newSocket)); std::placeholders::_1, newSocket));
} }
void I2CPServer::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket) void I2CPServer::HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<I2CPSession::proto::socket> socket)
{ {
if (!ecode && socket) if (!ecode && socket)
{ {

16
I2CP.h

@ -99,7 +99,14 @@ namespace client
{ {
public: public:
I2CPSession (I2CPServer& owner, std::shared_ptr<boost::asio::ip::tcp::socket> socket); #ifdef ANDROID
typedef boost::asio::local::stream_protocol proto;
#else
typedef boost::asio::ip::tcp proto;
#endif
I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket);
~I2CPSession (); ~I2CPSession ();
void Start (); void Start ();
@ -144,7 +151,7 @@ namespace client
private: private:
I2CPServer& m_Owner; I2CPServer& m_Owner;
std::shared_ptr<boost::asio::ip::tcp::socket> m_Socket; std::shared_ptr<proto::socket> m_Socket;
uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload; uint8_t m_Header[I2CP_HEADER_SIZE], * m_Payload;
size_t m_PayloadLen; size_t m_PayloadLen;
@ -173,7 +180,8 @@ namespace client
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<I2CPSession::proto::socket> socket);
private: private:
@ -183,7 +191,7 @@ namespace client
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::ip::tcp::acceptor m_Acceptor; I2CPSession::proto::acceptor m_Acceptor;
public: public:

2
Makefile.linux

@ -44,7 +44,7 @@ endif
# UPNP Support (miniupnpc 1.5 or 1.6) # UPNP Support (miniupnpc 1.5 or 1.6)
ifeq ($(USE_UPNP),1) ifeq ($(USE_UPNP),1)
LDFLAGS += -ldl LDFLAGS += -lminiupnpc
CXXFLAGS += -DUSE_UPNP CXXFLAGS += -DUSE_UPNP
endif endif

13
Makefile.mingw

@ -6,10 +6,15 @@ NEEDED_CXXFLAGS = -std=c++11
BOOST_SUFFIX = -mt BOOST_SUFFIX = -mt
INCFLAGS = -I/usr/include/ -I/usr/local/include/ INCFLAGS = -I/usr/include/ -I/usr/local/include/
LDFLAGS = -Wl,-rpath,/usr/local/lib \ LDFLAGS = -Wl,-rpath,/usr/local/lib \
-L/usr/local/lib \ -L/usr/local/lib
-L/c/dev/openssl \
-L/c/dev/boost/lib # UPNP Support
LDLIBS = \ ifeq ($(USE_UPNP),1)
CXXFLAGS += -DUSE_UPNP -DMINIUPNP_STATICLIB
LDLIBS = -Wl,-Bstatic -lminiupnpc
endif
LDLIBS += \
-Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_system$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_date_time$(BOOST_SUFFIX) \
-Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \ -Wl,-Bstatic -lboost_filesystem$(BOOST_SUFFIX) \

3
Streaming.cpp

@ -394,9 +394,12 @@ namespace stream
} }
} }
if (packets.size () > 0) if (packets.size () > 0)
{
if (m_SavedPackets.empty ()) // no NACKS
{ {
m_IsAckSendScheduled = false; m_IsAckSendScheduled = false;
m_AckSendTimer.cancel (); m_AckSendTimer.cancel ();
}
bool isEmpty = m_SentPackets.empty (); bool isEmpty = m_SentPackets.empty ();
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it: packets) for (auto it: packets)

78
UPnP.cpp

@ -6,13 +6,6 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#ifdef _WIN32
#include <windows.h>
#define dlsym GetProcAddress
#else
#include <dlfcn.h>
#endif
#include "Log.h" #include "Log.h"
#include "RouterContext.h" #include "RouterContext.h"
@ -24,32 +17,11 @@
#include <miniupnpc/miniupnpc.h> #include <miniupnpc/miniupnpc.h>
#include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnpcommands.h>
// These are per-process and are safe to reuse for all threads
decltype(upnpDiscover) *upnpDiscoverFunc;
decltype(UPNP_AddPortMapping) *UPNP_AddPortMappingFunc;
decltype(UPNP_GetValidIGD) *UPNP_GetValidIGDFunc;
decltype(UPNP_GetExternalIPAddress) *UPNP_GetExternalIPAddressFunc;
decltype(UPNP_DeletePortMapping) *UPNP_DeletePortMappingFunc;
decltype(freeUPNPDevlist) *freeUPNPDevlistFunc;
decltype(FreeUPNPUrls) *FreeUPNPUrlsFunc;
// Nice approach http://stackoverflow.com/a/21517513/673826
template<class M, typename F>
F GetKnownProcAddressImpl(M hmod, const char *name, F) {
auto proc = reinterpret_cast<F>(dlsym(hmod, name));
if (!proc) {
LogPrint(eLogError, "UPnP: Error resolving ", name, " from library, version mismatch?");
}
return proc;
}
#define GetKnownProcAddress(hmod, func) GetKnownProcAddressImpl(hmod, #func, func##Func);
namespace i2p namespace i2p
{ {
namespace transport namespace transport
{ {
UPnP::UPnP () : m_Thread (nullptr) , m_IsModuleLoaded (false) UPnP::UPnP () : m_Thread (nullptr)
{ {
} }
@ -65,33 +37,6 @@ namespace transport
void UPnP::Start() void UPnP::Start()
{ {
if (!m_IsModuleLoaded) {
#ifdef MAC_OSX
m_Module = dlopen ("libminiupnpc.dylib", RTLD_LAZY);
#elif _WIN32
m_Module = LoadLibrary ("miniupnpc.dll"); // official prebuilt binary, e.g., in upnpc-exe-win32-20140422.zip
#else
m_Module = dlopen ("libminiupnpc.so", RTLD_LAZY);
#endif
if (m_Module == NULL)
{
LogPrint (eLogError, "UPnP: Error loading UPNP library, version mismatch?");
return;
}
else
{
upnpDiscoverFunc = GetKnownProcAddress (m_Module, upnpDiscover);
UPNP_GetValidIGDFunc = GetKnownProcAddress (m_Module, UPNP_GetValidIGD);
UPNP_GetExternalIPAddressFunc = GetKnownProcAddress (m_Module, UPNP_GetExternalIPAddress);
UPNP_AddPortMappingFunc = GetKnownProcAddress (m_Module, UPNP_AddPortMapping);
UPNP_DeletePortMappingFunc = GetKnownProcAddress (m_Module, UPNP_DeletePortMapping);
freeUPNPDevlistFunc = GetKnownProcAddress (m_Module, freeUPNPDevlist);
FreeUPNPUrlsFunc = GetKnownProcAddress (m_Module, FreeUPNPUrls);
if (upnpDiscoverFunc && UPNP_GetValidIGDFunc && UPNP_GetExternalIPAddressFunc && UPNP_AddPortMappingFunc &&
UPNP_DeletePortMappingFunc && freeUPNPDevlistFunc && FreeUPNPUrlsFunc)
m_IsModuleLoaded = true;
}
}
m_Thread = new std::thread (std::bind (&UPnP::Run, this)); m_Thread = new std::thread (std::bind (&UPnP::Run, this));
} }
@ -123,16 +68,16 @@ namespace transport
{ {
int nerror = 0; int nerror = 0;
#if MINIUPNPC_API_VERSION >= 14 #if MINIUPNPC_API_VERSION >= 14
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, 2, &nerror);
#else #else
m_Devlist = upnpDiscoverFunc (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror); m_Devlist = upnpDiscover (2000, m_MulticastIf, m_Minissdpdpath, 0, 0, &nerror);
#endif #endif
int r; int r;
r = UPNP_GetValidIGDFunc (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); r = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
if (r == 1) if (r == 1)
{ {
r = UPNP_GetExternalIPAddressFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); r = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(r != UPNPCOMMAND_SUCCESS) if(r != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r); LogPrint (eLogError, "UPnP: UPNP_GetExternalIPAddress () returned ", r);
@ -171,7 +116,7 @@ namespace transport
std::string strDesc = "I2Pd"; std::string strDesc = "I2Pd";
try { try {
for (;;) { for (;;) {
r = UPNP_AddPortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0"); r = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), 0, "0");
if (r!=UPNPCOMMAND_SUCCESS) if (r!=UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r); LogPrint (eLogError, "UPnP: AddPortMapping (", strPort.c_str () ,", ", strPort.c_str () ,", ", m_NetworkAddr, ") failed with code ", r);
@ -208,20 +153,15 @@ namespace transport
strType = "UDP"; strType = "UDP";
} }
int r = 0; int r = 0;
r = UPNP_DeletePortMappingFunc (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0); r = UPNP_DeletePortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strType.c_str (), 0);
LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n"); LogPrint (eLogError, "UPnP: DeletePortMapping() returned : ", r, "\n");
} }
void UPnP::Close () void UPnP::Close ()
{ {
freeUPNPDevlistFunc (m_Devlist); freeUPNPDevlist (m_Devlist);
m_Devlist = 0; m_Devlist = 0;
FreeUPNPUrlsFunc (&m_upnpUrls); FreeUPNPUrls (&m_upnpUrls);
#ifndef _WIN32
dlclose (m_Module);
#else
FreeLibrary (m_Module);
#endif
} }
} }

6
UPnP.h

@ -48,12 +48,6 @@ namespace transport
struct UPNPDev * m_Devlist = 0; struct UPNPDev * m_Devlist = 0;
char m_NetworkAddr[64]; char m_NetworkAddr[64];
char m_externalIPAddress[40]; char m_externalIPAddress[40];
bool m_IsModuleLoaded;
#ifndef _WIN32
void *m_Module;
#else
HINSTANCE m_Module;
#endif
}; };
} }
} }

7
docs/build_notes_windows.md

@ -164,6 +164,13 @@ folder name included in downloaded archive.
Note that you might need to build DLL yourself for 64-bit systems Note that you might need to build DLL yourself for 64-bit systems
using msys2 as 64-bit DLLs are not provided by the project. using msys2 as 64-bit DLLs are not provided by the project.
You can also install it through the MSYS2
and build with USE_UPNP key.
```bash
pacman -S mingw-w64-i686-miniupnpc
make USE_UPNP=1
```
### Creating Visual Studio project ### Creating Visual Studio project

8
docs/configuration.md

@ -41,7 +41,7 @@ All options below still possible in cmdline, but better write it in config file:
* --http.pass= - Password for basic auth (default: random, see logs) * --http.pass= - Password for basic auth (default: random, see logs)
* --httpproxy.address= - The address to listen on (HTTP Proxy) * --httpproxy.address= - The address to listen on (HTTP Proxy)
* --httpproxy.port= - The port to listen on (HTTP Proxy) 4446 by default * --httpproxy.port= - The port to listen on (HTTP Proxy) 4444 by default
* --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS) * --httpproxy.keys= - optional keys file for proxy local destination (both HTTP and SOCKS)
* --httpproxy.enabled= - If HTTP proxy is enabled. true by default * --httpproxy.enabled= - If HTTP proxy is enabled. true by default
@ -60,9 +60,9 @@ All options below still possible in cmdline, but better write it in config file:
* --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified * --bob.port= - Port of BOB command channel. Usually 2827. BOB is off if not specified
* --bob.enabled= - If BOB is enabled. false by default * --bob.enabled= - If BOB is enabled. false by default
* --i2cp.address= - The address to listen on * --i2cp.address= - The address to listen on or an abstract address for Android LocalSocket
* --i2cp.port= - Port of I2CP server. Usually 7654. IPCP is off if not specified * --i2cp.port= - Port of I2CP server. Usually 7654. Ignored for Andorid
* --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't requeire I2CP * --i2cp.enabled= - If I2CP is enabled. false by default. Other services don't require I2CP
* --i2pcontrol.address= - The address to listen on (I2P control service) * --i2pcontrol.address= - The address to listen on (I2P control service)
* --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified * --i2pcontrol.port= - Port of I2P control service. Usually 7650. I2PControl is off if not specified

1
qt/i2pd_qt/.gitignore vendored

@ -0,0 +1 @@
i2pd_qt.pro.user*

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="1" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.8.0" android:versionCode="2" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

5
qt/i2pd_qt/i2pd.qrc

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>images/icon.png</file>
</qresource>
</RCC>

48
qt/i2pd_qt/i2pd_qt.pro

@ -11,14 +11,17 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = i2pd_qt TARGET = i2pd_qt
TEMPLATE = app TEMPLATE = app
QMAKE_CXXFLAGS *= -std=c++11 QMAKE_CXXFLAGS *= -std=c++11
DEFINES += USE_UPNP
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git # git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/android-ifaddrs.git # git clone https://github.com/PurpleI2P/android-ifaddrs.git
# change to your own # change to your own
BOOST_PATH = /mnt/media/android/Boost-for-Android-Prebuilt BOOST_PATH = /home/rebby/andp/Boost-for-Android-Prebuilt
OPENSSL_PATH = /mnt/media/android/OpenSSL-for-Android-Prebuilt OPENSSL_PATH = /home/rebby/andp/OpenSSL-for-Android-Prebuilt
IFADDRS_PATH = /mnt/media/android/android-ifaddrs MINIUPNP_PATH = /home/rebby/andp/MiniUPnP-for-Android-Prebuilt
IFADDRS_PATH = /home/rebby/andp/android-ifaddrs
# Steps in Android SDK manager: # Steps in Android SDK manager:
# 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html # 1) Check Extras/Google Support Library https://developer.android.com/topic/libraries/support-library/setup.html
@ -27,7 +30,7 @@ IFADDRS_PATH = /mnt/media/android/android-ifaddrs
SOURCES += DaemonQT.cpp\ SOURCES += DaemonQT.cpp\
mainwindow.cpp \ mainwindow.cpp \
../../HTTPServer.cpp ../../I2PControl.cpp ../../UPnP.cpp ../../Daemon.cpp ../../Config.cpp \ ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \
../../AddressBook.cpp \ ../../AddressBook.cpp \
../../api.cpp \ ../../api.cpp \
../../Base.cpp \ ../../Base.cpp \
@ -69,9 +72,9 @@ SOURCES += DaemonQT.cpp\
../../TunnelEndpoint.cpp \ ../../TunnelEndpoint.cpp \
../../TunnelGateway.cpp \ ../../TunnelGateway.cpp \
../../TunnelPool.cpp \ ../../TunnelPool.cpp \
../../UPnP.cpp \
../../util.cpp \ ../../util.cpp \
../../i2pd.cpp \ ../../i2pd.cpp
$$IFADDRS_PATH/ifaddrs.c
HEADERS += DaemonQT.h mainwindow.h \ HEADERS += DaemonQT.h mainwindow.h \
../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \ ../../HTTPServer.h ../../I2PControl.h ../../UPnP.h ../../Daemon.h ../../Config.h \
@ -122,9 +125,9 @@ HEADERS += DaemonQT.h mainwindow.h \
../../TunnelEndpoint.h \ ../../TunnelEndpoint.h \
../../TunnelGateway.h \ ../../TunnelGateway.h \
../../TunnelPool.h \ ../../TunnelPool.h \
../../UPnP.h \
../../util.h \ ../../util.h \
../../version.h \ ../../version.h
$$IFADDRS_PATH/ifaddrs.h
FORMS += mainwindow.ui FORMS += mainwindow.ui
@ -138,14 +141,19 @@ android {
message("Using Android settings") message("Using Android settings")
DEFINES += ANDROID=1 DEFINES += ANDROID=1
DEFINES += __ANDROID__ DEFINES += __ANDROID__
INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \ INCLUDEPATH += $$BOOST_PATH/boost_1_53_0/include \
$$OPENSSL_PATH/openssl-1.0.2/include \ $$OPENSSL_PATH/openssl-1.0.2/include \
$$MINIUPNP_PATH/miniupnp-2.0/include \
$$IFADDRS_PATH $$IFADDRS_PATH
DISTFILES += \ DISTFILES += \
android/AndroidManifest.xml android/AndroidManifest.xml
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
SOURCES += $$IFADDRS_PATH/ifaddrs.c ../../UPnP.cpp
HEADERS += $$IFADDRS_PATH/ifaddrs.h
equals(ANDROID_TARGET_ARCH, armeabi-v7a){ equals(ANDROID_TARGET_ARCH, armeabi-v7a){
DEFINES += ANDROID_ARM7A DEFINES += ANDROID_ARM7A
@ -156,7 +164,8 @@ LIBS += -L$$BOOST_PATH/boost_1_53_0/armeabi-v7a/lib \
-lboost_date_time-gcc-mt-1_53 \ -lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 \
-lboost_program_options-gcc-mt-1_53 \ -lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl -L$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/ -lcrypto -lssl \
-L$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/ -lminiupnpc
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl.a
@ -164,7 +173,8 @@ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto.a \
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \ ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so $$OPENSSL_PATH/openssl-1.0.2/armeabi-v7a/lib/libssl_1_0_0.so \
$$MINIUPNP_PATH/miniupnp-2.0/armeabi-v7a/lib/libminiupnpc.so
} }
equals(ANDROID_TARGET_ARCH, x86){ equals(ANDROID_TARGET_ARCH, x86){
# http://stackoverflow.com/a/30235934/529442 # http://stackoverflow.com/a/30235934/529442
@ -173,7 +183,8 @@ LIBS += -L$$BOOST_PATH/boost_1_53_0/x86/lib \
-lboost_date_time-gcc-mt-1_53 \ -lboost_date_time-gcc-mt-1_53 \
-lboost_filesystem-gcc-mt-1_53 \ -lboost_filesystem-gcc-mt-1_53 \
-lboost_program_options-gcc-mt-1_53 \ -lboost_program_options-gcc-mt-1_53 \
-L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl -L$$OPENSSL_PATH/openssl-1.0.2/x86/lib/ -lcrypto -lssl \
-L$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/ -lminiupnpc
PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl.a
@ -181,12 +192,23 @@ PRE_TARGETDEPS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto.a \
DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include DEPENDPATH += $$OPENSSL_PATH/openssl-1.0.2/include
ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \ ANDROID_EXTRA_LIBS += $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libcrypto_1_0_0.so \
$$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so $$OPENSSL_PATH/openssl-1.0.2/x86/lib/libssl_1_0_0.so \
$$MINIUPNP_PATH/miniupnp-2.0/x86/lib/libminiupnpc.so
} }
} }
linux:!android { linux:!android {
message("Using Linux settings") message("Using Linux settings")
LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread LIBS += -lcrypto -lssl -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread -lminiupnpc
}
!android:!symbian:!maemo5:!simulator {
message("Build with a system tray icon")
# see also http://doc.qt.io/qt-4.8/qt-desktop-systray-systray-pro.html for example on wince*
#sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS i2pd_qt.pro resources images
RESOURCES = i2pd.qrc
QT += xml
#INSTALLS += sources
} }

BIN
qt/i2pd_qt/images/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

120
qt/i2pd_qt/mainwindow.cpp

@ -1,10 +1,16 @@
#include "mainwindow.h" #include "mainwindow.h"
//#include "ui_mainwindow.h" //#include "ui_mainwindow.h"
#include <QMessageBox> #include <QMessageBox>
#include <QTimer>
#include "../../RouterContext.h"
#ifndef ANDROID
#include <QtDebug>
#endif
MainWindow::MainWindow(QWidget *parent) : MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)/*, QMainWindow(parent)/*,
ui(new Ui::MainWindow)*/ ui(new Ui::MainWindow)*/,
quitting(false)
{ {
//ui->setupUi(this); //ui->setupUi(this);
if (objectName().isEmpty()) if (objectName().isEmpty())
@ -22,27 +28,129 @@ MainWindow::MainWindow(QWidget *parent) :
verticalLayout1->setContentsMargins(0, 0, 0, 0); verticalLayout1->setContentsMargins(0, 0, 0, 0);
quitButton = new QPushButton(verticalLayoutWidget); quitButton = new QPushButton(verticalLayoutWidget);
quitButton->setObjectName(QStringLiteral("quitButton")); quitButton->setObjectName(QStringLiteral("quitButton"));
QSizePolicy sizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy.setHorizontalStretch(0); sizePolicy.setHorizontalStretch(1);
sizePolicy.setVerticalStretch(0); //sizePolicy.setVerticalStretch(1);
sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth()); sizePolicy.setHeightForWidth(quitButton->sizePolicy().hasHeightForWidth());
quitButton->setSizePolicy(sizePolicy); quitButton->setSizePolicy(sizePolicy);
verticalLayout1->addWidget(quitButton); verticalLayout1->addWidget(quitButton);
gracefulQuitButton = new QPushButton(verticalLayoutWidget);
gracefulQuitButton->setObjectName(QStringLiteral("gracefulQuitButton"));
QSizePolicy sizePolicy2(QSizePolicy::Maximum, QSizePolicy::Maximum);
sizePolicy2.setHorizontalStretch(1);
//sizePolicy2.setVerticalStretch(1);
sizePolicy2.setHeightForWidth(gracefulQuitButton->sizePolicy().hasHeightForWidth());
gracefulQuitButton->setSizePolicy(sizePolicy2);
verticalLayout1->addWidget(gracefulQuitButton);
setCentralWidget(centralWidget); setCentralWidget(centralWidget);
setWindowTitle(QApplication::translate("MainWindow", "MainWindow", 0)); setWindowTitle(QApplication::translate("MainWindow", "i2pd", 0));
quitButton->setText(QApplication::translate("MainWindow", "Quit", 0)); quitButton->setText(QApplication::translate("MainWindow", "Quit", 0));
gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful Quit", 0));
#ifndef ANDROID
createActions();
createTrayIcon();
#endif
QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton())); QObject::connect(quitButton, SIGNAL(released()), this, SLOT(handleQuitButton()));
QObject::connect(gracefulQuitButton, SIGNAL(released()), this, SLOT(handleGracefulQuitButton()));
#ifndef ANDROID
QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
setIcon();
trayIcon->show();
#endif
//QMetaObject::connectSlotsByName(this); //QMetaObject::connectSlotsByName(this);
} }
#ifndef ANDROID
void MainWindow::createActions() {
toggleWindowVisibleAction = new QAction(tr("&Toggle the window"), this);
connect(toggleWindowVisibleAction, SIGNAL(triggered()), this, SLOT(toggleVisibilitySlot()));
//quitAction = new QAction(tr("&Quit"), this);
//connect(quitAction, SIGNAL(triggered()), QApplication::instance(), SLOT(quit()));
}
void MainWindow::toggleVisibilitySlot() {
setVisible(!isVisible());
}
void MainWindow::createTrayIcon() {
trayIconMenu = new QMenu(this);
trayIconMenu->addAction(toggleWindowVisibleAction);
//trayIconMenu->addSeparator();
//trayIconMenu->addAction(quitAction);
trayIcon = new QSystemTrayIcon(this);
trayIcon->setContextMenu(trayIconMenu);
}
void MainWindow::setIcon() {
QIcon icon(":/images/icon.png");
trayIcon->setIcon(icon);
setWindowIcon(icon);
trayIcon->setToolTip(QApplication::translate("MainWindow", "i2pd", 0));
}
void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) {
switch (reason) {
case QSystemTrayIcon::Trigger:
case QSystemTrayIcon::DoubleClick:
case QSystemTrayIcon::MiddleClick:
setVisible(!isVisible());
break;
default:
qDebug() << "MainWindow::iconActivated(): unknown reason: " << reason << endl;
break;
}
}
void MainWindow::closeEvent(QCloseEvent *event) {
if(quitting){ QMainWindow::closeEvent(event); return; }
if (trayIcon->isVisible()) {
QMessageBox::information(this, tr("i2pd"),
tr("The program will keep running in the "
"system tray. To gracefully terminate the program, "
"choose <b>Graceful Quit</b> at the main i2pd window."));
hide();
event->ignore();
}
}
#endif
void MainWindow::handleQuitButton() { void MainWindow::handleQuitButton() {
qDebug("Quit pressed. Hiding the main window"); qDebug("Quit pressed. Hiding the main window");
#ifndef ANDROID
quitting=true;
#endif
close();
QApplication::instance()->quit();
}
void MainWindow::handleGracefulQuitButton() {
qDebug("Graceful Quit pressed.");
gracefulQuitButton->setText(QApplication::translate("MainWindow", "Graceful quit is in progress", 0));
gracefulQuitButton->setEnabled(false);
gracefulQuitButton->adjustSize();
verticalLayoutWidget->adjustSize();
i2p::context.SetAcceptsTunnels (false); // stop accpting tunnels
QTimer::singleShot(10*60*1000/*millis*/, this, SLOT(handleGracefulQuitTimerEvent()));
}
void MainWindow::handleGracefulQuitTimerEvent() {
qDebug("Hiding the main window");
#ifndef ANDROID
quitting=true;
#endif
close(); close();
qDebug("Performing quit");
QApplication::instance()->quit(); QApplication::instance()->quit();
} }

34
qt/i2pd_qt/mainwindow.h

@ -12,6 +12,11 @@
#include <QtWidgets/QPushButton> #include <QtWidgets/QPushButton>
#include <QtWidgets/QVBoxLayout> #include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget> #include <QtWidgets/QWidget>
#ifndef ANDROID
#include <QSystemTrayIcon>
#include <QCloseEvent>
#include <QMenu>
#endif
namespace Ui { namespace Ui {
class MainWindow; class MainWindow;
@ -25,14 +30,43 @@ public:
explicit MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = 0);
~MainWindow(); ~MainWindow();
//#ifndef ANDROID
// void setVisible(bool visible);
//#endif
private slots: private slots:
void handleQuitButton(); void handleQuitButton();
void handleGracefulQuitButton();
void handleGracefulQuitTimerEvent();
#ifndef ANDROID
void setIcon();
void iconActivated(QSystemTrayIcon::ActivationReason reason);
void toggleVisibilitySlot();
#endif
private: private:
#ifndef ANDROID
void createActions();
void createTrayIcon();
#endif
QWidget *centralWidget; QWidget *centralWidget;
QWidget *verticalLayoutWidget; QWidget *verticalLayoutWidget;
QVBoxLayout *verticalLayout1; QVBoxLayout *verticalLayout1;
QPushButton *quitButton; QPushButton *quitButton;
QPushButton *gracefulQuitButton;
#ifndef ANDROID
bool quitting;
QAction *toggleWindowVisibleAction;
QSystemTrayIcon *trayIcon;
QMenu *trayIconMenu;
#endif
protected:
#ifndef ANDROID
void closeEvent(QCloseEvent *event);
#endif
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

24
qt/i2pd_qt/mainwindow.ui

@ -37,6 +37,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="gracefulShutdownButton">
<property name="text">
<string>Graceful Quit</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</widget> </widget>
@ -60,8 +67,25 @@
</hint> </hint>
</hints> </hints>
</connection> </connection>
<connection>
<sender>gracefulShutdownButton</sender>
<signal>released()</signal>
<receiver>MainWindow</receiver>
<slot>handleGracefulQuitButton()</slot>
<hints>
<hint type="sourcelabel">
<x>395</x>
<y>319</y>
</hint>
<hint type="destinationlabel">
<x>399</x>
<y>239</y>
</hint>
</hints>
</connection>
</connections> </connections>
<slots> <slots>
<slot>handleQuitButton()</slot> <slot>handleQuitButton()</slot>
<slot>handleGracefulQuitButton()</slot>
</slots> </slots>
</ui> </ui>

Loading…
Cancel
Save