The socket is represented by the structure dap_events_socket_t, and in the code, it is typically handled through a pointer to this structure. This structure combines data related to the system’s input/output handler, including callbacks for read and write operations, as well as other events. Additionally, it manages buffering of data and buffer cleanup.

When working with event sockets, it is important to consider the execution context in which the pointer is being accessed. Depending on whether you are working within the context of the event socket or outside of it, the functions will behave differently.

Structures:

Functions:

STRUCTURES

Events socket

typedef struct dap_events_socket {
 
   dap_events_desc_type_t type;
   dap_events_socket_uuid_t uuid;
   dap_events_socket_t ** workers_es;
   size_t workers_es_size;       
   uint32_t flags;
   dap_context_t *context;
   dap_worker_t *worker;
   dap_server_t *server;
   dap_events_socket_callbacks_t callbacks;
   void *_inheritor;
   byte_t *buf_in, *buf_out;
   bool was_reassigned;
  union {
        SOCKET socket2;
        int fd2;
    };
 
#private fields...
 
} dap_events_socket_t;

The structure dap_events_socket_t is used to represent an event socket in the system. It contains various fields that hold information about the socket, its context, associated worker, server, and callback functions, among others. These fields are necessary to interact with the events socket.

Fields:

  1. dap_events_desc_type_t type: The type of the descriptor for the event socket. This field defines what kind of event socket this is, such as network sockets or other types of I/O descriptors. Listed in dap_events_desc_type_t enum structure.
  2. dap_events_socket_uuid_t uuid: A unique identifier (UUID) for the event socket. This is used to uniquely identify the socket within the system, ensuring that each socket can be individually referenced.
  3. dap_events_socket_t * *workers_es: A pointer to an array of event sockets associated with worker threads. This allows multiple worker event sockets to be managed together within the same socket structure.
  4. size_t workers_es_size: The size of the array workers_es, representing the number of worker event sockets. It provides the size for iterating through the array and managing multiple sockets associated with worker threads.
  5. uint32_t flags: Flags that define the behavior of the event socket. These flags can specify various operational parameters such as non-blocking mode, asynchronous operation, or specific handling options for the socket. List of available flags:
DAP_SOCK_READY_TO_READ      BIT( 0 )
DAP_SOCK_READY_TO_WRITE     BIT( 1 )
DAP_SOCK_SIGNAL_CLOSE       BIT( 2 )
DAP_SOCK_CONNECTING         BIT( 3 )
DAP_SOCK_REASSIGN_ONCE      BIT( 4 )
DAP_SOCK_KEEP_INHERITOR     BIT( 6 ) #for Windows only
DAP_SOCK_FILE_MAPPED        BIT( 7 )
DAP_SOCK_QUEUE_PTR          BIT( 8 )
  1. dap_context_t *context: A pointer to the associated context for the event socket. This context contains information about the execution environment where the event socket is active.
  2. dap_worker_t *worker: A pointer to the associated worker thread for the event socket. This field ties the event socket to a specific worker, which is responsible for processing events related to this socket.
  3. dap_server_t *server: A pointer to the associated server, if the event socket is part of a server. This field is used when the socket is bound to a server for handling network connections or other server-related events.
  4. dap_events_socket_callbacks_t callbacks: A structure containing the callback functions for various events associated with the event socket. These callbacks can handle events like reading, writing, or handling specific error conditions related to the socket.
  5. void *_inheritor: A pointer to an inheritor object, allowing the event socket to be extended or subclassed if needed. This can be used to add additional functionality or properties to the event socket structure.
  6. byte_t *buf_in, *buf_out: Pointers to input (buf_in) and output (buf_out) buffers. These buffers are used to temporarily store data that will be read from or written to the event socket. They are used in I/O operations to hold incoming or outgoing data until it can be processed.
  7. bool was_reassigned: A flag indicating whether the event socket has been reassigned. This could be useful for tracking whether the socket has been moved between workers, contexts, or has had its assignment changed during its lifecycle.

Union Fields:

The following fields are defined within a union, meaning only one of these fields can be used at a time:

  1. SOCKET socket: The actual socket descriptor used for I/O operations. This is the standard socket object that is used for communication over the network or other I/O operations.
  2. int fd: The file descriptor associated with the event socket. This is an integer used to refer to the socket handling.

Private Fields:

The remaining fields within the structure are considered private. These are not intended to be accessed or modified directly by the user. They are used internally to manage the event socket’s state and behavior.

Descriptors

