HCore SysNet

Files CCore/inc/sys/SysNet.h CCore/src/sys/SysNet.cpp

This part provides the OS backed network support.


#ifndef CCore_inc_sys_SysNet_h
#define CCore_inc_sys_SysNet_h
 
#include <CCore/inc/sys/SysWait.h>
#include <CCore/inc/sys/SysError.h>

#include <CCore/inc/TimeScope.h>
#include <CCore/inc/net/UDPoint.h>

namespace CCore {
namespace Sys {

/* classes */

struct UDPSocket;

struct AsyncUDPSocket;

struct AsyncUDPSocketWait;

/* struct UDPSocket */

struct UDPSocket
 {
  // private

  ....

  // public
  
  struct InResult
   {
    Net::UDPoint src;
    ulen len;
    ErrorType error;
   };
  
  // public
  
  ErrorType open(Net::UDPort udport) noexcept;
  
  ErrorType close() noexcept;
  
  ErrorType outbound(Net::UDPoint dst,PtrLen<const uint8> data) noexcept;
  
  WaitResult wait_in(MSec timeout) noexcept;
  
  WaitResult wait_in(TimeScope time_scope) noexcept;
  
  InResult inbound(PtrLen<uint8> buf) noexcept;
 };

/* struct AsyncUDPSocket */

struct AsyncUDPSocket
 {
  // private

  ....

  // public
  
  struct AsyncState;
  
  using Async = AsyncState * ;
  
  struct OutResult
   {
    bool pending;
    ErrorType error;
   };
  
  struct InResult
   {
    ErrorType error;
    Net::UDPoint src;
    ulen len;
   };
  
  struct StartInResult
   {
    bool pending;
    InResult result;
   };
  
  // public
  
  ErrorType open(Net::UDPort udport) noexcept;
  
  ErrorType close() noexcept;
  
  OutResult startOutbound(Async async,Net::UDPoint dst,PtrLen<const uint8> data) noexcept;
  
  ErrorType completeOutbound(Async async) noexcept;
  
  StartInResult startInbound(Async async,PtrLen<uint8> buf) noexcept;
  
  InResult completeInbound(Async async) noexcept;
 };

/* struct AsyncUDPSocketWait */

struct AsyncUDPSocketWait
 {
  // private

  ....

  // public
  
  static const ulen MaxAsyncs = .... ;
  
  ErrorType init(ulen async_count) noexcept;
  
  void exit() noexcept;
  
  AsyncUDPSocket::Async getAsync(ulen index) noexcept;
  
  bool addWait(ulen index) noexcept;
  
  bool delWait(ulen index) noexcept;
  
  WaitResult wait(MSec timeout) noexcept;
  
  WaitResult wait(TimeScope time_scope) noexcept;
  
  void interrupt() noexcept; // async , semaphore
  
  WaitResult waitAll(MSec timeout) noexcept;
  
  WaitResult waitAll(TimeScope time_scope) noexcept;
 };

} // namespace Sys
} // namespace CCore
 
#endif

UDPSocket

This structure supports work with UDP endpoints.


struct UDPSocket
 {
  // private

  ....

  // public
  
  struct InResult
   {
    Net::UDPoint src;
    ulen len;
    ErrorType error;
   };
  
  // public
  
  ErrorType open(Net::UDPort udport) noexcept;
  
  ErrorType close() noexcept;
  
  ErrorType outbound(Net::UDPoint dst,PtrLen<const uint8> data) noexcept;
  
  WaitResult wait_in(MSec timeout) noexcept;
  
  WaitResult wait_in(TimeScope time_scope) noexcept;
  
  InResult inbound(PtrLen<uint8> buf) noexcept;
 };

Using UDP protocol you can occupy a UDP port and receive UDP packets on that port, also you can send UDP packets to any host:port destination. To start working with a particular UDP port you create an instance of the structure UDPSocket and initialize it. Then you use methods of this structure to send and receive UDP packets. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.

open() initializes the instance and binds it to the given UDP port. The error code is returned. If the object is successfully initialized, it must be uninitialized by the method close().

close() uninitializes the instance. The error code is returned.

outbound() sends a UDP packet to the given destination. Destination is a pair IP address:UDP port.

wait_in() waits for inbound packets up to the given timeout. The WaitResult is returned. The value is 0, if a packet is available for reading, Wait_timeout, if timeout is expired and Wait_error, if some error happened.

indound() reads the packet data from the first inbound packet in the inbound queue and removes the packet from the queue. If the provided data buffer is not large enough, a error is returned (and the packet is lost). The return value has the inner type InResult. This structure has three fields: src, len and error. The src is the address of the packet originator. The len is the number of bytes, copied to the input buffer, this value is less or equal then the buf.len. The error is the error code. If the inbound queue is empty, the method blocks. You should never call this method alone, but only after the call of the method wait_in() to avoid infinite block.

AsyncUDPSocket

