void
IsoClientConnection_associate(IsoClientConnection self, IsoConnectionParameters* params,
		ByteBuffer* payload)
{
	Socket socket = TcpSocket_create();

	self->socket = socket;

	if (!Socket_connect(socket, params->hostname, params->tcpPort))
		goto returnError;

	self->cotpBuf = malloc(ISO_CLIENT_BUFFER_SIZE);
	self->cotpBuffer = calloc(1, sizeof(ByteBuffer));
	ByteBuffer_wrap(self->cotpBuffer, self->cotpBuf, 0, ISO_CLIENT_BUFFER_SIZE);

	self->cotpConnection = calloc(1, sizeof(CotpConnection));
	CotpConnection_init(self->cotpConnection, socket, self->cotpBuffer);

	/* COTP handshake */
	CotpIndication cotpIndication =
			CotpConnection_sendConnectionRequestMessage(self->cotpConnection);

	cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);

	if (cotpIndication != CONNECT_INDICATION)
		goto returnError;

	/* Upper layers handshake */
	AcseConnection acse;

	ByteBuffer acseBuffer;
	ByteBuffer_wrap(&acseBuffer, self->buffer1, 0, ISO_CLIENT_BUFFER_SIZE);

	AcseConnection_init(&acse);

	if (params != NULL)
		AcseConnection_setAuthenticationParameter(&acse, params->acseAuthParameter);

	AcseConnection_createAssociateRequestMessage(&acse, &acseBuffer, payload);

	ByteBuffer presentationBuffer;
	ByteBuffer_wrap(&presentationBuffer, self->buffer2, 0, ISO_CLIENT_BUFFER_SIZE);

	self->presentation = calloc(1, sizeof(IsoPresentation));
	IsoPresentation_init(self->presentation);
	IsoPresentation_createConnectPdu(self->presentation, &presentationBuffer, &acseBuffer);

	ByteBuffer sessionBuffer;
	ByteBuffer_wrap(&sessionBuffer, self->buffer1, 0, ISO_CLIENT_BUFFER_SIZE);

	self->session = calloc(1, sizeof(IsoSession));
	IsoSession_init(self->session);
	IsoSession_createConnectSpdu(self->session, &sessionBuffer,
			ByteBuffer_getSize(&presentationBuffer));

	ByteBuffer_append(&sessionBuffer, ByteBuffer_getBuffer(&presentationBuffer),
			ByteBuffer_getSize(&presentationBuffer));


	CotpConnection_sendDataMessage(self->cotpConnection, &sessionBuffer);

	cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);

	if (cotpIndication != DATA_INDICATION)
		goto returnError;

	IsoSessionIndication sessionIndication;

	sessionIndication =
			IsoSession_parseMessage(self->session, CotpConnection_getPayload(self->cotpConnection));

	if (sessionIndication != SESSION_CONNECT) {
		if (DEBUG) printf("IsoClientConnection_associate: no session connect indication\n");
		goto returnError;
	}


	IsoPresentationIndication presentationIndication;
	presentationIndication =
			IsoPresentation_parseAcceptMessage(self->presentation, IsoSession_getUserData(self->session));

	if (presentationIndication != PRESENTATION_OK) {
		if (DEBUG) printf("IsoClientConnection_associate: no presentation ok indication\n");
		goto returnError;
	}

	AcseIndication acseIndication;

	acseIndication = AcseConnection_parseMessage(&acse, &self->presentation->nextPayload);

	if (acseIndication != ACSE_ASSOCIATE) {
		if (DEBUG) printf("IsoClientConnection_associate: no ACSE_ASSOCIATE indication\n");
		goto returnError;
	}

	ByteBuffer acsePayload; //TODO allocate buffer dynamically???
	ByteBuffer_wrap(&acsePayload, acse.userDataBuffer, acse.userDataBufferSize, 1024);

	self->callback(ISO_IND_ASSOCIATION_SUCCESS, self->callbackParameter, &acsePayload);

	self->state = STATE_ASSOCIATED;

	AcseConnection_destroy(&acse);

	self->thread = Thread_create(connectionHandlingThread, self, false);
	Thread_start(self->thread);

	return;