typedef enum {
 
  DESCRIPTOR_TYPE_SOCKET_CLIENT = 0
  DESCRIPTOR_TYPE_SOCKET_LOCAL_CLIENT
  DESCRIPTOR_TYPE_SOCKET_LISTENING
  DESCRIPTOR_TYPE_SOCKET_LOCAL_LISTENING
  DESCRIPTOR_TYPE_SOCKET_UDP
  DESCRIPTOR_TYPE_SOCKET_CLIENT_SSL
  DESCRIPTOR_TYPE_FILE
  DESCRIPTOR_TYPE_PIPE
  DESCRIPTOR_TYPE_QUEUE
  #below there are non readable/writable descriptors 
  DESCRIPTOR_TYPE_TIMER
  DESCRIPTOR_TYPE_EVENT
 
} dap_events_desc_type_t;

This structure contains event socket descriptors used to determine the type of socket in the main worker loop.

Fields:

  1. DESCRIPTOR_TYPE_SOCKET_CLIENT = 0: This descriptor type represents a client socket used for establishing outgoing network connections.
  2. DESCRIPTOR_TYPE_SOCKET_LOCAL_CLIENT: This represents a local client socket, used for inter-process communication (IPC) through UNIX domain sockets or named pipes.
  3. DESCRIPTOR_TYPE_SOCKET_LISTENING: A descriptor representing a listening socket. This is used for sockets that are waiting for incoming requests.
  4. DESCRIPTOR_TYPE_SOCKET_LOCAL_LISTENING: Similar to DESCRIPTOR_TYPE_SOCKET_LISTENING, but for local listening sockets.
  5. DESCRIPTOR_TYPE_SOCKET_UDP: A descriptor for a UDP socket.
  6. DESCRIPTOR_TYPE_SOCKET_CLIENT_SSL: A descriptor for a client SSL. This represents a secure client-side socket used for encrypted communication over SSL protocol, used in HTTPS connections.
  7. DESCRIPTOR_TYPE_FILE: A descriptor for a file. This type represents a file descriptor used for file I/O operations, such as reading from or writing to a file on the filesystem.
  8. DESCRIPTOR_TYPE_PIPE: A descriptor for a pipe. Pipes are used for inter-process communication and allow data to be passed between processes.
  9. DESCRIPTOR_TYPE_QUEUE: A descriptor for an event queue. Event queues are used for storing events that will be processed later.

Events socket callbacks

typedef struct dap_events_socket_callbacks {
 
    dap_events_socket_callback_timer_t timer_callback;               
    dap_events_socket_callback_t new_callback;                        
    dap_events_socket_callback_t delete_callback;                
    dap_events_socket_callback_t read_callback;                   
    dap_events_socket_write_callback_t write_callback;               
    dap_events_socket_callback_t write_finished_callback;            
    dap_events_socket_callback_error_t error_callback;                
    dap_events_socket_worker_callback_t worker_assign_callback;
    dap_events_socket_worker_callback_t worker_unassign_callback; 
    void *arg;
    
union{
  dap_events_socket_callback_connected_t connected_callback;    
  dap_events_socket_callback_accept_t accept_callback;
  dap_events_socket_callback_event_t event_callback;               
  dap_events_socket_callback_queue_t queue_callback;           
  dap_events_socket_callback_queue_ptr_t queue_ptr_callback;  
  };
  
} dap_events_socket_callbacks_t;

The dap_events_socket_callbacks_t structure defines various callback functions associated with different events and operations for event sockets. These callbacks allow the system to respond to specific actions, such as reading, writing, handling errors, and managing worker assignments. The structure also includes an argument field for passing additional data to the callbacks and a union for event-specific callbacks that may vary depending on the socket type or operation.

Fields:

  1. dap_events_socket_callback_timer_t timer_callback: A callback function for timer events. This function is triggered when a timer associated with the event socket expires.
  2. dap_events_socket_callback_t new_callback: A callback function for handling new connections or initial events related to the event socket.
  3. dap_events_socket_callback_t delete_callback: A callback function triggered when the event socket is deleted or closed.
  4. dap_events_socket_callback_t read_callback: A callback function for read events. This is called when data is available to read from the socket, allowing the system to process the incoming data.
  5. dap_events_socket_write_callback_t write_callback: A callback function for write operations. This is triggered when data is ready to be written to the socket.
  6. dap_events_socket_callback_t write_finished_callback: A callback function that is triggered when a write operation is completed. It is useful for notifying the system that data has been successfully written or sent.
  7. dap_events_socket_callback_error_t error_callback: A callback function for error events. This callback is invoked when an error occurs with the socket, allowing the system to handle issues such as connection failures or read/write errors.
  8. dap_events_socket_worker_callback_t worker_assign_callback: A callback function for worker assignment. This is called when a worker thread is assigned to the event socket.
  9. dap_events_socket_worker_callback_t worker_unassign_callback: A callback function for worker unassignment. This callback is triggered when a worker is removed or unassigned from handling the event socket.
  10. void *arg: A generic argument that can be passed to the callback functions. This field allows for additional data to be provided when invoking any of the callbacks, enabling more flexible and dynamic callback behavior.

