astyled
This commit is contained in:
parent
90afc535a4
commit
ae2962a41c
6 changed files with 785 additions and 703 deletions
File diff suppressed because it is too large
Load diff
|
@ -21,27 +21,27 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function object to advise of new data arrival, or just periodic
|
* Callback function object to advise of new data arrival, or just periodic
|
||||||
* heartbeat if cnt is 0.
|
* heartbeat if cnt is 0.
|
||||||
*
|
*
|
||||||
* To interrupt the command, the code using ExecCmd should either
|
* To interrupt the command, the code using ExecCmd should either
|
||||||
* raise an exception inside newData() (and catch it in doexec's caller), or
|
* raise an exception inside newData() (and catch it in doexec's caller), or
|
||||||
* call ExecCmd::setKill()
|
* call ExecCmd::setKill()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ExecCmdAdvise {
|
class ExecCmdAdvise {
|
||||||
public:
|
public:
|
||||||
virtual ~ExecCmdAdvise() {}
|
virtual ~ExecCmdAdvise() {}
|
||||||
virtual void newData(int cnt) = 0;
|
virtual void newData(int cnt) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback function object to get more input data. Data has to be provided
|
* Callback function object to get more input data. Data has to be provided
|
||||||
* into the initial input string, set it to empty to signify eof.
|
* into the initial input string, set it to empty to signify eof.
|
||||||
*/
|
*/
|
||||||
class ExecCmdProvide {
|
class ExecCmdProvide {
|
||||||
public:
|
public:
|
||||||
virtual ~ExecCmdProvide() {}
|
virtual ~ExecCmdProvide() {}
|
||||||
virtual void newData() = 0;
|
virtual void newData() = 0;
|
||||||
};
|
};
|
||||||
|
@ -51,43 +51,43 @@ class ExecCmdProvide {
|
||||||
* asynchronous io as appropriate for things to work).
|
* asynchronous io as appropriate for things to work).
|
||||||
*
|
*
|
||||||
* Input to the command can be provided either once in a parameter to doexec
|
* Input to the command can be provided either once in a parameter to doexec
|
||||||
* or provided in chunks by setting a callback which will be called to
|
* or provided in chunks by setting a callback which will be called to
|
||||||
* request new data. In this case, the 'input' parameter to doexec may be
|
* request new data. In this case, the 'input' parameter to doexec may be
|
||||||
* empty (but not null)
|
* empty (but not null)
|
||||||
*
|
*
|
||||||
* Output from the command is normally returned in a single string, but a
|
* Output from the command is normally returned in a single string, but a
|
||||||
* callback can be set to be called whenever new data arrives, in which case
|
* callback can be set to be called whenever new data arrives, in which case
|
||||||
* it is permissible to consume the data and erase the string.
|
* it is permissible to consume the data and erase the string.
|
||||||
*
|
*
|
||||||
* Note that SIGPIPE should be ignored and SIGCLD blocked when calling doexec,
|
* Note that SIGPIPE should be ignored and SIGCLD blocked when calling doexec,
|
||||||
* else things might fail randomly. (This is not done inside the class because
|
* else things might fail randomly. (This is not done inside the class because
|
||||||
* of concerns with multithreaded programs).
|
* of concerns with multithreaded programs).
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ExecCmd {
|
class ExecCmd {
|
||||||
public:
|
public:
|
||||||
// Use vfork instead of fork. Our vfork usage is multithread-compatible as
|
// Use vfork instead of fork. Our vfork usage is multithread-compatible as
|
||||||
// far as I can see, but just in case...
|
// far as I can see, but just in case...
|
||||||
static void useVfork(bool on);
|
static void useVfork(bool on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add/replace environment variable before executing command. This must
|
* Add/replace environment variable before executing command. This must
|
||||||
* be called before doexec() to have an effect (possibly multiple
|
* be called before doexec() to have an effect (possibly multiple
|
||||||
* times for several variables).
|
* times for several variables).
|
||||||
* @param envassign an environment assignment string ("name=value")
|
* @param envassign an environment assignment string ("name=value")
|
||||||
*/
|
*/
|
||||||
void putenv(const std::string &envassign);
|
void putenv(const std::string& envassign);
|
||||||
void putenv(const std::string &name, const std::string& value);
|
void putenv(const std::string& name, const std::string& value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to set a limit on child process vm size. This will use
|
* Try to set a limit on child process vm size. This will use
|
||||||
* setrlimit() and RLIMIT_AS/VMEM if available. Parameter is in
|
* setrlimit() and RLIMIT_AS/VMEM if available. Parameter is in
|
||||||
* units of 2**10. Must be called before starting the command, default
|
* units of 2**10. Must be called before starting the command, default
|
||||||
* is inherit from parent.
|
* is inherit from parent.
|
||||||
*/
|
*/
|
||||||
void setrlimit_as(int mbytes);
|
void setrlimit_as(int mbytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set function objects to call whenever new data is available or on
|
* Set function objects to call whenever new data is available or on
|
||||||
* select timeout. The data itself is stored in the output string.
|
* select timeout. The data itself is stored in the output string.
|
||||||
* Must be set before calling doexec.
|
* Must be set before calling doexec.
|
||||||
|
@ -101,59 +101,60 @@ class ExecCmd {
|
||||||
void setProvide(ExecCmdProvide *p);
|
void setProvide(ExecCmdProvide *p);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set select timeout in milliseconds. The default is 1 S.
|
* Set select timeout in milliseconds. The default is 1 S.
|
||||||
* This is NOT a time after which an error will occur, but the period of
|
* This is NOT a time after which an error will occur, but the period of
|
||||||
* the calls to the advise routine (which normally checks for cancellation).
|
* the calls to the advise routine (which normally checks for cancellation).
|
||||||
*/
|
*/
|
||||||
void setTimeout(int mS);
|
void setTimeout(int mS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set destination for stderr data. The default is to let it alone (will
|
* Set destination for stderr data. The default is to let it alone (will
|
||||||
* usually go to the terminal or to wherever the desktop messages go).
|
* usually go to the terminal or to wherever the desktop messages go).
|
||||||
* There is currently no option to put stderr data into a program variable
|
* There is currently no option to put stderr data into a program variable
|
||||||
* If the parameter can't be opened for writing, the command's
|
* If the parameter can't be opened for writing, the command's
|
||||||
* stderr will be closed.
|
* stderr will be closed.
|
||||||
*/
|
*/
|
||||||
void setStderr(const std::string &stderrFile);
|
void setStderr(const std::string& stderrFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute command.
|
* Execute command.
|
||||||
*
|
*
|
||||||
* Both input and output can be specified, and asynchronous
|
* Both input and output can be specified, and asynchronous
|
||||||
* io (select-based) is used to prevent blocking. This will not
|
* io (select-based) is used to prevent blocking. This will not
|
||||||
* work if input and output need to be synchronized (ie: Q/A), but
|
* work if input and output need to be synchronized (ie: Q/A), but
|
||||||
* works ok for filtering.
|
* works ok for filtering.
|
||||||
* The function is exception-safe. In case an exception occurs in the
|
* The function is exception-safe. In case an exception occurs in the
|
||||||
* advise callback, fds and pids will be cleaned-up properly.
|
* advise callback, fds and pids will be cleaned-up properly.
|
||||||
*
|
*
|
||||||
* @param cmd the program to execute. This must be an absolute file name
|
* @param cmd the program to execute. This must be an absolute file name
|
||||||
* or exist in the PATH.
|
* or exist in the PATH.
|
||||||
* @param args the argument vector (NOT including argv[0]).
|
* @param args the argument vector (NOT including argv[0]).
|
||||||
* @param input Input to send TO the command.
|
* @param input Input to send TO the command.
|
||||||
* @param output Output FROM the command.
|
* @param output Output FROM the command.
|
||||||
* @return the exec output status (0 if ok), or -1
|
* @return the exec output status (0 if ok), or -1
|
||||||
*/
|
*/
|
||||||
int doexec(const std::string &cmd, const std::vector<std::string>& args,
|
int doexec(const std::string& cmd, const std::vector<std::string>& args,
|
||||||
const std::string *input = 0,
|
const std::string *input = 0,
|
||||||
std::string *output = 0);
|
std::string *output = 0);
|
||||||
|
|
||||||
/** Same as doexec but cmd and args in one vector */
|
/** Same as doexec but cmd and args in one vector */
|
||||||
int doexec1(const std::vector<std::string>& args,
|
int doexec1(const std::vector<std::string>& args,
|
||||||
const std::string *input = 0,
|
const std::string *input = 0,
|
||||||
std::string *output = 0) {
|
std::string *output = 0) {
|
||||||
if (args.empty())
|
if (args.empty()) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
return doexec(args[0],
|
return doexec(args[0],
|
||||||
std::vector<std::string>(args.begin() + 1, args.end()),
|
std::vector<std::string>(args.begin() + 1, args.end()),
|
||||||
input, output);
|
input, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The next four methods can be used when a Q/A dialog needs to be
|
* The next four methods can be used when a Q/A dialog needs to be
|
||||||
* performed with the command
|
* performed with the command
|
||||||
*/
|
*/
|
||||||
int startExec(const std::string &cmd, const std::vector<std::string>& args,
|
int startExec(const std::string& cmd, const std::vector<std::string>& args,
|
||||||
bool has_input, bool has_output);
|
bool has_input, bool has_output);
|
||||||
int send(const std::string& data);
|
int send(const std::string& data);
|
||||||
int receive(std::string& data, int cnt = -1);
|
int receive(std::string& data, int cnt = -1);
|
||||||
|
|
||||||
|
@ -162,16 +163,16 @@ class ExecCmd {
|
||||||
|
|
||||||
/** Read line. Timeout after timeosecs seconds */
|
/** Read line. Timeout after timeosecs seconds */
|
||||||
int getline(std::string& data, int timeosecs);
|
int getline(std::string& data, int timeosecs);
|
||||||
|
|
||||||
int wait();
|
int wait();
|
||||||
/** Wait with WNOHANG set.
|
/** Wait with WNOHANG set.
|
||||||
@return true if process exited, false else.
|
@return true if process exited, false else.
|
||||||
@param O: status, the wait(2) call's status value */
|
@param O: status, the wait(2) call's status value */
|
||||||
bool maybereap(int *status);
|
bool maybereap(int *status);
|
||||||
|
|
||||||
pid_t getChildPid();
|
pid_t getChildPid();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel/kill command. This can be called from another thread or
|
* Cancel/kill command. This can be called from another thread or
|
||||||
* from the advise callback, which could also raise an exception
|
* from the advise callback, which could also raise an exception
|
||||||
* to accomplish the same thing. In the owner thread, any I/O loop
|
* to accomplish the same thing. In the owner thread, any I/O loop
|
||||||
|
@ -187,7 +188,7 @@ class ExecCmd {
|
||||||
void zapChild();
|
void zapChild();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request process termination (SIGTERM or equivalent). This returns
|
* Request process termination (SIGTERM or equivalent). This returns
|
||||||
* immediately
|
* immediately
|
||||||
*/
|
*/
|
||||||
bool requestChildExit();
|
bool requestChildExit();
|
||||||
|
@ -197,8 +198,8 @@ class ExecCmd {
|
||||||
// a viewer. The default is to hide the window,
|
// a viewer. The default is to hide the window,
|
||||||
// because it avoids windows appearing and
|
// because it avoids windows appearing and
|
||||||
// disappearing when executing stuff for previewing
|
// disappearing when executing stuff for previewing
|
||||||
EXF_SHOWWINDOW = 1,
|
EXF_SHOWWINDOW = 1,
|
||||||
};
|
};
|
||||||
ExecCmd(int flags = 0);
|
ExecCmd(int flags = 0);
|
||||||
~ExecCmd();
|
~ExecCmd();
|
||||||
|
|
||||||
|
@ -221,37 +222,39 @@ class ExecCmd {
|
||||||
static bool backtick(const std::vector<std::string> cmd, std::string& out);
|
static bool backtick(const std::vector<std::string> cmd, std::string& out);
|
||||||
|
|
||||||
class Internal;
|
class Internal;
|
||||||
private:
|
private:
|
||||||
Internal *m;
|
Internal *m;
|
||||||
/* Copyconst and assignment are private and forbidden */
|
/* Copyconst and assignment are private and forbidden */
|
||||||
ExecCmd(const ExecCmd &) {}
|
ExecCmd(const ExecCmd&) {}
|
||||||
ExecCmd& operator=(const ExecCmd &) {return *this;};
|
ExecCmd& operator=(const ExecCmd&) {
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rexecute self process with the same arguments.
|
* Rexecute self process with the same arguments.
|
||||||
*
|
*
|
||||||
* Note that there are some limitations:
|
* Note that there are some limitations:
|
||||||
* - argv[0] has to be valid: an executable name which will be found in
|
* - argv[0] has to be valid: an executable name which will be found in
|
||||||
* the path when exec is called in the initial working directory. This is
|
* the path when exec is called in the initial working directory. This is
|
||||||
* by no means guaranteed. The shells do this, but argv[0] could be an
|
* by no means guaranteed. The shells do this, but argv[0] could be an
|
||||||
* arbitrary string.
|
* arbitrary string.
|
||||||
* - The initial working directory must be found and remain valid.
|
* - The initial working directory must be found and remain valid.
|
||||||
* - We don't try to do anything with fd 0,1,2. If they were changed by the
|
* - We don't try to do anything with fd 0,1,2. If they were changed by the
|
||||||
* program, their initial meaning won't be the same as at the moment of the
|
* program, their initial meaning won't be the same as at the moment of the
|
||||||
* initial invocation.
|
* initial invocation.
|
||||||
* - We don't restore the signals. Signals set to be blocked
|
* - We don't restore the signals. Signals set to be blocked
|
||||||
* or ignored by the program will remain ignored even if this was not their
|
* or ignored by the program will remain ignored even if this was not their
|
||||||
* initial state.
|
* initial state.
|
||||||
* - The environment is also not restored.
|
* - The environment is also not restored.
|
||||||
* - Others system aspects ?
|
* - Others system aspects ?
|
||||||
* - Other program state: application-dependant. Any external cleanup
|
* - Other program state: application-dependant. Any external cleanup
|
||||||
* (temp files etc.) must be performed by the application. ReExec()
|
* (temp files etc.) must be performed by the application. ReExec()
|
||||||
* duplicates the atexit() function to make this easier, but the
|
* duplicates the atexit() function to make this easier, but the
|
||||||
* ReExec().atexit() calls must be done explicitely, this is not automatic
|
* ReExec().atexit() calls must be done explicitely, this is not automatic
|
||||||
*
|
*
|
||||||
* In short, this is usable in reasonably controlled situations and if there
|
* In short, this is usable in reasonably controlled situations and if there
|
||||||
* are no security issues involved, but this does not perform miracles.
|
* are no security issues involved, but this does not perform miracles.
|
||||||
*/
|
*/
|
||||||
class ReExec {
|
class ReExec {
|
||||||
|
@ -259,13 +262,14 @@ public:
|
||||||
ReExec() {}
|
ReExec() {}
|
||||||
ReExec(int argc, char *argv[]);
|
ReExec(int argc, char *argv[]);
|
||||||
void init(int argc, char *argv[]);
|
void init(int argc, char *argv[]);
|
||||||
int atexit(void (*function)(void))
|
int atexit(void (*function)(void)) {
|
||||||
{
|
m_atexitfuncs.push(function);
|
||||||
m_atexitfuncs.push(function);
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
void reexec();
|
void reexec();
|
||||||
const std::string& getreason() {return m_reason;}
|
const std::string& getreason() {
|
||||||
|
return m_reason;
|
||||||
|
}
|
||||||
// Insert new args into the initial argv. idx designates the place
|
// Insert new args into the initial argv. idx designates the place
|
||||||
// before which the new args are inserted (the default of 1
|
// before which the new args are inserted (the default of 1
|
||||||
// inserts after argv[0] which would probably be an appropriate
|
// inserts after argv[0] which would probably be an appropriate
|
||||||
|
|
|
@ -84,9 +84,9 @@ using namespace std;
|
||||||
static const int one = 1;
|
static const int one = 1;
|
||||||
static const int zero = 0;
|
static const int zero = 0;
|
||||||
|
|
||||||
#define LOGSYSERR(who, call, spar) \
|
#define LOGSYSERR(who, call, spar) \
|
||||||
LOGERR(("%s: %s(%s) errno %d (%s)\n", who, call, \
|
LOGERR(("%s: %s(%s) errno %d (%s)\n", who, call, \
|
||||||
spar, errno, strerror(errno)))
|
spar, errno, strerror(errno)))
|
||||||
|
|
||||||
#ifndef MIN
|
#ifndef MIN
|
||||||
#define MIN(a,b) (a<b?a:b)
|
#define MIN(a,b) (a<b?a:b)
|
||||||
|
@ -99,7 +99,7 @@ static const int zero = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MILLIS(OLD, NEW) ( (long)(((NEW).tv_sec - (OLD).tv_sec) * 1000 + \
|
#define MILLIS(OLD, NEW) ( (long)(((NEW).tv_sec - (OLD).tv_sec) * 1000 + \
|
||||||
((NEW).tv_usec - (OLD).tv_usec) / 1000))
|
((NEW).tv_usec - (OLD).tv_usec) / 1000))
|
||||||
|
|
||||||
// Static method
|
// Static method
|
||||||
// Simplified interface to 'select()'. Only use one fd, for either
|
// Simplified interface to 'select()'. Only use one fd, for either
|
||||||
|
@ -116,12 +116,12 @@ int Netcon::select1(int fd, int timeo, int write)
|
||||||
FD_ZERO(&rd);
|
FD_ZERO(&rd);
|
||||||
FD_SET(fd, &rd);
|
FD_SET(fd, &rd);
|
||||||
if (write) {
|
if (write) {
|
||||||
ret = select(fd+1, 0, &rd, 0, &tv);
|
ret = select(fd + 1, 0, &rd, 0, &tv);
|
||||||
} else {
|
} else {
|
||||||
ret = select(fd+1, &rd, 0, 0, &tv);
|
ret = select(fd + 1, &rd, 0, 0, &tv);
|
||||||
}
|
}
|
||||||
if (!FD_ISSET(fd, &rd)) {
|
if (!FD_ISSET(fd, &rd)) {
|
||||||
LOGDEB2(("Netcon::select1: fd %d timeout\n",fd));
|
LOGDEB2(("Netcon::select1: fd %d timeout\n", fd));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -199,11 +199,11 @@ int SelectLoop::doLoop()
|
||||||
// Walk the netcon map and set up the read and write fd_sets
|
// Walk the netcon map and set up the read and write fd_sets
|
||||||
// for select()
|
// for select()
|
||||||
nfds = 0;
|
nfds = 0;
|
||||||
for (map<int,NetconP>::iterator it = m_polldata.begin();
|
for (map<int, NetconP>::iterator it = m_polldata.begin();
|
||||||
it != m_polldata.end(); it++) {
|
it != m_polldata.end(); it++) {
|
||||||
NetconP &pll = it->second;
|
NetconP& pll = it->second;
|
||||||
int fd = it->first;
|
int fd = it->first;
|
||||||
LOGDEB2(("Selectloop: fd %d flags 0x%x\n",fd, pll->m_wantedEvents));
|
LOGDEB2(("Selectloop: fd %d flags 0x%x\n", fd, pll->m_wantedEvents));
|
||||||
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
if (pll->m_wantedEvents & Netcon::NETCONPOLL_READ) {
|
||||||
FD_SET(fd, &rd);
|
FD_SET(fd, &rd);
|
||||||
nfds = MAX(nfds, fd + 1);
|
nfds = MAX(nfds, fd + 1);
|
||||||
|
@ -275,7 +275,7 @@ int SelectLoop::doLoop()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
map<int,NetconP>::iterator it = m_polldata.find(fd);
|
map<int, NetconP>::iterator it = m_polldata.find(fd);
|
||||||
if (it == m_polldata.end()) {
|
if (it == m_polldata.end()) {
|
||||||
/// This should not happen actually
|
/// This should not happen actually
|
||||||
LOGDEB2(("Netcon::selectloop: fd %d not found\n", fd));
|
LOGDEB2(("Netcon::selectloop: fd %d not found\n", fd));
|
||||||
|
@ -284,14 +284,14 @@ int SelectLoop::doLoop()
|
||||||
|
|
||||||
// Next start will be one beyond last serviced (modulo nfds)
|
// Next start will be one beyond last serviced (modulo nfds)
|
||||||
m_placetostart = fd + 1;
|
m_placetostart = fd + 1;
|
||||||
NetconP &pll = it->second;
|
NetconP& pll = it->second;
|
||||||
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) {
|
if (canread && pll->cando(Netcon::NETCONPOLL_READ) <= 0) {
|
||||||
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ;
|
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_READ;
|
||||||
}
|
}
|
||||||
if (canwrite && pll->cando(Netcon::NETCONPOLL_WRITE) <= 0) {
|
if (canwrite && pll->cando(Netcon::NETCONPOLL_WRITE) <= 0) {
|
||||||
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_WRITE;
|
pll->m_wantedEvents &= ~Netcon::NETCONPOLL_WRITE;
|
||||||
}
|
}
|
||||||
if (!(pll->m_wantedEvents & (Netcon::NETCONPOLL_WRITE|Netcon::NETCONPOLL_READ))) {
|
if (!(pll->m_wantedEvents & (Netcon::NETCONPOLL_WRITE | Netcon::NETCONPOLL_READ))) {
|
||||||
LOGDEB0(("Netcon::selectloop: fd %d has 0x%x mask, erasing\n",
|
LOGDEB0(("Netcon::selectloop: fd %d has 0x%x mask, erasing\n",
|
||||||
it->first, it->second->m_wantedEvents));
|
it->first, it->second->m_wantedEvents));
|
||||||
m_polldata.erase(it);
|
m_polldata.erase(it);
|
||||||
|
@ -324,7 +324,7 @@ int SelectLoop::remselcon(NetconP con)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
LOGDEB1(("Netcon::remselcon: fd %d\n", con->m_fd));
|
LOGDEB1(("Netcon::remselcon: fd %d\n", con->m_fd));
|
||||||
map<int,NetconP>::iterator it = m_polldata.find(con->m_fd);
|
map<int, NetconP>::iterator it = m_polldata.find(con->m_fd);
|
||||||
if (it == m_polldata.end()) {
|
if (it == m_polldata.end()) {
|
||||||
LOGDEB1(("Netcon::remselcon: con not found for fd %d\n", con->m_fd));
|
LOGDEB1(("Netcon::remselcon: con not found for fd %d\n", con->m_fd));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -336,7 +336,7 @@ int SelectLoop::remselcon(NetconP con)
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// Base class (Netcon) methods
|
// Base class (Netcon) methods
|
||||||
Netcon::~Netcon()
|
Netcon::~Netcon()
|
||||||
{
|
{
|
||||||
closeconn();
|
closeconn();
|
||||||
if (m_peer) {
|
if (m_peer) {
|
||||||
|
@ -369,7 +369,7 @@ void Netcon::setpeer(const char *hostname)
|
||||||
|
|
||||||
int Netcon::settcpnodelay(int on)
|
int Netcon::settcpnodelay(int on)
|
||||||
{
|
{
|
||||||
LOGDEB2(( "Netcon::settcpnodelay\n" ));
|
LOGDEB2(("Netcon::settcpnodelay\n"));
|
||||||
if (m_fd < 0) {
|
if (m_fd < 0) {
|
||||||
LOGERR(("Netcon::settcpnodelay: connection not opened\n"));
|
LOGERR(("Netcon::settcpnodelay: connection not opened\n"));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -386,7 +386,7 @@ int Netcon::settcpnodelay(int on)
|
||||||
int Netcon::set_nonblock(int onoff)
|
int Netcon::set_nonblock(int onoff)
|
||||||
{
|
{
|
||||||
int flags = fcntl(m_fd, F_GETFL, 0);
|
int flags = fcntl(m_fd, F_GETFL, 0);
|
||||||
if (flags != -1 ) {
|
if (flags != -1) {
|
||||||
int newflags = onoff ? flags | O_NONBLOCK : flags & ~O_NONBLOCK;
|
int newflags = onoff ? flags | O_NONBLOCK : flags & ~O_NONBLOCK;
|
||||||
if (newflags != flags)
|
if (newflags != flags)
|
||||||
if (fcntl(m_fd, F_SETFL, newflags) < 0) {
|
if (fcntl(m_fd, F_SETFL, newflags) < 0) {
|
||||||
|
@ -399,7 +399,7 @@ int Netcon::set_nonblock(int onoff)
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
// Data socket (NetconData) methods
|
// Data socket (NetconData) methods
|
||||||
|
|
||||||
NetconData::~NetconData()
|
NetconData::~NetconData()
|
||||||
{
|
{
|
||||||
freeZ(m_buf);
|
freeZ(m_buf);
|
||||||
m_bufbase = 0;
|
m_bufbase = 0;
|
||||||
|
@ -511,7 +511,7 @@ int NetconData::doreceive(char *buf, int cnt, int timeo)
|
||||||
LOGDEB2(("Netcon::doreceive: cnt %d, timeo %d\n", cnt, timeo));
|
LOGDEB2(("Netcon::doreceive: cnt %d, timeo %d\n", cnt, timeo));
|
||||||
cur = 0;
|
cur = 0;
|
||||||
while (cnt > cur) {
|
while (cnt > cur) {
|
||||||
got = receive(buf, cnt-cur, timeo);
|
got = receive(buf, cnt - cur, timeo);
|
||||||
LOGDEB2(("Netcon::doreceive: got %d\n", got));
|
LOGDEB2(("Netcon::doreceive: got %d\n", got));
|
||||||
if (got < 0) {
|
if (got < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -551,7 +551,7 @@ int NetconData::getline(char *buf, int cnt, int timeo)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// Transfer from buffer. Have to take a lot of care to keep counts and
|
// Transfer from buffer. Have to take a lot of care to keep counts and
|
||||||
// pointers consistant in all end cases
|
// pointers consistant in all end cases
|
||||||
int maxtransf = MIN(m_bufbytes, cnt-1);
|
int maxtransf = MIN(m_bufbytes, cnt - 1);
|
||||||
int nn = maxtransf;
|
int nn = maxtransf;
|
||||||
LOGDEB2(("Before loop, bufbytes %d, maxtransf %d, nn: %d\n",
|
LOGDEB2(("Before loop, bufbytes %d, maxtransf %d, nn: %d\n",
|
||||||
m_bufbytes, maxtransf, nn));
|
m_bufbytes, maxtransf, nn));
|
||||||
|
@ -648,7 +648,7 @@ int NetconCli::openconn(const char *host, unsigned int port, int timeo)
|
||||||
} else {
|
} else {
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
if ((hp = gethostbyname(host)) == 0) {
|
if ((hp = gethostbyname(host)) == 0) {
|
||||||
LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n",
|
LOGERR(("NetconCli::openconn: gethostbyname(%s) failed\n",
|
||||||
host));
|
host));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -723,7 +723,7 @@ int NetconCli::openconn(const char *host, const char *serv, int timeo)
|
||||||
if (host[0] != '/') {
|
if (host[0] != '/') {
|
||||||
struct servent *sp;
|
struct servent *sp;
|
||||||
if ((sp = getservbyname(serv, "tcp")) == 0) {
|
if ((sp = getservbyname(serv, "tcp")) == 0) {
|
||||||
LOGERR(("NetconCli::openconn: getservbyname failed for %s\n",serv));
|
LOGERR(("NetconCli::openconn: getservbyname failed for %s\n", serv));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// Callee expects the port number in host byte order
|
// Callee expects the port number in host byte order
|
||||||
|
@ -749,7 +749,7 @@ int NetconCli::setconn(int fd)
|
||||||
///////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////
|
||||||
// Methods for the main (listening) server connection
|
// Methods for the main (listening) server connection
|
||||||
|
|
||||||
NetconServLis::~NetconServLis()
|
NetconServLis::~NetconServLis()
|
||||||
{
|
{
|
||||||
#ifdef NETCON_ACCESSCONTROL
|
#ifdef NETCON_ACCESSCONTROL
|
||||||
freeZ(okaddrs.intarray);
|
freeZ(okaddrs.intarray);
|
||||||
|
@ -759,7 +759,7 @@ NetconServLis::~NetconServLis()
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// code for dumping a struct servent
|
// code for dumping a struct servent
|
||||||
static void dump_servent(struct servent *servp)
|
static void dump_servent(struct servent *servp)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Official name %s\n", servp->s_name);
|
fprintf(stderr, "Official name %s\n", servp->s_name);
|
||||||
for (char **cpp = servp->s_aliases; *cpp; cpp++) {
|
for (char **cpp = servp->s_aliases; *cpp; cpp++) {
|
||||||
|
@ -822,7 +822,7 @@ int NetconServLis::openservice(const char *serv, int backlog)
|
||||||
|
|
||||||
LOGDEB1(("NetconServLis::openservice: service opened ok\n"));
|
LOGDEB1(("NetconServLis::openservice: service opened ok\n"));
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
if (ret < 0 && m_fd >= 0) {
|
if (ret < 0 && m_fd >= 0) {
|
||||||
close(m_fd);
|
close(m_fd);
|
||||||
m_fd = -1;
|
m_fd = -1;
|
||||||
|
@ -841,14 +841,14 @@ int NetconServLis::openservice(int port, int backlog)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct sockaddr_in ipaddr;
|
struct sockaddr_in ipaddr;
|
||||||
if ((m_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
if ((m_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
LOGSYSERR("NetconServLis", "socket", "");
|
LOGSYSERR("NetconServLis", "socket", "");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
(void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR,(char *)&one, sizeof(one));
|
(void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
|
||||||
#ifdef SO_REUSEPORT
|
#ifdef SO_REUSEPORT
|
||||||
(void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT,(char *)&one, sizeof(one));
|
(void) setsockopt(m_fd, SOL_SOCKET, SO_REUSEPORT, (char *)&one, sizeof(one));
|
||||||
#endif /*SO_REUSEPORT*/
|
#endif /*SO_REUSEPORT*/
|
||||||
memset(&ipaddr, 0, sizeof(ipaddr));
|
memset(&ipaddr, 0, sizeof(ipaddr));
|
||||||
ipaddr.sin_family = AF_INET;
|
ipaddr.sin_family = AF_INET;
|
||||||
|
@ -983,10 +983,10 @@ NetconServLis::accept(int timeo)
|
||||||
// Retrieve peer's host name. Errors are non fatal
|
// Retrieve peer's host name. Errors are non fatal
|
||||||
if (m_serv.empty() || m_serv[0] != '/') {
|
if (m_serv.empty() || m_serv[0] != '/') {
|
||||||
struct hostent *hp;
|
struct hostent *hp;
|
||||||
if ((hp = gethostbyaddr((char *) & (who.sin_addr),
|
if ((hp = gethostbyaddr((char *) & (who.sin_addr),
|
||||||
sizeof(struct in_addr), AF_INET)) == 0) {
|
sizeof(struct in_addr), AF_INET)) == 0) {
|
||||||
LOGERR(("NetconServLis::accept: gethostbyaddr failed for addr 0x%lx\n",
|
LOGERR(("NetconServLis::accept: gethostbyaddr failed for addr 0x%lx\n",
|
||||||
who.sin_addr.s_addr));
|
who.sin_addr.s_addr));
|
||||||
con->setpeer(inet_ntoa(who.sin_addr));
|
con->setpeer(inet_ntoa(who.sin_addr));
|
||||||
} else {
|
} else {
|
||||||
con->setpeer(hp->h_name);
|
con->setpeer(hp->h_name);
|
||||||
|
@ -1033,7 +1033,7 @@ NetconServLis::checkperms(void *cl, int)
|
||||||
if (i < okmasks.len) {
|
if (i < okmasks.len) {
|
||||||
mask = okmasks.intarray[i];
|
mask = okmasks.intarray[i];
|
||||||
} else {
|
} else {
|
||||||
mask = okmasks.intarray[okmasks.len-1];
|
mask = okmasks.intarray[okmasks.len - 1];
|
||||||
}
|
}
|
||||||
LOGDEB2(("checkperms: trying okaddr 0x%x, mask 0x%x\n",
|
LOGDEB2(("checkperms: trying okaddr 0x%x, mask 0x%x\n",
|
||||||
okaddrs.intarray[i], mask));
|
okaddrs.intarray[i], mask));
|
||||||
|
@ -1080,9 +1080,9 @@ Usage()
|
||||||
|
|
||||||
static int op_flags;
|
static int op_flags;
|
||||||
#define OPT_MOINS 0x1
|
#define OPT_MOINS 0x1
|
||||||
#define OPT_s 0x2 /* Server */
|
#define OPT_s 0x2 /* Server */
|
||||||
#define OPT_c 0x4 /* Client */
|
#define OPT_c 0x4 /* Client */
|
||||||
#define OPT_n 0x8 /* Client sleeps forever */
|
#define OPT_n 0x8 /* Client sleeps forever */
|
||||||
|
|
||||||
extern int trycli(char *host, char *serv);
|
extern int trycli(char *host, char *serv);
|
||||||
extern int tryserv(char *serv);
|
extern int tryserv(char *serv);
|
||||||
|
@ -1118,7 +1118,7 @@ int main(int argc, char **argv)
|
||||||
default:
|
default:
|
||||||
Usage();
|
Usage();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
@ -1209,8 +1209,8 @@ int trycli(char *host, char *serv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int port = atoi(serv);
|
int port = atoi(serv);
|
||||||
int ret = port > 0 ?
|
int ret = port > 0 ?
|
||||||
clicon->openconn(host, port) : clicon->openconn(host, serv);
|
clicon->openconn(host, port) : clicon->openconn(host, serv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "openconn(%s, %s) failed\n", host, serv);
|
fprintf(stderr, "openconn(%s, %s) failed\n", host, serv);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1271,7 +1271,7 @@ public:
|
||||||
}
|
}
|
||||||
if (reason & Netcon::NETCONPOLL_READ) {
|
if (reason & Netcon::NETCONPOLL_READ) {
|
||||||
#define LL 200
|
#define LL 200
|
||||||
char buf[LL+1];
|
char buf[LL + 1];
|
||||||
int n;
|
int n;
|
||||||
if ((n = con->receive(buf, LL)) < 0) {
|
if ((n = con->receive(buf, LL)) < 0) {
|
||||||
fprintf(stderr, "receive failed\n");
|
fprintf(stderr, "receive failed\n");
|
||||||
|
@ -1282,7 +1282,7 @@ public:
|
||||||
}
|
}
|
||||||
buf[n] = 0;
|
buf[n] = 0;
|
||||||
fprintf(stderr, "%d received \"%s\"\n", getpid(), buf);
|
fprintf(stderr, "%d received \"%s\"\n", getpid(), buf);
|
||||||
con->setselevents(Netcon::NETCONPOLL_READ|Netcon::NETCONPOLL_WRITE);
|
con->setselevents(Netcon::NETCONPOLL_READ | Netcon::NETCONPOLL_WRITE);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1292,7 +1292,7 @@ private:
|
||||||
|
|
||||||
class MyNetconServLis : public NetconServLis {
|
class MyNetconServLis : public NetconServLis {
|
||||||
public:
|
public:
|
||||||
MyNetconServLis(SelectLoop &loop)
|
MyNetconServLis(SelectLoop& loop)
|
||||||
: NetconServLis(), m_loop(loop) {
|
: NetconServLis(), m_loop(loop) {
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
|
@ -1344,8 +1344,8 @@ int tryserv(char *serv)
|
||||||
sigaction(SIGTERM, &sa, 0);
|
sigaction(SIGTERM, &sa, 0);
|
||||||
|
|
||||||
int port = atoi(serv);
|
int port = atoi(serv);
|
||||||
int ret = port > 0 ?
|
int ret = port > 0 ?
|
||||||
servlis->openservice(port) : servlis->openservice(serv);
|
servlis->openservice(port) : servlis->openservice(serv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
fprintf(stderr, "openservice(%s) failed\n", serv);
|
fprintf(stderr, "openservice(%s) failed\n", serv);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
/// endpoints. Netcon also has server-side static code to handle a set
|
/// endpoints. Netcon also has server-side static code to handle a set
|
||||||
/// of client connections in parallel. This should be moved to a
|
/// of client connections in parallel. This should be moved to a
|
||||||
/// friend class.
|
/// friend class.
|
||||||
///
|
///
|
||||||
/// The client data transfer class can also be used for
|
/// The client data transfer class can also be used for
|
||||||
/// timeout-protected/asynchronous io using a given fd (ie a pipe
|
/// timeout-protected/asynchronous io using a given fd (ie a pipe
|
||||||
/// descriptor)
|
/// descriptor)
|
||||||
|
@ -48,25 +48,25 @@ class SelectLoop;
|
||||||
|
|
||||||
class Netcon {
|
class Netcon {
|
||||||
public:
|
public:
|
||||||
enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE=0x2};
|
enum Event {NETCONPOLL_READ = 0x1, NETCONPOLL_WRITE = 0x2};
|
||||||
Netcon()
|
Netcon()
|
||||||
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0),
|
: m_peer(0), m_fd(-1), m_ownfd(true), m_didtimo(0), m_wantedEvents(0),
|
||||||
m_loop(0) {
|
m_loop(0) {
|
||||||
}
|
}
|
||||||
virtual ~Netcon();
|
virtual ~Netcon();
|
||||||
/// Remember whom we're talking to. We let external code do this because
|
/// Remember whom we're talking to. We let external code do this because
|
||||||
/// the application may have a non-dns method to find the peer name.
|
/// the application may have a non-dns method to find the peer name.
|
||||||
virtual void setpeer(const char *hostname);
|
virtual void setpeer(const char *hostname);
|
||||||
/// Retrieve the peer's hostname. Only works if it was set before !
|
/// Retrieve the peer's hostname. Only works if it was set before !
|
||||||
virtual const char *getpeer() {
|
virtual const char *getpeer() {
|
||||||
return m_peer ? (const char *)m_peer : "none";
|
return m_peer ? (const char *)m_peer : "none";
|
||||||
}
|
}
|
||||||
/// Set or reset the TCP_NODELAY option.
|
/// Set or reset the TCP_NODELAY option.
|
||||||
virtual int settcpnodelay(int on = 1);
|
virtual int settcpnodelay(int on = 1);
|
||||||
/// Did the last receive() call time out ? Resets the flag.
|
/// Did the last receive() call time out ? Resets the flag.
|
||||||
virtual int timedout() {
|
virtual int timedout() {
|
||||||
int s = m_didtimo;
|
int s = m_didtimo;
|
||||||
m_didtimo = 0;
|
m_didtimo = 0;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
/// Return string version of last syscall error
|
/// Return string version of last syscall error
|
||||||
|
@ -111,7 +111,7 @@ public:
|
||||||
static int select1(int fd, int secs, int writing = 0);
|
static int select1(int fd, int secs, int writing = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
char *m_peer; // Name of the connected host
|
char *m_peer; // Name of the connected host
|
||||||
int m_fd;
|
int m_fd;
|
||||||
bool m_ownfd;
|
bool m_ownfd;
|
||||||
int m_didtimo;
|
int m_didtimo;
|
||||||
|
@ -127,7 +127,7 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// The selectloop interface is used to implement parallel servers.
|
/// The selectloop interface is used to implement parallel servers.
|
||||||
// The select loop mechanism allows several netcons to be used for io
|
// The select loop mechanism allows several netcons to be used for io
|
||||||
// in a program without blocking as long as there is data to be read
|
// in a program without blocking as long as there is data to be read
|
||||||
// or written. In a multithread program which is also using select, it
|
// or written. In a multithread program which is also using select, it
|
||||||
|
@ -136,13 +136,13 @@ protected:
|
||||||
class SelectLoop {
|
class SelectLoop {
|
||||||
public:
|
public:
|
||||||
SelectLoop()
|
SelectLoop()
|
||||||
: m_selectloopDoReturn(false), m_selectloopReturnValue(0),
|
: m_selectloopDoReturn(false), m_selectloopReturnValue(0),
|
||||||
m_placetostart(0),
|
m_placetostart(0),
|
||||||
m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0) {
|
m_periodichandler(0), m_periodicparam(0), m_periodicmillis(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loop waiting for events on the connections and call the
|
/// Loop waiting for events on the connections and call the
|
||||||
/// cando() method on the object when something happens (this will in
|
/// cando() method on the object when something happens (this will in
|
||||||
/// turn typically call the app callback set on the netcon). Possibly
|
/// turn typically call the app callback set on the netcon). Possibly
|
||||||
/// call the periodic handler (if set) at regular intervals.
|
/// call the periodic handler (if set) at regular intervals.
|
||||||
/// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
|
/// @return -1 for error. 0 if no descriptors left for i/o. 1 for periodic
|
||||||
|
@ -151,8 +151,8 @@ public:
|
||||||
|
|
||||||
/// Call from data handler: make selectloop return the param value
|
/// Call from data handler: make selectloop return the param value
|
||||||
void loopReturn(int value) {
|
void loopReturn(int value) {
|
||||||
m_selectloopDoReturn = true;
|
m_selectloopDoReturn = true;
|
||||||
m_selectloopReturnValue = value;
|
m_selectloopReturnValue = value;
|
||||||
}
|
}
|
||||||
/// Add a connection to be monitored (this will usually be called
|
/// Add a connection to be monitored (this will usually be called
|
||||||
/// from the server's listen connection's accept callback)
|
/// from the server's listen connection's accept callback)
|
||||||
|
@ -162,11 +162,11 @@ public:
|
||||||
int remselcon(NetconP con);
|
int remselcon(NetconP con);
|
||||||
|
|
||||||
/// Set a function to be called periodically, or a time before return.
|
/// Set a function to be called periodically, or a time before return.
|
||||||
/// @param handler the function to be called.
|
/// @param handler the function to be called.
|
||||||
/// - if it is 0, selectloop() will return after ms mS (and can be called
|
/// - if it is 0, selectloop() will return after ms mS (and can be called
|
||||||
/// again
|
/// again
|
||||||
/// - if it is not 0, it will be called at ms mS intervals. If its return
|
/// - if it is not 0, it will be called at ms mS intervals. If its return
|
||||||
/// value is <= 0, selectloop will return.
|
/// value is <= 0, selectloop will return.
|
||||||
/// @param clp client data to be passed to handler at every call.
|
/// @param clp client data to be passed to handler at every call.
|
||||||
/// @param ms milliseconds interval between handler calls or
|
/// @param ms milliseconds interval between handler calls or
|
||||||
/// before return. Set to 0 for no periodic handler.
|
/// before return. Set to 0 for no periodic handler.
|
||||||
|
@ -195,12 +195,12 @@ private:
|
||||||
///////////////////////
|
///////////////////////
|
||||||
class NetconData;
|
class NetconData;
|
||||||
|
|
||||||
/// Class for the application callback routine (when in selectloop).
|
/// Class for the application callback routine (when in selectloop).
|
||||||
///
|
///
|
||||||
/// This is set by the app on the NetconData by calling
|
/// This is set by the app on the NetconData by calling
|
||||||
/// setcallback(). It is then called from the NetconData's cando()
|
/// setcallback(). It is then called from the NetconData's cando()
|
||||||
/// routine, itself called by selectloop.
|
/// routine, itself called by selectloop.
|
||||||
///
|
///
|
||||||
/// It would be nicer to override cando() in a subclass instead of
|
/// It would be nicer to override cando() in a subclass instead of
|
||||||
/// setting a callback, but this can't be done conveniently because
|
/// setting a callback, but this can't be done conveniently because
|
||||||
/// accept() always creates a base NetconData (another approach would
|
/// accept() always creates a base NetconData (another approach would
|
||||||
|
@ -229,7 +229,7 @@ public:
|
||||||
|
|
||||||
/// Read from the connection
|
/// Read from the connection
|
||||||
/// @param buf the data buffer
|
/// @param buf the data buffer
|
||||||
/// @param cnt the number of bytes we should try to read (but we return
|
/// @param cnt the number of bytes we should try to read (but we return
|
||||||
/// as soon as we get data)
|
/// as soon as we get data)
|
||||||
/// @param timeo maximum number of seconds we should be waiting for data.
|
/// @param timeo maximum number of seconds we should be waiting for data.
|
||||||
/// @return the count of bytes actually read. 0 for timeout (call
|
/// @return the count of bytes actually read. 0 for timeout (call
|
||||||
|
@ -251,16 +251,16 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char *m_buf; // Buffer. Only used when doing getline()s
|
char *m_buf; // Buffer. Only used when doing getline()s
|
||||||
char *m_bufbase; // Pointer to current 1st byte of useful data
|
char *m_bufbase; // Pointer to current 1st byte of useful data
|
||||||
int m_bufbytes; // Bytes of data.
|
int m_bufbytes; // Bytes of data.
|
||||||
int m_bufsize; // Total buffer size
|
int m_bufsize; // Total buffer size
|
||||||
STD_SHARED_PTR<NetconWorker> m_user;
|
STD_SHARED_PTR<NetconWorker> m_user;
|
||||||
virtual int cando(Netcon::Event reason); // Selectloop slot
|
virtual int cando(Netcon::Event reason); // Selectloop slot
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Network endpoint, client side.
|
/// Network endpoint, client side.
|
||||||
class NetconCli : public NetconData {
|
class NetconCli : public NetconData {
|
||||||
public:
|
public:
|
||||||
NetconCli(int silent = 0) {
|
NetconCli(int silent = 0) {
|
||||||
m_silentconnectfailure = silent;
|
m_silentconnectfailure = silent;
|
||||||
|
@ -276,7 +276,7 @@ public:
|
||||||
/// AF_UNIX service. serv is ignored in this case.
|
/// AF_UNIX service. serv is ignored in this case.
|
||||||
int openconn(const char *host, unsigned int port, int timeo = -1);
|
int openconn(const char *host, unsigned int port, int timeo = -1);
|
||||||
|
|
||||||
/// Reuse existing fd.
|
/// Reuse existing fd.
|
||||||
/// We DONT take ownership of the fd, and do no closin' EVEN on an
|
/// We DONT take ownership of the fd, and do no closin' EVEN on an
|
||||||
/// explicit closeconn() or setconn() (use getfd(), close,
|
/// explicit closeconn() or setconn() (use getfd(), close,
|
||||||
/// setconn(-1) if you need to really close the fd and have no
|
/// setconn(-1) if you need to really close the fd and have no
|
||||||
|
@ -289,7 +289,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_silentconnectfailure; // No logging of connection failures if set
|
int m_silentconnectfailure; // No logging of connection failures if set
|
||||||
};
|
};
|
||||||
|
|
||||||
class NetconServCon;
|
class NetconServCon;
|
||||||
|
@ -316,9 +316,9 @@ class NetconServLis : public Netcon {
|
||||||
public:
|
public:
|
||||||
NetconServLis() {
|
NetconServLis() {
|
||||||
#ifdef NETCON_ACCESSCONTROL
|
#ifdef NETCON_ACCESSCONTROL
|
||||||
permsinit = 0;
|
permsinit = 0;
|
||||||
okaddrs.len = okmasks.len = 0;
|
okaddrs.len = okmasks.len = 0;
|
||||||
okaddrs.intarray = okmasks.intarray = 0;
|
okaddrs.intarray = okmasks.intarray = 0;
|
||||||
#endif /* NETCON_ACCESSCONTROL */
|
#endif /* NETCON_ACCESSCONTROL */
|
||||||
}
|
}
|
||||||
~NetconServLis();
|
~NetconServLis();
|
||||||
|
@ -327,7 +327,7 @@ public:
|
||||||
int openservice(const char *serv, int backlog = 10);
|
int openservice(const char *serv, int backlog = 10);
|
||||||
/// Open service by port number.
|
/// Open service by port number.
|
||||||
int openservice(int port, int backlog = 10);
|
int openservice(int port, int backlog = 10);
|
||||||
/// Wait for incoming connection. Returned connected Netcon
|
/// Wait for incoming connection. Returned connected Netcon
|
||||||
NetconServCon *accept(int timeo = -1);
|
NetconServCon *accept(int timeo = -1);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -337,7 +337,7 @@ protected:
|
||||||
virtual int cando(Netcon::Event reason);
|
virtual int cando(Netcon::Event reason);
|
||||||
|
|
||||||
// Empty if port was numeric, else service name or socket path
|
// Empty if port was numeric, else service name or socket path
|
||||||
std::string m_serv;
|
std::string m_serv;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef NETCON_ACCESSCONTROL
|
#ifdef NETCON_ACCESSCONTROL
|
||||||
|
@ -353,16 +353,16 @@ private:
|
||||||
/// Server-side accepted client connection. The only specific code
|
/// Server-side accepted client connection. The only specific code
|
||||||
/// allows closing the listening endpoint in the child process (in the
|
/// allows closing the listening endpoint in the child process (in the
|
||||||
/// case of a forking server)
|
/// case of a forking server)
|
||||||
class NetconServCon : public NetconData {
|
class NetconServCon : public NetconData {
|
||||||
public:
|
public:
|
||||||
NetconServCon(int newfd, Netcon* lis = 0) {
|
NetconServCon(int newfd, Netcon* lis = 0) {
|
||||||
m_liscon = lis;
|
m_liscon = lis;
|
||||||
m_fd = newfd;
|
m_fd = newfd;
|
||||||
}
|
}
|
||||||
/// This is for forked servers that want to get rid of the main socket
|
/// This is for forked servers that want to get rid of the main socket
|
||||||
void closeLisCon() {
|
void closeLisCon() {
|
||||||
if (m_liscon) {
|
if (m_liscon) {
|
||||||
m_liscon->closeconn();
|
m_liscon->closeconn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -22,12 +22,16 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "safefcntl.h"
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "safefcntl.h"
|
||||||
#include "safesysstat.h"
|
#include "safesysstat.h"
|
||||||
#include "safeunistd.h"
|
#include "safeunistd.h"
|
||||||
#ifndef _WIN32
|
#else
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -41,33 +45,34 @@ public:
|
||||||
FileToString(string& data) : m_data(data) {}
|
FileToString(string& data) : m_data(data) {}
|
||||||
string& m_data;
|
string& m_data;
|
||||||
bool init(size_t size, string *reason) {
|
bool init(size_t size, string *reason) {
|
||||||
if (size > 0)
|
if (size > 0) {
|
||||||
m_data.reserve(size);
|
m_data.reserve(size);
|
||||||
return true;
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
bool data(const char *buf, int cnt, string *reason) {
|
bool data(const char *buf, int cnt, string *reason) {
|
||||||
try {
|
try {
|
||||||
m_data.append(buf, cnt);
|
m_data.append(buf, cnt);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
catstrerror(reason, "append", errno);
|
catstrerror(reason, "append", errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool file_to_string(const string &fn, string &data, string *reason)
|
bool file_to_string(const string& fn, string& data, string *reason)
|
||||||
{
|
{
|
||||||
return file_to_string(fn, data, 0, size_t(-1), reason);
|
return file_to_string(fn, data, 0, size_t(-1), reason);
|
||||||
}
|
}
|
||||||
bool file_to_string(const string &fn, string &data, off_t offs, size_t cnt,
|
bool file_to_string(const string& fn, string& data, off_t offs, size_t cnt,
|
||||||
string *reason)
|
string *reason)
|
||||||
{
|
{
|
||||||
FileToString accum(data);
|
FileToString accum(data);
|
||||||
return file_scan(fn, &accum, offs, cnt, reason);
|
return file_scan(fn, &accum, offs, cnt, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool file_scan(const string &fn, FileScanDo* doer, string *reason)
|
bool file_scan(const string& fn, FileScanDo* doer, string *reason)
|
||||||
{
|
{
|
||||||
return file_scan(fn, doer, 0, size_t(-1), reason);
|
return file_scan(fn, doer, 0, size_t(-1), reason);
|
||||||
}
|
}
|
||||||
|
@ -77,29 +82,29 @@ const int RDBUFSZ = 8192;
|
||||||
// on both linux i586 and macosx (compared to just append())
|
// on both linux i586 and macosx (compared to just append())
|
||||||
// Also tried a version with mmap, but it's actually slower on the mac and not
|
// Also tried a version with mmap, but it's actually slower on the mac and not
|
||||||
// faster on linux.
|
// faster on linux.
|
||||||
bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs,
|
bool file_scan(const string& fn, FileScanDo* doer, off_t startoffs,
|
||||||
size_t cnttoread, string *reason)
|
size_t cnttoread, string *reason)
|
||||||
{
|
{
|
||||||
if (startoffs < 0) {
|
if (startoffs < 0) {
|
||||||
*reason += " file_scan: negative startoffs not allowed";
|
*reason += " file_scan: negative startoffs not allowed";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
bool noclosing = true;
|
bool noclosing = true;
|
||||||
int fd = 0;
|
int fd = 0;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
// Initialize st_size: if fn.empty() , the fstat() call won't happen.
|
// Initialize st_size: if fn.empty() , the fstat() call won't happen.
|
||||||
st.st_size = 0;
|
st.st_size = 0;
|
||||||
|
|
||||||
// If we have a file name, open it, else use stdin.
|
// If we have a file name, open it, else use stdin.
|
||||||
if (!fn.empty()) {
|
if (!fn.empty()) {
|
||||||
fd = open(fn.c_str(), O_RDONLY|O_BINARY);
|
fd = open(fn.c_str(), O_RDONLY | O_BINARY);
|
||||||
if (fd < 0 || fstat(fd, &st) < 0) {
|
if (fd < 0 || fstat(fd, &st) < 0) {
|
||||||
catstrerror(reason, "open/stat", errno);
|
catstrerror(reason, "open/stat", errno);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
noclosing = false;
|
noclosing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined O_NOATIME && O_NOATIME != 0
|
#if defined O_NOATIME && O_NOATIME != 0
|
||||||
|
@ -108,12 +113,12 @@ bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cnttoread != (size_t)-1 && cnttoread) {
|
if (cnttoread != (size_t) - 1 && cnttoread) {
|
||||||
doer->init(cnttoread+1, reason);
|
doer->init(cnttoread + 1, reason);
|
||||||
} else if (st.st_size > 0) {
|
} else if (st.st_size > 0) {
|
||||||
doer->init(size_t(st.st_size+1), reason);
|
doer->init(size_t(st.st_size + 1), reason);
|
||||||
} else {
|
} else {
|
||||||
doer->init(0, reason);
|
doer->init(0, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
off_t curoffs = 0;
|
off_t curoffs = 0;
|
||||||
|
@ -130,36 +135,40 @@ bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs,
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t toread = RDBUFSZ;
|
size_t toread = RDBUFSZ;
|
||||||
if (startoffs > 0 && curoffs < startoffs) {
|
if (startoffs > 0 && curoffs < startoffs) {
|
||||||
toread = size_t(MIN(RDBUFSZ, startoffs - curoffs));
|
toread = size_t(MIN(RDBUFSZ, startoffs - curoffs));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnttoread != size_t(-1)) {
|
if (cnttoread != size_t(-1)) {
|
||||||
toread = MIN(toread, cnttoread - totread);
|
toread = MIN(toread, cnttoread - totread);
|
||||||
}
|
}
|
||||||
ssize_t n = static_cast<ssize_t>(read(fd, buf, toread));
|
ssize_t n = static_cast<ssize_t>(read(fd, buf, toread));
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
catstrerror(reason, "read", errno);
|
catstrerror(reason, "read", errno);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (n == 0)
|
if (n == 0) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
curoffs += n;
|
curoffs += n;
|
||||||
if (curoffs - n < startoffs)
|
if (curoffs - n < startoffs) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (!doer->data(buf, n, reason)) {
|
|
||||||
goto out;
|
if (!doer->data(buf, n, reason)) {
|
||||||
}
|
goto out;
|
||||||
|
}
|
||||||
totread += n;
|
totread += n;
|
||||||
if (cnttoread > 0 && totread >= cnttoread)
|
if (cnttoread > 0 && totread >= cnttoread) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
out:
|
out:
|
||||||
if (fd >= 0 && !noclosing)
|
if (fd >= 0 && !noclosing) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,29 +190,28 @@ using namespace std;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class myCB : public FsTreeWalkerCB {
|
class myCB : public FsTreeWalkerCB {
|
||||||
public:
|
public:
|
||||||
FsTreeWalker::Status processone(const string &path,
|
FsTreeWalker::Status processone(const string& path,
|
||||||
const struct stat *st,
|
const struct stat *st,
|
||||||
FsTreeWalker::CbFlag flg)
|
FsTreeWalker::CbFlag flg) {
|
||||||
{
|
if (flg == FsTreeWalker::FtwDirEnter) {
|
||||||
if (flg == FsTreeWalker::FtwDirEnter) {
|
//cout << "[Entering " << path << "]" << endl;
|
||||||
//cout << "[Entering " << path << "]" << endl;
|
} else if (flg == FsTreeWalker::FtwDirReturn) {
|
||||||
} else if (flg == FsTreeWalker::FtwDirReturn) {
|
//cout << "[Returning to " << path << "]" << endl;
|
||||||
//cout << "[Returning to " << path << "]" << endl;
|
} else if (flg == FsTreeWalker::FtwRegular) {
|
||||||
} else if (flg == FsTreeWalker::FtwRegular) {
|
//cout << path << endl;
|
||||||
//cout << path << endl;
|
string s, reason;
|
||||||
string s, reason;
|
if (!file_to_string(path, s, &reason)) {
|
||||||
if (!file_to_string(path, s, &reason)) {
|
cerr << "Failed: " << reason << " : " << path << endl;
|
||||||
cerr << "Failed: " << reason << " : " << path << endl;
|
} else {
|
||||||
} else {
|
//cout <<
|
||||||
//cout <<
|
//"================================================" << endl;
|
||||||
//"================================================" << endl;
|
cout << path << endl;
|
||||||
cout << path << endl;
|
// cout << s;
|
||||||
// cout << s;
|
}
|
||||||
}
|
reason.clear();
|
||||||
reason.clear();
|
}
|
||||||
}
|
return FsTreeWalker::FtwOk;
|
||||||
return FsTreeWalker::FtwOk;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -214,8 +222,8 @@ static int op_flags;
|
||||||
|
|
||||||
static const char *thisprog;
|
static const char *thisprog;
|
||||||
static char usage [] =
|
static char usage [] =
|
||||||
"trreadfile [-o offs] [-c cnt] topdirorfile\n\n"
|
"trreadfile [-o offs] [-c cnt] topdirorfile\n\n"
|
||||||
;
|
;
|
||||||
static void
|
static void
|
||||||
Usage(void)
|
Usage(void)
|
||||||
{
|
{
|
||||||
|
@ -228,51 +236,71 @@ int main(int argc, const char **argv)
|
||||||
off_t offs = 0;
|
off_t offs = 0;
|
||||||
size_t cnt = size_t(-1);
|
size_t cnt = size_t(-1);
|
||||||
thisprog = argv[0];
|
thisprog = argv[0];
|
||||||
argc--; argv++;
|
argc--;
|
||||||
|
argv++;
|
||||||
|
|
||||||
while (argc > 0 && **argv == '-') {
|
while (argc > 0 && **argv == '-') {
|
||||||
(*argv)++;
|
(*argv)++;
|
||||||
if (!(**argv))
|
if (!(**argv))
|
||||||
/* Cas du "adb - core" */
|
/* Cas du "adb - core" */
|
||||||
Usage();
|
{
|
||||||
while (**argv)
|
Usage();
|
||||||
switch (*(*argv)++) {
|
}
|
||||||
case 'c': op_flags |= OPT_c; if (argc < 2) Usage();
|
while (**argv)
|
||||||
cnt = atoll(*(++argv)); argc--;
|
switch (*(*argv)++) {
|
||||||
goto b1;
|
case 'c':
|
||||||
case 'o': op_flags |= OPT_o; if (argc < 2) Usage();
|
op_flags |= OPT_c;
|
||||||
offs = strtoull(*(++argv), 0, 0); argc--;
|
if (argc < 2) {
|
||||||
goto b1;
|
Usage();
|
||||||
default: Usage(); break;
|
}
|
||||||
}
|
cnt = atoll(*(++argv));
|
||||||
b1: argc--; argv++;
|
argc--;
|
||||||
}
|
goto b1;
|
||||||
|
case 'o':
|
||||||
|
op_flags |= OPT_o;
|
||||||
|
if (argc < 2) {
|
||||||
|
Usage();
|
||||||
|
}
|
||||||
|
offs = strtoull(*(++argv), 0, 0);
|
||||||
|
argc--;
|
||||||
|
goto b1;
|
||||||
|
default:
|
||||||
|
Usage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
b1:
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
if (argc != 1)
|
if (argc != 1) {
|
||||||
Usage();
|
Usage();
|
||||||
string top = *argv++;argc--;
|
}
|
||||||
cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl;
|
string top = *argv++;
|
||||||
|
argc--;
|
||||||
|
cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl;
|
||||||
|
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (!top.empty() && stat(top.c_str(), &st) < 0) {
|
if (!top.empty() && stat(top.c_str(), &st) < 0) {
|
||||||
perror("stat");
|
perror("stat");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!top.empty() && S_ISDIR(st.st_mode)) {
|
if (!top.empty() && S_ISDIR(st.st_mode)) {
|
||||||
FsTreeWalker walker;
|
FsTreeWalker walker;
|
||||||
myCB cb;
|
myCB cb;
|
||||||
walker.walk(top, cb);
|
walker.walk(top, cb);
|
||||||
if (walker.getErrCnt() > 0)
|
if (walker.getErrCnt() > 0) {
|
||||||
cout << walker.getReason();
|
cout << walker.getReason();
|
||||||
} else {
|
}
|
||||||
string s, reason;
|
} else {
|
||||||
if (!file_to_string(top, s, offs, cnt, &reason)) {
|
string s, reason;
|
||||||
cerr << reason << endl;
|
if (!file_to_string(top, s, offs, cnt, &reason)) {
|
||||||
exit(1);
|
cerr << reason << endl;
|
||||||
} else {
|
exit(1);
|
||||||
cout << s;
|
} else {
|
||||||
}
|
cout << s;
|
||||||
}
|
}
|
||||||
exit(0);
|
}
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
#endif //TEST_READFILE
|
#endif //TEST_READFILE
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file in chunks, calling an accumulator for each chunk. Can be used
|
* Read file in chunks, calling an accumulator for each chunk. Can be used
|
||||||
* for reading in a file, computing an md5...
|
* for reading in a file, computing an md5...
|
||||||
*/
|
*/
|
||||||
class FileScanDo {
|
class FileScanDo {
|
||||||
|
@ -31,20 +31,20 @@ public:
|
||||||
virtual bool init(size_t size, std::string *reason) = 0;
|
virtual bool init(size_t size, std::string *reason) = 0;
|
||||||
virtual bool data(const char *buf, int cnt, std::string* reason) = 0;
|
virtual bool data(const char *buf, int cnt, std::string* reason) = 0;
|
||||||
};
|
};
|
||||||
bool file_scan(const std::string &filename, FileScanDo* doer, std::string *reason = 0);
|
bool file_scan(const std::string& filename, FileScanDo* doer, std::string *reason = 0);
|
||||||
/* Same but only process count cnt from offset offs. Set cnt to size_t(-1)
|
/* Same but only process count cnt from offset offs. Set cnt to size_t(-1)
|
||||||
* for no limit */
|
* for no limit */
|
||||||
bool file_scan(const std::string &fn, FileScanDo* doer, off_t offs, size_t cnt,
|
bool file_scan(const std::string& fn, FileScanDo* doer, off_t offs, size_t cnt,
|
||||||
std::string *reason = 0);
|
std::string *reason = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file into string.
|
* Read file into string.
|
||||||
* @return true for ok, false else
|
* @return true for ok, false else
|
||||||
*/
|
*/
|
||||||
bool file_to_string(const std::string &filename, std::string &data, std::string *reason = 0);
|
bool file_to_string(const std::string& filename, std::string& data, std::string *reason = 0);
|
||||||
|
|
||||||
/** Read file chunk into string. Set cnt to size_t(-1) for whole file */
|
/** Read file chunk into string. Set cnt to size_t(-1) for whole file */
|
||||||
bool file_to_string(const std::string &filename, std::string &data,
|
bool file_to_string(const std::string& filename, std::string& data,
|
||||||
off_t offs, size_t cnt, std::string *reason = 0);
|
off_t offs, size_t cnt, std::string *reason = 0);
|
||||||
|
|
||||||
#endif /* _READFILE_H_INCLUDED_ */
|
#endif /* _READFILE_H_INCLUDED_ */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue