socket_protocol (Socket Protocol)

Author:

Description:

This Module supports point to point communication for client-server issues.

Submodules:

Unittest:

See also the unittest documentation.

Module Documentation:

socket_protocol.AUTH_STATE_KEY_TRANSFERRED = 3

Authentification Status for ‘Key has been sent’

socket_protocol.AUTH_STATE_SEED_REQUESTED = 1

Authentification Status for ‘Seed was requested’

socket_protocol.AUTH_STATE_SEED_TRANSFERRED = 2

Authentification Status for ‘Seed has been sent’

socket_protocol.AUTH_STATE_TRUSTED_CONNECTION = 4

Authentification Status for a ‘Trusted Connection’

socket_protocol.AUTH_STATE_UNTRUSTED_CONNECTION = 0

Authentification Status for an ‘Untrusted Connection’

socket_protocol.AUTH_STATE__NAMES = {0: 'Untrusted Connection', 1: 'Seed was requested', 2: 'Seed has been sent', 3: 'Key has been sent', 4: 'Trusted Connection'}

Authentification Status names for previous defined authentification states

socket_protocol.DID_AUTH_KEY = 1

DID for authentification (key)

socket_protocol.DID_AUTH_SEED = 0

DID for authentification (seed)

socket_protocol.DID_CHANNEL_NAME = 0

DID for channel name

exception socket_protocol.RequestSidExistsError
exception socket_protocol.ResponseSidExistsError
socket_protocol.SID_AUTH_REQUEST = 0

SID for authentification request

socket_protocol.SID_AUTH_RESPONSE = 1

SID for authentification response

socket_protocol.SID_CHANNEL_NAME_REQUEST = 8

SID for channel name exchange request

socket_protocol.SID_CHANNEL_NAME_RESPONSE = 9

SID for channel name exchange response

socket_protocol.SID_EXECUTE_REQUEST = 30

SID for a execute request

socket_protocol.SID_EXECUTE_RESPONSE = 31

SID for a execute response

socket_protocol.SID_READ_REQUEST = 10

SID for a read data request

socket_protocol.SID_READ_RESPONSE = 11

SID for read data response

socket_protocol.SID_WRITE_REQUEST = 20

SID for a write data request

socket_protocol.SID_WRITE_RESPONSE = 21

SID for a write data response

socket_protocol.STATUS_AUTH_REQUIRED = 3

Status for ‘authentification is required’

socket_protocol.STATUS_BUFFERING_UNHANDLED_REQUEST = 1

Status for ‘unhandled request’

socket_protocol.STATUS_CALLBACK_ERROR = 2

Status for ‘callback errors’

socket_protocol.STATUS_CHECKSUM_ERROR = 5

Status for ‘checksum error’

socket_protocol.STATUS_LOG_LVL = {0: 20, 1: 30, 2: 40, 3: 30, 4: 40, 5: 40, 6: 30}

Status depending log level for messages

socket_protocol.STATUS_OKAY = 0

Status for ‘okay’

socket_protocol.STATUS_OPERATION_NOT_PERMITTED = 6

Status for ‘operation not permitted’

socket_protocol.STATUS_SERVICE_OR_DATA_UNKNOWN = 4

Status for ‘service or data unknown’

class socket_protocol.data_storage(*args, **kwargs)

This is a storage object for socket_protocol messages.

Parameters:
  • status (int) – The message status.
  • service_id (int) – The Service-ID.
  • data_id (int) – The Data-ID.
  • data (any) – The transfered data.
get_data(default=None)

This Method returns the message data.

Parameters:default – The default value, if no data is available.
get_data_id(default=None)

This Method returns the message Data-ID.

Parameters:default – The default value, if no data is available.
get_service_id(default=None)

This Method returns the message Service-ID.

Parameters:default – The default value, if no data is available.
get_status(default=None)

This Method returns the message status.

Parameters:default – The default value, if no data is available.
class socket_protocol.pure_json_protocol(comm_instance, secret=None, auto_auth=False, channel_name=None)

This class supports to transfer a message and it’s data.

Parameters:
  • comm_instance (instance) – A communication instance.
  • secret (str) – An optinal secret (e.g. created by binascii.hexlify(os.urandom(24))).
  • auto_auth (bool) – An optional parameter to enable (True) automatic authentification, otherwise you need to do it manually, if needed.
  • channel_name (str) – An optional parameter to set a channel name for logging of the communication.

Hint

  • The Service-ID is designed to identify the type of the communication (e.g. READ_REQUEST, WRITE_REQUEST, READ_RESPONSE, WRITE_RESPONSE, …)
  • The Data-ID is designed to identify the requests / responses using the same Service_ID.

Note