Union Fields (Event-Specific Callbacks):

The following callbacks are part of a union within the structure, meaning only one of these callbacks will be active at a time. These callbacks are more specific to certain event types or socket operations:

  1. dap_events_socket_callback_connected_t connected_callback: A callback triggered when a socket is connected.
  2. dap_events_socket_callback_accept_t accept_callback: A callback triggered when the socket accepts a connection.
  3. dap_events_socket_callback_event_t event_callback: A generic event callback that is triggered by various types of events related to the socket.
  4. dap_events_socket_callback_queue_t queue_callback: A callback for queue events. This is used when the socket is associated with a queue, triggering actions related to enqueuing or dequeuing events.
  5. dap_events_socket_callback_queue_ptr_t queue_ptr_callback: A callback for handling queue pointers.

Events socket with data

typedef struct dap_events_socket_w_data{
 
    struct dap_events_socket * esocket;
    size_t size;
       
    union{
        byte_t * data;
        void * ptr;
        uint64_t value;
    };
 
} dap_events_socket_w_data_t; {

The dap_events_socket_w_data_t structure is used for storing data that is associated with an event socket. This structure allows handling different types of data that can be written to or processed by the socket. The data is stored in a flexible manner, using a union to provide multiple types of data storage options: a byte array, a generic pointer, or a single 64-bit value.

Fields:

  1. struct dap_events_socket * esocket: A pointer to the associated event socket. This field links the data structure to the event socket that will process the data.
  2. size_t size: The size of the data in bytes.

Union Fields:

The following fields are part of a union, meaning only one of them can be used at any given time, depending on the type of data you need to handle:

  1. byte_t * data: A pointer to a byte array (data buffer). This field is used when the data is represented as a byte stream.
  2. void * ptr: A generic pointer to data of an undefined type. This provides flexibility, allowing to point to any data structure (not just a byte array) that can be passed to the event socket.
  3. uint64_t value: A single 64-bit value. This is used when the data to be passed is a simple numeric value, such as an integer or a flag, that fits into a 64-bit space.

UUID of the events socket with assigned worker

typedef struct dap_events_socket_uuid_ctrl {
 
dap_events_socket_uuid_t uuid;
dap_worker_t *worker;
 
} dap_events_socket_uuid_ctrl_t;

The dap_events_socket_uuid_ctrl_t structure is designed to associate an event socket’s unique identifier (UUID) with a specific worker thread (dap_worker_t).

Fields:

  1. dap_events_socket_uuid_t uuid: This field holds the unique identifier (UUID) of the event socket. The UUID is used to uniquely identify an event socket within the system, allowing operations to be tracked and managed based on the specific socket.
  2. dap_worker_t *worker: A pointer to the worker thread (dap_worker_t) that is responsible for processing events for this specific event socket.

FUNCTIONS

Events socket initialization

int dap_events_socket_init( void )
---
Return: int (0 is everything ok)

Arguments:

Function receives no arguments.

Description:

This function is necessary to prepare the event socket for operation.

Events socket deinitialization

void dap_events_socket_deinit(void)
---
Return: void

Arguments:

Function receives no arguments.

Description:

The function deinitializes the event socket after the work is completed.

Creation of the events socket (without context adding)

dap_events_socket_t *dap_events_socket_wrap_no_add( SOCKET a_sock, dap_events_socket_callbacks_t *a_callbacks )
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. SOCKET a_sock: A system socket descriptor which will be “wrapped” in the event-driven system. This socket will be associated with the dap_events_socket_t structure, allowing the system to handle it with event-driven callbacks.
  2. dap_events_socket_callbacks_t *a_callbacks: A pointer to a structure dap_events_socket_callbacks_t containing callback functions associated with the event socket. These callbacks define how various events on the socket, such as reading, writing, connecting, or error conditions, are handled.

Description:

The function creates an events socket.

If the socket creation fails (for example, due to memory allocation failure or invalid arguments), the function will return NULL.

Worker assigning

void dap_events_socket_assign_on_worker(dap_events_socket_t * a_es, struct dap_worker * a_worker)
---
Return: void

Arguments:

  1. dap_events_socket_t * a_es: A pointer to the event socket structure that needs to be assigned to a worker.
  2. struct dap_worker * a_worker: A pointer to the worker thread structure (dap_worker_t) that will handle the assigned event socket.

Description:

The function is responsible for assigning an event socket (dap_events_socket_t) to a specific worker thread (dap_worker_t). This allows the worker thread to handle events related to the given socket, such as reading or writing operations.

Possible errors:

  • 0 - Can’t assign esocket to worker
  • 1 - Can’t send pointer in queue

Worker reassigning (straight)

void dap_events_socket_reassign_between_workers_unsafe(dap_events_socket_t * a_es, dap_worker_t * a_worker_new)
---
Return: void

Arguments:

  1. dap_events_socket_t * a_es: A pointer to the event socket (dap_events_socket_t) that needs to be reassigned.
  2. dap_worker_t * a_worker_new: A pointer to the new worker thread (dap_worker_t) that will take over processing the events for the specified socket.

Description:

The function reassigns the event socket to another worker thread, first removing the context of the event socket using the dap_context_remove() function.

The following errors may occur:

  • -1 - No context assigned to esocket
  • Try to remove nonexistent socket

After that, the new worker thread is assigned.

Possible errors:

  • 0 - Can’t assign esocket to worker
  • 1 - Can’t send pointer in queue

Worker reassigning (safe)

void dap_events_socket_reassign_between_workers(dap_worker_t *a_worker_old, dap_events_socket_uuid_t a_es_uuid, dap_worker_t *a_worker_new)
---
Return: void

Arguments:

  1. dap_worker_t *a_worker_old: A pointer to the old worker thread (dap_worker_t) that is currently responsible for handling the event socket identified by a_es_uuid. This worker will no longer handle the socket after the reassignment.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket that needs to be reassigned.
  3. dap_worker_t *a_worker_new: A pointer to the new worker thread (dap_worker_t) that will take over handling the event socket. After reassignment, this worker will be responsible for processing the events of the socket.

Description:

At the beginning of the function, it checks if we are in the same context as the current worker thread (which is bound to the socket). If this is the case, the function dap_events_socket_reassign_between_workers_unsafe() will be called, as it will work faster in this situation.

Possible errors:

  • -1 - No context assigned to esocket
  • 0 - Can’t assign esocket to worker
  • 1 - Can’t send pointer in queue
  • Event socket doesn’t exist in worker
  • Try to remove nonexistent socket

If the worker thread’s context differs from the event socket’s context, the safe reassignment function will be used.

After that, the old worker is placed in the reassignment queue in case it’s possible.

Creation of the pipe socket

dap_events_socket_t * dap_events_socket_create_type_pipe(dap_worker_t *a_w, dap_events_socket_callback_t a_callback, uint32_t a_flags)
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. dap_worker_t *a_w: A pointer to the worker thread (dap_worker_t) that will be responsible for handling the event socket.
  2. dap_events_socket_callback_t a_callback: A callback function that will be associated with the event socket. This callback defines the actions that should be performed during certain socket events. Listed in the dap_events_socket_callbacks_t.
  3. uint32_t a_flags: Flags that specify configuration options for the event socket. Flags are listed in dap_events_socket_t structure description.

Description:

The function dap_events_socket_create_type_pipe is responsible for creating a pipe event socket. It takes a worker, a callback, and flags as input and returns an event socket.

Creation of the events socket

dap_events_socket_t * dap_events_socket_create(dap_events_desc_type_t a_type, dap_events_socket_callbacks_t* a_callbacks)
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. dap_events_desc_type_t a_type: The descriptor type for the event socket. It defines the type of the event socket, such as client socket, server socket, listening socket, etc. Listed in dap_events_desc_type_t.
  2. dap_events_socket_callbacks_t* a_callbacks: A pointer to a structure dap_events_socket_callbacks_t containing the callbacks associated with the event socket.

Description:

The function creates a new event socket.

If the socket creation fails (due to memory allocation failure or incorrect arguments), the function will return NULL.

Creation of the queue-type socket

dap_events_socket_t * dap_events_socket_create_type_queue_ptr(dap_worker_t * a_w, dap_events_socket_callback_queue_ptr_t a_callback)
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. dap_worker_t *a_w: A pointer to the worker thread (dap_worker_t) that will handle the event socket.
  2. dap_events_socket_callback_queue_ptr_t a_callback: A callback function for the event socket that handles queue-specific events. This callback contains in the dap_events_socket_callbacks_t structure.

Description:

The function creates a queue-type events socket.

As a result, a socket is created with the descriptor DESCRIPTOR_TYPE_QUEUE and the flag DAP_SOCK_QUEUE_PTR, enabling it to interact with other threads through queues. These threads can write or add to the event sockets of the worker thread through these queues.

In case the descriptor cannot be assigned to the socket, the error Not defined s_create_type_queue_ptr() for your platform will occur.

The created event socket is then added to the context, and if this fails, the following errors may occur:

  • -1 - “Can’t add NULL esocket to the context” if a NULL event socket is passed.
  • -2 - “Can’t add esocket to the bad context” if the context type is not a worker.
  • The function will also return an error if it is not supported for the socket type or platform.

If the event socket does not have an assigned worker thread, it will be bound to the provided worker thread.

Possible errors in this case:

  • 0 - Can’t assign esocket to worker
  • 1 - Can’t send pointer in queue

Reading data from the queue-type socket

int dap_events_socket_queue_proc_input_unsafe(dap_events_socket_t * a_esocket)
---
Return: int (error code, 0 if everything is ok)

Arguments:

  1. _dap_events_socket_t _a_esocket: The queue-type event socket to be processed.

Description:

The function reads data from an event socket with the descriptor DESCRIPTOR_TYPE_QUEUE.

Possible Errors:

  • -1 - Queue socket received invalid data
  • -3 - Read unaligned chunk from pipe
  • EAGAIN or EWOULDBLOCK - Can’t read message from pipe/SOCKET
  • -1 - Error in esocket queue_ptr
  • -2 - Queue socket accepted data but callback is NULL

If everything is fine, the function will return 0.

Creation of the event-type socket

dap_events_socket_t * dap_events_socket_create_type_event(dap_worker_t * a_w, dap_events_socket_callback_event_t a_callback)
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. dap_worker_t * a_w: A pointer to the worker thread that will be associated with the event socket.
  2. dap_events_socket_callback_event_t a_callback: A specific event oriented callback function to handle the events for the socket.

Description:

The function creates an event-type event socket with DESCRIPTOR_TYPE_EVENT descriptor. This allows the event socket to signal the worker dap_worker_t about various events.

Possible errors:

  • -1 - “Can’t add NULL esocket to the context” if a NULL event socket is passed
  • -2 - “Can’t add esocket to the bad context” if the context type is not a worker
  • The function will also return an error if it is not supported for the given socket format or platform

If the event socket does not have an assigned worker thread, the function will bind it to the provided worker thread.

Possible errors in this case:

  • 0 - Can’t assign esocket to worker
  • 1 - Can’t send pointer in queue

Reading data from the event-type socket

void dap_events_socket_event_proc_input_unsafe(dap_events_socket_t *a_esocket)
---
Return: void

Arguments:

  1. dap_events_socket_t * a_esocket: A pointer to the event socket to process.

Description:

The function reads data from an event socket with the descriptor DESCRIPTOR_TYPE_EVENT.

Possible errors:

  • EAGAIN or EWOULDBLOCK - Can’t read message from pipe/SOCKET
  • Event socket accepted data but callback is NULL

Event signal

int dap_events_socket_event_signal( dap_events_socket_t * a_es, uint64_t a_value)
---
Return: int (0 if everything is ok)

Arguments:

  1. dap_events_socket_t * a_es: The event socket to which the event signal will be sent.
  2. uint64_t a_value: The value to be passed with the event signal, which represents the event’s data or state.

Description:

The function is used to signal about some event, primarily to signal about closure of a socket.

Error Types:

  • EBADF: Invalid file descriptor. For example, the descriptor is closed or not valid for writing
  • EINVAL: Invalid buffer size for writing. The buffer size must be 8 bytes
  • ECONNRESET: The connection was reset by the remote host
  • EPIPE: Attempt to write to the closed end of a pipe

If another error occurs, the function will return 1.

Additionally, an error may occur if the output socket is connected to a pipe, but it fails to send a pointer to the pipe’s output:

  • -1: Haven’t sent pointer in pipe out queue

Creation of the listening socket

dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, SOCKET a_sock, dap_events_socket_callbacks_t *a_callbacks)
---
Return: dap_events_socket_t * (events socket)

