You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libiec61850/src/mms/iso_server/iso_connection.c

746 lines
24 KiB
C

/*
* iso_connection.c
*
* Copyright 2013-2023 Michael Zillgith
*
* This file is part of libIEC61850.
*
* libIEC61850 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* libIEC61850 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libIEC61850. If not, see <http://www.gnu.org/licenses/>.
*
* See COPYING file for the complete license text.
*/
#include "libiec61850_platform_includes.h"
#include "stack_config.h"
#include "buffer_chain.h"
#include "cotp.h"
#include "iso_session.h"
#include "iso_presentation.h"
#include "acse.h"
#include "iso_server.h"
#include "hal_socket.h"
#include "hal_thread.h"
#include "iso_server_private.h"
#ifndef DEBUG_ISO_SERVER
#ifdef DEBUG
#define DEBUG_ISO_SERVER 1
#else
#define DEBUG_ISO_SERVER 0
#endif /*DEBUG */
#endif /* DEBUG_ISO_SERVER */
#define RECEIVE_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100
#define SEND_BUF_SIZE CONFIG_MMS_MAXIMUM_PDU_SIZE + 100
#define TPKT_RFC1006_HEADER_SIZE 4
struct sIsoConnection
{
uint8_t* receiveBuffer;
ByteBuffer rcvBuffer;
uint8_t* sendBuffer;
uint8_t* cotpReadBuf;
uint8_t* cotpWriteBuf;
ByteBuffer cotpReadBuffer;
ByteBuffer cotpWriteBuffer;
MessageReceivedHandler msgRcvdHandler;
UserLayerTickHandler tickHandler;
void* handlerParameter; /* context parameter for msgRcvdHandler */
IsoServer isoServer;
Socket socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
TLSSocket tlsSocket;
#endif
int state;
IsoSession* session;
IsoPresentation* presentation;
CotpConnection* cotpConnection;
AcseConnection* acseConnection;
char* clientAddress;
char* localAddress;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Thread thread;
Semaphore conMutex;
#endif
#if (CONFIG_MMS_SINGLE_THREADED != 1) || (CONFIG_MMS_THREADLESS_STACK == 1)
HandleSet handleSet;
#endif
};
static void
finalizeIsoConnection(IsoConnection self)
{
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: finalizeIsoConnection (%p)--> close transport connection\n", self);
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
TLSSocket_close(self->tlsSocket);
#endif
#if (CONFIG_MMS_THREADLESS_STACK != 1)
#if (CONFIG_MMS_SINGLE_THREADED != 1)
if (self->handleSet) {
Handleset_destroy(self->handleSet);
self->handleSet = NULL;
}
#endif
#endif
GLOBAL_FREEMEM(self->session);
GLOBAL_FREEMEM(self->presentation);
GLOBAL_FREEMEM(self->acseConnection);
GLOBAL_FREEMEM(self->cotpReadBuf);
GLOBAL_FREEMEM(self->cotpWriteBuf);
if (self->cotpConnection) {
if (self->cotpConnection->handleSet)
Handleset_destroy(self->cotpConnection->handleSet);
GLOBAL_FREEMEM(self->cotpConnection->socketExtensionBuffer);
}
GLOBAL_FREEMEM(self->cotpConnection);
self->cotpConnection = NULL;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_destroy(self->conMutex);
#endif
GLOBAL_FREEMEM(self->receiveBuffer);
GLOBAL_FREEMEM(self->sendBuffer);
GLOBAL_FREEMEM(self->clientAddress);
GLOBAL_FREEMEM(self->localAddress);
IsoServer isoServer = self->isoServer;
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: connection %p closed\n", self);
private_IsoServer_decreaseConnectionCounter(isoServer);
}
void
IsoConnection_addToHandleSet(const IsoConnection self, HandleSet handles)
{
Handleset_addSocket(handles, self->socket);
}
void
IsoConnection_removeFromHandleSet(const IsoConnection self, HandleSet handles)
{
Handleset_removeSocket(handles, self->socket);
}
void
IsoConnection_callTickHandler(IsoConnection self)
{
CotpConnection_flushBuffer(self->cotpConnection);
if (self->tickHandler) {
self->tickHandler(self->handlerParameter);
}
}
void
IsoConnection_handleTcpConnection(IsoConnection self, bool isSingleThread)
{
#if (CONFIG_MMS_SINGLE_THREADED != 1)
if (isSingleThread == false) {
IsoConnection_callTickHandler(self);
if (Handleset_waitReady(self->handleSet, 10) < 1)
goto exit_function;
}
#endif
TpktState tpktState = CotpConnection_readToTpktBuffer(self->cotpConnection);
if (tpktState == TPKT_ERROR)
self->state = ISO_CON_STATE_STOPPED;
if (tpktState != TPKT_PACKET_COMPLETE)
goto exit_function;
CotpIndication cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);
switch (cotpIndication) {
case COTP_MORE_FRAGMENTS_FOLLOW:
goto exit_function;
case COTP_CONNECT_INDICATION:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: COTP connection indication\n");
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_lock(self);
#endif
CotpConnection_sendConnectionResponseMessage(self->cotpConnection);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_unlock(self);
#endif
break;
case COTP_DATA_INDICATION:
{
ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection);
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: COTP data indication (payload size = %i)\n", cotpPayload->size);
IsoSessionIndication sIndication = IsoSession_parseMessage(self->session, cotpPayload);
ByteBuffer* sessionUserData = IsoSession_getUserData(self->session);
switch (sIndication) {
case SESSION_CONNECT:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session connect indication\n");
if (IsoPresentation_parseConnect(self->presentation, sessionUserData)) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: presentation ok\n");
ByteBuffer* acseBuffer = &(self->presentation->nextPayload);
AcseIndication aIndication = AcseConnection_parseMessage(self->acseConnection, acseBuffer);
if (aIndication == ACSE_ASSOCIATE) {
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_lock(self);
#endif
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: cotp_server: acse associate\n");
ByteBuffer mmsRequest;
ByteBuffer_wrap(&mmsRequest, self->acseConnection->userDataBuffer,
self->acseConnection->userDataBufferSize, self->acseConnection->userDataBufferSize);
ByteBuffer mmsResponseBuffer; /* new */
ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
if (self->msgRcvdHandler != NULL) {
self->msgRcvdHandler(self->handlerParameter,
&mmsRequest, &mmsResponseBuffer);
}
struct sBufferChain mmsBufferPartStruct;
BufferChain mmsBufferPart = &mmsBufferPartStruct;
BufferChain_init(mmsBufferPart, mmsResponseBuffer.size, mmsResponseBuffer.size, NULL,
self->sendBuffer);
if (mmsResponseBuffer.size > 0) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: application payload size: %i\n",
mmsResponseBuffer.size);
struct sBufferChain acseBufferPartStruct;
BufferChain acseBufferPart = &acseBufferPartStruct;
acseBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
acseBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
AcseConnection_createAssociateResponseMessage(self->acseConnection,
ACSE_RESULT_ACCEPT, acseBufferPart, mmsBufferPart);
struct sBufferChain presentationBufferPartStruct;
BufferChain presentationBufferPart = &presentationBufferPartStruct;
presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
IsoPresentation_createCpaMessage(self->presentation, presentationBufferPart,
acseBufferPart);
struct sBufferChain sessionBufferPartStruct;
BufferChain sessionBufferPart = &sessionBufferPartStruct;
sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
IsoSession_createAcceptSpdu(self->session, sessionBufferPart, presentationBufferPart);
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
}
else {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: association error. No response from application!\n");
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_unlock(self);
#endif
}
else {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: acse association failed\n");
self->state = ISO_CON_STATE_STOPPED;
}
}
else {
self->state = ISO_CON_STATE_STOPPED;
}
break;
case SESSION_DATA:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session data indication\n");
if (!IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: presentation layer error\n");
self->state = ISO_CON_STATE_STOPPED;
break;
}
if (self->presentation->nextContextId == self->presentation->mmsContextId) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: mms message\n");
ByteBuffer* mmsRequest = &(self->presentation->nextPayload);
ByteBuffer mmsResponseBuffer;
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_lock(self);
#endif
ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);
if (self->msgRcvdHandler != NULL) {
self->msgRcvdHandler(self->handlerParameter,
mmsRequest, &mmsResponseBuffer);
}
/* send a response if required */
if (mmsResponseBuffer.size > 0) {
struct sBufferChain mmsBufferPartStruct;
BufferChain mmsBufferPart = &mmsBufferPartStruct;
BufferChain_init(mmsBufferPart, mmsResponseBuffer.size,
mmsResponseBuffer.size, NULL, self->sendBuffer);
struct sBufferChain presentationBufferPartStruct;
BufferChain presentationBufferPart = &presentationBufferPartStruct;
presentationBufferPart->buffer = self->sendBuffer + mmsBufferPart->length;
presentationBufferPart->partMaxLength = SEND_BUF_SIZE - mmsBufferPart->length;
IsoPresentation_createUserData(self->presentation,
presentationBufferPart, mmsBufferPart);
struct sBufferChain sessionBufferPartStruct;
BufferChain sessionBufferPart = &sessionBufferPartStruct;
sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
IsoSession_createDataSpdu(self->session, sessionBufferPart, presentationBufferPart);
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
}
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_unlock(self);
#endif
}
else {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: unknown presentation layer context!");
}
break;
case SESSION_FINISH:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session finish indication\n");
if (IsoPresentation_parseUserData(self->presentation, sessionUserData)) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: presentation ok\n");
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_lock(self);
#endif
struct sBufferChain acseBufferPartStruct;
BufferChain acseBufferPart = &acseBufferPartStruct;
acseBufferPart->buffer = self->sendBuffer;
acseBufferPart->partMaxLength = SEND_BUF_SIZE;
AcseConnection_createReleaseResponseMessage(self->acseConnection, acseBufferPart);
struct sBufferChain presentationBufferPartStruct;
BufferChain presentationBufferPart = &presentationBufferPartStruct;
presentationBufferPart->buffer = self->sendBuffer + acseBufferPart->length;
presentationBufferPart->partMaxLength = SEND_BUF_SIZE - acseBufferPart->length;
IsoPresentation_createUserDataACSE(self->presentation, presentationBufferPart, acseBufferPart);
struct sBufferChain sessionBufferPartStruct;
BufferChain sessionBufferPart = &sessionBufferPartStruct;
sessionBufferPart->buffer = self->sendBuffer + presentationBufferPart->length;
sessionBufferPart->partMaxLength = SEND_BUF_SIZE - presentationBufferPart->length;
IsoSession_createDisconnectSpdu(self->session, sessionBufferPart, presentationBufferPart);
CotpConnection_sendDataMessage(self->cotpConnection, sessionBufferPart);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
IsoConnection_unlock(self);
#endif
}
self->state = ISO_CON_STATE_STOPPED;
break;
case SESSION_ABORT:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session abort indication\n");
self->state = ISO_CON_STATE_STOPPED;
break;
case SESSION_ERROR:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session error indication\n");
self->state = ISO_CON_STATE_STOPPED;
break;
default: /* illegal state */
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: iso_connection: session illegal state\n");
self->state = ISO_CON_STATE_STOPPED;
break;
}
CotpConnection_resetPayload(self->cotpConnection);
}
break;
case COTP_ERROR:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: Connection closed\n");
self->state = ISO_CON_STATE_STOPPED;
break;
default:
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: COTP unknown indication: %i\n", cotpIndication);
self->state = ISO_CON_STATE_STOPPED;
break;
}
exit_function:
return;
}
#if ((CONFIG_MMS_SINGLE_THREADED == 0) && (CONFIG_MMS_THREADLESS_STACK == 0))
/* only for multi-thread mode */
static void*
handleTcpConnection(void* parameter)
{
IsoConnection self = (IsoConnection) parameter;
while(self->state == ISO_CON_STATE_RUNNING)
IsoConnection_handleTcpConnection(self, false);
IsoServer_closeConnection(self->isoServer, self);
finalizeIsoConnection(self);
self->state = ISO_CON_STATE_TERMINATED;
return NULL;
}
#endif /* (CONFIG_MMS_SINGLE_THREADED == 0) */
IsoConnection
IsoConnection_create(Socket socket, IsoServer isoServer, bool isSingleThread)
{
IsoConnection self = (IsoConnection) GLOBAL_CALLOC(1, sizeof(struct sIsoConnection));
if (self) {
self->socket = socket;
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (IsoServer_getTLSConfiguration(isoServer) != NULL) {
self->tlsSocket = TLSSocket_create(socket, IsoServer_getTLSConfiguration(isoServer), true);
if (self->tlsSocket == NULL) {
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: IsoConnection - TLS initialization failed\n");
GLOBAL_FREEMEM(self);
return NULL;
}
}
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
self->receiveBuffer = (uint8_t*) GLOBAL_MALLOC(RECEIVE_BUF_SIZE);
self->sendBuffer = (uint8_t*) GLOBAL_MALLOC(SEND_BUF_SIZE);
self->msgRcvdHandler = NULL;
self->tickHandler = NULL;
self->handlerParameter = NULL;
self->isoServer = isoServer;
self->state = ISO_CON_STATE_RUNNING;
self->clientAddress = Socket_getPeerAddress(self->socket);
self->localAddress = Socket_getLocalAddress(self->socket);
#if (CONFIG_MMS_THREADLESS_STACK != 1)
self->conMutex = Semaphore_create(1);
#endif
ByteBuffer_wrap(&(self->rcvBuffer), self->receiveBuffer, 0, RECEIVE_BUF_SIZE);
self->cotpReadBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
self->cotpWriteBuf = (uint8_t*) GLOBAL_MALLOC(CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
ByteBuffer_wrap(&(self->cotpReadBuffer), self->cotpReadBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
ByteBuffer_wrap(&(self->cotpWriteBuffer), self->cotpWriteBuf, 0, CONFIG_COTP_MAX_TPDU_SIZE + TPKT_RFC1006_HEADER_SIZE);
self->cotpConnection = (CotpConnection*) GLOBAL_CALLOC(1, sizeof(CotpConnection));
int socketExtensionBufferSize = CONFIG_MMS_MAXIMUM_PDU_SIZE + 1000;
uint8_t* socketExtensionBuffer = (uint8_t*)GLOBAL_MALLOC(socketExtensionBufferSize);
CotpConnection_init(self->cotpConnection, self->socket, &(self->rcvBuffer), &(self->cotpReadBuffer), &(self->cotpWriteBuffer),
socketExtensionBuffer, socketExtensionBufferSize);
#if (CONFIG_MMS_SUPPORT_TLS == 1)
if (self->tlsSocket)
self->cotpConnection->tlsSocket = self->tlsSocket;
#endif /* (CONFIG_MMS_SUPPORT_TLS == 1) */
self->session = (IsoSession*) GLOBAL_CALLOC(1, sizeof(IsoSession));
IsoSession_init(self->session);
self->presentation = (IsoPresentation*) GLOBAL_CALLOC(1, sizeof(IsoPresentation));
IsoPresentation_init(self->presentation);
self->acseConnection = (AcseConnection*) GLOBAL_CALLOC(1, sizeof(AcseConnection));
#if (CONFIG_MMS_SUPPORT_TLS == 1)
AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer),
IsoServer_getAuthenticatorParameter(self->isoServer), self->tlsSocket);
#else
AcseConnection_init(self->acseConnection, IsoServer_getAuthenticator(self->isoServer),
IsoServer_getAuthenticatorParameter(self->isoServer), NULL);
#endif
if (DEBUG_ISO_SERVER)
printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress);
#if (CONFIG_MMS_SINGLE_THREADED == 0)
#if (CONFIG_MMS_THREADLESS_STACK == 0)
if (isSingleThread == false) {
self->handleSet = Handleset_new();
Handleset_addSocket(self->handleSet, self->socket);
self->thread = Thread_create((ThreadExecutionFunction) handleTcpConnection, self, false);
}
#endif
#endif
}
return self;
}
int
IsoConnection_getState(IsoConnection self)
{
return self->state;
}
void
IsoConnection_start(IsoConnection self)
{
#if (CONFIG_MMS_SINGLE_THREADED == 0)
#if (CONFIG_MMS_THREADLESS_STACK == 0)
Thread_start(self->thread);
#endif
#endif
}
void
IsoConnection_destroy(IsoConnection self)
{
#if (CONFIG_MMS_THREADLESS_STACK == 0) && (CONFIG_MMS_SINGLE_THREADED == 0)
if (self->thread)
Thread_destroy(self->thread);
#endif
if (self->socket != NULL)
Socket_destroy(self->socket);
#if (CONFIG_MMS_SINGLE_THREADED != 1) || (CONFIG_MMS_THREADLESS_STACK == 1)
if (self->handleSet)
Handleset_destroy(self->handleSet);
#endif
if (self->cotpConnection) {
if (self->cotpConnection->handleSet)
Handleset_destroy(self->cotpConnection->handleSet);
GLOBAL_FREEMEM(self->cotpConnection->socketExtensionBuffer);
}
GLOBAL_FREEMEM(self);
}
char*
IsoConnection_getPeerAddress(IsoConnection self)
{
return self->clientAddress;
}
char*
IsoConnection_getLocalAddress(IsoConnection self)
{
return self->localAddress;
}
void
IsoConnection_lock(IsoConnection self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_wait(self->conMutex);
#endif
}
void
IsoConnection_unlock(IsoConnection self)
{
#if (CONFIG_MMS_THREADLESS_STACK != 1)
Semaphore_post(self->conMutex);
#endif
}
bool
IsoConnection_sendMessage(IsoConnection self, ByteBuffer* message)
{
bool success = false;
if (self->state == ISO_CON_STATE_STOPPED) {
if (DEBUG_ISO_SERVER)
printf("DEBUG_ISO_SERVER: sendMessage: connection already stopped!\n");
goto exit_error;
}
struct sBufferChain payloadBufferStruct;
BufferChain payloadBuffer = &payloadBufferStruct;
payloadBuffer->length = message->size;
payloadBuffer->partLength = message->size;
payloadBuffer->partMaxLength = message->size;
payloadBuffer->buffer = message->buffer;
payloadBuffer->nextPart = NULL;
struct sBufferChain presentationBufferStruct;
BufferChain presentationBuffer = &presentationBufferStruct;
presentationBuffer->buffer = self->sendBuffer;
presentationBuffer->partMaxLength = SEND_BUF_SIZE;
IsoPresentation_createUserData(self->presentation,
presentationBuffer, payloadBuffer);
struct sBufferChain sessionBufferStruct;
BufferChain sessionBuffer = &sessionBufferStruct;
sessionBuffer->buffer = self->sendBuffer + presentationBuffer->partLength;
IsoSession_createDataSpdu(self->session, sessionBuffer, presentationBuffer);
CotpIndication indication;
indication = CotpConnection_sendDataMessage(self->cotpConnection, sessionBuffer);
if (DEBUG_ISO_SERVER) {
if (indication != COTP_OK)
printf("ISO_SERVER: IsoConnection_sendMessage failed!\n");
else
printf("ISO_SERVER: IsoConnection_sendMessage success!\n");
}
if (indication == COTP_OK)
success = true;
exit_error:
return success;
}
void
IsoConnection_close(IsoConnection self)
{
if (self->state != ISO_CON_STATE_TERMINATED) {
self->state = ISO_CON_STATE_STOPPED;
#if (CONFIG_MMS_THREADLESS_STACK != 1) && (CONFIG_MMS_SINGLE_THREADED != 1)
/* wait for connection thread to terminate */
if (self->thread) {
Thread_destroy(self->thread);
self->thread = NULL;
}
else {
finalizeIsoConnection(self);
self->state = ISO_CON_STATE_TERMINATED;
}
#else
finalizeIsoConnection(self);
self->state = ISO_CON_STATE_TERMINATED;
#endif
}
}
void
IsoConnection_installListener(IsoConnection self, MessageReceivedHandler rcvdHandler,
UserLayerTickHandler tickHandler,
void* parameter)
{
self->msgRcvdHandler = rcvdHandler;
self->tickHandler = tickHandler;
self->handlerParameter = parameter;
}
void*
IsoConnection_getSecurityToken(IsoConnection self)
{
return self->acseConnection->securityToken;
}
bool
IsoConnection_isRunning(IsoConnection self)
{
if (self->state == ISO_CON_STATE_RUNNING)
return true;
else
return false;
}