The comm_instance needs to have at least the following interface:

  • A Method comm_instance.init_channel_name() to set the channel name.
  • A Constant comm_instance.IS_CLIENT to identify that the comm_instance is a client (True) or a server (False).
  • A Method comm_instance.is_connected() to identify if the instance is connected (True) or not (False).
  • A Method comm_instance.reconnect() to initiate a reconnect.
  • A Method comm_instance.register_callback() to register a data available callback.
  • A Method comm_instance.register_connect_callback() to register a connect callback.
  • A Method comm_instance.register_disconnect_callback() to register a disconnect callback.
  • A Method comm_instance.send() to send data via the comm_instance.

Note

The parameter auto_auth is only relevant, if a secret is given and the comm_instance is a client. The authentification is initiated directly after the connection is established.

Note

The channel_name-exchange will be initiated by the client directly after the the connection is established.

  • If a channel_name is given at both communication sides and they are different, the client name is taken over and the server will log a warning message.

Example:

import sys
sys.path.append('../..')


import report
import socket_protocol
from socket_protocol_server import example_protocol, DID_ASC_TIME
import tcp_socket
import time

if __name__ == '__main__':
    report.stdoutLoggingConfigure(log_name_lvl=[('root', 'INFO'), ])
    c = tcp_socket.tcp_client_stp('127.0.0.1', 17017)
    sp = example_protocol(c, channel_name='example_client')
    sp.send(socket_protocol.SID_READ_REQUEST, DID_ASC_TIME, None)
    print('The Client received: %s' % repr(sp.receive(socket_protocol.SID_READ_RESPONSE, 0).get_data()))

and

import sys
sys.path.append('../..')

import report
import socket_protocol
import tcp_socket
import time


DID_ASC_TIME = 0


class example_protocol(socket_protocol.pure_json_protocol):
    def __init__(self, *args, **kwargs):
        socket_protocol.pure_json_protocol.__init__(self, *args, **kwargs)
        #
        self.add_data((socket_protocol.SID_READ_REQUEST, socket_protocol.SID_READ_RESPONSE), DID_ASC_TIME, 'asc_time')
        #
        if not self.__comm_inst__.IS_CLIENT:
            self.register_callback(socket_protocol.SID_READ_REQUEST, 0, self.time_callback)

    def time_callback(self, msg):
        if msg.get_status() == socket_protocol.STATUS_OKAY:
            return socket_protocol.STATUS_OKAY, time.asctime()
        else:
            return socket_protocol.STATUS_OPERATION_NOT_PERMITTED, None


if __name__ == '__main__':
    report.stdoutLoggingConfigure(log_name_lvl=[('root', 'INFO'), ])
    s = tcp_socket.tcp_server_stp('127.0.0.1', 17017)
    sp = example_protocol(s, channel_name='example_server')

    i = 0
    while not s.is_connected() and i <= 20:
        i += 1
        time.sleep(.1)  # wait for a connection

    i = 0
    while s.is_connected() and i <= 20:
        i += 1
        time.sleep(.1)  # wait for disconnect

Will result to the following output:

2023-10-26 00:00:59,792: root.socket_protocol.example_client - INFO - prot-client: Resetting authentification state to AUTH_STATE_UNTRUSTED_CONNECTION
2023-10-26 00:00:59,792: root.socket_protocol.example_client - INFO - prot-client: Initialisation finished.
2023-10-26 00:00:59,792: root.socket_protocol.example_client - INFO - prot-client: TX -> service: read data request, data_id: asc_time, status: okay, data: "None"
2023-10-26 00:00:59,843: root.tcp_socket.example_client - INFO - comm-client: Connection established... (to 127.0.0.1:17017)
2023-10-26 00:00:59,843: root.socket_protocol.example_client - INFO - prot-client: TX -> service: channel name request, data_id: name, status: okay, data: "'example_client'"
2023-10-26 00:00:59,844: root.tcp_socket.example_client - INFO - comm-client: TX -> "(74): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 38 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 22 65 78 61 6d 70 6c 65 5f 63 6c 69 65 6e 74 22 7d f5 cd dd e7"
2023-10-26 00:00:59,893: root.tcp_socket.example_client - INFO - comm-client: TX -> "(63): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 31 30 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 6e 75 6c 6c 7d 45 05 7b b4"
2023-10-26 00:00:59,894: root.stringtools.stp - INFO - STP: message identified - (62): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 39 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 6e 75 6c 6c 7d 30 59 be 2f
2023-10-26 00:00:59,894: root.tcp_socket.example_client - INFO - comm-client: RX  <- "(62): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 39 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 6e 75 6c 6c 7d 30 59 be 2f"
2023-10-26 00:00:59,894: root.socket_protocol.example_client - INFO - prot-client: RX <- service: channel name response, data_id: name, status: okay, data: "None"
2023-10-26 00:00:59,945: root.stringtools.stp - INFO - STP: message identified - (85): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 31 31 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 22 54 68 75 20 4f 63 74 20 32 36 20 30 30 3a 30 30 3a 35 39 20 32 30 32 33 22 7d 3c 24 c7 8c
2023-10-26 00:00:59,945: root.tcp_socket.example_client - INFO - comm-client: RX  <- "(85): 7b 22 64 61 74 61 5f 69 64 22 3a 20 30 2c 20 22 73 65 72 76 69 63 65 5f 69 64 22 3a 20 31 31 2c 20 22 73 74 61 74 75 73 22 3a 20 30 2c 20 22 64 61 74 61 22 3a 20 22 54 68 75 20 4f 63 74 20 32 36 20 30 30 3a 30 30 3a 35 39 20 32 30 32 33 22 7d 3c 24 c7 8c"
2023-10-26 00:00:59,945: root.socket_protocol.example_client - INFO - prot-client: RX <- service: read data response, data_id: asc_time, status: okay, data: "'Thu Oct 26 00:00:59 2023'"
The Client received: 'Thu Oct 26 00:00:59 2023'
add_data(service_id, data_id, name)