Arguments:

  1. dap_server_t *a_server: The server associated with the socket.
  2. SOCKET a_sock: The given socket to be wrapped.
  3. dap_events_socket_callbacks_t *a_callbacks: A pointer to the callback functions associated with the event socket, listed in dap_events_socket_callbacks_t structure.

Description:

The function wraps a system socket a_sock into a dap_events_socket_t structure and assigns it the flag DAP_SOCK_READY_TO_READ, making it a listening event socket.

It returns NULL if incorrect arguments are provided or if memory for the event socket cannot be allocated.

Callback of delayed socket deletion

bool s_remove_and_delete_unsafe_delayed_delete_callback(void * a_arg)
---
Return: bool (returns false in any case)

Arguments:

  1. void *a_arg: A pointer to any type of argument that may be passed to the function.

Description:

The function finds out what context of the event socket is, removes it from the context, and then removes the socket itself.

Delayed socket deletion

void dap_events_socket_remove_and_delete_unsafe_delayed( dap_events_socket_t *a_es, bool a_preserve_inheritor )
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_es: The event socket to be removed and deleted.
  2. bool a_preserve_inheritor: A flag indicating whether the inheritor of the event socket should be preserved (true to keep the inheritor, false to delete it).

Description:

The function is designed to safely remove and delete an event socket (dap_events_socket_t) while optionally preserving its inheritor.

Possible errors:

  • -1 - No context assigned to esocket
  • ​​Try to remove nonexistent socket

The function then creates a timer to remove the event socket.

Descriptor closure

void dap_events_socket_descriptor_close(dap_events_socket_t *a_esocket)
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_esocket: The event socket whose descriptor is to be closed.

Description:

The function closes the socket descriptor. The socket becomes the INVALID_SOCKET.

Retrieve the socket from the context and delete it (straight)

void dap_events_socket_remove_and_delete_unsafe( dap_events_socket_t *a_es, bool preserve_inheritor)
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_es: The event socket to be removed and deleted.
  2. bool a_preserve_inheritor: A flag indicating whether the inheritor of the event socket should be preserved (true to keep the inheritor, false to delete it).

Description:

The function removes the event socket from the context, and then removes the socket itself.

Possible errors:

  • -1 - No context assigned to esocket
  • ​​Try to remove nonexistent socket

Set socket readable (straight)

void dap_events_socket_set_readable_unsafe( dap_events_socket_t *a_esocket, bool a_is_ready )
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_esocket: The event socket (a_esocket) whose state is being modified.
  2. bool a_is_ready: A boolean value indicating whether the event socket should be marked as readable:
    • true: Set the socket as ready to read.
    • false: Unset the readable state.

