Bredbandskollen CLI  1.2
Asynchronous network task engine
Public Member Functions | Protected Member Functions | Friends | List of all members
Task Class Reference

The purpose of a task is to manage socket connections, and/or to execute timers. More...

#include <task.h>

Inheritance diagram for Task:
Inheritance graph
[legend]
Collaboration diagram for Task:
Collaboration graph
[legend]

Public Member Functions

 Task (const std::string &task_name)
 Create a task with the given name. More...
 
virtual ~Task ()
 
virtual double start ()
 
virtual double timerEvent ()
 
void resetTimer (double s)
 Run timerEvent after s seconds instead of previous value.
 
bool finishedOK () const
 Return true if the task has finished normally. More...
 
bool wasKilled () const
 Return true if the task is finished and was aborted by another task. More...
 
bool wasError () const
 Return true if the task terminated with an error. More...
 
bool wasTimeout () const
 Return true if the task terminated with a timeout. More...
 
bool hasStarted () const
 
void killChildTaskWhenFinished ()
 
virtual SocketConnectionnewClient (int, const char *, uint16_t, ServerSocket *)
 
virtual bool adoptConnection (Socket *conn)
 
virtual void connAdded (SocketConnection *)
 
virtual void connRemoved (SocketConnection *)
 
virtual void serverAdded (ServerSocket *)
 
virtual void serverRemoved (ServerSocket *)
 
std::string result () const
 To get the "result" of the task after it has finished.
 
std::set< Socket * > getMyConnections () const
 Return all current connections.
 
bool isActive (Socket *conn) const
 Return true if the connection still exists.
 
void wakeUp ()
 Restart all idle connections.
 
bool wakeUpConnection (SocketConnection *s)
 If s is idle, restart it and return true. Otherwise return false.
 
void cancelConnection (SocketConnection *s)
 Terminate and remove a connection.
 
std::string message () const
 Return the current (outgoing) message.
 
bool startObserving (Task *to)
 
void executeHandler (Task *receiver, const std::string &message)
 
double elapsed () const
 Return number of seconds since the task was started. More...
 
virtual TaskcreateWorkerTask (unsigned int wno)
 
virtual void finishWorkerTask (unsigned int)
 
virtual void newWorkerChannel (SocketReceiver *, unsigned int)
 
virtual void workerMessage (SocketReceiver *, const char *buf, size_t len)
 Called if parent/worker sends a message through a SocketReceiver:
 
virtual PollState connectionReady (SocketConnection *)
 
virtual PollState msgFromConnection (SocketConnection *, const std::string &)
 
uint64_t bytesSent () const
 Number of bytes sent through SocketConnection objects owned by me.
 
uint64_t bytesReceived () const
 Number of bytes received through SocketConnection objects owned by me.
 
void resetByteCount ()
 Reset the values for the methods Task::bytesSent and Task::bytesReceived.
 
void notifyBytesSent (uint64_t n)
 Notify the task that data has been sent on its behalf. More...
 
void notifyBytesReceived (uint64_t n)
 Notify the task that data has been received on its behalf. More...
 
- Public Member Functions inherited from Logger
 Logger (std::string label)
 
std::string label () const
 Return the object's log label.
 
void resetLabel (const std::string &new_label)
 Modify the object's log label.
 

Protected Member Functions

bool addConnection (SocketConnection *conn)
 
bool addConnected (SocketConnection *conn)
 
bool addServer (ServerSocket *conn)
 As Task::addConnected, but with a server connection.
 
bool parseListen (const TaskConfig &tc, const std::string &log_label)
 
virtual bool tlsSetKey (ServerSocket *conn, const std::string &crt_path, const std::string &key_path, const std::string &password)
 Use SSL certificate for a listening socket.
 
void setResult (const std::string &res)
 
virtual void setError (const std::string &msg)
 
virtual void setTimeout ()
 
void setMessage (const std::string &msg)
 
virtual void taskFinished (Task *task)
 