Method to add a name for a specific message.

Parameters:
  • service_id (int or list of ints) – The Service-ID of the message. See class definitions starting with SID_.
  • data_id (int) – The Data-ID of the message.
  • name (str) – The Name for the transfered message.
add_msg_to_auth_whitelist_(service_id, data_id)

Method to add a specific message to the list, where no authentification is required.

Parameters:
  • service_id (int) – The Service-ID of the message. See class definitions starting with SID_.
  • data_id (int) – The Data-ID of the message.
add_service(req_sid, resp_sid, req_name=None, resp_name=None)

Method to add a Service defined by Request- and Response Serivce-ID.

Parameters:
  • req_sid (int) – The Request Service-ID.
  • resp_sid (int) – The Response Service-ID.
add_status(status, name)

Method to add a name for a status.

Parameters:
  • status (int) – The Status. See class definitions starting with STATUS_.
  • name (str) – The Name for the Status.
authentificate(timeout=2)

This method authetificates the client at the server.

Parameters:timeout (float) – The timeout for the authentification (requesting seed, sending key and getting authentification_feedback).
Returns:True, if authentification was successfull; False, if not.
Return type:bool

Note

An authentification will only processed, if a secret had been given on initialisation.

Note

Client and Server needs to use the same secret.

check_authentification_state()

This Method return the Authitification State as boolean value.

Returns:True, if authentification state is okay, otherwise False
Return type:bool
connection_established()

This Method returns the Connection state including authentification as a boolean value.

Returns:True, if the connection is established (incl. authentification, if a secret has been given)
Return type:bool
is_connected()

This Methods returns Connection state of the Communication Instance comm_instance.is_connected().

Returns:True if the comm_instance is connected, otherwise False..
Return type:bool
receive(service_id, data_id, timeout=1)

This Method returns a message object for a defined message or None, if this message is not available after the given timout.

Parameters:
  • service_id (int) – The Service-ID for the message. See class definitions starting with SID_.
  • data_id (int) – The Data-ID for the message.
  • timeout (float) – The timeout for receiving.
Returns:

The received data storage object or None, if no data was received.

Return type:

data_storage

reconnect()

This methods initiates a reconnect by calling comm_instance.reconnect().

register_callback(service_id, data_id, callback, *args, **kwargs)

This method registers a callback for the given parameters. Giving None means, that all Service-IDs or all Data-IDs are used. If a message hitting these parameters has been received, the callback will be executed.

Parameters:
  • service_id (int) – The Service-ID for the message. See class definitions starting with SID_.
  • data_id (int) – The Data-ID for the message.

Note

The callback() is priorised in the following order:

  • Callbacks with defined Service-ID and Data-ID.
  • Callbacks with a defined Service-ID and all Data-IDs.
  • Callbacks with a defined Data-ID and all Service-IDs.
  • Unspecific Callbacks.

Note

The callback() is executed with these arguments:

Parameters given at the callback call:

  • The first Arguments is the received message as data_storage object.
  • Further arguments given at registration.
  • Further keyword arguments given at registration.

Return value of the callback:

If the Callback is a Request Callback for a registered Service, the return value has to be a tuple or list with

  • response_status: The response status (see class definitions starting with STA_*.
  • response_data: A JSON iterable object to be used as data for the response.

Note

Only registered services will respond via the callbacks return values with the same data_id.

send(service_id, data_id, data, status=0, timeout=2)

This methods sends out a message with the given content.

Parameters:
  • service_id (int) – The Service-ID for the message. See class definitions starting with SERVICE_.
  • data_id (int) – The Data-ID for the message.
  • data (str) – The data to be transfered. The data needs to be json compatible.
  • status (int) – The Status for the message. All requests should have STATUS_OKAY.
  • timeout (float) – The timeout for sending data (e.g. time to establish new connection).
Returns:

True if data had been sent, otherwise False.

Return type:

bool

class socket_protocol.struct_json_protocol(*args, **kwargs)

This Class has the same functionality like pure_json_protocol. The message length is less than for pure_json_protocol, but the functionality and compatibility is reduced. See also parent pure_json_protocol.

Note

This class is depreceated and here for compatibility reasons (to support old clients or servers). Usage of pure_json_protocol is recommended.