This structure supports work with UDP endpoints in an asynchronous manner similar to the async file operations.


struct AsyncUDPSocket
 {
  // private

  ....

  // public
  
  struct AsyncState;
  
  using Async = AsyncState * ;
  
  struct OutResult
   {
    bool pending;
    ErrorType error;
   };
  
  struct InResult
   {
    ErrorType error;
    Net::UDPoint src;
    ulen len;
   };
  
  struct StartInResult
   {
    bool pending;
    InResult result;
   };
  
  // public
  
  ErrorType open(Net::UDPort udport) noexcept;
  
  ErrorType close() noexcept;
  
  OutResult startOutbound(Async async,Net::UDPoint dst,PtrLen<const uint8> data) noexcept;
  
  ErrorType completeOutbound(Async async) noexcept;
  
  StartInResult startInbound(Async async,PtrLen<uint8> buf) noexcept;
  
  InResult completeInbound(Async async) noexcept;
 };

To start working with a particular UDP port you create an instance of the structure UDPSocket and initialize it. Then you use methods of this structure to send and receive UDP packets. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.

open() initializes the instance and binds it to the given UDP port. The error code is returned. If the object is successfully initialized, it must be uninitialized by the method close().

close() uninitializes the instance. The error code is returned. This method aborts any pending operations.

startOutbound() starts the outbound operation. The first argument is an async token. This token has the inner type Async, which is usually a pointer to a structure. The data buffer is in use during the whole operation, so it must be held intact until the operation is complete. The return value has the inner type OutResult. This structure has two fields: pending and error. The first field is true, if the operation is not finished yet. The second is a error code. If the operation is pending, you must wait until the token is finished and then complete the operation using the method completeOutbound().

completeOutbound() completes the pending outbound operation. The error code is returned.

startInbound() starts the inbound operation. The first argument is an async token. This token has the inner type Async, which is usually a pointer to a structure. The data buffer is in use during the whole operation, so it must be held intact until the operation is complete. The return value has the inner type StartInResult. This structure has two fields: pending and result. The first field is true, if the operation is not finished yet. The second is an operation result. If the operation is pending, you must wait until the token is finished and then complete the operation using the method completeInbound().

completeInbound() completes the pending inbound operation. The operation result is returned. This value has the inner type InResult. This structure has three fields: error, src and len. The error is the error code. The src is the address of the packet originator. The len is the number of bytes, copied to the input buffer, this value is less or equal then the buf.len.

To work with async tokens there is the structure AsyncUDPSocketWait.


struct AsyncUDPSocketWait
 {
  // private

  ....

  // public
  
  static const ulen MaxAsyncs = .... ; // like 50-100
  
  ErrorType init(ulen async_count) noexcept;
  
  void exit() noexcept;
  
  AsyncUDPSocket::Async getAsync(ulen index) noexcept;
  
  bool addWait(ulen index) noexcept;
  
  bool delWait(ulen index) noexcept;
  
  WaitResult wait(MSec timeout) noexcept;
  
  WaitResult wait(TimeScope time_scope) noexcept;
  
  void interrupt() noexcept; // async , semaphore
  
  WaitResult waitAll(MSec timeout) noexcept;
  
  WaitResult waitAll(TimeScope time_scope) noexcept;
 };

This structure is a pool of tokens. To work with tokens you create an instance of this structure and initialize it. Then you use its methods to do async socket operations. Finally, you uninitialize the instance. Copying of the instances is prohibited. The private content of the structure is target-dependent.

init() initializes the instance. The argument is the async pool size. This value must not exceed the inner constant MaxAsync. Otherwise the method returns a error. If the object is successfully initialized, it must be uninitialized by the method exit(). The pool contains async_count async tokens. They are indexed by the numbers from the range [0,async_count). Some of them comprise the "wait set". Initially the set is empty.

exit() uninitalizes the instance.

getAsync() returns the token with the given index.

addWait() adds the token with the given index to the wait set. The return value is true, if the token was included in the set, and false, if the token is already in the set.

delWait() removes the token with the given index from the wait set. The return value is true, if the token was excluded from the set, and false, if the token is already not in the set.

wait() waits while one of the tokens from the wait set is finished, i.e. some async socket operation is started with this token and it is finished. The return value has the type WaitResult. The value is the index of the token been finished, or one of the negative special values. Two variants of wait() accepts timeouts of different kinds: as a MSec or as a TimeScope. The special return values have the following meanings:

  1. Wait_error — the function has failed for some reason,
  2. Wait_timeout — the wait is terminated by timeout,
  3. Wait_interrupt — the wait is terminated by the interrupt().

interrupt() is a special method. This method can be used to interrupt the wait(). Unlike other methods, this one can be called in parallel to other method calls. This method has a "semaphore behavior", i.e. several calls provide several interrupts.

waitAll() waits while all tokens from the wait set are finished. The return value is 0, if it has happened. Otherwise — one of special values.