Description:

The function sets the DAP_SOCK_READY_TO_READ flag for the event socket if it hasn’t been set previously.

It then sets the same flag in the system functions depending on the platform.

The function will return one of the following errors if the operation fails:

  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure is specified
  • EBADF: An invalid file descriptor was provided
  • EEXIST: An attempt to add an already existing file descriptor to the event list
  • ENOENT: An attempt to remove a non-existent file descriptor from the event list
  • EPERM: Insufficient privileges to perform the operation
  • EBUSY: The specified file descriptor is already in use by another instance of epoll
  • -666 - Wrong poll index when removing from context
  • Esocket is not assigned with anything

Set socket writable (straight)

void dap_events_socket_set_writable_unsafe(dap_events_socket_t *a_esocket, bool a_is_ready )
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_es: The event socket whose state is being modified.
  2. bool a_is_ready: A boolean value indicating whether the event socket should be marked as writable:
    • true: Set the socket as ready to write.
    • false: Unset the writable state.

Description:

The function sets the event socket flag DAP_SOCK_READY_TO_WRITE if it hasn’t been set previously.

After that, it propagates the same flag to the system functions depending on the platform.

The function will return one of the following errors if the operation fails:

  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure
  • EBADF: Invalid file descriptor
  • EEXIST: Attempt to add an already existing file descriptor to the event list
  • ENOENT: Attempt to remove a non-existent file descriptor from the event list
  • EPERM: Missing required privileges to perform the operation
  • EBUSY: The specified file descriptor is already in use by another instance of epoll
  • -666: Wrong poll index when remove from context
  • Esocket is not assigned with anything

Send socket pointer into the queue

int dap_events_socket_queue_ptr_send( dap_events_socket_t *a_es, void *a_arg)
---
Return: int (error code, 0 if everything is ok)

Arguments:

  1. dap_events_socket_t *a_es: The event socket through which the data will be sent.
  2. void *a_arg: A pointer to the data of any type that needs to be sent.