returnError:
	self->callback(ISO_IND_ASSOCIATION_FAILED, self->callbackParameter, &acsePayload);

	AcseConnection_destroy(&acse);

	self->state = STATE_ERROR;
	return;
}
static void
handleTcpConnection(IsoConnection self)
{
    if (DEBUG_ISO_SERVER)
        printf("ISO_SERVER: connection %p started\n", self);

    CotpIndication cotpIndication;

    IsoSessionIndication sIndication;

    AcseIndication aIndication;
    AcseConnection acseConnection;

    ByteBuffer receiveBuffer;

    self->cotpConnection = (CotpConnection*) calloc(1, sizeof(CotpConnection));
    CotpConnection_init(self->cotpConnection, self->socket, &receiveBuffer);

    self->session = (IsoSession*) calloc(1, sizeof(IsoSession));
    IsoSession_init(self->session);

    self->presentation = (IsoPresentation*) calloc(1, sizeof(IsoPresentation));
    IsoPresentation_init(self->presentation);

    AcseConnection_init(&acseConnection, IsoServer_getAuthenticator(self->isoServer),
            IsoServer_getAuthenticatorParameter(self->isoServer));

    while (self->msgRcvdHandlerParameter == NULL)
        Thread_sleep(1);

    if (DEBUG_ISO_SERVER)
        printf("ISO_SERVER: IsoConnection: Start to handle connection for client %s\n", self->clientAddress);

    while (self->state == ISO_CON_STATE_RUNNING) {
        ByteBuffer_wrap(&receiveBuffer, self->receiveBuffer, 0, RECEIVE_BUF_SIZE);

        cotpIndication = CotpConnection_parseIncomingMessage(self->cotpConnection);

        switch (cotpIndication) {
        case CONNECT_INDICATION:
            if (DEBUG_ISO_SERVER)
                printf("ISO_SERVER: COTP connection indication\n");

            Semaphore_wait(self->conMutex);

            CotpConnection_sendConnectionResponseMessage(self->cotpConnection);

            Semaphore_post(self->conMutex);

            break;
        case DATA_INDICATION:
            {
                if (DEBUG_ISO_SERVER)
                    printf("ISO_SERVER: COTP data indication\n");

                ByteBuffer* cotpPayload = CotpConnection_getPayload(self->cotpConnection);

                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);

                        aIndication = AcseConnection_parseMessage(&acseConnection, acseBuffer);

                        self->securityToken = acseConnection.securityToken;

                        if (aIndication == ACSE_ASSOCIATE) {

                            Semaphore_wait(self->conMutex);

                            if (DEBUG_ISO_SERVER)
                                printf("ISO_SERVER: cotp_server: acse associate\n");

                            ByteBuffer mmsRequest;

                            ByteBuffer_wrap(&mmsRequest, acseConnection.userDataBuffer,
                                    acseConnection.userDataBufferSize, acseConnection.userDataBufferSize);
                            ByteBuffer mmsResponseBuffer; /* new */

                            ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);

                            self->msgRcvdHandler(self->msgRcvdHandlerParameter,
                                    &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_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(&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");
                            }

                            Semaphore_post(self->conMutex);
                        }
                        else {
                            if (DEBUG_ISO_SERVER)
                                printf("ISO_SERVER: iso_connection: acse association failed\n");
                            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: cotp_server: presentation 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;

                        IsoServer_userLock(self->isoServer);
                        Semaphore_wait(self->conMutex);

                        ByteBuffer_wrap(&mmsResponseBuffer, self->sendBuffer, 0, SEND_BUF_SIZE);

                        self->msgRcvdHandler(self->msgRcvdHandlerParameter,
                                mmsRequest, &mmsResponseBuffer);

                        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);
                        }

                        Semaphore_post(self->conMutex);
                        IsoServer_userUnlock(self->isoServer);
                    }
                    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");

                        struct sBufferChain acseBufferPartStruct;
                        BufferChain acseBufferPart = &acseBufferPartStruct;
                        acseBufferPart->buffer = self->sendBuffer;
                        acseBufferPart->partMaxLength = SEND_BUF_SIZE;

                        AcseConnection_createReleaseResponseMessage(&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);
                    }

                    //TODO else send ABORT message

                    break;

                case SESSION_ABORT:
                    self->state = ISO_CON_STATE_STOPPED;
                    break;

                case SESSION_ERROR:
                    self->state = ISO_CON_STATE_STOPPED;
                    break;

                default: /* illegal state */
                    self->state = ISO_CON_STATE_STOPPED;
                    break;
                }
            }
            break;
        case 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;
        }
    }

    IsoServer_closeConnection(self->isoServer, self);

    if (self->socket != NULL)
        Socket_destroy(self->socket);

    free(self->session);
    free(self->presentation);

    AcseConnection_destroy(&acseConnection);

    CotpConnection_destroy(self->cotpConnection);
    free(self->cotpConnection);

    Semaphore_destroy(self->conMutex);

    free(self->receiveBuffer);
    free(self->sendBuffer);
    free(self->clientAddress);

    IsoServer isoServer = self->isoServer;

    free(self);

    if (DEBUG_ISO_SERVER)
        printf("ISO_SERVER: connection %p closed\n", self);

    private_IsoServer_decreaseConnectionCounter(isoServer);
}
Exemple #3
0
static void
handleTcpConnection(IsoConnection self) {
	CotpIndication cotpIndication;
	CotpConnection cotpConnection;

	IsoSessionIndication sIndication;
	IsoSession session;

	IsoPresentation presentation;
	IsoPresentationIndication pIndication;

	AcseIndication aIndication;
	AcseConnection acseConnection;

	ByteBuffer receiveBuffer;

	ByteBuffer responseBuffer1;
	ByteBuffer responseBuffer2;

	CotpConnection_init(&cotpConnection, self->socket, &receiveBuffer);
	IsoSession_init(&session);
	IsoPresentation_init(&presentation);
	AcseConnection_init(&acseConnection);
	AcseConnection_setAuthenticationParameter(&acseConnection,
			IsoServer_getAuthenticationParameter(self->isoServer));

	while (self->msgRcvdHandlerParameter == NULL)
		Thread_sleep(1);

	printf("IsoConnection: state = RUNNING. Start to handle connection\n");

	while (self->state == ISO_CON_STATE_RUNNING) {
		ByteBuffer_wrap(&receiveBuffer, self->receive_buf, 0, RECEIVE_BUF_SIZE);
		ByteBuffer_wrap(&responseBuffer1, self->send_buf_1, 0, SEND_BUF_SIZE);
		ByteBuffer_wrap(&responseBuffer2, self->send_buf_2, 0, SEND_BUF_SIZE);

		cotpIndication = CotpConnection_parseIncomingMessage(&cotpConnection);

		switch (cotpIndication) {
		case CONNECT_INDICATION:
			if (DEBUG) printf("COTP connection indication\n");
			CotpConnection_sendConnectionResponseMessage(&cotpConnection);
			break;
		case DATA_INDICATION:
			if (DEBUG) printf("COTP data indication\n");

			ByteBuffer* cotpPayload = CotpConnection_getPayload(&cotpConnection);

			sIndication = IsoSession_parseMessage(&session, cotpPayload);

			ByteBuffer* sessionUserData = IsoSession_getUserData(&session);

			switch (sIndication) {
			case SESSION_CONNECT:
				if (DEBUG) printf("cotp_server: session connect indication\n");

				pIndication = IsoPresentation_parseConnect(&presentation, sessionUserData);

				if (pIndication == PRESENTATION_OK) {
					if (DEBUG) printf("cotp_server: presentation ok\n");

					ByteBuffer* acseBuffer = &(presentation.nextPayload);

					aIndication = AcseConnection_parseMessage(&acseConnection, acseBuffer);

					if (aIndication == ACSE_ASSOCIATE) {
						if (DEBUG) printf("cotp_server: acse associate\n");

						ByteBuffer mmsRequest;

						ByteBuffer_wrap(&mmsRequest, acseConnection.userDataBuffer,
								acseConnection.userDataBufferSize, acseConnection.userDataBufferSize);

						self->msgRcvdHandler(self->msgRcvdHandlerParameter,
													&mmsRequest, &responseBuffer1);

						if (responseBuffer1.size > 0) {
							if (DEBUG) printf("cotp_server: application payload size: %i\n",
									responseBuffer1.size);

							AcseConnection_createAssociateResponseMessage(&acseConnection, &responseBuffer2,
									&responseBuffer1);

							responseBuffer1.size = 0;

							IsoPresentation_createCpaMessage(&presentation, &responseBuffer1,
									&responseBuffer2);

							responseBuffer2.size = 0;

							IsoSession_createAcceptSpdu(&session, &responseBuffer2,
									responseBuffer1.size);

							ByteBuffer_append(&responseBuffer2, responseBuffer1.buffer,
									responseBuffer1.size);

							CotpConnection_sendDataMessage(&cotpConnection, &responseBuffer2);

							break;
						}
						else {
							if (DEBUG) printf("cotp_server: association error. No response from application!\n");
						}
					}
					else {
						if (DEBUG) printf("cotp_server: acse association failed\n");
						self->state = ISO_CON_STATE_STOPPED;
					}

				}
				break;
			case SESSION_DATA:
				if (DEBUG) printf("cotp_server: session data indication\n");

				pIndication = IsoPresentation_parseUserData(&presentation, sessionUserData);

				if (pIndication == PRESENTATION_ERROR) {
					if (DEBUG) printf("cotp_server: presentation error\n");
					self->state = ISO_CON_STATE_STOPPED;
					break;
				}

				if (presentation.nextContextId == 3) {
					if (DEBUG) printf("cotp_server: mms message\n");

					ByteBuffer* mmsRequest = &(presentation.nextPayload);

					self->msgRcvdHandler(self->msgRcvdHandlerParameter,
													mmsRequest, &responseBuffer1);

					IsoPresentation_createUserData(&presentation,
							&responseBuffer2, &responseBuffer1);

					responseBuffer1.size = 0;

					IsoSession_createDataSpdu(&session, &responseBuffer1);

					ByteBuffer_append(&responseBuffer1, responseBuffer2.buffer,
							responseBuffer2.size);

					CotpConnection_sendDataMessage(&cotpConnection, &responseBuffer1);
				}

				break;
			case SESSION_ERROR:
				self->state = ISO_CON_STATE_STOPPED;
				break;
			}
			break;
		case ERROR:
			if (DEBUG) printf("COTP protocol error\n");
			self->state = ISO_CON_STATE_STOPPED;
			break;
		default:
			if (DEBUG) printf("COTP Unknown Indication: %i\n", cotpIndication);
			self->state = ISO_CON_STATE_STOPPED;
			break;
		}
	}

	Socket_destroy(self->socket);

	//if (DEBUG)
		printf("IsoConnection: connection closed!\n");

	AcseConnection_destroy(&acseConnection);

	IsoServer_closeConnection(self->isoServer, self);

	CotpConnection_destroy(&cotpConnection);
}