virtual void taskMessage (Task *task)
 
virtual void handleExecution (Task *sender, const std::string &message)
 Callback to execute code on behalf of another Task.
 
bool terminated () const
 Return true if task is finished. More...
 
void addNewTask (Task *task, Task *parent=nullptr)
 Insert another Task for execution by the EventLoop.
 
void addNewThread (Task *task, const std::string &name="ThreadLoop", std::ostream *log_file=nullptr, Task *parent=nullptr)
 Run task in a new thread.
 
void getMyTasks (std::set< Task * > &tset)
 Add all my child tasks to the given set.
 
void abortMyTasks ()
 Terminate all my child tasks.
 
void abortTask (Task *task)
 Terminate a task.
 
void abortAllTasks ()
 Terminate all tasks and exit the EventLoop.
 
int runProcess (const char *const argv[])
 
virtual void processFinished (int pid, int wstatus)
 Will be called to notify when an external process has terminated.
 
WorkerProcesscreateWorker (std::ostream *log_file=nullptr, unsigned int channels=1, unsigned int wno=0)
 Run task returned by this->createWorkerTask in a child process. Return nullptr on failure.
 
WorkerProcesscreateWorker (const std::string &log_file_name, unsigned int channels=1, unsigned int wno=0)
 Run task returned by this->createWorkerTask in a child process. Return nullptr on failure.
 
- Protected Member Functions inherited from Logger
std::ostream & errno_log () const
 Write a line of error log after a failed system call has set the global errno to a non-zero value. More...
 
std::ostream & err_log () const
 Write a line of error log. More...
 
std::ostream & warn_log () const
 Write a line of warning log. More...
 
std::ostream & log () const
 Write a line of info log. More...
 
std::ostream & dbg_log () const
 Write a line of debug log. More...
 

Friends

class EventLoop
 

Additional Inherited Members

- Static Public Member Functions inherited from Logger
static void setLogFile (std::ostream &stream)
 Set global log destination. More...
 
static void reopenLogFile (const std::string &filename)
 If current log is a file (ofstream), reopen it with new filename:
 
static void setLogLimit (unsigned int loglines=0, unsigned int warnlines=0, unsigned int errlines=0)
 Set max number of lines of info/warn/err log. More...
 
static void sayTime (std::ostream &stream)
 Write current local time to the given stream.
 
static bool inError ()
 Return true if any error has been logged (globally since start)
 
static std::ostream & err_log (const std::string &label)
 Write a line of error log. More...
 
static std::ostream & warn_log (const std::string &label)
 Write a line of warning log. More...
 
static std::ostream & log (const std::string &label)
 Write a line of info log. More...
 
static void flushLogFile ()
 
static void pauseLogging ()
 Disable all log output until next call to Logger::setLogFile.
 
static double secondsSince (const TimePoint &t)
 
static double secondsTo (const TimePoint &t)
 
static int64_t msSince (const TimePoint &t)
 
static int64_t msTo (const TimePoint &t)
 
static bool hasExpired (const TimePoint &t)
 Return true if current time is after the given TimePoint.
 
static TimePoint timeNow ()
 Return current time.
 
static TimePoint timeAfter (double s)
 Return current time plus s seconds.
 
static TimePoint timeMax ()
 Return a very distant time.
 
static std::chrono::microseconds toUs (double t)
 Convert s (seconds) to std::chrono::microseconds.
 
static std::string dateString (time_t t=0)
 Return local time, formatted as 2023-10-14T09:38:47+0200.
 
static std::string dateString2 (time_t t=0)
 Return local time, formatted as Sat, 14 Oct 2023 09:38:47.
 
static std::string createHashKey (unsigned int length=20)
 Return a random string. More...
 

Detailed Description

The purpose of a task is to manage socket connections, and/or to execute timers.

This is essentially an abstract base class. You must create subclasses and pass subclass objects to the EventLoop's addTask method.

Timers are very simple; the start method must return the number of seconds until the timerEvent method should be called. The overridden timerEvent can do whatever it needs and then return the number of seconds until it should be called again. A value <= 0 means it will never be called again.

Note that the application will be single threaded. Thus, timers (and other callbacks) must avoid blocking and generally try do be as quick as possible, otherwise all subsequent timers will be delayed.

The Task may create SocketConnection objects and add them using the addConnection method. It may also create ServerSocket objects and add them with addServer; whenever a client connects to the server, you will be notified through the newClient method.

Constructor & Destructor Documentation

◆ Task()

Task::Task ( const std::string &  task_name)

Create a task with the given name.

The name will be used as a log label and may be retrieved using the inherited Logger::label method.

The EventLoop might not be available when the constructor is run, so do not use it in the constructor of any subclass. Any asynchronous initialization should be performed in the Task::start() method.

◆ ~Task()

Task::~Task ( )
virtual

A Task object will be deleted by the EventLoop after it has finished and its parent task has been notified.

Member Function Documentation

◆ addConnected()

bool Task::addConnected ( SocketConnection conn)
protected

Use this if conn contains a socket that has already been connected. Returns false (and deletes conn) on failure. On success, returns true and calls connAdded on owner task, then calls connected() on conn to get initial state.

◆ addConnection()

bool Task::addConnection ( SocketConnection conn)
protected

To add a new client connection. Will delete conn and return false on immediate failure. connRemoved will not be called in that case.

The connection must belong to a running task (probably this one). I.e. the task must have been added to the EventLoop and the start() method must have been called. You can't do this in the constructor!

If successfully added, we will call connAdded and return true. The EventLoop takes ownership of the SocketConnection object and will call connRemoved and then delete it if the connection fails or is closed or when the task is finished.

◆ adoptConnection()

bool Task::adoptConnection ( Socket conn)
virtual

Request for me to adopt a socket owned by some other task. Return false to reject. Otherwise set me as owner and return true.

◆ connAdded()

virtual void Task::connAdded ( SocketConnection )
inlinevirtual

This will be called to notify us when a new client socket object has been successfully added to this task. If you need to know that, override this method.

Reimplemented in WSBlistener, and WebServerTask.

◆ connectionReady()

PollState Task::connectionReady ( SocketConnection )
virtual

Normally, SocketConnection objects are designed for a specific type of Task, i.e. a HttpServerConnection might be designed for a WebServerTask. However, some SocketConnection subclasses are "generic" and meant to work with any Task object as owner. When such SocketConnection objects want to contact the owner, they may use this method to signal that the socket has been connetced.

Return PollState::READ to keep the connection, or PollState::CLOSE to close it.

Reimplemented in UnixDomainBridge.

◆ connRemoved()

virtual void Task::connRemoved ( SocketConnection )
inlinevirtual

This will be called when a client socket object has been removed from this task, just before it is deleted. If you need to know that, override this method.

Reimplemented in WSBlistener, WebServerTask, and SingleRequest.

◆ createWorkerTask()

virtual Task* Task::createWorkerTask ( unsigned int  wno)
inlinevirtual

Override this if you intend to start child processes with createWorker(). It will be executed in the child process. wno is the argument last parameter you supplied to createWorker(). You must create a Task with new and return its address.

◆ elapsed()

double Task::elapsed ( ) const
inline

Return number of seconds since the task was started.

The start time of a task is when the Task::start method is executed. Do not call this method until the task has been added to the EventLoop.

◆ executeHandler()

void Task::executeHandler ( Task receiver,
const std::string &  message 
)
inline

Execute receiver's Task::handleExecution method immediately. The call will be ignored unless this task is observing the receiver. Note that you could also call receiver->handleExecution() (or any other method in receiver) directly. However, that might be dangerous since your pointer to the receiver is a weak reference and you must somehow make sure that the receiver still exists. The advantages of using this API instead of directly calling methods in the receiver task are:

  1. Safer; the call will be ignored if the receiver task doesn't exist.
  2. The sender and receiver classes do not have to know each other.
  3. Since you are observing the receiver, you will be notified when the receiver task terminates.