Description:

The function sends a pointer to the event socket into the queue.

Possible errors:

  • EINVAL - Invalid message size or priority
  • EINTR - The system call was interrupted by a signal
  • EPERM - Insufficient permissions
  • EAGAIN - The queue is full
  • ETIMEDOUT - The call timed out before the message was sent
  • -666 - Insufficient memory

Events socket deletion (straight)

void dap_events_socket_delete_unsafe(dap_events_socket_t *a_esocket, bool a_preserve_inheritor)
---
Return: void 

Arguments:

  1. dap_events_socket_t *a_esocket: The event socket to be deleted.
  2. bool a_preserve_inheritor: A flag indicating whether the inheritor (if present) should be preserved (true) or deleted (false).

Description:

The function assigns the INVALID_SOCKET value to the socket. After which all socket fields are cleared, and the socket itself is completely deleted.

Retrieve the socket from the context and delete it

void dap_events_socket_remove_and_delete(dap_worker_t *a_worker, dap_events_socket_uuid_t a_es_uuid)
---
Return: void 

Arguments:

  1. dap_worker_t *a_worker: A pointer to the worker thread that is handling the event socket. Worker is also tied to the definite context.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket to be removed and deleted.

Description:

If the context of the worker thread and the event socket are the same, the function dap_events_socket_remove_and_delete_unsafe() will be called to remove the socket, as it will execute faster.

Otherwise, the event socket’s UUID will be sent to the queue for deletion.

Set socket readable

void dap_events_socket_set_readable(dap_worker_t *a_worker, dap_events_socket_uuid_t a_es_uuid, bool a_is_ready)
---
Return: void 

Arguments:

  1. dap_worker_t *a_worker: A pointer to the worker thread which is assigned to the socket.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket for which the flag is to be set.
  3. bool a_is_ready: A boolean value indicating whether the socket should be marked as ready to read. If true, the socket will be marked as readable; if false, it will be unset

Description:

If the context of the worker thread and the event socket match, the function dap_events_socket_set_readable_unsafe() will be called, as it will execute faster.

Otherwise, the UUID of the event socket is sent in the queue along with the flag DAP_SOCK_READY_TO_READ that needs to be set.

Set socket writable

void dap_events_socket_set_writable(dap_worker_t *a_worker, dap_events_socket_uuid_t a_es_uuid, bool a_is_ready)
---
Return: void 

Arguments:

  1. dap_worker_t *a_worker: A pointer to the worker thread which is assigned to the socket.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket for which the flag is to be set.
  3. bool a_is_ready: A flag indicating whether the event socket is ready to be marked as writable (true to set the flag, false to unset it).

Description:

If the context of the worker thread and the event socket match, the function dap_events_socket_set_writable_unsafe() will be called, as it will execute faster.

Otherwise, the UUID of the event socket is sent to the queue along with the DAP_SOCK_READY_TO_WRITE flag that needs to be set.

Write data to the socket (safe)

size_t dap_events_socket_write(dap_worker_t *a_worker, dap_events_socket_uuid_t a_es_uuid, const void *a_data, size_t a_data_size)
---
Return: size_t (written data size)

Arguments:

  1. dap_worker_t *a_worker: The worker thread to which the event socket is assigned.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket where the data is to be written.
  3. const void *a_data: A pointer to the data that needs to be written to the event socket.
  4. size_t a_data_size: The size of the data to be written.

Description:

If the context of the worker thread and the event socket match, the function dap_events_socket_write_unsafe() will be called, as it will execute faster.

The function assigns the DAP_SOCK_READY_TO_WRITE flag to the event socket and sends its UUID to the queue along with the data that needs to be written to the socket.

Write formatted data to the socket (safe)

size_t dap_events_socket_write_f(dap_worker_t *a_worker, dap_events_socket_uuid_t a_es_uuid, const char *a_format, ...)
---
Return: size_t (written data size)

Arguments:

  1. dap_worker_t *a_worker: A pointer to the worker thread handling the event socket.
  2. dap_events_socket_uuid_t a_es_uuid: The UUID of the event socket to which data will be written.
  3. const char *a_format: A format string, similar to printf format, that specifies how the additional arguments will be formatted.
  4. ...: Additional arguments to be written.

Description:

The function formats the data and sends it for writing to the socket. If the worker is in the same context as the event socket, the function dap_events_socket_write_unsafe() will be called.

