Please ponder: nodelay, console newlines, print out json, silence some trivia, move to 'return' for Lua statements
#include <readline.h>
#include <fstream>
#include "dolog.hh"
+ #include "ext/json11/json11.hpp"
vector<pair<struct timeval, string> > g_confDelta;
void doClient(ComboAddress server, const std::string& command)
{
- cout<<"Connecting to "<<server.toStringWithPort()<<endl;
+ if(g_verbose)
+ cout<<"Connecting to "<<server.toStringWithPort()<<endl;
int fd=socket(server.sin4.sin_family, SOCK_STREAM, 0);
if (fd < 0) {
cerr<<"Unable to connect to "<<server.toStringWithPort()<<endl;
return;
}
SConnect(fd, server);
-
+ setTCPNoDelay(fd);
SodiumNonce theirs, ours;
ours.init();
if(!command.empty()) {
string msg=sodEncryptSym(command, g_key, ours);
- putMsgLen32(fd, msg.length());
+ putMsgLen32(fd, (uint32_t) msg.length());
if(!msg.empty())
writen2(fd, msg);
uint32_t len;
readn2(fd, resp.get(), len);
msg.assign(resp.get(), len);
msg=sodDecryptSym(msg, g_key, theirs);
- cout<<msg<<endl;
+ cout<<msg;
}
}
else {
continue;
string msg=sodEncryptSym(line, g_key, ours);
- putMsgLen32(fd, msg.length());
+ putMsgLen32(fd, (uint32_t) msg.length());
writen2(fd, msg);
uint32_t len;
if(!getMsgLen32(fd, &len)) {
readn2(fd, resp.get(), len);
msg.assign(resp.get(), len);
msg=sodDecryptSym(msg, g_key, theirs);
- cout<<msg<<endl;
+ cout<<msg;
+ cout.flush();
}
else {
cout<<endl;
string response;
try {
- std::lock_guard<std::mutex> lock(g_luamutex);
- g_outputBuffer.clear();
- resetLuaSideEffect();
- auto ret=g_lua.executeCode<
- boost::optional<
- boost::variant<
- string,
- shared_ptr<DownstreamState>
- >
- >
- >(line);
-
- if(ret) {
- if (const auto strValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
- cout<<(*strValue)->getName()<<endl;
- }
- else if (const auto strValue = boost::get<string>(&*ret)) {
- cout<<*strValue<<endl;
- }
+ bool withReturn=true;
+ retry:;
+ try {
+ std::lock_guard<std::mutex> lock(g_luamutex);
+ g_outputBuffer.clear();
+ resetLuaSideEffect();
+ auto ret=g_lua.executeCode<
+ boost::optional<
+ boost::variant<
+ string,
+ shared_ptr<DownstreamState>,
+ std::unordered_map<string, double>
+ >
+ >
+ >(withReturn ? ("return "+line) : line);
+
+ if(ret) {
+ if (const auto strValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
+ cout<<(*strValue)->getName()<<endl;
+ }
+ else if (const auto strValue = boost::get<string>(&*ret)) {
+ cout<<*strValue<<endl;
+ }
+ else if(const auto um = boost::get<std::unordered_map<string, double> >(&*ret)) {
+ using namespace json11;
+ Json::object o;
+ for(const auto& v : *um)
+ o[v.first]=v.second;
+ Json out = o;
+ cout<<out.dump()<<endl;
+ }
+ }
+ else
+ cout << g_outputBuffer;
+ if(!getLuaNoSideEffect())
+ feedConfigDelta(line);
}
- else
- cout << g_outputBuffer;
- if(!getLuaNoSideEffect())
- feedConfigDelta(line);
+ catch(const LuaContext::SyntaxErrorException&) {
+ if(withReturn) {
+ withReturn=false;
+ goto retry;
+ }
+ throw;
+ }
+ }
+ catch(const LuaContext::WrongTypeException& e) {
+ std::cerr<<"Command returned an object we can't print"<<std::endl;
+ // tried to return something we don't understand
}
catch(const LuaContext::ExecutionErrorException& e) {
std::cerr << e.what();
void controlClientThread(int fd, ComboAddress client)
try
{
+ setTCPNoDelay(fd);
SodiumNonce theirs;
readn2(fd, (char*)theirs.value, sizeof(theirs.value));
SodiumNonce ours;
// cerr<<"Have decrypted line: "<<line<<endl;
string response;
try {
- std::lock_guard<std::mutex> lock(g_luamutex);
- g_outputBuffer.clear();
- resetLuaSideEffect();
- auto ret=g_lua.executeCode<
- boost::optional<
- boost::variant<
- string,
- shared_ptr<DownstreamState>
- >
- >
- >(line);
+ bool withReturn=true;
+ retry:;
+ try {
+ std::lock_guard<std::mutex> lock(g_luamutex);
+
+ g_outputBuffer.clear();
+ resetLuaSideEffect();
+ auto ret=g_lua.executeCode<
+ boost::optional<
+ boost::variant<
+ string,
+ shared_ptr<DownstreamState>,
+ std::unordered_map<string, double>
+ >
+ >
+ >(withReturn ? ("return "+line) : line);
if(ret) {
if (const auto strValue = boost::get<shared_ptr<DownstreamState>>(&*ret)) {
- response=(*strValue)->getName();
+ response=(*strValue)->getName()+"\n";
}
else if (const auto strValue = boost::get<string>(&*ret)) {
- response=*strValue;
+ response=*strValue+"\n";
}
+ else if(const auto um = boost::get<std::unordered_map<string, double> >(&*ret)) {
+ using namespace json11;
+ Json::object o;
+ for(const auto& v : *um)
+ o[v.first]=v.second;
+ Json out = o;
+ response=out.dump()+"\n";
+ }
}
else
response=g_outputBuffer;
if(!getLuaNoSideEffect())
feedConfigDelta(line);
+ }
+ catch(const LuaContext::SyntaxErrorException&) {
+ if(withReturn) {
+ withReturn=false;
+ goto retry;
+ }
+ throw;
+ }
}
catch(const LuaContext::ExecutionErrorException& e) {
response = "Error: " + string(e.what()) + ": ";
g_lua.writeFunction("generateDNSCryptCertificate", [](const std::string& providerPrivateKeyFile, const std::string& certificateFile, const std::string privateKeyFile, uint32_t serial, time_t begin, time_t end) {
setLuaNoSideEffect();
#ifdef HAVE_DNSCRYPT
- unsigned char privateKey[DNSCRYPT_PRIVATE_KEY_SIZE];
unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey));
- sodium_mlock(privateKey, sizeof(privateKey));
sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
- sodium_memzero(privateKey, sizeof(privateKey));
try {
DnsCryptPrivateKey privateKey;
}
sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
- sodium_memzero(privateKey, sizeof(privateKey));
sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey));
- sodium_munlock(privateKey, sizeof(privateKey));
#else
g_outputBuffer="Error: DNSCrypt support is not enabled.\n";
#endif
g_lua.writeFunction("getAction", [](unsigned int num) {
setLuaNoSideEffect();
+ boost::optional<std::shared_ptr<DNSAction>> ret;
auto rulactions = g_rulactions.getCopy();
- if(num >= rulactions.size())
- return std::shared_ptr<DNSAction>();
- return rulactions[num].second;
+ if(num < rulactions.size())
+ ret=rulactions[num].second;
+ return ret;
});
g_lua.registerFunction("getStats", &DNSAction::getStats);
#include <boost/optional.hpp>
#include <poll.h>
#include <iomanip>
+ #include <netinet/tcp.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
bool g_singleThreaded;
-int writen2(int fd, const void *buf, size_t count)
+size_t writen2(int fd, const void *buf, size_t count)
{
const char *ptr = (char*)buf;
const char *eptr = ptr + count;
- int res;
+ ssize_t res;
while(ptr != eptr) {
res = ::write(fd, ptr, eptr - ptr);
if(res < 0) {
else if (res == 0)
throw std::runtime_error("could not write all bytes, got eof in writen2");
- ptr += res;
+ ptr += (size_t) res;
}
return count;
}
-int readn2(int fd, void* buffer, unsigned int len)
+size_t readn2(int fd, void* buffer, size_t len)
{
- unsigned int pos=0;
- int res;
+ size_t pos=0;
+ ssize_t res;
for(;;) {
res = read(fd, (char*)buffer + pos, len - pos);
if(res == 0)
unixDie("failed in readn2");
}
- pos+=res;
+ pos+=(size_t)res;
if(pos == len)
break;
}
return len;
}
-int readn2WithTimeout(int fd, void* buffer, size_t len, int timeout)
+size_t readn2WithTimeout(int fd, void* buffer, size_t len, int timeout)
{
size_t pos = 0;
do {
return len;
}
-int writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout)
+size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout)
{
size_t pos = 0;
do {
return getLong((unsigned char *)p);
}
-
-
-/** strips a domain suffix from a domain, returns true if it stripped */
-bool stripDomainSuffix(string *qname, const string &domain)
-{
- if(!endsOn(*qname, domain))
- return false;
-
- if(toLower(*qname)==toLower(domain))
- *qname="@";
- else {
- if((*qname)[qname->size()-domain.size()-1]!='.')
- return false;
-
- qname->resize(qname->size()-domain.size()-1);
- }
- return true;
-}
-
-/** Chops off the start of a domain, so goes from 'www.ds9a.nl' to 'ds9a.nl' to 'nl' to ''. Return zero on the empty string */
-bool chopOff(string &domain)
-{
- if(domain.empty())
- return false;
-
- string::size_type fdot=domain.find('.');
-
- if(fdot==string::npos)
- domain="";
- else {
- string::size_type remain = domain.length() - (fdot + 1);
- char tmp[remain];
- memcpy(tmp, domain.c_str()+fdot+1, remain);
- domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-)
- }
- return true;
-}
-
-/** Chops off the start of a domain, so goes from 'www.ds9a.nl.' to 'ds9a.nl.' to 'nl.' to '.' Return zero on the empty string */
-bool chopOffDotted(string &domain)
-{
- if(domain.empty() || (domain.size()==1 && domain[0]=='.'))
- return false;
-
- string::size_type fdot=domain.find('.');
- if(fdot == string::npos)
- return false;
-
- if(fdot==domain.size()-1)
- domain=".";
- else {
- string::size_type remain = domain.length() - (fdot + 1);
- char tmp[remain];
- memcpy(tmp, domain.c_str()+fdot+1, remain);
- domain.assign(tmp, remain);
- }
- return true;
-}
-
-
-bool ciEqual(const string& a, const string& b)
+static bool ciEqual(const string& a, const string& b)
{
if(a.size()!=b.size())
return false;
}
/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
-bool endsOn(const string &domain, const string &suffix)
+static bool endsOn(const string &domain, const string &suffix)
{
if( suffix.empty() || ciEqual(domain, suffix) )
return true;
return true;
}
+/** strips a domain suffix from a domain, returns true if it stripped */
+bool stripDomainSuffix(string *qname, const string &domain)
+{
+ if(!endsOn(*qname, domain))
+ return false;
+
+ if(toLower(*qname)==toLower(domain))
+ *qname="@";
+ else {
+ if((*qname)[qname->size()-domain.size()-1]!='.')
+ return false;
+
+ qname->resize(qname->size()-domain.size()-1);
+ }
+ return true;
+}
+
static void parseService4(const string &descr, ServiceTuple &st)
{
vector<string>parts;
return true; // we pretend this happened.
}
+ void setTCPNoDelay(int sock)
+ {
+ int flag = 1;
+ setsockopt(sock, /* socket affected */
+ IPPROTO_TCP, /* set option at TCP level */
+ TCP_NODELAY, /* name of option */
+ (char *) &flag, /* the cast is historical cruft */
+ sizeof(flag)); /* length of option value */
+ }
+
+
bool setNonBlocking(int sock)
{
int flags=fcntl(sock,F_GETFL,0);
typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
-bool chopOff(string &domain);
-bool chopOffDotted(string &domain);
-
-bool endsOn(const string &domain, const string &suffix);
string nowTime();
const string unquotify(const string &item);
string humanDuration(time_t passed);
}
}
-int writen2(int fd, const void *buf, size_t count);
-inline int writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
-int readn2(int fd, void* buffer, unsigned int len);
-int readn2WithTimeout(int fd, void* buffer, size_t len, int timeout);
-int writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout);
+size_t writen2(int fd, const void *buf, size_t count);
+inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
+size_t readn2(int fd, void* buffer, size_t len);
+size_t readn2WithTimeout(int fd, void* buffer, size_t len, int timeout);
+size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout);
const string toLower(const string &upper);
const string toLowerCanonic(const string &upper);
//! Sets the socket into non-blocking mode.
bool setNonBlocking( int sock );
+ void setTCPNoDelay(int sock);
bool isNonBlocking(int sock);
int closesocket(int fd);
bool setCloseOnExec(int sock);