Note: Essentially, the receiver's Task::handleExecution method executes from within the sender's method (event handler). If the receiver in any way modifies the sender from within its Task::handleExecution method, bad things may happen. Code the Task::handleExecution methods carefully.

◆ finishedOK()

bool Task::finishedOK ( ) const
inline

Return true if the task has finished normally.

This method is meant to be used in the taskFinished callback.

◆ finishWorkerTask()

virtual void Task::finishWorkerTask ( unsigned int  )
inlinevirtual

This will be called in child process directly before exit. Override if you need to clean up after createWorkerTask.

◆ hasStarted()

bool Task::hasStarted ( ) const
inline

Return true if the task has been added to the EventLoop and its Task::start() method has been executed.

◆ killChildTaskWhenFinished()

void Task::killChildTaskWhenFinished ( )
inline

Call this in the start() callback if you want all child tasks to be killed when this task is finished.

◆ msgFromConnection()

PollState Task::msgFromConnection ( SocketConnection ,
const std::string &   
)
virtual

Normally, SocketConnection objects are designed for a specific type of Task, i.e. a HttpServerConnection might be designed for a WebServerTask. However, some SocketConnection subclasses are "generic" and meant to work with any Task object as owner. When such SocketConnection objects have a message for their owner, they may use this method.

Return PollState::READ to keep the connection, or PollState::CLOSE to close it.

Reimplemented in UnixDomainBridge.

◆ newClient()

virtual SocketConnection* Task::newClient ( int  ,
const char *  ,
uint16_t  ,
ServerSocket  
)
inlinevirtual

Ignore this unless the task is a server task. If a new remote connection is made through any ServerSocket object owned by us, the client socket, ip address and port number will be passed to the below method. Override it to create and return an object of a subclass to SocketConnection, otherwise the client socket will be closed. The object will be owned by the implementation and will be deleted when the connection has been closed. You must create the object with new.

Reimplemented in WebServerTask, and LoadBalancer.

◆ newWorkerChannel()

virtual void Task::newWorkerChannel ( SocketReceiver ,
unsigned int   
)
inlinevirtual

Called during startup of worker process, once for each SocketReceiver object. Will be called before serverAdded with the same SocketReceiver. Overload this if your worker process has two or more SocketReceiver objects with different confguration (i.e. different SSL keys).

Reimplemented in WebServerTask.

◆ notifyBytesReceived()

void Task::notifyBytesReceived ( uint64_t  n)
inline

Notify the task that data has been received on its behalf.

For use only by custom SocketConnection subclasses after calling recv directly on a socket. Don't call the this methods unless you know what you're doing.

◆ notifyBytesSent()

void Task::notifyBytesSent ( uint64_t  n)
inline

Notify the task that data has been sent on its behalf.

For use only by custom SocketConnection subclasses after calling send directly on a socket. Don't call the this methods unless you know what you're doing.

◆ parseListen()

bool Task::parseListen ( const TaskConfig tc,
const std::string &  log_label 
)
protected

Check config file for listening (server) sockets. The sockets are added to the task, with the given log_label. E.g.

listen 80 192.36.30.2
listen 8080
listen 443 tls /etc/ssl/fd.crt /etc/ssl/fd.key 4lEGyLax

The value of the listen parameter is either a port number, e.g. "8080", or a port number followed by a space and an ip address, e.g. "8080 192.168.0.1". The address is either ipv4 or ipv6. If connections are to be encrypted, add "tls" followed by paths to your SSL certificate and private key, optionally followed by the password (if the key is protected by a password).

◆ runProcess()

int Task::runProcess ( const char *const  argv[])
protected

Start execution of external command, return an ID. On immediate failure, return value is -1.

◆ serverAdded()

virtual void Task::serverAdded ( ServerSocket )
inlinevirtual