Possible errors in this case:

  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure is provided
  • EBADF: Invalid file descriptor
  • EEXIST: Attempt to add an already existing file descriptor to the event list
  • ENOENT: Attempt to remove a non-existent file descriptor from the event list
  • EPERM: Insufficient privileges to perform the operation
  • EBUSY: The specified file descriptor is already in use by another instance of epoll
  • -666: Wrong poll index when removing from context
  • Esocket is not assigned with anything

If the contexts differ, the socket pointer will be sent to a queue for data writing.

Possible errors in this case:

  • EINVAL: Incorrect message size or priority
  • EINTR: System call was interrupted by a signal
  • EPERM: Insufficient permissions
  • EAGAIN: Queue is full
  • ETIMEDOUT: The call timed out before the message was transmitted
  • -666: Insufficient memory

Write data to the socket (straight)

size_t dap_events_socket_write_unsafe(dap_events_socket_t *a_es, const void *a_data, size_t a_data_size)
---
Return: size_t (written data size)

Arguments:

  1. dap_events_socket_t *a_es: The event socket where the data will be written.
  2. const void *a_data: Pointer to the data to be written.
  3. size_t a_data_size: The size of the data to be written.

Description:

The function sends data to be written to the socket and sets the socket’s flag to DAP_SOCK_READY_TO_WRITE.

Possible errors:

  • 0: “Attempt to write into NULL esocket!” or “Trying to write into closing socket”
  • -1: Trying to write to foreign context
  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure
  • EBADF: Invalid file descriptor
  • EEXIST: Attempt to add an already existing file descriptor to the event list
  • ENOENT: Attempt to remove a non-existent file descriptor from the event list
  • EPERM: Insufficient privileges to perform the operation
  • EBUSY: The specified file descriptor is already in use by another instance of epoll
  • -666: Wrong poll index when removing from context
  • Esocket is not assigned with anything

Write formatted data to the socket (straight)

ssize_t dap_events_socket_write_f_unsafe(dap_events_socket_t *a_es, const char *a_format, ...)
---
Return: ssize_t (written signed data size)

Arguments:

  1. dap_events_socket_t *a_es: The event socket where the data will be written.
  2. const char *a_format: A format string, similar to printf format, that specifies how the additional arguments will be formatted.
  3. ...: Additional arguments to be written.

Description:

The function formats the data and sends it for writing to the socket.

Possible errors:

  • 0 - Can’t write formatted data to NULL buffer output
  • <0 - Can’t write out formatted data
  • EINVAL: Invalid argument. For example, an incorrect file descriptor, operation type, or event structure
  • EBADF: Invalid file descriptor
  • EEXIST: Attempt to add an already existing file descriptor to the event list
  • ENOENT: Attempt to remove a non-existent file descriptor from the event list
  • EPERM: Insufficient privileges to perform the operation
  • EBUSY: The specified file descriptor is already in use by another epoll instance
  • -666 - “Wrong poll index when removing from context”
  • Esocket is not assigned with anything

Retrieving data from the input buffer

size_t dap_events_socket_pop_from_buf_in(dap_events_socket_t *a_es, void *a_data, size_t a_data_size)
---
Return: size_t (size of the retrieved data)

Arguments:

  1. dap_events_socket_t *a_es: The event socket from which the data will be read.
  2. void *a_data: A pointer to the buffer where the retrieved data will be stored.
  3. size_t a_data_size: The size of the data being retrieved.

Description:

The function extracts data from the input buffer and stores it in the variable a_data via the pointer.

At the same time, the buffer size buf_in_size is reduced by the amount of a_data_size of the extracted data.

Buffer shrinking

void dap_events_socket_shrink_buf_in(dap_events_socket_t * a_es, size_t shrink_size)
---
Return: void

Arguments:

  • dap_events_socket_t *a_es: The event socket which input buffer will be shrunk.
  • size_t shrink_size: The size (in bytes) by which the input buffer should be reduced.

Description:

The function shrinks the input buffer buf_in_size by shifting the data to the left.

Input data to the output buffer

size_t dap_events_socket_insert_buf_out(dap_events_socket_t * a_es, void *a_data, size_t a_data_size)
---
Return: size_t (size of the inserted data)

Arguments:

  • dap_events_socket_t *a_es: The event socket to which the data will be inserted.
  • void *a_data: A pointer to the data that needs to be inserted into the output buffer.
  • size_t a_data_size: The size of the data to be inserted.

Description:

The function inserts data a_data into the output buffer.

Possible error: -ENOMEM - No room for data to be inserted.