This will be called to notify us when a new server (listening) socket object has been successfully added to this task. If you need to know that, override this method.

Reimplemented in WSBlistener.

◆ serverRemoved()

virtual void Task::serverRemoved ( ServerSocket )
inlinevirtual

This will be called when a server socket object has been removed from this task, just before it is deleted. If you need to know that, override this method.

Reimplemented in WSBlistener, and LoadBalancer.

◆ setError()

virtual void Task::setError ( const std::string &  msg)
inlineprotectedvirtual

Called to signal fatal error. May be overridden to "catch" errors. It should always call Task::setResult with an empty string.

◆ setMessage()

void Task::setMessage ( const std::string &  msg)
protected

Call to signal that the task has a "message" to deliver. The parent will be notified using the taskMessage method. Only the last message will be stored, and it may be retrieved using the message method.

◆ setResult()

void Task::setResult ( const std::string &  res)
protected

When the task is done, it should notify the EventLoop by calling the Task::setResult method. Then the task's parent will be notified and the task will be deleted. The "result" of the task should be a non-empty string on success, and an empty string on timeout or error. Of course, subclasses can calculate more complex custom "results" in addition to this simple string.

◆ setTimeout()

virtual void Task::setTimeout ( )
inlineprotectedvirtual

Called to signal timeout. May be overridden to "catch" timeouts. It should always call Task::setResult with an empty string.

◆ start()

virtual double Task::start ( )
inlinevirtual

When the EventLoop starts executing a task, it will call its start method. All non-trivial initialization, e.g. creating new socket connections, should be performed in the start method.

If the task needs a timer, the start method must return the number of seconds until timerEvent should be called, or <= 0 if you don't want it to be called.

Reimplemented in WsUploadTask, WsDownloadTask, UploadTask, UploadInfoTask, SpeedTest, PingSweepTask, MeasurementTask, DownloadTask, WebsocketBridge, WebServerTask, SingleRequest, UnixDomainBridge, ThreadBridge, SynchronousBridge, LoadBalancer, and BridgeTask.

◆ startObserving()

bool Task::startObserving ( Task to)
inline

Notify that this task will be observing task "to". This task will be notified through a call to taskFinished if "to" terminates before me. (A parent task is observing its child tasks by default.)

◆ taskFinished()

virtual void Task::taskFinished ( Task task)
inlineprotectedvirtual

Called when an observed task, e.g. a child task, terminates. Override this method to handle such events.

Reimplemented in SpeedTest, MeasurementAgent, WebsocketBridge, BridgeTask, and HttpRequestEngine.

◆ taskMessage()

virtual void Task::taskMessage ( Task task)
inlineprotectedvirtual

Called when an a child task has (set/sent) a message. Override this method to handle such events.

Reimplemented in SpeedTest, and MeasurementAgent.

◆ terminated()

bool Task::terminated ( ) const
inlineprotected

Return true if task is finished.

By default, this will return true if the task has called the Task::setResult method.

The task will be deleted very soon unless return value is false. So this method is mostly useful within the Task subclass itself, checking if it is about to be removed.

◆ timerEvent()

virtual double Task::timerEvent ( )
inlinevirtual

Return number of seconds until this method should be called again, or <= 0 if you don't want it to be called again.

Reimplemented in WsUploadTask, WsDownloadTask, UploadTask, PingSweepTask, InfoTask, DownloadTask, SingleRequest, and ThreadBridge.

◆ wasError()

bool Task::wasError ( ) const
inline

Return true if the task terminated with an error.

This method is meant to be used in the taskFinished callback.

◆ wasKilled()

bool Task::wasKilled ( ) const
inline

Return true if the task is finished and was aborted by another task.

This method is meant to be used in the taskFinished callback.

◆ wasTimeout()

bool Task::wasTimeout ( ) const
inline

Return true if the task terminated with a timeout.

This method is meant to be used in the taskFinished callback.


The documentation for this class was generated from the following files: