Initial import of TCAP project from Motivity.

This commit is contained in:
Vance Shipley 2011-03-07 23:57:05 +01:00
commit 2c7a40e5ba
67 changed files with 33991 additions and 0 deletions

17
TCAP/Makefile Normal file
View File

@ -0,0 +1,17 @@
.PHONY: all
all:
cd asn_src && $(MAKE)
cd src && $(MAKE)
cd doc && $(MAKE)
.PHONY: doc
doc:
cd doc && $(MAKE) $@
.PHONY: clean
clean:
cd asn_src && $(MAKE) $@
cd src && $(MAKE) $@
cd doc && $(MAKE) $@

View File

@ -0,0 +1,38 @@
ROSEINCLUDES = -I ../itu
EBIN = ../../ebin/ansi
ERLC = erlc
ERLCFLAGS = -b beam -W -v -o $(EBIN)
ASNC = $(ERLC)
ASNCFLAGS = -W -b ber_bin +optimize +driver +noobj $(ROSEINCLUDES)
$(EBIN)/%.beam:%.erl
$(ERLC) $(ERLCFLAGS) $<
.SECONDARY: %.erl
%.erl:%.asn
$(ASNC) $(ASNCFLAGS) $<
.PHONY: default
default: all
.PHONY: all
all: $(EBIN)/TR.beam
# $(EBIN)/TCAPPackage.beam \
# $(EBIN)/TCAP-Remote-Operations-Information-Objects.beam
TCAPPackage.erl: $(EBIN)/TCAP-Remote-Operations-Information-Objects.beam
.PHONY: clean
clean:
- rm -f *.asn1db
- rm -f $(EBIN)/TR.beam
# $(EBIN)/TCAPPackage.beam \
# $(EBIN)/TCAP-Remote-Operations-Information-Objects.beam
- rm -f TR.erl TCAPPackage.erl
- rm -f TR.hrl TCAPPackage.hrl

View File

@ -0,0 +1,116 @@
TCAP-Remote-Operations-Information-Objects
{iso(1) memberbody(2) usa(840) t1-114(10013) modules(0) informationObjects(1) version4(4)} DEFINITIONS ::=
BEGIN
--Exports Everything
IMPORTS
emptyBind, emptyUnbind
FROM Remote-Operations-Useful-Definitions
{joint-iso-ccitt remote-operations(4) useful-definitions(7) version1(0)};
OPERATION ::= CLASS {
&ArgumentType OPTIONAL,
&argumentTypeOptional BOOLEAN OPTIONAL,
&returnResult BOOLEAN DEFAULT TRUE,
&ResultType OPTIONAL,
&resultTypeOptional BOOLEAN OPTIONAL,
&Errors ERROR OPTIONAL,
&Linked OPERATION OPTIONAL,
&synchronous BOOLEAN DEFAULT FALSE,
&alwaysReturns BOOLEAN DEFAULT TRUE,
&InvokePriority Priority OPTIONAL,
&ResultPriority Priority OPTIONAL,
&invokeLast BOOLEAN DEFAULT FALSE,
&operationCode OperationCode UNIQUE OPTIONAL
} WITH SYNTAX {
[ARGUMENT &ArgumentType [OPTIONAL &argumentTypeOptional]]
[RESULT &ResultType [OPTIONAL &resultTypeOptional]]
[RETURN RESULT &returnResult]
[ERRORS &Errors]
[LINKED &Linked]
[SYNCHRONOUS &synchronous]
[ALWAYS RETURNS &alwaysReturns]
[INVOKE PRIORITY &InvokePriority]
[RESULT PRIORITY &ResultPriority]
[LAST &invokeLast]
[CODE &operationCode]
}
ERROR ::= CLASS {
&ParameterType OPTIONAL,
&parameterTypeOptional BOOLEAN OPTIONAL,
&ErrorPriority Priority OPTIONAL,
&errorCode ErrorCode UNIQUE OPTIONAL
} WITH SYNTAX {
[PARAMETER &ParameterType [OPTIONAL &parameterTypeOptional]]
[PRIORITY &ErrorPriority]
[CODE &errorCode]
}
OPERATION-PACKAGE ::= CLASS {
&Both OPERATION OPTIONAL,
&Consumer OPERATION OPTIONAL,
&Supplier OPERATION OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
} WITH SYNTAX {
[OPERATIONS &Both]
[CONSUMER INVOKES &Supplier]
[SUPPLIER INVOKES &Consumer]
[ID &id]
}
CONNECTION-PACKAGE ::= CLASS {
&bind OPERATION DEFAULT emptyBind,
&unbind OPERATION DEFAULT emptyUnbind,
&responderCanUnbind BOOLEAN DEFAULT FALSE,
&unbindCanFail BOOLEAN DEFAULT FALSE,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
} WITH SYNTAX {
[BIND &bind]
[UNBIND &unbind]
[RESPONDER UNBIND &responderCanUnbind]
[FAILURE TO UNBIND &unbindCanFail]
[ID &id]
}
CONTRACT ::= CLASS {
&connection CONNECTION-PACKAGE OPTIONAL,
&OperationsOf OPERATION-PACKAGE OPTIONAL,
&InitiatorConsumerOf OPERATION-PACKAGE OPTIONAL,
&InitiatorSupplierOf OPERATION-PACKAGE OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
} WITH SYNTAX {
[CONNECTION &connection]
[OPERATIONS OF &OperationsOf]
[INITIATOR CONSUMER OF &InitiatorConsumerOf]
[RESPONDER CONSUMER OF &InitiatorSupplierOf]
[ID &id]
}
ROS-OBJECT-CLASS ::= CLASS {
&Is ROS-OBJECT-CLASS OPTIONAL,
&Initiates CONTRACT OPTIONAL,
&Responds CONTRACT OPTIONAL,
&InitiatesAndResponds CONTRACT OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE
} WITH SYNTAX {
[IS &Is]
[BOTH &InitiatesAndResponds]
[INITIATES &Initiates]
[RESPONDS &Responds]
ID &id
}
OperationCode ::= CHOICE {
national [PRIVATE 16] IMPLICIT INTEGER(-32768..32767),
private [PRIVATE 17] IMPLICIT INTEGER
}
ErrorCode ::= CHOICE {
national [PRIVATE 19] INTEGER(-128..127),
private [PRIVATE 20] INTEGER
}
Priority ::= INTEGER(0..MAX)
END --end of Information Object Specifications

View File

@ -0,0 +1,211 @@
TCAPPackage
{iso(1) memberbody(2) usa(840) t1-114(10013) modules(0) tcapPackage(0) version4(4)} DEFINITIONS ::=
BEGIN
IMPORTS
OPERATION, ERROR
FROM TCAP-Remote-Operations-Information-Objects
{iso(1) memberbody(2) usa(840) t1-114(10013) modules(0) informationObjects(1) version4(4)};
PackageType ::= CHOICE {
unidirectional [PRIVATE 1] IMPLICIT UniTransactionPDU,
queryWithPerm [PRIVATE 2] IMPLICIT TransactionPDU,
queryWithoutPerm [PRIVATE 3] IMPLICIT TransactionPDU,
response [PRIVATE 4] IMPLICIT TransactionPDU,
conversationWithPerm [PRIVATE 5] IMPLICIT TransactionPDU,
conversationWithoutPerm [PRIVATE 6] IMPLICIT TransactionPDU,
abort [PRIVATE 22] IMPLICIT Abort
}
UniTransactionPDU ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
componentPortion ComponentSequence
}
TransactionPDU ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
componentPortion ComponentSequence OPTIONAL
}
-- TransactionPDU should include either a Dialogue Portion,
-- a Component Sequence or both
TransactionID ::= [PRIVATE 7] IMPLICIT OCTET STRING
-- 0 octets for the Unidirectional, 4 octets for Query, Response & Abort
-- 8 octets for Conversation in the order Originating then Responding TID
Abort ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
causeInformation CHOICE {
abortCause P-Abort-cause,
userInformation UserAbortInformation
} OPTIONAL
}
-- When the Abort package is generated by the Transaction sublayer,
-- the P-Abort-cause must be present
P-Abort-cause ::= [PRIVATE 23] IMPLICIT INTEGER {
unrecognizedPackageType(1),
incorrectTransactionPortion(2),
badlyStructuredTransactionPortion(3),
unassignedRespondingTransactionID(4),
permissionToReleaseProblem(5), -- for further study
resourceUnavailable(6),
unrecognizedDialoguePortionID(7),
badlyStructuredDialoguePortion(8),
missingDialoguePortion(9),
inconsistentDialoguePortion(10)
}
DialoguePortion ::= [PRIVATE 25] IMPLICIT SEQUENCE {
version ProtocolVersion OPTIONAL,
applicationContext CHOICE {
integerApplicationId IntegerApplicationContext,
objectApplicationId ObjectIDApplicationContext
} OPTIONAL,
userInformation UserInformation OPTIONAL,
securityContext CHOICE {
integerSecurityId [0] IMPLICIT INTEGER,
objectSecurityId [1] IMPLICIT OBJECT IDENTIFIER
} OPTIONAL,
confidentiality [2] IMPLICIT Confidentiality OPTIONAL
}
ProtocolVersion ::= [PRIVATE 26] IMPLICIT OCTET STRING(SIZE (1))
-- 0000 0000 not used
-- 0000 0001 T1.114-1996
-- 0000 0010 T1.114-2000
-- other reserved
-- These values can be combined using the bit-wise logical or operation
-- to indicate support for more than one version, e.g. the value 0000 0011
-- means that both 1996 and 2000 versions are supported
IntegerApplicationContext ::= [PRIVATE 27] IMPLICIT INTEGER
ObjectIDApplicationContext ::= [PRIVATE 28] IMPLICIT OBJECT IDENTIFIER
UserInformation ::= [PRIVATE 29] IMPLICIT SEQUENCE OF EXTERNAL
Confidentiality ::= SEQUENCE {
confidentialityId CHOICE {
integerConfidentialityId [0] IMPLICIT INTEGER,
objectConfidentialityId [1] IMPLICIT OBJECT IDENTIFIER
} OPTIONAL,
...
-- The extension marker indicates the possible presence of items
-- in the confidentiality set that are used by the confidentiality
-- algorithm.
}
UserAbortInformation ::= [PRIVATE 24] EXTERNAL
ComponentSequence ::= [PRIVATE 8] IMPLICIT SEQUENCE OF ComponentPDU{InvokeId, {Invocable}, {Returnable}}
-- Component Portion specification starts below
ComponentPDU{InvokeId:InvokeIdSet, OPERATION:Invocable, OPERATION:Returnable}
::= CHOICE {
invokeLast [PRIVATE 9] IMPLICIT Invoke{{InvokeIdSet}, {Invocable}}
(CONSTRAINED BY { -- invocable.&invokeLast must be TRUE --}
! RejectProblem:generalincorrectComponentPortion),
returnResultLast [PRIVATE 10] IMPLICIT ReturnResult{{Returnable}},
returnError [PRIVATE 11] IMPLICIT ReturnError{{Errors {{Returnable}}}},
reject [PRIVATE 12] IMPLICIT Reject,
invokeNotLast [PRIVATE 13] IMPLICIT Invoke{{InvokeIdSet}, {Invocable}}
(CONSTRAINED BY { -- invocable.&invokeLast must be FALSE --}
! RejectProblem:generalincorrectComponentPortion),
returnResultNotLast [PRIVATE 14] IMPLICIT ReturnResult{{Returnable}}
} (CONSTRAINED BY {-- must conform to the above definition --} ! RejectProblem:generalunrecognisedComponentType)
Invoke{InvokeId:InvokeIdSet, OPERATION:Operations} ::= SEQUENCE {
componentIDs [PRIVATE 15] IMPLICIT OCTET STRING(SIZE (0..2))
-- The invoke ID precedes the correlation id. There may be no
-- identifier,only an invoke ID, or both invoke and correlation ID.
(CONSTRAINED BY {-- must be unambiguous --}
! RejectProblem:invokeduplicateInvocation)
(CONSTRAINED BY {-- correlation ID must identify an outstanding operation --}
! RejectProblem:invokeunrecognisedCorrelationId) OPTIONAL,
-- operationCode
opcode OPERATION.&operationCode ({Operations} ! RejectProblem:invokeunrecognisedOperation),
-- OPERATION.&ParameterType
parameter OPERATION.&ResultType ({Operations}{@opcode}
! RejectProblem:invoke-mistypedArgument) OPTIONAL
} (CONSTRAINED BY {-- must conform to the above definition --} ! RejectProblem:generalincorrectComponentPortion)
(CONSTRAINED BY {-- must have consistent encoding --} ! RejectProblem:generalbadlyStructuredCompPortion)
(CONSTRAINED BY {-- must conform to T1.114.3 encoding rules --} ! RejectProblem:generalincorrectComponentCoding)
ReturnResult{OPERATION:Operations} ::= SEQUENCE {
componentID [PRIVATE 15] IMPLICIT OCTET STRING(SIZE (1))
(CONSTRAINED BY {-- must be that of an outstanding operation --}
! RejectProblem:returnResultunrecognisedCorrelationId)
(CONSTRAINED BY {-- which returns a result --}
! RejectProblem:returnResultunexpectedReturnResult),
parameter OPERATION.&ResultType
-- ({Operations}{@opcode} !RejectProblem:returnResultincorrectParameter)
OPTIONAL
} (CONSTRAINED BY {-- must conform to the above definition --} ! RejectProblem:generalincorrectComponentPortion)
(CONSTRAINED BY {-- must have consistent encoding --} ! RejectProblem:generalbadlyStructuredCompPortion)
(CONSTRAINED BY {-- must conform to T1.114.3 encoding rules --} ! RejectProblem:generalincorrectComponentCoding)
ReturnError{ERROR:Errors} ::= SEQUENCE {
componentID [PRIVATE 15] IMPLICIT OCTET STRING(SIZE (1))
(CONSTRAINED BY {-- must be that of an outstanding operation --}
! RejectProblem:returnErrorunrecognisedCorrelationId)
(CONSTRAINED BY {-- which returns an error --}
! RejectProblem:returnErrorunexpectedReturnError),
errorCode ERROR.&errorCode({Errors} ! RejectProblem:returnErrorunrecognisedError)
(CONSTRAINED BY {-- must be in the &Errors field of the associated operation --}
! RejectProblem:returnErrorunexpectedError),
parameter ERROR.&ParameterType ({Errors}{@errorCode} !RejectProblem:returnErrorincorrectParameter) OPTIONAL
} (CONSTRAINED BY {-- must conform to the above definition --} ! RejectProblem:generalincorrectComponentPortion)
(CONSTRAINED BY {-- must have consistent encoding --} ! RejectProblem:generalbadlyStructuredCompPortion)
(CONSTRAINED BY {-- must conform to T1.114.3 encoding rules --} ! RejectProblem:generalincorrectComponentCoding)
Reject ::= SEQUENCE {
componentID [PRIVATE 15] IMPLICIT OCTET STRING(SIZE (0..1)),
rejectProblem [PRIVATE 21] IMPLICIT Problem,
parameter CHOICE {
paramSequence [PRIVATE 16] IMPLICIT SEQUENCE {},
paramSet [PRIVATE 18] IMPLICIT SET {}
-- The choice between paramSequence and paramSet is implementation
-- dependent, however paramSequence is preferred.
}
} (CONSTRAINED BY {-- must conform to the above definition --} ! RejectProblem:generalincorrectComponentPortion)
(CONSTRAINED BY {-- must have consistent encoding --} ! RejectProblem:generalbadlyStructuredCompPortion)
(CONSTRAINED BY {-- must conform to T1.114.3 encoding rules --} ! RejectProblem:generalincorrectComponentCoding)
-- PROBLEMS, the specification of Problems follows
Problem ::= INTEGER {
generalunrecognisedComponentType(257),
generalincorrectComponentPortion(258),
generalbadlyStructuredCompPortion(259),
generalincorrectComponentCoding(260),
invokeduplicateInvocation(513),
invokeunrecognisedOperation(514),
invokeincorrectParameter(515),
invokeunrecognisedCorrelationID(516),
returnResultunrecognisedCorrelationID(769),
returnResultunexpectedReturnResult(770),
returnResultincorrectParameter(771),
returnErrorunrecognisedCorrelationID(1025),
returnErrorunexpectedReturnError(1026),
returnErrorunrecognisedError(1027),
returnErrorunexpectedError(1028),
returnErrorincorrectParameter(1029),
-- Applications using T1.114-1988 report Transaction portion
-- problems using a Reject component with a problem code in
-- the range 1281e6
-- It is preferred that other applications report
-- these problems using the Abort package type
transactionunrecognizedPackageType(1281),
transactionincorrectTransPortion(1282),
transactionbadlyStructuredTransPortion(1283),
transactionunassignedRespondingTransID(1284),
transactionpermissionToReleaseProblem(1285),
transactionresourceUnavailable(1286)
}
TCInvokeIdSet ::= InvokeId(WITH COMPONENTS { present (-128..127) })
END

103
TCAP/asn_src/ANSI/TR.asn Normal file
View File

@ -0,0 +1,103 @@
TR
{joint-iso-itu-t(2) country(16) ca(124) motivity(113594) tcap(10) modules(0) ansi(1) tr(0) version1(1)} DEFINITIONS ::=
BEGIN
PackageType ::= CHOICE {
unidirectional [PRIVATE 1] IMPLICIT UniTransactionPDU,
queryWithPerm [PRIVATE 2] IMPLICIT TransactionPDU,
queryWithoutPerm [PRIVATE 3] IMPLICIT TransactionPDU,
response [PRIVATE 4] IMPLICIT TransactionPDU,
conversationWithPerm [PRIVATE 5] IMPLICIT TransactionPDU,
conversationWithoutPerm [PRIVATE 6] IMPLICIT TransactionPDU,
abort [PRIVATE 22] IMPLICIT Abort
}
UniTransactionPDU ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
componentPortion ComponentSequence
}
TransactionPDU ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
componentPortion ComponentSequence OPTIONAL
}
-- TransactionPDU should include either a Dialogue Portion,
-- a Component Sequence or both
TransactionID ::= [PRIVATE 7] IMPLICIT OCTET STRING
-- 0 octets for the Unidirectional, 4 octets for Query, Response & Abort
-- 8 octets for Conversation in the order Originating then Responding TID
Abort ::= SEQUENCE {
identifier TransactionID,
dialoguePortion DialoguePortion OPTIONAL,
causeInformation CHOICE {
abortCause P-Abort-cause,
userInformation UserAbortInformation
} OPTIONAL
}
-- When the Abort package is generated by the Transaction sublayer,
-- the P-Abort-cause must be present
P-Abort-cause ::= [PRIVATE 23] IMPLICIT INTEGER {
unrecognizedPackageType(1),
incorrectTransactionPortion(2),
badlyStructuredTransactionPortion(3),
unassignedRespondingTransactionID(4),
permissionToReleaseProblem(5), -- for further study
resourceUnavailable(6),
unrecognizedDialoguePortionID(7),
badlyStructuredDialoguePortion(8),
missingDialoguePortion(9),
inconsistentDialoguePortion(10)
}
DialoguePortion ::= [PRIVATE 25] IMPLICIT SEQUENCE {
version ProtocolVersion OPTIONAL,
applicationContext CHOICE {
integerApplicationId IntegerApplicationContext,
objectApplicationId ObjectIDApplicationContext
} OPTIONAL,
userInformation UserInformation OPTIONAL,
securityContext CHOICE {
integerSecurityId [0] IMPLICIT INTEGER,
objectSecurityId [1] IMPLICIT OBJECT IDENTIFIER
} OPTIONAL,
confidentiality [2] IMPLICIT Confidentiality OPTIONAL
}
ProtocolVersion ::= [PRIVATE 26] IMPLICIT OCTET STRING(SIZE (1))
-- 0000 0000 not used
-- 0000 0001 T1.114-1996
-- 0000 0010 T1.114-2000
-- other reserved
-- These values can be combined using the bit-wise logical or operation
-- to indicate support for more than one version, e.g. the value 0000 0011
-- means that both 1996 and 2000 versions are supported
IntegerApplicationContext ::= [PRIVATE 27] IMPLICIT INTEGER
ObjectIDApplicationContext ::= [PRIVATE 28] IMPLICIT OBJECT IDENTIFIER
UserInformation ::= [PRIVATE 29] IMPLICIT SEQUENCE OF EXTERNAL
Confidentiality ::= SEQUENCE {
confidentialityId CHOICE {
integerConfidentialityId [0] IMPLICIT INTEGER,
objectConfidentialityId [1] IMPLICIT OBJECT IDENTIFIER
} OPTIONAL,
...
-- The extension marker indicates the possible presence of items
-- in the confidentiality set that are used by the confidentiality
-- algorithm.
}
UserAbortInformation ::= [PRIVATE 24] EXTERNAL
-- leave this portion undecoded
ComponentSequence ::= TYPE-IDENTIFIER.&Type
END

View File

@ -0,0 +1,75 @@
DialoguePDUs {itu-t recommendation q 773 modules(2) dialoguePDUs(2) version1(1)
} DEFINITIONS ::=
BEGIN
EXPORTS dialogue-as-id, DialoguePDU;
-- abstract syntax name for structured dialogue APDUs
dialogue-as-id OBJECT IDENTIFIER ::=
{itu-t recommendation q 773 as(1) dialogue-as(1) version1(1)}
DialoguePDU ::= CHOICE {
dialogueRequest AARQ-apdu,
dialogueResponse AARE-apdu,
dialogueAbort ABRT-apdu
}
AARQ-apdu ::= [APPLICATION 0] IMPLICIT SEQUENCE {
protocol-version
[0] IMPLICIT BIT STRING {version1(0)} DEFAULT {version1},
application-context-name [1] OBJECT IDENTIFIER,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
AARE-apdu ::= [APPLICATION 1] IMPLICIT SEQUENCE {
protocol-version
[0] IMPLICIT BIT STRING {version1(0)} DEFAULT {version1},
application-context-name [1] OBJECT IDENTIFIER,
result [2] Associate-result,
result-source-diagnostic [3] Associate-source-diagnostic,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
-- RLRQ PDU is currently not used.
-- It is included for completeness only.
RLRQ-apdu ::= [APPLICATION 2] IMPLICIT SEQUENCE {
reason [0] IMPLICIT Release-request-reason OPTIONAL,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
-- RLRE PDU is currently not used.
-- It is included for completeness only
RLRE-apdu ::= [APPLICATION 3] IMPLICIT SEQUENCE {
reason [0] IMPLICIT Release-response-reason OPTIONAL,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
ABRT-apdu ::= [APPLICATION 4] IMPLICIT SEQUENCE {
abort-source [0] IMPLICIT ABRT-source,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
ABRT-source ::= INTEGER {dialogue-service-user(0), dialogue-service-provider(1)
}
Associate-result ::= INTEGER {accepted(0), reject-permanent(1)}
Associate-source-diagnostic ::= CHOICE {
dialogue-service-user
[1] INTEGER {null(0), no-reason-given(1),
application-context-name-not-supported(2)},
dialogue-service-provider
[2] INTEGER {null(0), no-reason-given(1), no-common-dialogue-portion(2)}
}
-- Release-request-reason is currently not used.
-- It is included for completeness only.
Release-request-reason ::= INTEGER {normal(0), urgent(1), user-defined(30)
}
-- Release-response-reason is currently not used.
-- It is included for completeness only.
Release-response-reason ::= INTEGER {
normal(0), not-finished(1), user-defined(30)}
END -- DialoguePDUs

77
TCAP/asn_src/ITU/Makefile Normal file
View File

@ -0,0 +1,77 @@
EBIN = ../../ebin/itu
ERLC = erlc
ERLCFLAGS = -b beam -W -v +warn_unused_vars -o $(EBIN)
ASNC = $(ERLC)
ASNCFLAGS = -W -b ber_bin +optimize +driver
$(EBIN)/%.beam:%.erl
$(ERLC) $(ERLCFLAGS) $<
.SECONDARY: %.erl
%.erl:%.asn
$(ASNC) $(ASNCFLAGS) $<
.PHONY: default
default: all
.PHONY: all
all: q773 q755 q775
.PHONY: q773
q773: $(EBIN)/TR.beam $(EBIN)/TCAPMessages.beam \
$(EBIN)/DialoguePDUs.beam $(EBIN)/UnidialoguePDUs.beam
TR.erl: TCAPMessages.erl
TCAPMessages.erl: Remote-Operations-Useful-Definitions.erl
.PHONY: q755
q755: $(EBIN)/TC-Testing-User.beam
TC-Testing-User.erl: TC-TMP.erl Remote-Operations-Information-Objects.erl
.PHONY: q775
q775: $(EBIN)/TCAP-Examples.beam $(EBIN)/TCAP-Tools.beam
TCAP-Examples.erl: Remote-Operations-Information-Objects.erl
TCAP-Tools.erl: Remote-Operations-Information-Objects.erl
TC-Notation-Extensions.erl: TCAPMessages.erl \
Remote-Operations-Useful-Definitions.erl \
Remote-Operations-Information-Objects.erl \
Remote-Operations-Generic-ROS-PDUs.erl \
UnidialoguePDUs.erl DialoguePDUs.erl
Remote-Operations-Useful-Definitions.erl: \
Remote-Operations-Information-Objects.asn \
Remote-Operations-Generic-ROS-PDUs.asn \
Remote-Operations-Useful-Definitions.asn
$(ASNC) $(ASNCFLAGS) $^
Remote-Operations-Information-Objects.erl: \
Remote-Operations-Information-Objects.asn \
Remote-Operations-Generic-ROS-PDUs.asn \
Remote-Operations-Useful-Definitions.asn
$(ASNC) $(ASNCFLAGS) $^
.PHONY: clean
clean:
- rm -f *.asn1db
- rm -f TR.erl TCAPMessages.erl \
DialoguePDUs.erl UnidialoguePDUs.erl \
Remote-Operations-Useful-Definitions.erl \
Remote-Operations-Information-Objects.erl \
Remote-Operations-Generic-ROS-PDUs.erl \
TC-Testing-User.erl TC-TMP.erl \
TCAP-Examples.erl TCAP-Tools.erl \
TC-Notation-Extensions.erl
- rm -f Remote-Operations-Generic-ROS-PDUs.hrl \
DialoguePDUs.hrl UnidialoguePDUs.hrl \
TCAPMessages.hrl TR.hrl \
TC-Testing-User.hrl TC-TMP.hrl \
TCAP-Examples.hrl
- rm -f $(EBIN)/TR.beam $(EBIN)/TCAPMessages.beam \
$(EBIN)/DialoguePDUs.beam $(EBIN)/UnidialoguePDUs.beam \
$(EBIN)/TC-Testing-User.beam \
$(EBIN)/TCAP-Examples.beam $(EBIN)/TCAP-Tools.beam

View File

@ -0,0 +1,161 @@
-- Module Remote-Operations-Generic-ROS-PDUs (Rec. X.880:07/1994)
Remote-Operations-Generic-ROS-PDUs {joint-iso-itu-t remote-operations(4)
generic-ROS-PDUs(6) version1(0)} DEFINITIONS IMPLICIT TAGS ::=
BEGIN
-- exports everything
IMPORTS
OPERATION, ERROR
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)};
ROS{InvokeId:InvokeIdSet, OPERATION:Invokable, OPERATION:Returnable} ::=
CHOICE {
invoke [1] Invoke{{InvokeIdSet}, {Invokable}},
returnResult [2] ReturnResult{{Returnable}},
returnError [3] ReturnError{{Errors {{Returnable}}}},
reject [4] Reject
}
(CONSTRAINED BY { -- must conform to the above definition --} !
RejectProblem:general-unrecognizedPDU)
Invoke{InvokeId:InvokeIdSet, OPERATION:Operations} ::= SEQUENCE {
invokeId
InvokeId(InvokeIdSet)
(CONSTRAINED BY { -- must be unambiguous --} !
RejectProblem:invoke-duplicateInvocation),
linkedId
CHOICE {present [0] IMPLICIT present < InvokeId,
absent [1] IMPLICIT NULL
}
(CONSTRAINED BY { -- must identify an outstanding operation --} !
RejectProblem:invoke-unrecognizedLinkedId)
(CONSTRAINED BY { -- which has one or more linked operations--} !
RejectProblem:invoke-linkedResponseUnexpected) OPTIONAL,
opcode
OPERATION.&operationCode
({Operations} !RejectProblem:invoke-unrecognizedOperation),
argument
OPERATION.&ArgumentType
({Operations}{@opcode} !RejectProblem:invoke-mistypedArgument) OPTIONAL
}
(CONSTRAINED BY { -- must conform to the above definition --} !
RejectProblem:general-mistypedPDU)
(WITH COMPONENTS {
...,
linkedId ABSENT
} |
WITH COMPONENTS {
...,
linkedId PRESENT,
opcode (CONSTRAINED BY {
-- must be in the &Linked field of the associated operation --}
!RejectProblem:invoke-unexpectedLinkedOperation)
})
-- continued on the next page
ReturnResult{OPERATION:Operations} ::= SEQUENCE {
invokeId
InvokeId
(CONSTRAINED BY { -- must be that for an outstanding operation --} !
RejectProblem:returnResult-unrecognizedInvocation)
(CONSTRAINED BY { -- which returns a result --} !
RejectProblem:returnResult-resultResponseUnexpected),
result
SEQUENCE {opcode
OPERATION.&operationCode({Operations})
(CONSTRAINED BY { -- identified by invokeId --} !
RejectProblem:returnResult-unrecognizedInvocation),
result
OPERATION.&ResultType
({Operations}{@.opcode} !
RejectProblem:returnResult-mistypedResult)} OPTIONAL
}
(CONSTRAINED BY { -- must conform to the above definition --} !
RejectProblem:general-mistypedPDU)
ReturnError{ERROR:Errors} ::= SEQUENCE {
invokeId
InvokeId
(CONSTRAINED BY { -- must be that for an outstanding operation --} !
RejectProblem:returnError-unrecognizedInvocation)
(CONSTRAINED BY { -- which returns an error --} !
RejectProblem:returnError-errorResponseUnexpected),
errcode
ERROR.&errorCode({Errors} !RejectProblem:returnError-unrecognizedError)
(CONSTRAINED BY {
-- must be in the &Errors field of the associated operation --} !
RejectProblem:returnError-unexpectedError),
parameter
ERROR.&ParameterType
({Errors}{@errcode} !RejectProblem:returnError-mistypedParameter)
OPTIONAL
}
(CONSTRAINED BY { -- must conform to the above definition --} !
RejectProblem:general-mistypedPDU)
Reject ::= SEQUENCE {
invokeId InvokeId,
problem
CHOICE {general [0] GeneralProblem,
invoke [1] InvokeProblem,
returnResult [2] ReturnResultProblem,
returnError [3] ReturnErrorProblem}
}
(CONSTRAINED BY { -- must conform to the above definition --} !
RejectProblem:general-mistypedPDU)
GeneralProblem ::= INTEGER {
unrecognizedPDU(0), mistypedPDU(1), badlyStructuredPDU(2)}
-- continued on the next page
InvokeProblem ::= INTEGER {
duplicateInvocation(0), unrecognizedOperation(1), mistypedArgument(2),
resourceLimitation(3), releaseInProgress(4), unrecognizedLinkedId(5),
linkedResponseUnexpected(6), unexpectedLinkedOperation(7)}
ReturnResultProblem ::= INTEGER {
unrecognizedInvocation(0), resultResponseUnexpected(1), mistypedResult(2)
}
ReturnErrorProblem ::= INTEGER {
unrecognizedInvocation(0), errorResponseUnexpected(1), unrecognizedError(2),
unexpectedError(3), mistypedParameter(4)}
RejectProblem ::= INTEGER {
general-unrecognizedPDU(0), general-mistypedPDU(1),
general-badlyStructuredPDU(2), invoke-duplicateInvocation(10),
invoke-unrecognizedOperation(11), invoke-mistypedArgument(12),
invoke-resourceLimitation(13), invoke-releaseInProgress(14),
invoke-unrecognizedLinkedId(15), invoke-linkedResponseUnexpected(16),
invoke-unexpectedLinkedOperation(17),
returnResult-unrecognizedInvocation(20),
returnResult-resultResponseUnexpected(21), returnResult-mistypedResult(22),
returnError-unrecognizedInvocation(30),
returnError-errorResponseUnexpected(31), returnError-unrecognizedError(32),
returnError-unexpectedError(33), returnError-mistypedParameter(34)}
InvokeId ::= CHOICE {present INTEGER,
absent NULL
}
noInvokeId InvokeId ::= absent:NULL
NoInvokeId InvokeId ::= {noInvokeId}
Errors{OPERATION:Operations} ERROR ::= {Operations.&Errors}
-- continued on the next page
Bind{OPERATION:operation} ::= CHOICE {
bind-invoke [16] OPERATION.&ArgumentType({operation}),
bind-result [17] OPERATION.&ResultType({operation}),
bind-error [18] OPERATION.&Errors.&ParameterType({operation})
}
Unbind{OPERATION:operation} ::= CHOICE {
unbind-invoke [19] OPERATION.&ArgumentType({operation}),
unbind-result [20] OPERATION.&ResultType({operation}),
unbind-error [21] OPERATION.&Errors.&ParameterType({operation})
}
END -- end of generic ROS PDU definitions

View File

@ -0,0 +1,113 @@
-- Module Remote-Operations-Information-Objects (Rec. X.880:07/1994)
Remote-Operations-Information-Objects {joint-iso-itu-t remote-operations(4)
informationObjects(5) version1(0)} DEFINITIONS ::=
BEGIN
-- exports everything
IMPORTS
emptyBind, emptyUnbind
FROM Remote-Operations-Useful-Definitions {joint-iso-itu-t
remote-operations(4) useful-definitions(7) version1(0)};
OPERATION ::= CLASS {
&ArgumentType OPTIONAL,
&argumentTypeOptional BOOLEAN OPTIONAL,
&returnResult BOOLEAN DEFAULT TRUE,
&ResultType OPTIONAL,
&resultTypeOptional BOOLEAN OPTIONAL,
&Errors ERROR OPTIONAL,
&Linked OPERATION OPTIONAL,
&synchronous BOOLEAN DEFAULT FALSE,
&alwaysReturns BOOLEAN DEFAULT TRUE,
&InvokePriority Priority OPTIONAL,
&ResultPriority Priority OPTIONAL,
&operationCode Code UNIQUE OPTIONAL
}
WITH SYNTAX {
[ARGUMENT &ArgumentType [OPTIONAL &argumentTypeOptional]]
[RESULT &ResultType [OPTIONAL &resultTypeOptional]]
[RETURN RESULT &returnResult]
[ERRORS &Errors]
[LINKED &Linked]
[SYNCHRONOUS &synchronous]
[ALWAYS RESPONDS &alwaysReturns]
[INVOKE PRIORITY &InvokePriority]
[RESULT-PRIORITY &ResultPriority]
[CODE &operationCode]
}
ERROR ::= CLASS {
&ParameterType OPTIONAL,
&parameterTypeOptional BOOLEAN OPTIONAL,
&ErrorPriority Priority OPTIONAL,
&errorCode Code UNIQUE OPTIONAL
}
WITH SYNTAX {
[PARAMETER &ParameterType [OPTIONAL &parameterTypeOptional]]
[PRIORITY &ErrorPriority]
[CODE &errorCode]
}
OPERATION-PACKAGE ::= CLASS {
&Both OPERATION OPTIONAL,
&Consumer OPERATION OPTIONAL,
&Supplier OPERATION OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
}
WITH SYNTAX {
[OPERATIONS &Both]
[CONSUMER INVOKES &Supplier]
[SUPPLIER INVOKES &Consumer]
[ID &id]
}
CONNECTION-PACKAGE ::= CLASS {
&bind OPERATION DEFAULT emptyBind,
&unbind OPERATION DEFAULT emptyUnbind,
&responderCanUnbind BOOLEAN DEFAULT FALSE,
&unbindCanFail BOOLEAN DEFAULT FALSE,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
}
WITH SYNTAX {
[BIND &bind]
[UNBIND &unbind]
[RESPONDER UNBIND &responderCanUnbind]
[FAILURE TO UNBIND &unbindCanFail]
[ID &id]
}
CONTRACT ::= CLASS {
&connection CONNECTION-PACKAGE OPTIONAL,
&OperationsOf OPERATION-PACKAGE OPTIONAL,
&InitiatorConsumerOf OPERATION-PACKAGE OPTIONAL,
&InitiatorSupplierOf OPERATION-PACKAGE OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE OPTIONAL
}
WITH SYNTAX {
[CONNECTION &connection]
[OPERATIONS OF &OperationsOf]
[INITIATOR CONSUMER OF &InitiatorConsumerOf]
[RESPONDER CONSUMER OF &InitiatorSupplierOf]
[ID &id]
}
ROS-OBJECT-CLASS ::= CLASS {
&Is ROS-OBJECT-CLASS OPTIONAL,
&Initiates CONTRACT OPTIONAL,
&Responds CONTRACT OPTIONAL,
&InitiatesAndResponds CONTRACT OPTIONAL,
&id OBJECT IDENTIFIER UNIQUE
}
WITH SYNTAX {
[IS &Is]
[BOTH &InitiatesAndResponds]
[INITIATES &Initiates]
[RESPONDS &Responds]
ID &id
}
Code ::= CHOICE {local INTEGER, global OBJECT IDENTIFIER}
Priority ::= INTEGER(0..MAX)
END -- end of Information Object specifications

View File

@ -0,0 +1,91 @@
-- Module Remote-Operations-Useful-Definitions (Rec. X.880:07/1994)
Remote-Operations-Useful-Definitions {joint-iso-itu-t remote-operations(4)
useful-definitions(7) version1(0)} DEFINITIONS IMPLICIT TAGS ::=
BEGIN
-- exports everything
IMPORTS
OPERATION, ERROR, OPERATION-PACKAGE, Code
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)}
InvokeId, ROS{}
FROM Remote-Operations-Generic-ROS-PDUs {joint-iso-itu-t
remote-operations(4) generic-ROS-PDUs(6) version1(0)};
emptyBind OPERATION ::= {ERRORS {refuse}
SYNCHRONOUS TRUE
}
emptyUnbind OPERATION ::= {SYNCHRONOUS TRUE
}
refuse ERROR ::= {CODE local:-1
}
no-op OPERATION ::= {ALWAYS RESPONDS FALSE
CODE local:-1
}
Forward{OPERATION:OperationSet} OPERATION ::=
{OperationSet | OperationSet.&Linked.&Linked |
OperationSet.&Linked.&Linked.&Linked.&Linked}
Reverse{OPERATION:OperationSet} OPERATION ::= {Forward{{OperationSet.&Linked}}}
ConsumerPerforms{OPERATION-PACKAGE:package} OPERATION ::=
{Forward{{package.&Consumer}} | Forward{{package.&Both}} |
Reverse{{package.&Supplier}} | Reverse{{package.&Both}}}
SupplierPerforms{OPERATION-PACKAGE:package} OPERATION ::=
{Forward{{package.&Supplier}} | Forward{{package.&Both}} |
Reverse{{package.&Consumer}} | Reverse{{package.&Both}}}
AllOperations{OPERATION-PACKAGE:package} OPERATION ::=
{ConsumerPerforms{package} | SupplierPerforms{package}}
-- continued on the next page
recode{OPERATION:operation, Code:code} OPERATION ::= {
ARGUMENT operation.&ArgumentType
OPTIONAL operation.&argumentTypeOptional
RESULT operation.&ResultType
OPTIONAL operation.&resultTypeOptional
RETURN RESULT operation.&returnResult
ERRORS {operation.&Errors}
LINKED {operation.&Linked}
SYNCHRONOUS operation.&synchronous
ALWAYS RESPONDS operation.&alwaysReturns
INVOKE PRIORITY {operation.&InvokePriority}
RESULT-PRIORITY {operation.&ResultPriority}
CODE code
}
switch{OPERATION-PACKAGE:package, OBJECT IDENTIFIER:id} OPERATION-PACKAGE ::=
{
OPERATIONS {package.&Both}
CONSUMER INVOKES {package.&Consumer}
SUPPLIER INVOKES {package.&Supplier}
ID id
}
combine{OPERATION-PACKAGE:ConsumerConsumes, OPERATION-PACKAGE:ConsumerSupplies,
OPERATION-PACKAGE:base} OPERATION-PACKAGE ::= {
OPERATIONS {ConsumerConsumes.&Both | ConsumerSupplies.&Both}
CONSUMER INVOKES {ConsumerConsumes.&Consumer | ConsumerSupplies.&Supplier}
SUPPLIER INVOKES {ConsumerConsumes.&Supplier | ConsumerSupplies.&Consumer}
ID base.&id
}
ROS-SingleAS{InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::=
ROS{{InvokeIdSet}, {AllOperations {package}}, {AllOperations {package}}}
ROS-ConsumerAS{InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::=
ROS
{{InvokeIdSet}, {ConsumerPerforms {package}},
{SupplierPerforms {package}}}
ROS-SupplierAS{InvokeId:InvokeIdSet, OPERATION-PACKAGE:package} ::=
ROS
{{InvokeIdSet}, {SupplierPerforms {package}},
{ConsumerPerforms {package}}}
END -- end of useful definitions.

View File

@ -0,0 +1,84 @@
-- Module TC-Notation-Extensions (Q.775:06/1997)
TC-Notation-Extensions {itu-t recommendation q 775 modules(2)
notation-extension(4) version1(1)} DEFINITIONS ::=
BEGIN
IMPORTS
TCMessage{}
FROM TCAPMessages {itu-t recommendation q 773 modules(2) messages(1)
version3(3)}
Bind{}, Unbind{}
FROM Remote-Operations-Generic-ROS-PDUs {joint-iso-itu-t
remote-operations(4) generic-ROS-PDUs(6) version1(0)}
AllOperations{}, ConsumerPerforms{}, SupplierPerforms{}, combine{}
FROM Remote-Operations-Useful-Definitions {joint-iso-itu-t
remote-operations(4) useful-definitions(7) version1(0)}
CONTRACT, OPERATION-PACKAGE
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)}
UniDialoguePDU, uniDialogue-as-id
FROM UnidialoguePDUs {itu-t recommendation q 773 modules(2)
unidialoguePDUs(3) version1(1)}
DialoguePDU, dialogue-as-id
FROM DialoguePDUs {itu-t recommendation q 773 modules(2) dialoguePDUs(2)
version1(1)};
APPLICATION-CONTEXT ::= CLASS {
&associationContract CONTRACT,
&dialogueMode DialogueMode,
&termination Termination OPTIONAL,
&componentGrouping BOOLEAN DEFAULT TRUE,
&dialogueAndComponentGrouping BOOLEAN DEFAULT TRUE,
&AdditionalASEs OBJECT IDENTIFIER OPTIONAL,
&AbstractSyntaxes ABSTRACT-SYNTAX,
&applicationContextName OBJECT IDENTIFIER UNIQUE
}
WITH SYNTAX {
CONTRACT &associationContract
DIALOGUE MODE &dialogueMode
[TERMINATION &termination]
[COMPONENT GROUPING ALLOWED &componentGrouping]
[DIALOGUE WITH COMPONENTS ALLOWED &dialogueAndComponentGrouping]
[ADDITIONAL ASES &AdditionalASEs]
ABSTRACT SYNTAXES &AbstractSyntaxes
APPLICATION CONTEXT NAME &applicationContextName
}
DialogueMode ::= ENUMERATED {structured(1), unstructured(2)}
Termination ::= ENUMERATED {basic(1), prearranged(2)}
dialogue-abstract-syntax ABSTRACT-SYNTAX ::= {
DialoguePDU
IDENTIFIED BY dialogue-as-id
}
uniDialogue-abstract-syntax ABSTRACT-SYNTAX ::= {
UniDialoguePDU
IDENTIFIED BY uniDialogue-as-id
}
TCSingleAS{OPERATION-PACKAGE:package} ::=
TCMessage{{AllOperations {package}}, {AllOperations {package}}}
TCConsumerAS{OPERATION-PACKAGE:package} ::=
TCMessage{{ConsumerPerforms {package}}, {ConsumerPerforms {package}}}
TCSupplierAS{OPERATION-PACKAGE:package} ::=
TCMessage{{SupplierPerforms {package}}, {SupplierPerforms {package}}}
AllPackagesAS{APPLICATION-CONTEXT:ac} ::=
TCSingleAS
{combine{{ac.&associationContract.&OperationsOf |
ac.&associationContract.&InitiatorConsumerOf |
ac.&associationContract.&InitiatorSupplierOf},
{}, --was illegaly empty, needs to be changed
{-- Information Object of class OPERATION-PACKAGE to be defined --}}}
ConnectionAS{APPLICATION-CONTEXT:ac} ::= CHOICE {
bind Bind{ac.&associationContract.&connection.&bind},
unbind Unbind{ac.&associationContract.&connection.&unbind}
}
END

View File

@ -0,0 +1,56 @@
-- Module TC-TMP (Q.755.2:09/1997)
TC-TMP {itu-t recommendation q 755 modules(0) tmp(2) version1(1)} DEFINITIONS
IMPLICIT TAGS ::=
BEGIN
TMP-PDU ::= CHOICE {
testInit [0] TestInit,
testContinue [1] CommandSequence,
testDataEcho [2] UserData
}
CommandSequence ::= SEQUENCE SIZE (0..maxNbOfCommands) OF TestCommand
maxNbOfCommands INTEGER ::= 30
TestInit ::= SEQUENCE {
timeout INTEGER(1..127) OPTIONAL, -- T-Test (unit is 30 sec)
commands CommandSequence,
...
}
UserData ::= CHOICE {
simple OCTET STRING(SIZE (0..maxUserDataLength)),
complex [0] ABSTRACT-SYNTAX.&Type
}
maxUserDataLength INTEGER ::= 2048
TestCommand ::= CHOICE {wait [0] DialogueReference,
action [1] ActionInfo
}
DialogueReference ::= CHOICE {unspecified NULL,
dialogue INTEGER(0..255)
}
ActionInfo ::= SEQUENCE {
service ServiceType,
dialogueReference DialogueReference DEFAULT unspecified:NULL,
to-be-echoed UserData OPTIONAL,
...
}
ServiceType ::= ENUMERATED {
v1988uniReq(10), v1993uniReq(11), v1988beginReq(12), v1993beginReq(13),
continueReq(14), basicEndReq(15), localEndReq(16), uAbortReq(17),
class1invokeReq(21), class2invokeReq(22), class3invokeReq(23),
class4invokeReq(24), linkedInvokeReq(25), resultNlReq(26), resultLReq(27),
uErrorReq(28), uCancelReq(29), uRejectReq(30), ...
}
-- abstract syntax name for TMP-PDUs
tmp-pdus-as OBJECT IDENTIFIER ::=
{itu-t recommendation q 755 as(4) tmp-pdus(1) version1(1)}
END

View File

@ -0,0 +1,89 @@
-- Module TC-Testing-User (Q.755.2:09/1997)
TC-Testing-User {itu-t recommendation q 755 modules(0) testing-user(1)
version1(1)} DEFINITIONS ::=
BEGIN
IMPORTS
-- OPERATION,
-- ERROR
--FROM TCAPMessages {itu-t recommendation q 773 modules(2) messages(1) version2(2)}
-- APPLICATION-SERVICE-ELEMENT
--FROM Notation-Extensions {joint-iso-itu-t remote-operations(4) notation-extension(2)}
TMP-PDU
FROM TC-TMP {itu-t recommendation q 755 modules(0) tmp(2) version1(1)}
OPERATION-PACKAGE, Code, OPERATION, ERROR
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)};
-- application-context-names
ac-id OBJECT IDENTIFIER ::=
{itu-t recommendation q 755 ac(5)}
testing-ac-id OBJECT IDENTIFIER ::= {ac-id testing-ac(1) version1(1)}
-- ase
testing-User-ASE OPERATION-PACKAGE ::= {
CONSUMER INVOKES {localConsumerOperation | globalConsumerOperation}
-- consumer is the test system
SUPPLIER INVOKES
{class1SupplierOperation | class2SupplierOperation |
class3SupplierOperation | class4SupplierOperation |
globalSupplierOperation}
-- supplier is the test responder
ID testing-ac-id
}
localConsumerOperation OPERATION ::= {
ARGUMENT TMP-PDU RESULT TMP-PDU ERRORS {localSupplierError}
CODE local:0
}
globalConsumerOperation OPERATION ::= {
ARGUMENT TMP-PDU RESULT TMP-PDU ERRORS {globalSupplierError}
CODE
global:{itu-t recommendation q 755 operations(1) consumer(1)}
}
class1SupplierOperation OPERATION ::= {
ARGUMENT TMP-PDU RESULT TMP-PDU ERRORS {localConsumerError}
LINKED {localConsumerOperation}
CODE local:1
}
class2SupplierOperation OPERATION ::= {
ARGUMENT TMP-PDU ERRORS {localConsumerError}
LINKED {localConsumerOperation}
CODE local:2
}
class3SupplierOperation OPERATION ::= {
ARGUMENT TMP-PDU RESULT TMP-PDU CODE local:3
}
class4SupplierOperation OPERATION ::= {ARGUMENT TMP-PDU CODE local:4
}
globalSupplierOperation OPERATION ::= {
ARGUMENT TMP-PDU RESULT TMP-PDU ERRORS {globalConsumerError}
LINKED {globalConsumerOperation}
CODE
global:{itu-t recommendation q 755 operations(1) supplier(2)}
}
localConsumerError ERROR ::= {PARAMETER TMP-PDU CODE local:1
}
globalConsumerError ERROR ::= {
PARAMETER TMP-PDU CODE
global:{itu-t recommendation q 755 errors(2) consumer(1)}
}
localSupplierError ERROR ::= {PARAMETER TMP-PDU CODE local:2
}
globalSupplierError ERROR ::= {
PARAMETER TMP-PDU CODE
global:{itu-t recommendation q 755 errors(2) supplier(2)}
}
END

View File

@ -0,0 +1,71 @@
-- Module TCAP-Examples (Q.775:06/1997)
TCAP-Examples {itu-t recommendation q 775 modules(2) examples(2) version1(1)}
DEFINITIONS ::=
BEGIN
IMPORTS
OPERATION, ERROR
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)};
provideRoutingInformation OPERATION ::= {
ARGUMENT RequestArgument
RESULT RoutingInformation
ERRORS
{invalidCalledNumber | subscriberNotReachable | calledBarred |
processingFailure}
LINKED {getCallingPartyAddress}
}
-- timer T-pi = 10 s
getCallingPartyAddress OPERATION ::= {
RESULT CallingPartyAddress
ERRORS {callingPartyAddressNotAvailable | processingFailure}
CODE local:0
}
-- timer T-gp = 5 s
invalidCalledNumber ERROR ::= {CODE local:1
}
subscriberNotReachable ERROR ::= {CODE local:2
}
calledBarred ERROR ::= {CODE local:3
}
callingPartyAddressNotAvailable ERROR ::= {CODE local:4
}
processingFailure ERROR ::= {CODE local:5
}
-- data types
RequestArgument ::= SEQUENCE {
calledNumber IsdnNumber,
basicService BasicServiceIndicator OPTIONAL
}
RoutingInformation ::= CHOICE {
reroutingNumber [0] IMPLICIT IsdnNumber,
forwardedToNumber [1] IMPLICIT IsdnNumber
}
BasicServiceIndicator ::= ENUMERATED {speech(0), unrestrictedDigital(1)}
CallingPartyAddress ::= IsdnNumber
IsdnNumber ::= SEQUENCE {
typeOfAddress TypeOfAddress,
digits TelephonyString
}
TypeOfAddress ::= ENUMERATED {national(0), international(1), private(2)}
TelephonyString ::=
IA5String
(FROM ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "*" |
"#"))(SIZE (1..15))
END

View File

@ -0,0 +1,43 @@
-- Module TCAP-Tools (Q.775:06/1997)
TCAP-Tools {itu-t recommendation q 775 modules(2) tools(1) version1(1)}
DEFINITIONS ::=
BEGIN
EXPORTS cancel, cancelFailed, cancelled;
IMPORTS
OPERATION, ERROR
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)};
-- TCInvokeIdSet
-- FROM TCAPMessages {itu-t recommendation q 773 modules(2) messages(1)
-- version3(3)};
cancel OPERATION ::= {
-- ARGUMENT present < TCInvokeIdSet
ARGUMENT INTEGER (-128..127)
-- a TC-user may redefine this type to include
-- an empty result so that it becomes a Class 1 operation
ERRORS {cancelFailed}
}
-- timer = 15 s
cancelFailed ERROR ::= {
PARAMETER SET {
problem [0] CancelProblem,
-- invokeId [1] present < TCInvokeIdSet
invokeId [1] INTEGER (-128..127)
}
CODE local:0
}
CancelProblem ::= ENUMERATED {unknownInvocation(0), tooLate(1), notCancellable(2)}
-- a TC-user may redefine this type to include application-specific problems
cancelled ERROR ::= {
CODE local:0
}
-- an error of this type should be included in the error list of cancellable operations
END

View File

@ -0,0 +1,89 @@
TCAPMessages {itu-t recommendation q 773 modules(2) messages(1) version3(3)}
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
-- EXPORTS everything
-- Transaction Portion fields.
IMPORTS
ROS{}, InvokeId
FROM Remote-Operations-Generic-ROS-PDUs {joint-iso-itu-t
remote-operations(4) generic-ROS-PDUs(6) version1(0)}
OPERATION
FROM Remote-Operations-Information-Objects {joint-iso-itu-t
remote-operations(4) informationObjects(5) version1(0)};
TCMessage{OPERATION:Invokable, OPERATION:Returnable} ::= CHOICE {
unidirectional [APPLICATION 1] Unidirectional{{Invokable}, {Returnable}},
begin [APPLICATION 2] Begin{{Invokable}, {Returnable}},
end [APPLICATION 4] End{{Invokable}, {Returnable}},
continue [APPLICATION 5] Continue{{Invokable}, {Returnable}},
abort [APPLICATION 7] Abort
}
Unidirectional{OPERATION:Invokable, OPERATION:Returnable} ::= SEQUENCE {
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion{{Invokable}, {Returnable}}
}
Begin{OPERATION:Invokable, OPERATION:Returnable} ::= SEQUENCE {
otid OrigTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion{{Invokable}, {Returnable}} OPTIONAL
}
End{OPERATION:Invokable, OPERATION:Returnable} ::= SEQUENCE {
dtid DestTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion{{Invokable}, {Returnable}} OPTIONAL
}
Continue{OPERATION:Invokable, OPERATION:Returnable} ::= SEQUENCE {
otid OrigTransactionID,
dtid DestTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion{{Invokable}, {Returnable}} OPTIONAL
}
Abort ::= SEQUENCE {
dtid DestTransactionID,
reason CHOICE {p-abortCause P-AbortCause,
u-abortCause DialoguePortion} OPTIONAL
}
-- NOTE - When the Abort Message is generated by the Transaction sublayer, a p-Abort Cause may be
-- present. The u-abortCause may be generated by the component sublayer in which case it is an ABRT
-- APDU, or by the TC-User in which case it could be either an ABRT APDU or data in some user-defined
-- abstract syntax.
DialoguePortion ::= [APPLICATION 11] EXPLICIT EXTERNAL
-- The dialogue portion carries the dialogue control PDUs as value of the external data type. The direct
-- reference should be set to {itu-t recommendation q 773 as(1) dialogue-as(1) version1(1)} if structured
-- dialogue is used and to {itu-t recommendation q 773 as(1) unidialogue-as(2) version1(1)} if unstructured
-- dialogue is used.
OrigTransactionID ::= [APPLICATION 8] OCTET STRING(SIZE (1..4))
DestTransactionID ::= [APPLICATION 9] OCTET STRING(SIZE (1..4))
P-AbortCause ::= [APPLICATION 10] INTEGER {
unrecognizedMessageType(0), unrecognizedTransactionID(1),
badlyFormattedTransactionPortion(2), incorrectTransactionPortion(3),
resourceLimitation(4)}(0..127)
-- COMPONENT PORTION. The last field in the transaction portion of the TCAP message is the
-- component portion. The component portion may be absent.
ComponentPortion{OPERATION:Invokable, OPERATION:Returnable} ::=
[APPLICATION 12] SEQUENCE SIZE (1..MAX) OF Component{{Invokable}, {Returnable}}
-- Component Portion fields
-- Recommendation X.880 defines four Application Protocol Data Units (APDUs) for invoking
-- operations, returning results or error, and for the rejection of invalid PDUs.
-- TCAP adds returnResultNotLast to allow for the segmentation of a result.
Component{OPERATION:Invokable, OPERATION:Returnable} ::= CHOICE {
basicROS ROS{{TCInvokeIdSet}, {Invokable}, {Returnable}},
returnResultNotLast [7] returnResult < ROS{{}, {}, {Returnable}}
}
TCInvokeIdSet ::= InvokeId(WITH COMPONENTS { present (-128..127) })
END -- TCAPMessages

58
TCAP/asn_src/ITU/TR.asn Normal file
View File

@ -0,0 +1,58 @@
TR {joint-iso-itu-t(2) country(16) ca(124) mti(113594) tcap(10) modules(0) itu-t(0) tr(0) version1(1)}
DEFINITIONS IMPLICIT TAGS ::=
BEGIN
IMPORTS
Abort, DialoguePortion, OrigTransactionID, DestTransactionID
FROM TCAPMessages {itu-t recommendation q 773 modules(2) messages(1) version3(3)};
-- The Transaction sub-layer ignores the content of the ComponentPortion
-- so we have redefined these Types without parameterization and defined
-- ComponentPortion as an OCTET STRING so that it can be passed to the
-- Component sub-layer for decoding there
TCMessage ::= CHOICE {
unidirectional [APPLICATION 1] Unidirectional,
begin [APPLICATION 2] Begin,
end [APPLICATION 4] End,
continue [APPLICATION 5] Continue,
abort [APPLICATION 7] Abort,
...
}
Unidirectional ::= SEQUENCE {
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion
}
Begin ::= SEQUENCE {
otid OrigTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion OPTIONAL
}
End ::= SEQUENCE {
dtid DestTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion OPTIONAL
}
Continue ::= SEQUENCE {
otid OrigTransactionID,
dtid DestTransactionID,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion OPTIONAL
}
-- used to derive otid/dtid from unknown message type
Unknown ::= SEQUENCE {
otid OrigTransactionID OPTIONAL,
dtid DestTransactionID OPTIONAL,
dialoguePortion DialoguePortion OPTIONAL,
components ComponentPortion OPTIONAL
}
-- leave this portion undecoded
ComponentPortion ::= TYPE-IDENTIFIER.&Type
END

View File

@ -0,0 +1,20 @@
UnidialoguePDUs {itu-t recommendation q 773 modules(2) unidialoguePDUs(3)
version1(1)} DEFINITIONS ::=
BEGIN
EXPORTS uniDialogue-as-id, UniDialoguePDU;
-- Abstract syntax name for unstructured dialogue APDUs
uniDialogue-as-id OBJECT IDENTIFIER ::=
{itu-t recommendation q 773 as(1) unidialogue-as(2) version1(1)}
UniDialoguePDU ::= CHOICE {unidialoguePDU AUDT-apdu}
AUDT-apdu ::= [APPLICATION 0] IMPLICIT SEQUENCE {
protocol-version
[0] IMPLICIT BIT STRING {version1(0)} DEFAULT {version1},
application-context-name [1] OBJECT IDENTIFIER,
user-information [30] IMPLICIT SEQUENCE OF EXTERNAL OPTIONAL
}
END -- UNIDialoguePDU

11
TCAP/asn_src/Makefile Normal file
View File

@ -0,0 +1,11 @@
.PHONY: all
all:
cd itu && $(MAKE)
cd ansi && $(MAKE)
.PHONY: clean
clean:
cd itu && $(MAKE) $@
cd ansi && $(MAKE) $@

12
TCAP/doc/Makefile Normal file
View File

@ -0,0 +1,12 @@
.PHONY: all
all: doc
.PHONY: doc
doc:
cd html && $(MAKE) $@
.PHONY: clean
clean:
cd html && $(MAKE) $@

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

24
TCAP/doc/html/Makefile Normal file
View File

@ -0,0 +1,24 @@
## $Id: Makefile,v 1.3 2005/02/10 06:39:56 vances Exp $
ERL = erl
SRC = ../../src
%.html:${SRC}/%.erl
${ERL} -noshell -run edoc_run file '"$<"' '[{dir,"."}]' -s init stop
%.html:${SRC}/itu/%.erl
${ERL} -noshell -run edoc_run file '"$<"' '[{dir,"."}]' -s init stop
DOCS = tcap.html tcap_tco_server.html
.PHONY: default
default: doc
.PHONY: doc
doc: $(DOCS)
.PHONY: clean
clean:
- rm -f $(DOCS)

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

BIN
TCAP/doc/html/inap_aei.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

359
TCAP/doc/html/index.html Normal file
View File

@ -0,0 +1,359 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>TCAP User's Guide</title>
<link rel="stylesheet" type="text/css" href="stylesheet.css">
</head>
<body bgcolor="white">
<h1>TCAP User's Guide</h1>
<p>Copyright &#169; 2003-2005 <a href=http://www.motivity.ca>Motivity Telecom Inc.</a></p>
<p><b>Version:</b> 1.1</p>
<p><b>Authors:</b> Vance Shipley (<a href="mailto:vances@motivity.ca"><tt>vances@motivity.ca</tt></a>).</p>
<p>The <a href="tcap.html"><tt>tcap</tt></a> application is a protocol stack
implementation of the Transaction Capabilities Application Part (TCAP) of
the Signaling System No. 7 (SS7) specifications <cite>ITU-T Q.771-Q.774</cite> and
<cite>ANSI T1.114-2000</cite>. Transaction Capabilities (TC) users include
the Intelligent Network Application Protocol (INAP) ITU-T Q.1208 and the Mobile
Application Part (MAP) 3GPP 29.002.</p>
<h3>Requirements</h3>
<p>This application includes only the TCAP procedures and must be used
with a seperate application providing the SCCP service.
The <a href="http://www.motivity.ca/nms"><tt>nms</tt></a>
application provides a binding to the embedded SCCP layer on the
TX3220/TX4000 boards. An native Erlang SCCP User Adaptation (SUA)
for SIGTRAN SCTP is planned.</p>
<h3>Transaction Capabilities</h3>
<p>Transaction Capabilities (TC) provides support for interactive
applications in a distributed environment through a generic remote procedure
call service. TC provides the framework for invoking remote procedures
and returning the results of these procedures.</p>
<a href="transaction_capabilities.png">Figure 1-1</a>
shows the structure of TC using SS7 network services. TC is composed of two
sublayers; the Component Sublayer (CSL) and the Transaction Sublayer (TSL).
The CSL deals with components which are the Application Protocol Data Units (APDU)
that convey remote operations and their responses. The CSL optionally may
utilize the dialogue portion protocol for conveying information related to
application context or user information. The TSL deals with the exchange of
messages containing components and optionally, a dialogue portion, between TC-Users.</p>
<p>Figure 1-1: TC in SS7
<img alt="diagram of transaction capabilities" name="figure1-1" src="transaction_capabilities.png"></p>
<h3>Open Systems Interconnection (OSI)</h3>
<p>TC is based on the Remote Operations concept defined in Recommendation X.880 (ROS).
TC allows communication between TC-Users across an SS7 network.
This communication can be modelled with the OSI seven layer stack as shown in
<a href="osi_model.png">Figure-2.1</a>. SS7 does not define an Intermediate Services Part
(ISP) so the Presentation, Session and Transport layers are formally missing however
some aspects of the these are present in TC. CSL lies entirely within the application layer.</p>
<p>Figure 2-1: TC in OSI
<img alt="diagram of osi layers" name="figure2-1" src="osi_model.png"></p>
<a href="application_process.png">Figure-2.2</a> shows the structure of the OSI Application Layer.
An Application Process (AP) consists of application code within and outside the OSI
framework. The part of an application which resides in the OSI framework is called
an Application Entity (AE). The AE may contain a number of cooperating components,
each with it's own protocol elements. These components are called Application
Service Elements (ASE). An ASE is a separately defined (standardized) part of an
Application Entity. ASEs provide a service to higher level ASEs not a higher level
layer. The distinction being that unlike layer services an ASE service may consider
only part of the communication between Application Entities.</p>
<p>Figure 2-2: OSI Application Process
<img alt="diagram of application process" name="figure2-2" src="application_process.png"></p>
<p>The Component sublayer is in partial alignment with the capabilities of the
Remote Operation Service Element (ROSE) X.219 and X.229. The X.229 protocol is
contained within the TC component protocol. CSL includes some extensions to ROSE.
The dialogue control facilities are in partial alignment with the capabilities
of the Association Control Service Element (ACSE) X.217 and X.227. The abstract
syntax for the dialogue control APDUs are a subset of the OSI ACSE abstract syntax.</p>
<a href="tcap_application_process.png">Figure-2.3</a> shows an Application Process
with an Application Entity which includes the Transaction Capabilities ASE and the
Mobile Application Part ASE.</p>
<p>Figure 2-3: SS7 Application Process
<img alt="diagram of SS7 application process" name="figure2-3" src="tcap_application_process.png"></p>
<p>An Application Entity (AE) is the part of your Application Process (AP) which
uses the services of a combined set of ASEs. An AE-Type defines a set of functions
used for communications. For example one AE-Type may combine a TC ASE with a MAP ASE
while another combines a TC ASE with an INAP ASE. An AE Invocation (AEI) is an instance
of an AE and it's ASEs.</p>
<p>An AEI may perform a subset of the communication functions defined by the AE-Type.
The actual procedures that may need to be performed for an instance of communication
are determined by the Application Context (AC). The Application Context states which
functions are needed. Based on this information the AEI is instantiated from the
AE-Type which fits these criteria.</p>
<p>Using the <a href="tcap.html"><tt>tcap</tt></a> application you will implement
your Application Process (AP) and Application Entity (AE) in Erlang. The set of
processes which make up an instance of the Component Sublayer (CSL) form the TC ASE.
For each new dialogue an AEI including a TC ASE and a TC-User ASE (e.g. MAP) is created.
The AE uses the ASEs together to provide higher level functions to the AP.</p>
<p>Figure 3-1: AE Invocations
<img alt="diagram of AE invocations" name="figure3-1" src="ae_invocations.png"></p>
<p>For example you may have an AE which uses TCAP and MAP ASEs implemented in a
<tt>gen_fsm</tt> callback module named ae_map_v3. An AEI for a location update
could be created as:
<pre>
gen_fsm:start_link(ae_map_v3, ['networkLocUpContext-v3', TSL], [])</pre>
<p>Where <tt>'networkLocUpContext-v3'</tt> is the application context name and
<tt>TSL</tt> is a reference to the transaction sublayer used for this operation.
The callback module would start TC and MAP and coordinate them to provide the
location update service to the Application Program.</p>
<pre>
-module(ae_map_v3).
-export([init/1, handle_event/2]).
-behaviour(gen_fsm).
-record(state, {ac, tsl, csl, map}).
init([AC, TSL]) ->
case tcap:open(TSL, self(), []) of
{ok, CSL} ->
case map:open(CSL, self(), []) of
{ok, MAP} ->
State = #state{ac = AC, tsl = TSL, csl = CSL, map = MAP},
{ok, idle, State};
Error ->
Error
end;
Error ->
Error
end.
</pre>
<p>In ASN.1 an <tt>OPERATION-PACKAGE</tt> type is used to define an ASE. An
<tt>APPLICATION-CONTEXT</tt> type defines an AC. An application protocol is defined
by the set of all possible ACs. The above example uses these definitions from the
3GPP/GSM MAP specification:</p>
<pre>
networkLocUpContext-v3 APPLICATION-CONTEXT ::= {
-- Responder is HLR if Initiator is VLR
INITIATOR CONSUMER OF {locationUpdatingPackage-v3 | dataRestorationPackage-v3}
RESPONDER CONSUMER OF {subscriberDataMngtPackage-v3 | tracingPackage-v3}
ID {map-ac networkLocUp(1) version3(3)}
}
</pre>
<pre>
locationUpdatingPackage-v3 OPERATION-PACKAGE ::= {
-- Supplier is HLR if Consumer is VLR
CONSUMER INVOKES {updateLocation}
SUPPLIER INVOKES {forwardCheckSs-Indication}
}
</pre>
<pre>
updateLocation OPERATION ::= { --Timer m
ARGUMENT UpdateLocationArg
RESULT UpdateLocationRes
ERRORS {systemFailure | dataMissing | unexpectedDataValue | unknownSubscriber | roamingNotAllowed}
CODE local:2
}
</pre>
<p>In a complex AE there may be multiple TC-User ASEs. The operation codes
(e.g. <tt>local:2</tt> for the <tt>updateLocation</tt> above) of the received
components allow the AE to distribute to the appropriate ASE. While the
<tt>locationUpdatingPackage-v3</tt> definition above appears informally in the
current specifications MAP is still viewed as having a single Application Service Element
for historical reasons. The Intelligent Network Application Protocol (INAP) however
clearly defines many distinct ASEs. <a href="inap_aei.png">Figure 3-2</a>
shows the configuration of an AEI for INAP using the
<tt>scf-to-ssf-status-reporting-v1</tt> AC.</p>
<p>Figure 3-2: Example INAP AEI
<img alt="diagram of INAP AEI" name="figure3-2" src="inap_aei.png"></p>
<h3>Addressing</h3>
<p>When used with SS7 network services the addressesing of the Signaling Connection
Control Part (SCCP) is used. The SCCP CalledParty and CallingParty address formats
are used in the TCAP address parameters; Destination Address and Originating Address.
These parameters identify the destination and originating TC-user.</p>
<p>The SCCP Subsystem Number (SSN) is used by SCCP for message distrubution to
seperate instances of the TCAP Transaction Sublayer (TSL).</p>
<p>Figure 4-1: SSN Distribution
<img alt="diagram of ssn distribution" name="figure4-1" src="ssn_distribution.png"></p>
<h3>Process Communication</h3>
<p>A number of processes interact to provide the TCAP service.
<a href="tcap_messaging.png">Figure 5-1</a> depicts the message paths
between processes used with the TCAP application.</p>
<p>The TCAP protocol layer is split into two sublayers; the Transaction
Sublayer and the Component Sublayer.</p>
<p>In the transaction sublayer a transaction coordinator (TCO)
process performs marshalling of incoming indications from the
SCCP service access point (SAP). It spawns a transaction state
machine (TSM) for each new transaction.</p>
<p>In the component sublayer a dialogue handler (DHA) process
is started for each transaction. It then spawns a component
coordinator process (CCO). For a remotely initiated transaction
DHA is started by TCO. For a locally initiated transaction DHA
is started by the TC-User. An invocation state machine (ISM)
is started for each locally invoked operation involved in the
transaction.<p>
<p>Figure 5-1<br>
<img alt="diagram of process communication" name="figure5-1" src="tcap_messaging.png"></p>
<h3>Modules</h3>
<h5><tt>tcap</tt></h5>
<p>This module implements the application programming interface (API) for the application.</p>
<h5><tt>tcap_app</tt></h5>
<p>This is the start module for the application.
It is an <tt>application</tt> behaviour callback module.</p>
<h5><tt>tcap_sup</tt></h5>
<p>This module implements the top level supervisor for the application.
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_sap_sup</tt></h5>
<p>This module implements a supervisor at the SAP level, one per SAP.
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_tco_server</tt></h5>
<p>This module implements the transaction coordinator (TCO).
It is a <tt>gen_server</tt> behaviour callback module.</p>
<h5><tt>tcap_transaction_sup</tt></h5>
<p>This module implements a supervisor at the transaction level, one per transaction.
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_tsm_fsm</tt></h5>
<p>This module implements the transaction state machine (TSM).
It is a <tt>gen_fsm</tt> behaviour callback module.</p>
<h5><tt>tcap_dialogue_sup</tt></h5>
<p>This module implements a supervisor at the dialogue level, one per dialogue (transaction).
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_dha_fsm</tt></h5>
<p>This module implements the dialogue handler (DHA).
It is a <tt>gen_fsm</tt> behaviour callback module.</p>
<h5><tt>tcap_components_sup</tt></h5>
<p>This module implements a supervisor at the components level, one per component sequence (dialogue/transaction).
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_cco_server</tt></h5>
<p>This module implements the component coordinator (CCO).
It is a <tt>gen_server</tt> behaviour callback module.</p>
<h5><tt>tcap_invocation_sup</tt></h5>
<p>This module implements a supervisor at the invocation level, one per component sequence (dialogue/transaction).
It is a <tt>supervisor</tt> behaviour callback module.</p>
<h5><tt>tcap_ism_fsm</tt></h5>
<p>This module implements the invocation state machine (ISM).
It is a <tt>gen_fsm</tt> behaviour callback module.</p>
<h3>Supervision Tree</h3>
<p>The processes which make up an instance of the TCAP service layer are all instantiated within a single
supervision tree. When the application is started a top level supervisor is created with no children.
The user calls <a href="tcap.html#open-3"><tt>tcap:open/3</tt></a> to create a new
service access point (SAP) which dynamically adds a <tt>tcap_sap_sup</tt> supervisor with one worker TCO.</p>
<a href="tcap_supervision.png">Figure 5-2</a> shows the structure of the supervision tree.</p>
<p>For every new transaction ID assigned (Begin indication or request) a <tt>tcap_transaction_sup</tt>
supervisor is dynamically added to the <tt>tcap_sap_sup</tt> supervisor with one TSM worker and a
<tt>tcap_dialogue_sup</tt> supervisor. In the case of a Unidirectional primitive no transaction is
assigned. Instead a <tt>tcap_dialogue_sup</tt> supervisor is dynamically added to the <tt>tcap_sap_sup</tt>
supervisor.</p>
<p>When a <tt>tcap_dialogue_sup</tt> supervisor is started it immediately creates a DHA worker and a
<tt>tcap_components_sup</tt> supervisor with one CCO worker and a <tt>tcap_invocation_sup</tt> supervisor.</p>
<p>A <tt>tcap_ism_fsm</tt> worker is dynamically added to the <tt>tcap_invocation_sup</tt> supervisor for
each locally invoked operation.</p>
<p>Figure 5-2<br>
<img alt="diagram of supervision tree" name="figure5-2" src="tcap_supervision.png"></p>
<h3>Distribution</h3>
<p>In order to facilitate building very large systems the processes involved may be distributed across nodes.
<a href="tcap_distribution.png">Figure 6-1</a> shows some examples of how this distribution may be accomplished.</p>
<p>Figure 6-1<br>
<img alt="diagram of process distribution" name="figure6-1" src="tcap_distribution.png"></p>
<p>When a SAP is created with <a href="tcap.html#open-3"><tt>tcap:open/3</tt></a> the
<a href="tcap_tco_server.html"><tt>tcap_tco_server</tt></a> callback module name is provided to start a TCO
which can adapt the specific implementation of SCCP in use to this TCAP service layer. Arguments are also
passed to specify instance specific configuration such as SCCP subsystem number.</p>
<p>The <a href="tcap_tco_server.html"><tt>tcap_tco_server</tt></a> callback module exports start functions
used to create SAP, TCO, TSM and DHA processes. This allows the user to configure how the application is
distributed.</p>
<p>The DHA always starts the CCO and ISM processes on it's local node.</p>
<h3>Primitives (ITU)</h3>
<h4>TC-User &#8594 Component Sublayer</h4>
<h5>Dialogue Handling</h5>
<tt>{'TC', 'UNI', request, Parms}</tt><br>
<tt>{'TC', 'BEGIN', request, Parms}</tt><br>
<tt>{'TC', 'CONTINUE', request, Parms}</tt><br>
<tt>{'TC', 'END', request, Parms}</tt><br>
<tt>{'TC', 'U-ABORT', request, Parms}</tt><br>
<h5>Component Handling</h5>
<tt>{'TC', 'INVOKE', request, Parms}</tt><br>
<tt>{'TC', 'RESULT-L', request, Parms}</tt><br>
<tt>{'TC', 'RESULT-NL', request, Parms}</tt><br>
<tt>{'TC', 'U-ERROR', request, Parms}</tt><br>
<tt>{'TC', 'U-CANCEL', request, Parms}</tt><br>
<tt>{'TC', 'U-REJECT', request, Parms}</tt><br>
<h4>Component Sublayer &#8594 TC-User</h4>
<h5>Dialogue Handling</h5>
<tt>{'TC', 'UNI', indication, Parms}</tt><br>
<tt>{'TC', 'BEGIN', indication, Parms}</tt><br>
<tt>{'TC', 'END', indication, Parms}</tt><br>
<tt>{'TC', 'U-ABORT', indication, Parms}</tt><br>
<tt>{'TC', 'P-ABORT', indication, Parms}</tt><br>
<tt>{'TC', 'NOTICE', indication, Parms}</tt><br>
<h5>Component Handling</h5>
<tt>{'TC', 'INVOKE', indication, Parms}</tt><br>
<tt>{'TC', 'RESULT-L', indication, Parms}</tt><br>
<tt>{'TC', 'RESULT-NL', indication, Parms}</tt><br>
<tt>{'TC', 'U-ERROR', indication, Parms}</tt><br>
<tt>{'TC', 'L-CANCEL', indication, Parms}</tt><br>
<tt>{'TC', 'L-REJECT', indication, Parms}</tt><br>
<tt>{'TC', 'R-REJECT', indication, Parms}</tt><br>
<tt>{'TC', 'U-REJECT', indication, Parms}</tt><br>
<tt>{'TC', 'TIMER-RESET', indication, Parms}</tt><br>
<h4>Component Sublayer &#8594 Transaction Sublayer</h4>
<tt>{'TR', 'UNI', request, Parms}</tt><br>
<tt>{'TR', 'BEGIN', request, Parms}</tt><br>
<tt>{'TR', 'CONTINUE', request, Parms}</tt><br>
<tt>{'TR', 'END', request, Parms}</tt><br>
<tt>{'TR', 'U-ABORT', request, Parms}</tt><br>
<h4>Transaction Sublayer &#8594 Component Sublayer</h4>
<tt>{'TR', 'UNI', indication, Parms}</tt><br>
<tt>{'TR', 'BEGIN', indication, Parms}</tt><br>
<tt>{'TR', 'CONTINUE', indication, Parms}</tt><br>
<tt>{'TR', 'END', indication, Parms}</tt><br>
<tt>{'TR', 'U-ABORT', indication, Parms}</tt><br>
<tt>{'TR', 'P-ABORT', indication, Parms}</tt><br>
<tt>{'TR', 'NOTICE', indication, Parms}</tt><br>
<h4>Transaction Sublayer &#8594 SCCP</h4>
<tt>{'N', 'UNITDATA', request, Parms}</tt><br>
<h4>SCCP &#8594 Transaction Sublayer</h4>
<tt>{'N', 'UNITDATA', indication, Parms}</tt><br>
<tt>{'N', 'NOTICE', indication, Parms}</tt><br>
</body>
</html>

BIN
TCAP/doc/html/osi_model.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

1919
TCAP/doc/inap_aei.graffle Normal file

File diff suppressed because it is too large Load Diff

2183
TCAP/doc/osi_model.graffle Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

13
TCAP/ebin/tcap.app Normal file
View File

@ -0,0 +1,13 @@
{application, tcap,
[{description, "Transaction Capabilities Application Part"},
{vsn, "0.1"},
{modules, [tcap, tcap_app, tcap_sup,
transaction_coordinator_sup, transaction_coordinator_server,
transaction_sup, transaction_fsm,
dialogue_sup, dialogue_fsm,
component_cordinator_sup, component_cordinator,
invocation_sup, invocation_fsm]},
{registered, []},
{applications, [kernel, stdlib, sccp]},
{env, [{supref, {local, tcap_sup}}]},
{mod, {tcap_app, []}}]}.

View File

@ -0,0 +1,102 @@
%%% $Id: sccp_adaptation.erl,v 1.1 2005/02/11 03:32:45 vances Exp $
%%%---------------------------------------------------------------------
%%% @author Vance Shipley <vances@motivity.ca>
%%%
%%% @doc Example Transaction Coordinator (TCO) adaptation callback module.
%%%
%%% @private
%%%
-module(tcap_example_adaptation).
-author('vances@motivity.ca').
-vsn('$Revision: 1.1 $').
-behaviour(tcap_tco_server).
% export the gen_server call backs
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
% export the tcap_tco_server specific call backs
-export([send_primitive/2, start_transaction/2, start_dialogue/2]).
-record(state, {nsap}).
%%----------------------------------------------------------------------
%% The tcap_tco_server specific call backs
%%----------------------------------------------------------------------
%% @spec (Primitive, State) -> void()
%% Primitive = {'N', 'UNITDATA', request, UdataParams}
%%
%% @doc Deliver service primitive to the SCCP layer.
%%
send_primitive(Primitive, State) ->
State#state.nsap ! Primitive.
%% @spec (DialogueID, CSL, State) -> pid()
%% DialogueID = int()
%%
%% @doc Start a MAP dialogue state machine (DSM) TC-User process.
%%
start_user(DialogueID, CSL, State) ->
map:open(State#state.map, DialogueID, CSL).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% @spec (Args) -> Result.
%% Args = [NSAP:int()]
%% Result = {ok, State}
%%
%% @doc Initialize the Transaction Coordinator (TCO).
%%
init([NSAP]) ->
case sccp:start_link(self(), NSAP) of
{ok, NSAP} ->
case map:start_link(self(), NSAP) of
{ok, MAP} ->
{ok, #state{nsap = NSAP, map = MAP}}.
Error ->
Error
end;
Error ->
Error
end.
%% @hidden
%%
handle_call(_Event, _From, State) ->
{noreply, State}.
%% @spec (Primitive, State) -> Result.
%% Primitive = {'N', GenericName, indication, Parameter}
%% GenericName = 'UNITDATA' | 'NOTICE'
%% Parameter = #'UNITDATA'{} | #'NOTICE'{}
%% State = #state{}
%%
%% @doc Handle a service primitive received from the SCCP SAP.
%%
handle_info({'N', _, indication, _} = Primitive, State) ->
{primitive, Primitive, State}.
%% @hidden
%%
handle_cast(_Event, State) ->
{noreply, State};
%% @hidden
terminate(_Reason, _State) ->
ok.
%% @hidden
code_change(_OldVersion, State, _Extra) ->
{ok, State}.
%%----------------------------------------------------------------------
%% internal functions
%%----------------------------------------------------------------------

120
TCAP/include/tcap.hrl Normal file
View File

@ -0,0 +1,120 @@
%%% $Id: tcap.hrl,v 1.1 2005/01/04 05:43:50 vances Exp $
%%%---------------------------------------------------------------------
%%% Copyright Motivity Telecom Inc. 2004
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% ITU-T recommendation Q.771 Functional Decsription of
%%% Transaction Capabilities describes the primitives and
%%% their parameters used in the TC-Service and TR-Service
%%% interfaces. Each primitive has a record defined here
%%% containing it's parameters. Modules using the these
%%% services utilize these records to format messages:
%%%
%%% {'TC', 'BEGIN', request, Begin} when is_record(Begin, 'TC-BEGIN')
%%% {'TR', 'UNI', indication, Unidirectional} when is_record(Unidirectional, 'TR-UNI')
%%%
%%%
%%% TC-User
%%%
%%% componentsPresent is a boolean
%% reference: Table 3/Q.771 - TC-UNI primitives
-record('TC-UNI', {qos, destAddress, appContextName, origAddress, dialogueID,
userInfo, componentsPresent}).
%% reference: Table 4/Q.771 - TC-BEGIN primitives
-record('TC-BEGIN', {qos, destAddress, appContextName, origAddress, dialogueID,
userInfo, componentsPresent}).
%% reference: Table 5/Q.771 - TC-CONTINUE primitives
-record('TC-CONTINUE', {qos, origAddress, appContextName, dialogueID,
userInfo, componentsPresent}).
%% reference: Table 7/Q.771 - TC-END primitives
-record('TC-END', {qos, dialogueID, appContextName, componentsPresent,
userInfo, termination}).
%% reference: Table 8/Q.771 - TC-U-ABORT primitives
-record('TC-U-ABORT', {qos, dialogueID, abortReason, appContextName, userInfo}).
%% abortReason is one of applicationContextNotSupported, dialogueRefused, userSpecific
%% reference: Table 9/Q.771 - TC-NOTICE primitives
-record('TC-NOTICE', {dialogueID, origAddress, destAddress, reportCause}).
%% reference: Table 10/Q.771 - Operation invocation primitives
-record('TC-INVOKE', {dialogueID, class, invokeID, linkedID, operation,
parameters, lastComponent, timeout}).
%% reference: Table 11/Q.771 - Report of success primitives
-record('TC-RESULT-L', {dialogueID, invokeID, operation, parameters,
lastComponent}).
-record('TC-RESULT-NL', {dialogueID, invokeID, operation, parameters,
lastComponent}).
%% reference: Table 12/Q.771 - Report of failure primitives
-record('TC-U-ERROR', {dialogueID, invokeID, error, parameters,
lastComponent}).
%% reference: Table 13/Q.771 - User rejection primitives
-record('TC-U-REJECT', {dialogueID, invokeID, problemCode,
lastComponent}).
%% reference: Table 14/Q.771 - TC-CANCEL primitives
-record('TC-L-CANCEL', {dialogueID, invokeID}).
-record('TC-U-CANCEL', {dialogueID, invokeID}).
%% reference: Table 14bis/Q.771 TC-TIMER-RESET primitives
-record('TC-TIMER-RESET', {dialogueID, invokeID}).
%% reference: Table 15/Q.771 - Component sublayer rejection primitives
-record('TC-L-REJECT', {dialogueID, invokeID, problemCode, lastComponent}).
-record('TC-R-REJECT', {dialogueID, invokeID, problemCode, lastComponent}).
%% reference: Table 16/Q.771 - Primitive for Abort
-record('TC-P-ABORT', {qos, dialogueID, pAbort}).
%% pAbort is either a P-AbortCause or abnormalDialogue or noCommonDialoguePortion
%%%
%%% TR-User
%%%
%%% userData is a 'TR-user-data' record
%%%
%%% Q.771 does not provide a distinction between the dialogue portion and
%%% component portion within the user data parameter. In 3.1.1 it says
%%% "a dialogue portion is formatted and sent concatenated with the
%%% (sequence of) components(s)."
%%% This is probably due to dialogue handling being added after Q.771 was
%%% first written. We will define a record for the user data.
-record('TR-user-data', {dialoguePortion, componentPortion}).
%% reference: Table 18/Q.771 - TR-UNI primitives
-record('TR-UNI', {qos, destAddress, origAddress, userData}).
%% reference: Table 19/Q.771 - Primitives for transaction begin
-record('TR-BEGIN', {qos, destAddress, origAddress, transactionID, userData}).
%% reference: Table 20/Q.771 - Transaction continuation primitives
-record('TR-CONTINUE', {qos, origAddress, transactionID, userData}).
%% reference: Table 22/Q.771 - TR-END primitives
-record('TR-END', {qos, transactionID, termination, userData}).
%% reference: Table 23/Q.771 - TR-U-ABORT primitives
-record('TR-U-ABORT', {qos, transactionID, userData}).
%% reference: Table 24/Q.771 - Transaction sublayer abort primitive
-record('TR-P-ABORT', {qos, transactionID, pAbort}).
%% pAbort is a P-AbortCause
%% reference: Table 25/Q.771 - TR-NOTICE primitive
-record('TR-NOTICE', {transactionID, origAddress, destAddress, reportCause}).

38
TCAP/src/ANSI/Makefile Normal file
View File

@ -0,0 +1,38 @@
## $id$
SCCPINCDIR = ../../../SCCP/itu/include
EBIN = ../../ebin/itu
ERLC = erlc
EMULATOR = beam
ERLCFLAGS = -b $(EMULATOR) -o $(EBIN) -W -v +warn_unused_vars -I ../asn_src -I ../include -I $(SCCPINCDIR)
$(EBIN)/%.$(EMULATOR):%.erl
$(ERLC) $(ERLCFLAGS) $<
BEAMS = $(EBIN)/tcap_tco_server.$(EMULATOR) \
$(EBIN)/tcap_tsm_fsm.$(EMULATOR) \
$(EBIN)/tcap_dha_fsm.$(EMULATOR) \
$(EBIN)/tcap_cco_server.$(EMULATOR) \
$(EBIN)/tcap_ism_fsm.$(EMULATOR)
.PHONY: default
default: all
.PHONY: all
all: $(BEAMS)
.PHONY: install
.PHONY: clean
clean:
- rm -f $(BEAMS)
tcap_tco_server.$(EMULATOR): tcap_tco_server.erl \
../../asn_src/TCAPMessages.hrl ../../include/tcap.hrl \
$(SCCPINCDIR)/sccp.hrl
tcap_tsm_fsm.$(EMULATOR): tcap_tsm_fsm.erl \
../../asn_src/TCAPMessages.hrl ../../include/tcap.hrl \
$(SCCPINCDIR)/sccp.hrl

View File

@ -0,0 +1,98 @@
%%% $Id: queryWithPerm_fsm.erl,v 1.5 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc ANSI TCAP'Query with Permission' package.
%%% <p>This module implements an ANSI TCAP 'Query with Permission' package
%%% type transaction process. The components within the received
%%% transaction PDU are executed sequentially in this process.</p>
%%%
%%% @reference ANSI T1.114-2000
%%%
%%% @private
%%%
-module(queryWithPerm_fsm).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.5 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
terminate/3, code_change/4]).
%% call backs for gen_fsm states in this module
%% our published API functions
-export([]).
-include("TCAPPackage.hrl").
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% initialize the server
init([SccpParms, TransactionPDU]) ->
{CalledParty, CallingParty, QualityOfServiceParameterSet} = SccpParms,
{ok,
process_flag(trap_exit, true),
{ok, StateName, StateData, Timeout}.
%% handle events sent with gen_fsm:send_all_state_event/2
handle_event(Event, StateName, StateData) ->
{next_state, StateName, StateData}.
% trapped exit signals
handle_info({'EXIT', Pid, Reason}, State) ->
{stop, Reason, State}.
%% handle events sent with gen_fsm:sync_send_all_state_event/2,3
handle_sync_event(Event, From, StateName, StateData) ->
{next_state, StateName, StateData}.
% handle other received messages
handle_info(Unknown, State) ->
error_logger:error_msg("Received unknown message: ~p~n", [Unknown]),
{next_state, StateName, StateData}.
% someone wants us to shutdown and cleanup
terminate(Reason, State) -> ok.
% upgrading the running code
code_change(_OldVsn, StateName, StateData, _Extra) ->
{ok, StateName, StateData}.
%%%
%%% The states for the 'Query with Permission' finite state machine
%%%
package_sent(timeout, StateData) ->
{next_state, StateName, StateData, Timeout};
package_sent(Event, StateData) ->
{next_state, StateName, StateData, Timeout}.
package_received(timeout, StateData) ->
{next_state, StateName, StateData, Timeout};
package_received(Event, StateData) ->
{next_state, StateName, StateData, Timeout}.
%%%
%%% internal functions
%%%

View File

@ -0,0 +1,80 @@
%%% $Id: tcap_cco_server.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc TCAP Component Coordinator (CCO) functional block within the
%%% component sub-layer of ANSI TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_cco_server).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_server).
%% call backs needed for gen_server behaviour
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {supervisor, usap, dialogueID}).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% initialize the server
init([Supervisor, USAP, DialogueID]) ->
process_flag(trap_exit, true),
{ok, #state{supervisor = Supervisor, usap = USAP, dialogueID = DialogueID}}.
%% shutdown the server
handle_call(stop, _From, State) ->
{stop, shutdown, ok, State};
%% unrecognized calls
handle_call(Other, From, State) ->
error_logger:error_report([{unknown_call, Other}, {from, From}]),
{noreply, State}.
%% unrecognized casts
handle_cast(Other, State) ->
error_logger:error_report([{unknown_cast, Other}]),
{noreply, State}.
%% trapped exit signals
handle_info({'EXIT', _Pid, Reason}, State) ->
{stop, Reason, State};
%% unknown messages
handle_info(Unknown, State) ->
error_logger:error_msg("Received unknown message: ~p~n", [Unknown]),
{noreply, State}.
%% someone wants us to shutdown and cleanup
terminate(_Reason, _State) -> ok.
%% upgrading the running code
code_change(_, _, _) -> ok.
%%%
%%% internal functions
%%%

View File

@ -0,0 +1,809 @@
%%% $Id: tcap_dha_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Dialogue Handler (DHA) functional block within the component
%%% sub-layer of ANSI TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_dha_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_info/3, handle_event/3, handle_sync_event/4,
terminate/3, code_change/4]).
%% transaction_fsm state callbacks
-export([idle/2, wait_for_uni_components/2, wait_for_begin_components/2,
initiation_received/2, wait_cont_components_ir/2,
wait_cont_components_active/2, wait_for_end_components/2,
initiation_sent/2, active/2]).
%% record definitions for TR-User primitives
-include("tcap.hrl").
%% record definitions for N-User primitives
-include("sccp.hrl").
%% record definitions for TCAP messages
%-include("TCAPMessages.hrl").
%-include("UnidialoguePDUs.hrl").
%-include("DialoguePDUs.hrl").
%% the dialogue_fsm state data
-record(state, {usap, tco, supid, cco, otid, did, parms, appContextMode}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% Start the Dialogue Handler (DHA) process
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
init({USAP, DialogueID, TCO, Supervisor}) ->
init({USAP, DialogueID, TCO, undefined, Supervisor});
init({USAP, DialogueID, TCO, SupId, Supervisor}) ->
%% Start a Component Coordinator (CCO) process
ChildName = list_to_atom("cco_sup_" ++ integer_to_list(DialogueID)),
StartFunc = {supervisor, start_link, [component_coordinator_sup, [USAP, DialogueID]]},
ChildSpec = {ChildName, StartFunc, permanent, infinity,
supervisor, [component_coordinator_sup]},
{ok, CCO} = supervisor:start_child(Supervisor, ChildSpec),
process_flag(trap_exit, true),
{ok, idle, #state{usap = USAP, did = DialogueID,
tco = TCO, supid = SupId, cco = CCO}}.
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
%%% TC-UNI request from TCU
idle({'TC', 'UNI', request, UniParms}, State)
when is_record(UniParms, 'TC-UNI') ->
%% Dialogue info included?
case UniParms#'TC-UNI'.userInfo of
undefined ->
DialoguePortion = undefined;
UserInfo when is_binary(UserInfo) ->
%% Build AUDT apdu
DialoguePortion = 'UnidialoguePDUs':encode('AUDT-apdu',
#'AUDT-apdu'{'application-context-name' = UniParms#'TC-UNI'.appContextName,
'user-information' = UserInfo})
end,
TrParms = #'TR-UNI'{qos = UniParms#'TC-UNI'.qos,
destAddress = UniParms#'TC-UNI'.destAddress,
origAddress = UniParms#'TC-UNI'.origAddress,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms},
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_uni_components, NewState};
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
%%% TC-BEGIN request from TCU
idle({'TC', 'BEGIN', request, BeginParms}, State)
when is_record(BeginParms, 'TC-BEGIN') ->
%% Dialogue info included?
case BeginParms#'TC-BEGIN'.userInfo of
undefined ->
DialoguePortion = undefined;
UserInfo when is_binary(UserInfo) ->
%% Set protocol version = 1
%% Build AARQ apdu
DialoguePortion = 'DialoguePDUs':encode('AARQ-apdu',
#'AARQ-apdu'{'protocol-version' = version1,
'application-context-name' = BeginParms#'TC-BEGIN'.appContextName,
'user-information' = UserInfo})
end,
TrParms = #'TR-BEGIN'{qos = BeginParms#'TC-BEGIN'.qos,
destAddress = BeginParms#'TC-BEGIN'.destAddress,
origAddress = BeginParms#'TC-BEGIN'.origAddress,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms,
%% Set application context mode
appContextMode = BeginParms#'TC-BEGIN'.appContextName},
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_begin_components, NewState};
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
%%% TR-UNI indication from TSL
idle({'TR', 'UNI', indication, UniParms}, State) when is_record(UniParms, 'TR-UNI') ->
%% Extract dialogue portion
case extract_uni_dialogue_portion(UniParms#'TR-UNI'.userData) of
incorrect_dialogue_portion -> %% Dialogue portion correct? (no)
%% Discard components
{stop, normal, State};
no_version1 -> %% Is version 1 supported? (no)
%% Discard components
{stop, normal, State};
TcParms when is_record(TcParms, 'TC-UNI') ->
if
is_record(UniParms#'TR-UNI'.userData, 'TR-user-data'),
(UniParms#'TR-UNI'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (UniParms#'TR-UNI'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Assign dialogue ID
DialogueID = transaction_coordinator_server:new_tid(),
NewTcParms = TcParms#'TC-UNI'{qos = UniParms#'TR-UNI'.qos,
destAddress = UniParms#'TR-UNI'.destAddress,
origAddress = UniParms#'TR-UNI'.origAddress,
dialogueID = DialogueID,
componentsPresent = ComponentsPresent},
NewState = State#state{did = DialogueID, parms = NewTcParms},
%% Components to CHA
case ComponentsPresent of
true ->
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok % should never happen
end,
%% TC-UNI indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'UNI', indication, NewTcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 3 of 11)
%%% TR-BEGIN indication from TSL
idle({'TR', 'BEGIN', indication, BeginParms}, State) when is_record(BeginParms, 'TR-BEGIN') ->
%% Extract dialogue portion
case extract_begin_dialogue_portion(BeginParms#'TR-BEGIN'.userData) of
incorrect_dialogue_portion -> %% Dialogue portion correct? (no)
%% Build ABORT apdu
ABRT = 'DialoguePDUs':encode('ABRT-apdu', #'ABRT-apdu'{'abort-source' = 'dialogue-service-provider'}),
%% Discard components
%% TR-U-ABORT request to TSL
TrParms = {transactionID = BeginParms#'TR-BEGIN'.transactionID,
userData = #'TR-user-data'{dialoguePortion = ABRT}},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID, parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
no_version1 -> %% Is version 1 supported? (no)
DialoguePortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.dialoguePortion,
%% Build AARE apdu
AARE = 'DialoguePDUs':encode('AARE-apdu', #'AARE-apdu'{
'protocol-version' = version1,
'application-context-name' = DialoguePortion#'AARQ-apdu'.'application-context-name',
result = reject-permanent,
'result-source-diagnostic' = {'dialogue-service-provider', 'no-common-dialogue-portion'}}),
%% Discard components
%% TR-P-ABORT request to TSL
TrParms = {transactionID = BeginParms#'TR-P-ABORT'.transactionID, pAbort = AARE},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID,
appContextMode = DialoguePortion#'AARQ-apdu'.'application-context-name',
parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'P-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
TcParms when is_record(TcParms, 'TC-BEGIN') ->
if
is_record(BeginParms#'TR-BEGIN'.userData, 'TR-user-data'),
(BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Assign dialogue ID
DialogueID = transaction_coordinator_server:new_tid(),
NewTcParms = TcParms#'TC-BEGIN'{qos = BeginParms#'TR-BEGIN'.qos,
destAddress = BeginParms#'TR-BEGIN'.destAddress,
origAddress = BeginParms#'TR-BEGIN'.origAddress,
dialogueID = DialogueID,
componentsPresent = ComponentsPresent},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID, did = DialogueID,
parms = NewTcParms, appContextMode = TcParms#'TC-BEGIN'.appContextName},
%% TC-BEGIN indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'BEGIN', indication, NewTcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
{next_state, initiation_received, NewState}
end.
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%%% TC-CONTINUE request from TCU
initiation_received({'TC', 'CONTINUE', request, ContParms}, State) when is_record(ContParms, 'TC-CONTINUE') ->
%% Dialogue info included?
case ContParms#'TC-CONTINUE'.userInfo of
UserInfo when is_binary(UserInfo) ->
AARE = #'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = ContParms#'TC-CONTINUE'.appContextName,
result = accepted,
'result-source-diagnostic' = {'dialogue-service-user', null},
'user-information' = UserInfo},
DialoguePortion = 'DialoguePDUs':encode('AARE-apdu', AARE),
TrParms = #'TR-CONTINUE'{qos = ContParms#'TC-CONTINUE'.qos,
origAddress = ContParms#'TR-CONTINUE'.origAddress,
transactionID = State#state.otid,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms};
undefined ->
NewState = State
end,
{next_state, wait_cont_components_ir, NewState};
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%%% TC-END request from TCU
initiation_received({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END') ->
%% Prearranged end?
case EndParms#'TC-END'.termination of
prearranged ->
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
basic ->
%% Dialogue info included?
case EndParms#'TC-END'.userInfo of
UserInfo when is_binary(UserInfo) ->
AARE = #'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = EndParms#'TC-END'.appContextName,
result = accepted,
'result-source-diagnostic' = {'dialogue-service-user', null},
'user-information' = UserInfo},
DialoguePortion = 'DialoguePDUs':encode('AARE-apdu', AARE),
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms};
undefined ->
NewState = State
end,
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_end_components, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 6 of 11)
%%% TC-U-ABORT request from TCU
initiation_received({'TC', 'U-ABORT', request, AbortParms}, State) when is_record(AbortParms, 'TC-U-ABORT'),
(AbortParms#'TC-U-ABORT'.abortReason == applicationContextNotSupported)
or (AbortParms#'TC-U-ABORT'.abortReason == dialogueRefused)
or (AbortParms#'TC-U-ABORT'.abortReason == userSpecified) ->
case State#state.appContextMode of
%% Is application context mode set? (no)
undefined ->
UserData = #'TR-user-data'{};
%% Abort reason present and = AC-name not supported OR dialogue refused?
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == applicationContextNotSupported ->
%% Set protocol version = 1
%% Build AARE-pdu (rejected)
AARE = 'DialoguePDUs':encode('AARE-apdu',
#'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = AbortParms#'TC-U-ABORT'.appContextName,
result = 'reject-permanent',
'result-source-diagnostic' = {'dialogue-service-user', 'application-context-name-not-supported'}}),
UserData = #'TR-user-data'{dialoguePortion = AARE};
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == dialogueRefused ->
%% Set protocol version = 1
%% Build AARE-pdu (rejected)
AARE = 'DialoguePDUs':encode('AARE-apdu',
#'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = AbortParms#'TC-U-ABORT'.appContextName,
result = 'reject-permanent',
'result-source-diagnostic' = {'dialogue-service-user', null}}),
UserData = #'TR-user-data'{dialoguePortion = AARE};
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == userSpecified ->
%% Build ABRT-apdu (abort source = dialogue-service-user)
ABRT = 'DialoguePDUs':encode('ABRT-apdu',
#'ABRT-apdu'{'abort-source' = 'dialogue-service-user',
'user-information' = AbortParms#'TC-U-ABORT'.userInfo}),
UserData = #'TR-user-data'{dialoguePortion = ABRT}
end,
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = AbortParms#'TC-U-ABORT'.qos,
transactionID = State#state.otid,
userData = UserData},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}.
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TC-END request from TCU
initiation_sent({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END'),
EndParms#'TC-END'.termination == prearranged -> % termination must be prearranged
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TC-U-ABORT request from TCU (local action)
initiation_sent({'TC', 'U-ABORT', request, AbortParms}, State) when is_record(AbortParms, 'TC-U-ABORT') ->
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = AbortParms#'TC-U-ABORT'.qos, transactionID = State#state.otid},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TR-END indication from TSL
initiation_sent({'TR', 'END', indication, EndParms}, State) when is_record(EndParms, 'TR-END') ->
if
is_record(EndParms#'TR-END'.userData, 'TR-user-data'),
(EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Dialogue portion included?
%% AC Mode set?
%% Extract dialogue portion
%% Dialogue portion correct?
case extract_dialogue_portion(EndParms#'TR-END'.userData, State#state.appContextMode) of
abort ->
%% Discard components
%% TC-P-ABORT indication to TCU
TcParms = #'TC-P-ABORT'{qos = EndParms#'TR-END'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
AARE ->
%% TC-END indication to TCU
TcParms = #'TC-END'{qos = EndParms#'TR-END'.qos,
dialogueID = State#state.did,
appContextName = State#state.appContextMode,
componentsPresent = ComponentsPresent,
userInfo = AARE,
termination = EndParms#'TR-END'.termination},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'END', indication, TcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%% NOTE: currently the TCO short circuits this function and sends directly to TCU
initiation_sent({'TR', 'NOTICE', indication, NoticeParms}, State) when is_record(NoticeParms, 'TR-NOTICE') ->
%% TC-NOTICE indication to TCU
TcParms = #'TC-NOTICE'{dialogueID = State#state.did,
origAddress = NoticeParms#'TR-NOTICE'.origAddress,
destAddress = NoticeParms#'TR-NOTICE'.destAddress,
reportCause = NoticeParms#'TR-NOTICE'.reportCause},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'NOTICE', indication, TcParms}),
{next_state, initiation_sent, NewState};
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-CONTINUE indication from TSL
initiation_sent({'TR', 'CONTINUE', indication, ContParms}, State) when is_record(ContParms, 'TR-CONTINUE') ->
if
is_record(ContParms#'TR-CONTINUE'.userData, 'TR-user-data'),
(ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (ContParms#'TR-END'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Dialogue portion included?
%% AC Mode set?
%% Extract dialogue portion
%% Dialogue portion correct?
case extract_dialogue_portion(ContParms#'TR-CONTINUE'.userData, State#state.appContextMode) of
abort ->
%% Discard components
%% TC-P-ABORT indication to TCU
TcParms = #'TC-P-ABORT'{qos = ContParms#'TR-CONTINUE'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Build ABRT apdu
ABRT = 'DialoguePDUs':encode('ABRT-apdu',
#'ABRT-apdu'{'abort-source' = 'dialogue-service-provider'}),
UserData = #'TR-user-data'{dialoguePortion = ABRT},
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = ContParms#'TC-U-ABORT'.qos,
transactionID = NewState#state.otid, userData = UserData},
LastState = State#state{parms = TrParms},
gen_fsm:send_event(LastState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(LastState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, LastState};
AARE ->
%% TC-CONTINUE indication to TCU
TcParms = #'TC-CONTINUE'{qos = ContParms#'TR-CONTINUE'.qos,
origAddress = ContParms#'TR-CONTINUE'.origAddress,
appContextName = State#state.appContextMode,
dialogueID = State#state.did,
userInfo = AARE,
componentsPresent = ComponentsPresent},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'END', indication, TcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
{next_state, active, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-U-ABORT indication from TSL
initiation_sent({'TR', 'U-ABORT', indication, AbortParms}, State) when is_record(AbortParms, 'TR-U-ABORT') ->
case catch begin
if
%% Is AC mode set? (no) Is Dialogue portion present? (no)
State#state.appContextMode == undefined and (not is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data')
or (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion == undefined) ->
throw(#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos, dialogueID = State#state.did});
%% Is AC mode set? (no) Is Dialogue portion present? (yes)
State#state.appContextMode == undefined, is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data'),
AbortParms#'TR-U-ABORT'.userData /= undefined ->
throw(#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did, pAbort = abnormalDialogue});
%% Is User Data included in primitive? (no)
not is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data');
(AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion == undefined ->
throw(#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did, pAbort = abnormalDialogue});
true -> ok
end,
%% Is PDU type = ABRT or AARE (rejected)?
case 'DialoguePDUs':decode('DialoguePDU', (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion) of
%% Is abstract syntax = dialogue-PDU AS? (no)
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
APDU#'AARE-apdu'.'application-context-name' /= State#state.appContextMode ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue};
%% Is Abort source = user? (yes)
{dialoguePDU, APDU} when is_record(APDU, 'ABRT-apdu'),
element(1, APDU#'ABRT-apdu'.'abort-source') == 'dialogue-service-user' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = userSpecific,
userInfo = APDU#'ABRT-apdu'.'user-information'};
%% Is Associate source = user? (yes)
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'), APDU#'AARE-apdu'.'result-source-diagnostic'
== {'dialogue-service-user', 'application-context-name-not-supported'},
APDU#'AARE-apdu'.result == 'reject-permanent' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = applicationContextNotSupported,
appContextName = APDU#'AARE-apdu'.'application-context-name',
userInfo = APDU#'AARE-apdu'.'user-information'};
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
element(1, APDU#'AARE-apdu'.'result-source-diagnostic') == 'dialogue-service-user',
APDU#'AARE-apdu'.result == 'reject-permanent' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = dialogueRefused,
appContextName = APDU#'AARE-apdu'.'application-context-name',
userInfo = APDU#'AARE-apdu'.'user-information'};
%% Is AARE (no common dialogue portion)?
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
APDU#'AARE-apdu'.'result-source-diagnostic' == {'dialogue-service-provider', 'no-common-dialogue-portion'} ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = noCommonDialoguePortion};
_ ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue}
end
end of
TcParms when is_record(TcParms, 'TC-U-ABORT') ->
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'U-ABORT', indication, TcParms});
TcParms when is_record(TcParms, 'TC-P-ABORT') ->
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms})
end,
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-P-ABORT indication from TSL
initiation_sent({'TR', 'P-ABORT', indication, AbortParms}, State) when is_record(AbortParms, 'TR-P-ABORT') ->
TcParms = #'TC-P-ABORT'{qos = AbortParms#'TR-P-ABORT'.qos,
dialogueID = State#state.did,
pAbort = AbortParms#'TR-P-ABORT'.pAbort},
NewState = State#state{parms = TcParms},
%% TC-P-ABORT indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}.
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
%% TC-CONTINUE request from TCU
active({'TC', 'CONTINUE', request, ContParms}, State) when is_record(ContParms, 'TC-CONTINUE') ->
NewState = State#state{parms = ContParms},
%% Request component to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_cont_components_active, NewState};
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
%% TC-END request from TCU
active({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END') ->
%% Prearranged end?
case EndParms#'TC-END'.termination of
prearranged ->
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
basic ->
%% Request component to CHA
gen_fsm:send_event(State#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_end_components, State}
end.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
wait_for_uni_components('no-component', State) ->
wait_for_uni_components1(State);
wait_for_uni_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-UNI'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-UNI'{userData = NewUserData},
wait_for_uni_components1(State#state{parms = TrParms}).
wait_for_uni_components1(State) ->
%% TR-UNI request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'UNI', request, State#state.parms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(State#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
wait_for_begin_components('no-component', State) ->
wait_for_begin_components1(State);
wait_for_begin_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-BEGIN'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-BEGIN'{userData = NewUserData},
wait_for_begin_components1(State#state{parms = TrParms}).
wait_for_begin_components1(State) ->
%% Assign local transaction ID
TrParms = (State#state.parms)#'TR-BEGIN'{transactionID = transaction_coordinator_server:new_tid()},
%% TR-BEGIN request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'BEGIN', request, TrParms}),
{next_state, initiation_sent, State#state{parms = TrParms}}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
wait_cont_components_ir('no-component', State) ->
wait_cont_components_ir1(State);
wait_cont_components_ir({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-CONTINUE'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-CONTINUE'{userData = NewUserData},
wait_cont_components_ir1(State#state{parms = TrParms}).
wait_cont_components_ir1(State) ->
%% TR-CONTINUE request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'CONTINUE', request, State#state.parms}),
{next_state, initiation_sent, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
wait_cont_components_active('no-component', State) ->
wait_cont_components_active1(State);
wait_cont_components_active({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-CONTINUE'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-CONTINUE'{userData = NewUserData},
wait_cont_components_active1(State#state{parms = TrParms}).
wait_cont_components_active1(State) ->
%% TR-CONTINUE request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'CONTINUE', request, State#state.parms}),
{next_state, active, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
wait_for_end_components('no-component', State) ->
wait_for_end_components1(State);
wait_for_end_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-END'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-END'{userData = NewUserData},
wait_for_end_components1(State#state{parms = TrParms}).
wait_for_end_components1(State) ->
%% TR-END request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'END', request, State#state.parms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(State#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, State}.
%% Dialogue portion included? (yes)
extract_uni_dialogue_portion(UserData) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion correct?
case 'UnidialoguePDUs':decode('UnidialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{unidialoguePDU, AUDT} when is_record(AUDT, 'AUDT-apdu') ->
%% Is version 1 supported?
case lists:member(version1, AUDT#'AUDT-apdu'.'protocol-version') of
true ->
#'TC-UNI'{appContextName = AUDT#'AUDT-apdu'.'application-context-name',
userInfo = AUDT#'AUDT-apdu'.'user-information'};
false ->
no_version1
end;
_ ->
incorrect_dialogue_portion
end;
%% Dialogue portion included? (no)
extract_uni_dialogue_portion(_DialoguePortion) ->
#'TC-UNI'{}.
%% Dialogue portion included? (yes)
extract_begin_dialogue_portion(UserData) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion correct?
case 'DialoguePDUs':decode('DialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{dialoguePDU, AARQ} when is_record(AARQ, 'AARQ-apdu') ->
%% Is version 1 supported?
case lists:member(version1, AARQ#'AARQ-apdu'.'protocol-version') of
true ->
%% Set application context mode
#'TC-BEGIN'{appContextName = AARQ#'AARQ-apdu'.'application-context-name',
userInfo = AARQ#'AARQ-apdu'.'user-information'};
false ->
no_version1
end;
_ ->
incorrect_dialogue_portion
end;
%% Dialogue portion included? (no)
extract_begin_dialogue_portion(_DialoguePortion) ->
#'TC-BEGIN'{}.
extract_dialogue_portion(UserData, undefined) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion included? (yes) AC mode set? (no)
abort;
extract_dialogue_portion(UserData, _AppContextName) when not is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion == undefined ->
%% Dialogue portion included? (no) AC mode set? (yes)
abort;
extract_dialogue_portion(UserData, _AppContextName) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Extract dialogue portion
case 'DialoguePDUs':decode('DialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{dialoguePDU, AARE} when is_record(AARE, 'AARE-apdu') ->
AARE; %% Dialogue portion correct? (yes)
_ ->
abort %% Dialogue portion correct? (no)
end.
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("dialogue_fsm (~w) received unexpected message: ~w~n", [Info]),
{next_state, StateName, State}.
%% handle an event sent using gen:fsm_send_all_state_event/2
handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData}.
%% handle an event sent using gen_fsm:sync_send_all_state_event/2,3
handle_sync_event(_Event, _From, StateName, StateData) ->
{next_state, StateName, StateData}.
%% handle a shutdown request
terminate(_Reason, _StateName, State) when State#state.supid == undefined ->
%% we were started by TSM, no worries
ok;
terminate(_Reason, _StateName, State) ->
%% signal TCO so he can reap the ChildSpec of our supervisor
gen_server:cast(State#state.tco, {'dha-stopped', State#state.supid}).
%% handle updating state data due to a code replacement
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

View File

@ -0,0 +1,66 @@
%%% $Id: tcap_ism_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Invocation State Machine (ISM) functional block within the
%%% component sub-layer of ANSI TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_ism_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_info/3, terminate/3, code_change/4]).
%% invocation_fsm state callbacks
-export([]).
%% record definitions for TC-User primitives
-include("tcap.hrl").
%% record definitions for TCAP messages
%-include("TCAPMessages.hrl").
%% the invocation_fsm state data
-record(state, {usap, dialogueID, cco}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% Start the Invocation State Machine (ISM) process
%% reference: Figure A.7/Q.774 (sheet 1 of 6)
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("~w (~w) received unexpected message: ~w~n", [?Module, self(), Event]),
{next_state, StateName, State};
%% handle a shutdown request
terminate(_Reason, _StateName, State) -> ok.
%% handle updating state data due to a code replacement
code_change(OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

View File

@ -0,0 +1,213 @@
%%% $Id: tcap_server.erl,v 1.5 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc ANSI TCAP service.
%%%
%%% @private
%%%
-module(tcap_server).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.5 $').
-behaviour(gen_server).
%% call backs needed for gen_server behaviour
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% our published API functions
-export([start_link/1, stop/1]).
-include("TCAPPackage.hrl").
%%----------------------------------------------------------------------
%% The tcap_server exported API
%%----------------------------------------------------------------------
start_link(SubSystemNumber) when is_integer(SubSystemNumber) ->
RegName = "tcap" ++ "ssn" ++ integer_to_list(SubSystemNumber),
gen_server:start_link({local, list_to_atom(RegName)}, ?MODULE,
SubSystemNumber, []).
stop(SubSystemNumber) when is_integer(SubSystemNumber) ->
RegName = "tcap" ++ "ssn" ++ integer_to_list(SubSystemNumber),
gen_server:call(list_to_atom(RegName), stop).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% initialize the server
init([SubSystemNumber]) when is_integer(SubSystemNumber) ->
NSAPName = "sccp_" ++ "ssn" ++ integer_to_list(SubSystemNumber),
process_flag(trap_exit, true),
{ok, list_to_atom(NSAPName)}.
%% shutdown the sccp server
handle_call(stop, _From, State) ->
{stop, shutdown, State};
%% unrecognized calls
handle_call(Other, From, State) ->
error_logger:error_report([{unknown_call, Other}, {from, From}]),
{noreply, State}.
%%%
%%% service primitives received from the TC-User
%%%
handle_cast({'TC', 'UNIDIRECTIONAL', request, Parameters}, State) ->
{noreply, State};
handle_cast({'TC', 'QUERY-W', request, Parameters}, State) ->
OTID = new_transaction_id(),
FsmName = list_to_atom("tr_" ++ integer_to_list(OTID)),
FsmArgs = [SccpParms, TransactionPDU],
FsmOptions = [],
StartArgs = [{local, FsmName}, queryWithPerm_fsm, FsmArgs, FsmOptions],
StartFunc = {gen_fsm, start_link, StartArgs},
supervisor:start_child(tcap_sup, {FsmName, StartFunc, transient, worker,
[queryWithPerm_fsm]}),
{noreply, State};
handle_cast({'TC', 'QUERY-WO', request, Parameters}, State) ->
{noreply, State};
handle_cast({'TC', 'CONVERSATION-W', request, Parameters}, State) ->
{noreply, State};
handle_cast({'TC', 'CONVERSATION-WO', request, Parameters}, State) ->
{noreply, State};
handle_cast({'TC', 'RESPONSE', request, Parameters}, State) ->
{noreply, State};
handle_cast({'TC', 'ABORT', request, Parameters}, State) ->
{noreply, State}.
%%%
%%% service primitives received from the SCCP service
%%%
handle_cast({'N', 'UNITDATA', indication, {CalledParty, CallingParty,
QualityOfServiceParameterSet, NPDU}}, NSAP) ->
SccpParms = {CalledParty, CallingParty, QualityOfServiceParameterSet},
%%
%% Transaction Portion
%% reference T1.114.2 3.1
%%
{ok, Package} = 'TCAPPackage':decode('PackageType', NPDU),
case Package of
%%
%% Unidirectional
%%
%% Sends information in one direction only with no reply
%% expected. No TCAP Transaction is established.
%%
{unidirectional, UniTransactionPDU} ->
error_logger:error_report([{unhandled_primitive, unidirectional},
{caller, Caller}, {called, Called}, {package, Package}]),
{noreply, NSAP};
%%
%% Query with permission
%%
%% Initiates a TCAP transaction and informs the destination
%% it may end the TCAP transaction.
%%
{queryWithPerm, TransactionPDU} ->
OTID = new_transaction_id(),
FsmName = list_to_atom("tcap_" ++ integer_to_list(OTID)),
FsmArgs = [SccpParms, TransactionPDU],
FsmOptions = [],
StartArgs = [{local, FsmName}, queryWithPerm_fsm, FsmArgs, FsmOptions],
StartFunc = {gen_fsm, start_link, StartArgs},
supervisor:start_child(tcap_sup, {FsmName, StartFunc, transient, worker,
[queryWithPerm_fsm]}),
{noreply, NSAP};
%%
%% Query without permission
%%
%% Initiates a TCAP transaction and informs the destination
%% it may not end the TCAP transaction.
%%
{queryWithoutPerm, TransactionPDU} ->
error_logger:error_report([{unhandled_primitive, queryWithoutPerm},
{caller, Caller}, {called, Called}, {package, Package}]),
{noreply, NSAP};
%%
%% Response
%%
%% Ends a TCAP transaction
%%
{response, TransactionPDU} ->
{noreply, NSAP};
%%
%% Conversation with permission
%%
%% Continues a TCAP transaction and informs the destination
%% that it may end the TCAP transaction.
%%
{conversationWithPerm, TransactionPDU} ->
error_logger:error_report([{unhandled_primitive, conversationWithPerm},
{caller, Caller}, {called, Called}, {package, Package}]),
{noreply, NSAP};
%%
%% Conversation without permission
%%
%% Continues a TCAP transaction and informs the destination
%% that it may not end the TCAP transaction.
%%
{conversationWithoutPerm, TransactionPDU} ->
error_logger:error_report([{unhandled_primitive, conversationWithoutPerm},
{caller, Caller}, {called, Called}, {package, Package}]),
{noreply, NSAP};
%%
%% Abort
%%
%% Informs the destination that the sender has terminated
%% the transaction without sending any pending components.
%%
{abort, Abort} ->
error_logger:error_report([{unhandled_primitive, abaort},
{caller, Caller}, {called, Called}, {package, Package}]),
{noreply, NSAP}
end.
%% unrecognized casts
handle_cast(Other, State) ->
error_logger:error_report([{unknown_cast, Other}]),
{noreply, State}.
% trapped exit signals
handle_info({'EXIT', Pid, Reason}, State) ->
{stop, Reason, State};
% unknown messages
handle_info(Unknown, State) ->
error_logger:error_msg("Received unknown message: ~p~n", [Unknown]),
{noreply, State}.
% someone wants us to shutdown and cleanup
terminate(Reason, State) -> ok.
% upgrading the running code
code_change(_, _, _) -> ok.
%%%
%%% internal functions
%%%
%% get the next originating transaction id from the global counter
new_transaction_id() ->
ets:update_counter(tcap, transactionID, {2, 1, 16#ffffffff, 0}).

View File

@ -0,0 +1,386 @@
%%% $Id: tcap_tco_server.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Transaction Coordinator (TCO) functional block within the
%%% transaction sub-layer of ANSI TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_tco_server).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_server).
%% call backs needed for gen_server behaviour
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% our published API functions
-export([new_tid/0]).
-include("TCAPMessages.hrl").
-include("tcap.hrl").
-include("sccp.hrl").
-record(state, {supervisor, nsap, usap}).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% initialize the server
init([Supervisor, NSAP, USAP]) ->
% NSAP = "sccp_" ++ "ssn" ++ integer_to_list(SubSystemNumber),
process_flag(trap_exit, true),
{ok, #state{supervisor = Supervisor, nsap = NSAP, usap = USAP}}.
%% shutdown the server
handle_call(stop, _From, State) ->
{stop, shutdown, ok, State};
%% unrecognized calls
handle_call(Other, From, State) ->
error_logger:error_report([{unknown_call, Other}, {from, From}]),
{noreply, State}.
%%%
%%% service primitive indications from the network layer
%%%
%%% reference: Figure A.3/Q.774 (sheet 1 of 4)
%%%
handle_cast({'N', 'UNITDATA', indication, UdataParms}, State)
when is_record(UdataParms, 'N-UNITDATA') ->
case 'TR':decode('TCMessage', UdataParms#'N-UNITDATA'.userData) of
{ok, {unidirectional, TPDU}} ->
case 'TR':decode('Unidirectional', TPDU) of
{ok, Unidirectional} ->
%% Create a Dialogue Handler (DHA)
DialogueID = new_tid(),
SupId = list_to_atom("dha_" ++ integer_to_list(DialogueID)),
{ok, {M, F, A, Mods} = application:get_env(start_dha),
StartFunc = {M, F, A ++ [{State#state.nsap, State#state.usap, DialogueID, self(), SupId}]},
ChildSpec = {SupId, StartFunc, temporary, 10000, worker, Mods},
{ok, DHA} = supervisor:start_child(State#state.supervisor, ChildSpec),
%% TR-UNI indication CSL <- TSL
UserData = #'TR-user-data'{dialoguePortion = Unidirectional#'Unidirectional'.dialoguePortion,
componentPortion = Unidirectional#'Unidirectional'.components},
TrParms = #'TR-UNI'{qos =
destAddress = UdataParms#'N-UNITDATA'.calledAddress,
origAddress = UdataParms#'N-UNITDATA'.callingAddress,
userData = UserData},
gen_fsm:send_event(DHA, {'TR', 'UNI', indication, TrParms}),
{noreply, State};
{error, Reason} ->
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
error_logger:error_report(["Syntax error in received N-UNI",
{nsap, State#state.nsap}, {error, Reason},
{caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {'begin', TPDU}} ->
case 'TR':decode('Begin', TPDU) of
{ok, Begin} ->
%% Assign local transaction ID
TID = new_tid(),
ChildName = list_to_atom("tsm_sup_" ++ integer_to_list(TID)),
{ok, {M, F, A, Mods} = application:get_env(start_tsm),
StartFunc = {M, F, A ++ [{State#state.nsap, State#state.usap, TID}]},
ChildSpec = {ChildName, StartFunc, temporary, infinity, supervisor, Mods},
%% Is TID = no TID?
%% Note: The assignment of the ID above just gets the next available
%% value and doesn't ensure that it is not in use (unlikely)
%% or that there are enough resources available. The real
%% test is in whether the start succeeds.
case supervisor:start_child(State#state.supervisor, ChildSpec) of
{ok, TSM} ->
%% Created a Transaction State Machine (TSM)
TsmParms = UdataParms#'N-UNITDATA'{userData = Begin},
%% BEGIN received TSM <- TCO
gen_fsm:send_event(TSM, {'BEGIN', received, TsmParms});
_Other ->
%% TID = no TID
%% Build ABORT message (P-Abort Cause = Resource Limitation)
Abort = {abort, #'Abort'{dtid = TPDU#'Begin'.otid,
reason = {'p-abortCause', resourceLimitation}}},
NewTPDU = list_to_binary('TCMessage':encode('TCMessage', Abort)),
SccpParms = #'N-UNITDATA'{calledAddress = UdataParms#'N-UNITDATA'.callingAddress,
callingAddress = UdataParms#'N-UNITDATA'.calledAddress,
sequenceControl = false, returnOption = false, importance = none,
userData = NewTPDU},
%% TR-UNI request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
error_logger:error_report(["Unable to create TSM for received N-BEGIN",
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}])
end,
{noreply, State};
{error, Reason} ->
%% TODO
%% is OTID derivable?
%% Build ABORT message with appropraite P-Abort Cause value
%% N-UNITDATA request TSL -> SCCP
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (4)
error_logger:error_report(["Syntax error in received N-BEGIN", {error, Reason},
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {continue, TPDU}} ->
case 'TR':decode('Continue', TPDU) of
{ok, Continue} ->
%% DTID assigned?
case catch ets:lookup_element(transaction, TPDU#'Continue'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-CONTINUE",
{dtid, TPDU#'End'.dtid}, {nsap, State#state.nsap},
{caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
%% TODO
%% Build ABORT message with appropriate P-Abort Cause values
%% N-UNITDATA request TSL -> SCCP
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (4)
{noreply, State};
TSM ->
TsmParms = UdataParms#'N-UNITDATA'{userData = Continue},
%% CONTINUE received TSM <- TCO
gen_fsm:send_event(TSM, {'CONTINUE', received, TsmParms}),
{noreply, State}
end;
{error, Reason} ->
%% TODO
%% OTID derivable?
%% DTID assigned?
%% Build ABORT message with appropraite P-Abort Cause value
%% N-UNITDATA request TSL -> SCCP
%% Local Abort TSM <- TCO
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (2)
error_logger:error_report(["Syntax error in received N-CONTINUE", {error, Reason},
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {'end', TPDU}} ->
case 'TR':decode('End', TPDU) of
{ok, End} ->
%% DTID assigned?
case catch ets:lookup(transaction, TPDU#'End'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-END",
{dtid, TPDU#'End'.dtid}, {nsap, State#state.nsap},
{caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
{noreply, State};
TSM ->
TsmParms = UdataParms#'N-UNITDATA'{userData = End},
%% END received TSM <- TCO
gen_fsm:send_event(TSM, {'END', received, TsmParms}),
{noreply, State}
end;
{error, Reason} ->
%% TODO
%% DTID assigned?
%% Local Abort TSM <- TCO
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (5)
error_logger:error_report(["Syntax error in received N-END", {error, Reason},
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {abort, TPDU}} ->
case 'TR':decode('Abort', TPDU) of
{ok, Abort} ->
%% DTID assigned?
case catch ets:lookup(transaction, TPDU#'Abort'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-ABORT",
{dtid, TPDU#'Abort'.dtid}, {nsap, State#state.nsap},
{caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
{noreply, State};
TSM ->
TsmParms = UdataParms#'N-UNITDATA'{userData = Abort},
%% Abort received TSM <- TCO
gen_fsm:send_event(TSM, {'ABORT', received, TsmParms}),
{noreply, State}
end;
{error, Reason} ->
%% TODO
%% DTID assigned?
%% Local Abort TSM <- TCO
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (5)
error_logger:error_report(["Syntax error in received N-ABORT", {error, Reason},
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {error, Reason}} ->
%% TODO
%% Message type unknown
%% OTID derivable?
%% DTID assigned?
%% Build ABORT message with appropraite P-Abort Cause value
%% N-UNITDATA request TSL -> SCCP
%% Local Abort TSM <- TCO
%% Discard received message
%% reference: Figure A.3/Q/774 (sheet 4 of 4) label (2)
error_logger:error_report(["Unknown TCMessage received", {error, Reason},
{nsap, State#state.nsap}, {caller, UdataParms#'N-UNITDATA'.callingAddress},
{called, UdataParms#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
handle_cast({'N', 'NOTICE', indication, NoticeParms}, State) ->
%% Extract the originating transactionID
case 'TR':decode('TCMessage', NoticeParms#'N-NOTICE'.userData) of
{ok, {'begin', TPDU}} ->
case 'TR':decode('Begin', TPDU) of
{ok, Begin} ->
TransactionID = Begin#'Begin'.otid;
_ ->
TransactionID = undefined
end;
{ok, {continue, TPDU}} ->
case 'TR':decode('Continue', TPDU) of
{ok, Continue} ->
TransactionID = Continue#'Continue'.otid;
_ ->
TransactionID = undefined
end;
_ ->
TransactionID = undefined
end,
%% TR-NOTICE indication CSL <- TSL
%% reference: Figure A.3/Q.774 (sheet 2 of 4)
%% The CSL is a null layer for this indication so it becomes
%% TC-NOTICE indication TCU <- TSL
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%% reference: Figure A.3/Q.774 (sheet 10 of 11)
TcParms = #'TC-NOTICE'{
dialogueID = TransactionID,
origAddress = NoticeParms#'N-NOTICE'.callingAddress,
destAddress = NoticeParms#'N-NOTICE'.calledAddress,
reportCause = NoticeParms#'N-NOTICE'.reason},
gen_fsm:send_event(State#state.usap, {'TC', 'NOTICE', indication, TcParms}),
{noreply, State};
%%%
%%% service primitive requests from the TR-User
%%% reference: Figure A.3/Q.774 (sheets 2&3 of 4)
handle_cast({'TR', 'UNI', request, UniParms}, State)
when is_record(UniParms, 'TR-UNI') ->
%% Assemble TR-portion of UNI message
{SequenceControl, ReturnOption, Importance} = UniParms#'TR-UNI'.qos,
DialoguePortion = (UniParms#'TR-UNI'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (UniParms#'TR-UNI'.userData)#'TR-user-data'.componentPortion,
TPDU = 'TR':encode('TCMessage', {unidirectional, #'Unidirectional'{
dialoguePortion = DialoguePortion, components = ComponentPortion}}),
SccpParms = #'N-UNITDATA'{calledAddress = UniParms#'TR-UNI'.destAddress,
callingAddress = UniParms#'TR-UNI'.origAddress,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = Importance, userData = TPDU},
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{noreply, State};
handle_cast({'TR', 'BEGIN', request, BeginParms}, State)
when is_record(BeginParms, 'TR-BEGIN') ->
%% Create a Transaction State Machine (TSM)
OTID = BeginParms#'TR-BEGIN'.transactionID,
ChildName = list_to_atom("tsm_" ++ integer_to_list(OTID)),
{ok, {M, F, A, Mods}} = application:get_env(start_tsm),
StartFunc = {M, F, A ++ [{State#state.nsap, State#state.usap, OTID, ChildName}]},
ChildSpec = {ChildName, StartFunc, temporary, infinity, worker, Mods},
{ok, TSM} = supervisor:start_child(State#state.supervisor, ChildSpec),
gen_fsm:send_event(TSM, {'BEGIN', transaction, BeginParms}),
{noreply, State};
handle_cast({'TR', 'CONTINUE', request, ContParms}, State)
when is_record(ContParms, 'TR-CONTINUE') ->
TransactionID = ContParms#'TR-CONTINUE'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'CONTINUE', transaction, ContParms}),
{noreply, State};
handle_cast({'TR', 'END', request, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
TransactionID = EndParms#'TR-END'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'END', transaction, EndParms}),
{noreply, State};
handle_cast({'TR', 'U-ABORT', request, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
TransactionID = AbortParms#'TR-U-ABORT'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'ABORT', transaction, AbortParms}),
{noreply, State};
%%
%% The TSM sends us a message as it's last action so
%% we can remove the supervisor child specification
%%
handle_cast({'tsm-stopped', SupRef}, State) ->
supervisor:delete_child(State#state.supervisor, SupRef),
%% reference: Figure A.3/Q/774 (sheet 2 of 4)
{noreply, State};
%% unrecognized casts
handle_cast(Other, State) ->
error_logger:error_report([{unknown_cast, Other}]),
{noreply, State}.
%% trapped exit signals
handle_info({'EXIT', _Pid, Reason}, State) ->
{stop, Reason, State};
%% unknown messages
handle_info(Unknown, State) ->
error_logger:error_msg("Received unknown message: ~p~n", [Unknown]),
{noreply, State}.
%% someone wants us to shutdown and cleanup
terminate(_Reason, _State) -> ok.
%% upgrading the running code
code_change(_, _, _) -> ok.
%%%
%%% internal functions
%%%
%% get the next originating transaction id from the global counter
%%
%% TODO: we are simply assuming that when the counter rolls over the last
%% transaction to have this ID is long gone (4.2 billion IDs)
%%
%% reference: Figure A.3 bis/Q.774
new_tid() ->
ets:update_counter(transaction, transactionID, {2, 1, 16#ffffffff, 0}).

View File

@ -0,0 +1,406 @@
%%% $Id: tcap_tsm_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Transaction State Machine (TCM) functional block within the
%%% transaction sub-layer of ANSI TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_tsm_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
terminate/3, code_change/4]).
%% transaction_fsm state callbacks
-export([idle/2, initiation_sent/2, initiation_received/2, active/2]).
%% record definitions for TR-User primitives
-include("tcap.hrl").
%% record definitions for N-User primitives
-include("sccp.hrl").
%% record definitions for TCAP messages
-include("TCAPMessages.hrl").
%% the transaction_fsm state data
-record(state, {nsap, usap, tco, supervisor, supref, localTID, remoteTID,
local_address, remote_address, dha}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% initialize the server
init({NSAP, USAP, TID, Supervisor, SupRef, TCO}) ->
%% store our process identifier in the global transaction ID table
ets:insert(transaction, {TID, self()}),
process_flag(trap_exit, true),
{ok, idle, #state{nsap = NSAP, usap = USAP, localTID = TID, supervisor = Supervisor,
supref = SupRef, tco = TCO}}.
%%%
%%% idle state handler
%%%
%% started by remote
%% reference: Figure A.4/Q.774 (sheet 1 of 5)
idle({'BEGIN', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
%% Store remote address and remote TID
NewState = State#state{remote_address = SccpParms#'N-UNITDATA'.callingAddress,
remoteTID = (SccpParms#'N-UNITDATA'.userData)#'Begin'.otid},
{ok, Begin} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% Start a Dialogue Handler (DHA)
SupId = list_to_atom("dha_sup_" ++ integer_to_list(State#state.localTID)),
StartFunc = {supervisor, start_link,
[dialogue_sup, [{State#state.usap, State#state.localTID, self()}]]},
ChildSpec = {SupId, StartFunc, permanent, infinity, supervisor, [dialogue_sup]},
{ok, DHA} = supervisor:start_child(State#state.supervisor, ChildSpec),
QOS = {SccpParms#'N-UNITDATA'.sequenceControl, SccpParms#'N-UNITDATA'.returnOption},
UserData = #'TR-user-data'{dialoguePortion = Begin#'Begin'.dialoguePortion,
componentPortion = Begin#'Begin'.components},
TrParms = #'TR-BEGIN'{qos = QOS,
destAddress = SccpParms#'N-UNITDATA'.calledAddress,
origAddress = SccpParms#'N-UNITDATA'.callingAddress,
transactionID = State#state.localTID,
userData = UserData},
%% TR-BEGIN CSL <- TSL
gen_fsm:send_event(DHA, {'TR', 'BEGIN', indication, TrParms}),
{next_state, initiation_received, NewState#state{dha = DHA}};
%% started by TR-User
%% reference: Figure A.4/Q.774 (sheet 1 of 5)
idle({'BEGIN', transaction, BeginParms}, State)
when is_record(BeginParms, 'TR-BEGIN') ->
%% Store local address
%% NOTE - This may be provided by TC-user or be implicitly associated with
%% the access point at which the N-UNITDATA primitive is issued.
NewState = State#state{local_address = BeginParms#'TR-BEGIN'.origAddress},
DialoguePortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion,
Begin = #'Begin'{otid = State#state.localTID, dialoguePortion = DialoguePortion,
components = ComponentPortion},
%% Assemble TR-portion of BEGIN message
TPDU = list_to_binary('TR':encode('TCMessage', {'begin', Begin})),
{SequenceControl, ReturnOption} = BeginParms#'TR-BEGIN'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = BeginParms#'TR-BEGIN'.destAddress,
callingAddress = BeginParms#'TR-BEGIN'.origAddress,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(NewState#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, initiation_sent, NewState}.
%%%
%%% initiation_received state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue from TR-User
initiation_received({'CONTINUE', transaction, ContParms}, State)
when is_record(ContParms, 'TR-CONTINUE') ->
%% Store new local address if it is provided by User
case ContParms#'TR-CONTINUE'.origAddress of
undefined ->
NewState = State;
NewAddress ->
NewState = State#state{local_address = NewAddress}
end,
DialoguePortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion,
Continue = #'Continue'{otid = State#state.localTID, dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of CONTINUE message
TPDU = list_to_binary('TR':encode('TCMessage', {continue, Continue})),
{SequenceControl, ReturnOption} = ContParms#'TR-CONTINUE'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = NewState#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(NewState#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, active, NewState};
%% End from TR-User (prearranged)
initiation_received({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END'),
EndParms#'TR-END'.termination == prearranged ->
{stop, normal, State};
%% End from TR-User (not prearranged)
initiation_received({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
DialoguePortion = (EndParms#'TR-END'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion,
End = #'End'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of END message
TPDU = list_to_binary('TR':encode('TCMessage', {'end', End})),
{SequenceControl, ReturnOption} = EndParms#'TR-END'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State};
%% Abort from TR-User
initiation_received({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
Cause = (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion,
Abort = #'Abort'{reason = {'u-abortCause', Cause}},
%% Assemble TR-portion of ABORT message
TPDU = list_to_binary('TR':encode('TCMessage', {abort, Abort})),
{SequenceControl, ReturnOption} = AbortParms#'TR-U-ABORT'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State}.
%%%
%%% initiation_sent state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue from remote
initiation_sent({'CONTINUE', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
%% Store remote address and remote TID
OTID = (SccpParms#'N-UNITDATA'.userData)#'Begin'.otid,
NewState = State#state{ remote_address
= SccpParms#'N-UNITDATA'.callingAddress, remoteTID = OTID},
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Continue} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = Continue#'Continue'.dialoguePortion,
componentPortion = Continue #'Continue'.components},
TrParms = #'TR-CONTINUE'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(NewState#state.dha, {'TR', 'CONTINUE', indication, TrParms}),
{next_state, active, NewState};
%% End from remote
initiation_sent({'END', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, End} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = End#'End'.dialoguePortion,
componentPortion = End#'End'.components},
TrParms = #'TR-END'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'END', indication, TrParms}),
{stop, normal, State};
%% Abort from remote
initiation_sent({'ABORT', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Abort} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% TR-U-ABORT?
case Abort#'Abort'.reason of
{'p-abortCause', Cause} ->
TrParms = #'TR-P-ABORT'{qos = QOS,
transactionID = State#state.localTID,
pAbort = Cause},
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms});
{'u-abortCause', Cause} ->
UserData = #'TR-user-data'{dialoguePortion = Cause},
TrParms = #'TR-U-ABORT'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'U-ABORT', indication, TrParms})
end,
{stop, normal, State};
%% Local Abort
initiation_sent({'local-abort', received, Cause}, State) ->
TrParms = #'TR-P-ABORT'{pAbort = Cause},
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms}),
{stop, normal, State};
%% End from TR-User
initiation_sent({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
{stop, normal, State};
%% Abort from TR-User
initiation_sent({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
%% Purely local action
{stop, normal, State}.
%%%
%%% active state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue received from remote
active({'CONTINUE', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Continue} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = Continue#'Continue'.dialoguePortion,
componentPortion = Continue#'Continue'.components},
TrParms = #'TR-CONTINUE'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'CONTINUE', indication, TrParms}),
{next_state, active, State};
%% Continue from TR-User
active({'CONTINUE', transaction, ContParms}, State)
when is_record(ContParms, 'TR-CONTINUE') ->
DialoguePortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion,
Continue = #'Continue'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of CONTINUE message
TPDU = list_to_binary('TR':encode('TCMessage', {continue, Continue})),
{SequenceControl, ReturnOption} = ContParms#'TR-CONTINUE'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, active, State};
%% End from remote
active({'END', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, End} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = End#'End'.dialoguePortion,
componentPortion = End#'End'.components},
TrParms = #'TR-END'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
%% TR-END indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'END', indication, TrParms}),
{stop, normal, State};
%% End from TR-User (prearranged)
active({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END'),
EndParms#'TR-END'.termination == prearranged ->
{stop, normal, State};
%% End from TR-User (not prearranged)
active({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
DialoguePortion = (EndParms#'TR-END'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion,
End = #'End'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of END message
TPDU = list_to_binary('TR':encode('TCMessage', {'end', End})),
{SequenceControl, ReturnOption} = EndParms#'TR-END'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State};
%% Abort received from remote
active({'ABORT', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Abort} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% TR-U-ABORT?
case Abort#'Abort'.reason of
{'p-abortCause', Cause} -> % No
TrParms = #'TR-P-ABORT'{qos = QOS,
transactionID = State#state.localTID,
pAbort = Cause},
%% TR-P-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms});
{'u-abortCause', Cause} -> % Yes
UserData = #'TR-user-data'{dialoguePortion = Cause},
TrParms = #'TR-U-ABORT'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
%% TR-U-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'U-ABORT', indication, TrParms})
end,
{stop, normal, State};
%% Local Abort
active({'local-abort', received, Cause}, State) ->
TrParms = #'TR-P-ABORT'{qos = {false, false},
transactionID = State#state.localTID, pAbort= Cause},
%% TR-P-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms}),
{stop, normal, State};
%% Abort from TR-User
active({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
Cause = (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion,
Abort = #'Abort'{reason = {'u-abortCause', Cause}},
%% Assemble TR-portion of ABORT message
TPDU = list_to_binary('TR':encode('TCMessage', {abort, Abort})),
{SequenceControl, ReturnOption} = AbortParms#'TR-U-ABORT'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State}.
%% handle an event sent using gen_fsm:send_all_state_event/2
handle_event(Event, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Event]),
{next_state, StateName, State}.
%% handle an event sent using gen_fsm:sync_send_all_state_event/2,3
handle_sync_event(Event, _From, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Event]),
{next_state, StateName, State}.
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Info]),
{next_state, StateName, State}.
%% handle a shutdown request
terminate(_Reason, _StateName, State) ->
ets:delete(transaction, State#state.localTID),
%% signal TCO that we are stopping
gen_server:cast(State#state.supervisor, {'tsm-stopped', State#state.supref}).
%% handle updating state data due to a code replacement
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

39
TCAP/src/ITU/Makefile Normal file
View File

@ -0,0 +1,39 @@
## $id$
SCCPINCDIR = ../../../SCCP/itu/include
EBIN = ../../ebin/itu
ERL = erl
ERLC = erlc
EMULATOR = beam
ERLCFLAGS = -b ${EMULATOR} -o ${EBIN} -W -v +warn_unused_vars -I ../../asn_src/itu -I ../../include -I ${SCCPINCDIR}
${EBIN}/%.${EMULATOR}:%.erl
${ERLC} ${ERLCFLAGS} $<
BEAMS = ${EBIN}/tcap_tco_server.${EMULATOR} \
${EBIN}/tcap_tsm_fsm.${EMULATOR} \
${EBIN}/tcap_dha_fsm.${EMULATOR} \
${EBIN}/tcap_cco_server.${EMULATOR} \
${EBIN}/tcap_ism_fsm.${EMULATOR}
.PHONY: default
default: all
.PHONY: all
all: ${BEAMS}
.PHONY: install
.PHONY: clean
clean:
- rm -f ${BEAMS}
tcap_tco_server.${EMULATOR}: tcap_tco_server.erl \
../../asn_src/TCAPMessages.hrl ../../include/tcap.hrl \
${SCCPINCDIR}/sccp.hrl
tcap_tsm_fsm.${EMULATOR}: tcap_tsm_fsm.erl \
../../asn_src/TCAPMessages.hrl ../../include/tcap.hrl \
${SCCPINCDIR}/sccp.hrl

View File

@ -0,0 +1,79 @@
%%% $Id: tcap_cco_server.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc TCAP Component Coordinator (CCO) functional block within the
%%% component sub-layer of ITU TCAP.
%%%
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_cco_server).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_server).
%% call backs needed for gen_server behaviour
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-record(state, {supervisor, usap, dialogueID}).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% initialize the server
init([Supervisor, USAP, DialogueID]) ->
process_flag(trap_exit, true),
{ok, #state{supervisor = Supervisor, usap = USAP, dialogueID = DialogueID}}.
%% shutdown the server
handle_call(stop, _From, State) ->
{stop, shutdown, ok, State};
%% unrecognized calls
handle_call(Other, From, State) ->
error_logger:error_report([{unknown_call, Other}, {from, From}]),
{noreply, State}.
%% unrecognized casts
handle_cast(Other, State) ->
error_logger:error_report([{unknown_cast, Other}]),
{noreply, State}.
%% trapped exit signals
handle_info({'EXIT', _Pid, Reason}, State) ->
{stop, Reason, State};
%% unknown messages
handle_info(Unknown, State) ->
error_logger:error_msg("Received unknown message: ~p~n", [Unknown]),
{noreply, State}.
%% someone wants us to shutdown and cleanup
terminate(_Reason, _State) -> ok.
%% upgrading the running code
code_change(_, _, _) -> ok.
%%%
%%% internal functions
%%%

View File

@ -0,0 +1,807 @@
%%% $Id: tcap_dha_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Dialogue Handler (DHA) functional block within the component
%%% sub-layer of ITU TCAP.
%%%
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_dha_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_info/3, handle_event/3, handle_sync_event/4,
terminate/3, code_change/4]).
%% transaction_fsm state callbacks
-export([idle/2, wait_for_uni_components/2, wait_for_begin_components/2,
initiation_received/2, wait_cont_components_ir/2,
wait_cont_components_active/2, wait_for_end_components/2,
initiation_sent/2, active/2]).
%% record definitions for TR-User primitives
-include("tcap.hrl").
%% record definitions for N-User primitives
-include("sccp.hrl").
%% record definitions for TCAP messages
%-include("TCAPMessages.hrl").
%-include("UnidialoguePDUs.hrl").
%-include("DialoguePDUs.hrl").
%% the dialogue_fsm state data
-record(state, {usap, tco, supid, cco, otid, did, parms, appContextMode}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% Start the Dialogue Handler (DHA) process
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
init({USAP, DialogueID, TCO, Supervisor}) ->
init({USAP, DialogueID, TCO, undefined, Supervisor});
init({USAP, DialogueID, TCO, SupId, Supervisor}) ->
%% Start a Component Coordinator (CCO) process
ChildName = list_to_atom("cco_sup_" ++ integer_to_list(DialogueID)),
StartFunc = {supervisor, start_link, [component_coordinator_sup, [USAP, DialogueID]]},
ChildSpec = {ChildName, StartFunc, permanent, infinity,
supervisor, [component_coordinator_sup]},
{ok, CCO} = supervisor:start_child(Supervisor, ChildSpec),
process_flag(trap_exit, true),
{ok, idle, #state{usap = USAP, did = DialogueID,
tco = TCO, supid = SupId, cco = CCO}}.
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
%%% TC-UNI request from TCU
idle({'TC', 'UNI', request, UniParms}, State)
when is_record(UniParms, 'TC-UNI') ->
%% Dialogue info included?
case UniParms#'TC-UNI'.userInfo of
undefined ->
DialoguePortion = undefined;
UserInfo when is_binary(UserInfo) ->
%% Build AUDT apdu
DialoguePortion = 'UnidialoguePDUs':encode('AUDT-apdu',
#'AUDT-apdu'{'application-context-name' = UniParms#'TC-UNI'.appContextName,
'user-information' = UserInfo})
end,
TrParms = #'TR-UNI'{qos = UniParms#'TC-UNI'.qos,
destAddress = UniParms#'TC-UNI'.destAddress,
origAddress = UniParms#'TC-UNI'.origAddress,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms},
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_uni_components, NewState};
%% reference: Figure A.5/Q.774 (sheet 1 of 11)
%%% TC-BEGIN request from TCU
idle({'TC', 'BEGIN', request, BeginParms}, State)
when is_record(BeginParms, 'TC-BEGIN') ->
%% Dialogue info included?
case BeginParms#'TC-BEGIN'.userInfo of
undefined ->
DialoguePortion = undefined;
UserInfo when is_binary(UserInfo) ->
%% Set protocol version = 1
%% Build AARQ apdu
DialoguePortion = 'DialoguePDUs':encode('AARQ-apdu',
#'AARQ-apdu'{'protocol-version' = version1,
'application-context-name' = BeginParms#'TC-BEGIN'.appContextName,
'user-information' = UserInfo})
end,
TrParms = #'TR-BEGIN'{qos = BeginParms#'TC-BEGIN'.qos,
destAddress = BeginParms#'TC-BEGIN'.destAddress,
origAddress = BeginParms#'TC-BEGIN'.origAddress,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms,
%% Set application context mode
appContextMode = BeginParms#'TC-BEGIN'.appContextName},
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_begin_components, NewState};
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
%%% TR-UNI indication from TSL
idle({'TR', 'UNI', indication, UniParms}, State) when is_record(UniParms, 'TR-UNI') ->
%% Extract dialogue portion
case extract_uni_dialogue_portion(UniParms#'TR-UNI'.userData) of
incorrect_dialogue_portion -> %% Dialogue portion correct? (no)
%% Discard components
{stop, normal, State};
no_version1 -> %% Is version 1 supported? (no)
%% Discard components
{stop, normal, State};
TcParms when is_record(TcParms, 'TC-UNI') ->
if
is_record(UniParms#'TR-UNI'.userData, 'TR-user-data'),
(UniParms#'TR-UNI'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (UniParms#'TR-UNI'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Assign dialogue ID
DialogueID = transaction_coordinator_server:new_tid(),
NewTcParms = TcParms#'TC-UNI'{qos = UniParms#'TR-UNI'.qos,
destAddress = UniParms#'TR-UNI'.destAddress,
origAddress = UniParms#'TR-UNI'.origAddress,
dialogueID = DialogueID,
componentsPresent = ComponentsPresent},
NewState = State#state{did = DialogueID, parms = NewTcParms},
%% Components to CHA
case ComponentsPresent of
true ->
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok % should never happen
end,
%% TC-UNI indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'UNI', indication, NewTcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 3 of 11)
%%% TR-BEGIN indication from TSL
idle({'TR', 'BEGIN', indication, BeginParms}, State) when is_record(BeginParms, 'TR-BEGIN') ->
%% Extract dialogue portion
case extract_begin_dialogue_portion(BeginParms#'TR-BEGIN'.userData) of
incorrect_dialogue_portion -> %% Dialogue portion correct? (no)
%% Build ABORT apdu
ABRT = 'DialoguePDUs':encode('ABRT-apdu', #'ABRT-apdu'{'abort-source' = 'dialogue-service-provider'}),
%% Discard components
%% TR-U-ABORT request to TSL
TrParms = {transactionID = BeginParms#'TR-BEGIN'.transactionID,
userData = #'TR-user-data'{dialoguePortion = ABRT}},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID, parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
no_version1 -> %% Is version 1 supported? (no)
DialoguePortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.dialoguePortion,
%% Build AARE apdu
AARE = 'DialoguePDUs':encode('AARE-apdu', #'AARE-apdu'{
'protocol-version' = version1,
'application-context-name' = DialoguePortion#'AARQ-apdu'.'application-context-name',
result = reject-permanent,
'result-source-diagnostic' = {'dialogue-service-provider', 'no-common-dialogue-portion'}}),
%% Discard components
%% TR-P-ABORT request to TSL
TrParms = {transactionID = BeginParms#'TR-P-ABORT'.transactionID, pAbort = AARE},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID,
appContextMode = DialoguePortion#'AARQ-apdu'.'application-context-name',
parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'P-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
TcParms when is_record(TcParms, 'TC-BEGIN') ->
if
is_record(BeginParms#'TR-BEGIN'.userData, 'TR-user-data'),
(BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Assign dialogue ID
DialogueID = transaction_coordinator_server:new_tid(),
NewTcParms = TcParms#'TC-BEGIN'{qos = BeginParms#'TR-BEGIN'.qos,
destAddress = BeginParms#'TR-BEGIN'.destAddress,
origAddress = BeginParms#'TR-BEGIN'.origAddress,
dialogueID = DialogueID,
componentsPresent = ComponentsPresent},
NewState = State#state{otid = BeginParms#'TR-BEGIN'.transactionID, did = DialogueID,
parms = NewTcParms, appContextMode = TcParms#'TC-BEGIN'.appContextName},
%% TC-BEGIN indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'BEGIN', indication, NewTcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
{next_state, initiation_received, NewState}
end.
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%%% TC-CONTINUE request from TCU
initiation_received({'TC', 'CONTINUE', request, ContParms}, State) when is_record(ContParms, 'TC-CONTINUE') ->
%% Dialogue info included?
case ContParms#'TC-CONTINUE'.userInfo of
UserInfo when is_binary(UserInfo) ->
AARE = #'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = ContParms#'TC-CONTINUE'.appContextName,
result = accepted,
'result-source-diagnostic' = {'dialogue-service-user', null},
'user-information' = UserInfo},
DialoguePortion = 'DialoguePDUs':encode('AARE-apdu', AARE),
TrParms = #'TR-CONTINUE'{qos = ContParms#'TC-CONTINUE'.qos,
origAddress = ContParms#'TR-CONTINUE'.origAddress,
transactionID = State#state.otid,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms};
undefined ->
NewState = State
end,
{next_state, wait_cont_components_ir, NewState};
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%%% TC-END request from TCU
initiation_received({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END') ->
%% Prearranged end?
case EndParms#'TC-END'.termination of
prearranged ->
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
basic ->
%% Dialogue info included?
case EndParms#'TC-END'.userInfo of
UserInfo when is_binary(UserInfo) ->
AARE = #'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = EndParms#'TC-END'.appContextName,
result = accepted,
'result-source-diagnostic' = {'dialogue-service-user', null},
'user-information' = UserInfo},
DialoguePortion = 'DialoguePDUs':encode('AARE-apdu', AARE),
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination,
userData = #'TR-user-data'{dialoguePortion = DialoguePortion}},
NewState = State#state{parms = TrParms};
undefined ->
NewState = State
end,
%% Request components to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_end_components, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 6 of 11)
%%% TC-U-ABORT request from TCU
initiation_received({'TC', 'U-ABORT', request, AbortParms}, State) when is_record(AbortParms, 'TC-U-ABORT'),
(AbortParms#'TC-U-ABORT'.abortReason == applicationContextNotSupported)
or (AbortParms#'TC-U-ABORT'.abortReason == dialogueRefused)
or (AbortParms#'TC-U-ABORT'.abortReason == userSpecified) ->
case State#state.appContextMode of
%% Is application context mode set? (no)
undefined ->
UserData = #'TR-user-data'{};
%% Abort reason present and = AC-name not supported OR dialogue refused?
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == applicationContextNotSupported ->
%% Set protocol version = 1
%% Build AARE-pdu (rejected)
AARE = 'DialoguePDUs':encode('AARE-apdu',
#'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = AbortParms#'TC-U-ABORT'.appContextName,
result = 'reject-permanent',
'result-source-diagnostic' = {'dialogue-service-user', 'application-context-name-not-supported'}}),
UserData = #'TR-user-data'{dialoguePortion = AARE};
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == dialogueRefused ->
%% Set protocol version = 1
%% Build AARE-pdu (rejected)
AARE = 'DialoguePDUs':encode('AARE-apdu',
#'AARE-apdu'{'protocol-version' = version1,
'application-context-name' = AbortParms#'TC-U-ABORT'.appContextName,
result = 'reject-permanent',
'result-source-diagnostic' = {'dialogue-service-user', null}}),
UserData = #'TR-user-data'{dialoguePortion = AARE};
_AppContextName when AbortParms#'TC-U-ABORT'.abortReason == userSpecified ->
%% Build ABRT-apdu (abort source = dialogue-service-user)
ABRT = 'DialoguePDUs':encode('ABRT-apdu',
#'ABRT-apdu'{'abort-source' = 'dialogue-service-user',
'user-information' = AbortParms#'TC-U-ABORT'.userInfo}),
UserData = #'TR-user-data'{dialoguePortion = ABRT}
end,
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = AbortParms#'TC-U-ABORT'.qos,
transactionID = State#state.otid,
userData = UserData},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}.
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TC-END request from TCU
initiation_sent({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END'),
EndParms#'TC-END'.termination == prearranged -> % termination must be prearranged
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TC-U-ABORT request from TCU (local action)
initiation_sent({'TC', 'U-ABORT', request, AbortParms}, State) when is_record(AbortParms, 'TC-U-ABORT') ->
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = AbortParms#'TC-U-ABORT'.qos, transactionID = State#state.otid},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%%% TR-END indication from TSL
initiation_sent({'TR', 'END', indication, EndParms}, State) when is_record(EndParms, 'TR-END') ->
if
is_record(EndParms#'TR-END'.userData, 'TR-user-data'),
(EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Dialogue portion included?
%% AC Mode set?
%% Extract dialogue portion
%% Dialogue portion correct?
case extract_dialogue_portion(EndParms#'TR-END'.userData, State#state.appContextMode) of
abort ->
%% Discard components
%% TC-P-ABORT indication to TCU
TcParms = #'TC-P-ABORT'{qos = EndParms#'TR-END'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
AARE ->
%% TC-END indication to TCU
TcParms = #'TC-END'{qos = EndParms#'TR-END'.qos,
dialogueID = State#state.did,
appContextName = State#state.appContextMode,
componentsPresent = ComponentsPresent,
userInfo = AARE,
termination = EndParms#'TR-END'.termination},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'END', indication, TcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 7 of 11)
%% NOTE: currently the TCO short circuits this function and sends directly to TCU
initiation_sent({'TR', 'NOTICE', indication, NoticeParms}, State) when is_record(NoticeParms, 'TR-NOTICE') ->
%% TC-NOTICE indication to TCU
TcParms = #'TC-NOTICE'{dialogueID = State#state.did,
origAddress = NoticeParms#'TR-NOTICE'.origAddress,
destAddress = NoticeParms#'TR-NOTICE'.destAddress,
reportCause = NoticeParms#'TR-NOTICE'.reportCause},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'NOTICE', indication, TcParms}),
{next_state, initiation_sent, NewState};
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-CONTINUE indication from TSL
initiation_sent({'TR', 'CONTINUE', indication, ContParms}, State) when is_record(ContParms, 'TR-CONTINUE') ->
if
is_record(ContParms#'TR-CONTINUE'.userData, 'TR-user-data'),
(ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion /= undefined ->
case 'TC':decode('ComponentPortion', (ContParms#'TR-END'.userData)#'TR-user-data'.componentPortion) of
[] = Components -> ComponentsPresent = false;
Components -> ComponentsPresent = true
end;
true ->
Components = undefined,
ComponentsPresent = false
end,
%% Dialogue portion included?
%% AC Mode set?
%% Extract dialogue portion
%% Dialogue portion correct?
case extract_dialogue_portion(ContParms#'TR-CONTINUE'.userData, State#state.appContextMode) of
abort ->
%% Discard components
%% TC-P-ABORT indication to TCU
TcParms = #'TC-P-ABORT'{qos = ContParms#'TR-CONTINUE'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Build ABRT apdu
ABRT = 'DialoguePDUs':encode('ABRT-apdu',
#'ABRT-apdu'{'abort-source' = 'dialogue-service-provider'}),
UserData = #'TR-user-data'{dialoguePortion = ABRT},
%% TR-U-ABORT request to TSL
TrParms = #'TR-U-ABORT'{qos = ContParms#'TC-U-ABORT'.qos,
transactionID = NewState#state.otid, userData = UserData},
LastState = State#state{parms = TrParms},
gen_fsm:send_event(LastState#state.tco, {'TR', 'U-ABORT', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(LastState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, LastState};
AARE ->
%% TC-CONTINUE indication to TCU
TcParms = #'TC-CONTINUE'{qos = ContParms#'TR-CONTINUE'.qos,
origAddress = ContParms#'TR-CONTINUE'.origAddress,
appContextName = State#state.appContextMode,
dialogueID = State#state.did,
userInfo = AARE,
componentsPresent = ComponentsPresent},
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'END', indication, TcParms}),
%% Any components?
case ComponentsPresent of
true ->
%% Components to CHA
gen_fsm:send_event(NewState#state.cco, {components, Components});
false ->
ok
end,
{next_state, active, NewState}
end;
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-U-ABORT indication from TSL
initiation_sent({'TR', 'U-ABORT', indication, AbortParms}, State) when is_record(AbortParms, 'TR-U-ABORT') ->
case catch begin
if
%% Is AC mode set? (no) Is Dialogue portion present? (no)
State#state.appContextMode == undefined and (not is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data')
or (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion == undefined) ->
throw(#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos, dialogueID = State#state.did});
%% Is AC mode set? (no) Is Dialogue portion present? (yes)
State#state.appContextMode == undefined, is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data'),
AbortParms#'TR-U-ABORT'.userData /= undefined ->
throw(#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did, pAbort = abnormalDialogue});
%% Is User Data included in primitive? (no)
not is_record(AbortParms#'TR-U-ABORT'.userData, 'TR-user-data');
(AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion == undefined ->
throw(#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did, pAbort = abnormalDialogue});
true -> ok
end,
%% Is PDU type = ABRT or AARE (rejected)?
case 'DialoguePDUs':decode('DialoguePDU', (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion) of
%% Is abstract syntax = dialogue-PDU AS? (no)
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
APDU#'AARE-apdu'.'application-context-name' /= State#state.appContextMode ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue};
%% Is Abort source = user? (yes)
{dialoguePDU, APDU} when is_record(APDU, 'ABRT-apdu'),
element(1, APDU#'ABRT-apdu'.'abort-source') == 'dialogue-service-user' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = userSpecific,
userInfo = APDU#'ABRT-apdu'.'user-information'};
%% Is Associate source = user? (yes)
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'), APDU#'AARE-apdu'.'result-source-diagnostic'
== {'dialogue-service-user', 'application-context-name-not-supported'},
APDU#'AARE-apdu'.result == 'reject-permanent' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = applicationContextNotSupported,
appContextName = APDU#'AARE-apdu'.'application-context-name',
userInfo = APDU#'AARE-apdu'.'user-information'};
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
element(1, APDU#'AARE-apdu'.'result-source-diagnostic') == 'dialogue-service-user',
APDU#'AARE-apdu'.result == 'reject-permanent' ->
#'TC-U-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
abortReason = dialogueRefused,
appContextName = APDU#'AARE-apdu'.'application-context-name',
userInfo = APDU#'AARE-apdu'.'user-information'};
%% Is AARE (no common dialogue portion)?
{dialoguePDU, APDU} when is_record(APDU, 'AARE-apdu'),
APDU#'AARE-apdu'.'result-source-diagnostic' == {'dialogue-service-provider', 'no-common-dialogue-portion'} ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = noCommonDialoguePortion};
_ ->
#'TC-P-ABORT'{qos = AbortParms#'TR-U-ABORT'.qos,
dialogueID = State#state.did,
pAbort = abnormalDialogue}
end
end of
TcParms when is_record(TcParms, 'TC-U-ABORT') ->
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'U-ABORT', indication, TcParms});
TcParms when is_record(TcParms, 'TC-P-ABORT') ->
NewState = State#state{parms = TcParms},
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms})
end,
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
%% reference: Figure A.5/Q.774 (sheet 8 of 11)
%% TR-P-ABORT indication from TSL
initiation_sent({'TR', 'P-ABORT', indication, AbortParms}, State) when is_record(AbortParms, 'TR-P-ABORT') ->
TcParms = #'TC-P-ABORT'{qos = AbortParms#'TR-P-ABORT'.qos,
dialogueID = State#state.did,
pAbort = AbortParms#'TR-P-ABORT'.pAbort},
NewState = State#state{parms = TcParms},
%% TC-P-ABORT indication to TCU
gen_fsm:send_event(NewState#state.usap, {'TC', 'P-ABORT', indication, TcParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState}.
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
%% TC-CONTINUE request from TCU
active({'TC', 'CONTINUE', request, ContParms}, State) when is_record(ContParms, 'TC-CONTINUE') ->
NewState = State#state{parms = ContParms},
%% Request component to CHA
gen_fsm:send_event(NewState#state.cco, 'request-components'),
%% Process components
{next_state, wait_cont_components_active, NewState};
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
%% TC-END request from TCU
active({'TC', 'END', request, EndParms}, State) when is_record(EndParms, 'TC-END') ->
%% Prearranged end?
case EndParms#'TC-END'.termination of
prearranged ->
%% TR-END request to TSL
TrParms = #'TR-END'{qos = EndParms#'TC-END'.qos,
transactionID = State#state.otid,
termination = EndParms#'TC-END'.termination},
NewState = State#state{parms = TrParms},
gen_fsm:send_event(NewState#state.tco, {'TR', 'END', request, TrParms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(NewState#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, NewState};
basic ->
%% Request component to CHA
gen_fsm:send_event(State#state.cco, 'request-components'),
%% Process components
{next_state, wait_for_end_components, State}
end.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
wait_for_uni_components('no-component', State) ->
wait_for_uni_components1(State);
wait_for_uni_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-UNI'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-UNI'{userData = NewUserData},
wait_for_uni_components1(State#state{parms = TrParms}).
wait_for_uni_components1(State) ->
%% TR-UNI request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'UNI', request, State#state.parms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(State#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 2 of 11)
wait_for_begin_components('no-component', State) ->
wait_for_begin_components1(State);
wait_for_begin_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-BEGIN'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-BEGIN'{userData = NewUserData},
wait_for_begin_components1(State#state{parms = TrParms}).
wait_for_begin_components1(State) ->
%% Assign local transaction ID
TrParms = (State#state.parms)#'TR-BEGIN'{transactionID = transaction_coordinator_server:new_tid()},
%% TR-BEGIN request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'BEGIN', request, TrParms}),
{next_state, initiation_sent, State#state{parms = TrParms}}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
wait_cont_components_ir('no-component', State) ->
wait_cont_components_ir1(State);
wait_cont_components_ir({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-CONTINUE'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-CONTINUE'{userData = NewUserData},
wait_cont_components_ir1(State#state{parms = TrParms}).
wait_cont_components_ir1(State) ->
%% TR-CONTINUE request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'CONTINUE', request, State#state.parms}),
{next_state, initiation_sent, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
wait_cont_components_active('no-component', State) ->
wait_cont_components_active1(State);
wait_cont_components_active({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-CONTINUE'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-CONTINUE'{userData = NewUserData},
wait_cont_components_active1(State#state{parms = TrParms}).
wait_cont_components_active1(State) ->
%% TR-CONTINUE request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'CONTINUE', request, State#state.parms}),
{next_state, active, State}.
%% reference: Figure A.5 bis/Q.774
%% reference: Figure A.5/Q.774 (sheet 5 of 11)
%% reference: Figure A.5/Q.774 (sheet 9 of 11)
wait_for_end_components('no-component', State) ->
wait_for_end_components1(State);
wait_for_end_components({'requested-components', Components}, State) ->
%% Assemble component portion
ComponentPortion = 'TC':encode('ComponentPortion', Components),
%% Assemble TSL user data
UserData = (State#state.parms)#'TR-END'.userData,
NewUserData = UserData#'TR-user-data'{componentPortion = ComponentPortion},
TrParms = (State#state.parms)#'TR-END'{userData = NewUserData},
wait_for_end_components1(State#state{parms = TrParms}).
wait_for_end_components1(State) ->
%% TR-END request to TSL
gen_fsm:send_event(State#state.tco, {'TR', 'END', request, State#state.parms}),
%% Dialogue terminated to CHA
gen_fsm:send_event(State#state.cco, 'dialogue-terminated'),
%% Free dialogue ID
{stop, normal, State}.
%% Dialogue portion included? (yes)
extract_uni_dialogue_portion(UserData) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion correct?
case 'UnidialoguePDUs':decode('UnidialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{unidialoguePDU, AUDT} when is_record(AUDT, 'AUDT-apdu') ->
%% Is version 1 supported?
case lists:member(version1, AUDT#'AUDT-apdu'.'protocol-version') of
true ->
#'TC-UNI'{appContextName = AUDT#'AUDT-apdu'.'application-context-name',
userInfo = AUDT#'AUDT-apdu'.'user-information'};
false ->
no_version1
end;
_ ->
incorrect_dialogue_portion
end;
%% Dialogue portion included? (no)
extract_uni_dialogue_portion(_DialoguePortion) ->
#'TC-UNI'{}.
%% Dialogue portion included? (yes)
extract_begin_dialogue_portion(UserData) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion correct?
case 'DialoguePDUs':decode('DialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{dialoguePDU, AARQ} when is_record(AARQ, 'AARQ-apdu') ->
%% Is version 1 supported?
case lists:member(version1, AARQ#'AARQ-apdu'.'protocol-version') of
true ->
%% Set application context mode
#'TC-BEGIN'{appContextName = AARQ#'AARQ-apdu'.'application-context-name',
userInfo = AARQ#'AARQ-apdu'.'user-information'};
false ->
no_version1
end;
_ ->
incorrect_dialogue_portion
end;
%% Dialogue portion included? (no)
extract_begin_dialogue_portion(_DialoguePortion) ->
#'TC-BEGIN'{}.
extract_dialogue_portion(UserData, undefined) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Dialogue portion included? (yes) AC mode set? (no)
abort;
extract_dialogue_portion(UserData, _AppContextName) when not is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion == undefined ->
%% Dialogue portion included? (no) AC mode set? (yes)
abort;
extract_dialogue_portion(UserData, _AppContextName) when is_record(UserData, 'TR-user-data'),
UserData#'TR-user-data'.dialoguePortion /= undefined ->
%% Extract dialogue portion
case 'DialoguePDUs':decode('DialoguePDU', UserData#'TR-user-data'.dialoguePortion) of
{dialoguePDU, AARE} when is_record(AARE, 'AARE-apdu') ->
AARE; %% Dialogue portion correct? (yes)
_ ->
abort %% Dialogue portion correct? (no)
end.
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("dialogue_fsm (~w) received unexpected message: ~w~n", [Info]),
{next_state, StateName, State}.
%% handle an event sent using gen:fsm_send_all_state_event/2
handle_event(_Event, StateName, StateData) ->
{next_state, StateName, StateData}.
%% handle an event sent using gen_fsm:sync_send_all_state_event/2,3
handle_sync_event(_Event, _From, StateName, StateData) ->
{next_state, StateName, StateData}.
%% handle a shutdown request
terminate(_Reason, _StateName, State) when State#state.supid == undefined ->
%% we were started by TSM, no worries
ok;
terminate(_Reason, _StateName, State) ->
%% signal TCO so he can reap the ChildSpec of our supervisor
gen_server:cast(State#state.tco, {'dha-stopped', State#state.supid}).
%% handle updating state data due to a code replacement
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

View File

@ -0,0 +1,65 @@
%%% $Id: tcap_ism_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Invocation State Machine (ISM) functional block within the
%%% component sub-layer of ITU TCAP.
%%%
%%% @reference ANSI T1.114.4 Transaction Capabilities Procedures
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_ism_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_info/3, terminate/3, code_change/4]).
%% invocation_fsm state callbacks
-export([]).
%% record definitions for TC-User primitives
-include("tcap.hrl").
%% record definitions for TCAP messages
%-include("TCAPMessages.hrl").
%% the invocation_fsm state data
-record(state, {usap, dialogueID, cco}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% Start the Invocation State Machine (ISM) process
%% reference: Figure A.7/Q.774 (sheet 1 of 6)
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("~w (~w) received unexpected message: ~w~n", [?Module, self(), Event]),
{next_state, StateName, State};
%% handle a shutdown request
terminate(_Reason, _StateName, State) -> ok.
%% handle updating state data due to a code replacement
code_change(OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

View File

@ -0,0 +1,696 @@
%%% $Id: tcap_tco_server.erl,v 1.7 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Transaction Coordinator (TCO) functional block within the
%%% transaction sub-layer of ITU TCAP.
%%%
%%% <p>This module implements the transaction coordinator (TCO)
%%% functional block. Adaptations to specific SCCP layer
%%% and TC-User implementations may be implemented as callback
%%% modules behaving to this behaviour module. This module behaves
%%% to <tt>gen_server</tt>.</p>
%%%
%%% <h2>Usage</h2>
%%% <p>The callback module should be implemented as a gen_server
%%% behaviour but with a <tt>tcap_tco_server</tt> behaviour
%%% module attribute:
%%% <pre>
%%% -behaviour(tcap_tco_server).</pre></p>
%%%
%%% <p>The call back module handles the SCCP -&gt; TCAP primitives
%%% directly, performs any reformatting required, and returns the
%%% standard primitives to the <tt>tcap_tco_server</tt> handler. A
%%% very simple example is the
%%% <a href="http://www.motivity.ca/sccp"><tt>sccp</tt></a>
%%% application which implements the SCCP SAP as a pid() which sends
%%% and receives messages in the primitive format. In our callback
%%% module we create a <tt>handle_info/2</tt> clause which matches
%%% the primitives:</p>
%%%
%%% <p><pre>handle_info({'N', _, indication, _} = Primitive, State) -&gt;
%%% {primitive, Primitive, State}.</pre>
%%% As the example above illustrates the <tt>tcap_tco_server</tt>
%%% behaviour extends the allowed return values to accept the direct
%%% return of a received service primitive.</p>
%%%
%%% <p>The <tt>handle_cast/2</tt> function may be used in the same
%%% way.</p>
%%%
%%% <h2><a name="calbacks">Callback Functions</a></h2>
%%%
%%% <p>In addition to the <tt>gen_server</tt> callbacks the following
%%% callback functions are used.</p>
%%%
%%% <h3><a name="send_primitive-2">send_primitive/2</a></h3>
%%%
%%% <p><tt>send_primitive(Primitive, State) -&gt; void()</tt>
%%% <ul><li><tt>Primitive = {'N', 'UNITDATA', request, UdataParams}</tt></li>
%%% <li><tt>UdataParams = #'N-UNITDATA'{}</tt></li>
%%% </ul>
%%% The TCO will call this function when it has a service primitive
%%% to deliver to the SCCP layer.</p>
%%%
%%% <h3><a name="start_user-2">start_user/2</a></h3>
%%%
%%% <p><tt>start_user(CSL, DialogueID, State) -&gt; pid()</tt>
%%% <ul><li><tt>CSL = {DHA, CCO}</tt></li>
%%% <li><tt>DHA = pid()</tt></li>
%%% <li><tt>CCO = pid()</tt></li>
%%% <li><tt>DialogueID = tid()</tt></li>
%%% </ul>
%%% This function is called by a dialogue handler (DHA) to initialize
%%% a local TC-User for a dialogue begun by a remote TC-User.</p>
%%% <p><tt>CSL</tt> is the component sublayer identifier which
%%% contains the pids of the dialogue handler and component coordinator.</p>
%%% <p>Returns the pid of the TC-User process whcih will handle the
%%% new dialogue.</p>
%%%
%%% <h3><a name="start_transaction-1">start_transaction/2</a></h3>
%%%
%%% <p><tt>start_transaction(TransactionID, State) -&gt; StartFunc</tt>
%%% <ul><li><tt>TransactionID = tid()</tt></li>
%%% <li><tt>State = term()</tt></li>
%%% <li><tt>StartFunc = {M,F,A}</tt></li>
%%% <li><tt>M = F = atom()</tt></li>
%%% <li><tt>A = [term()]</tt></li>
%%% </ul>
%%% The callback module may optionally export this function
%%% to overide the default method used to start a transaction
%%% state machine (TSM).</p>
%%% <p>StartFunc defines the function call used to start the TSM
%%% process. It should be a module-function-arguments tuple
%%% <tt>{M,F,A}</tt> used as <tt>apply(M,F,A)</tt>.</p>
%%% <p>The start function must create and link to the child process,
%%% and should return <tt>{ok, Child}</tt> where <tt>Child</tt> is
%%% the pid of the child process.</p>
%%% <p>See the description of StartFunc in the supervisor module.</p>
%%%
%%% <h3><a name="start_dialogue-1">start_dialogue/1</a></h3>
%%%
%%% <p><tt>start_dialogue(DialogueID, State) -&gt; StartFunc</tt>
%%% <ul><li><tt>DialogueID = tid()</tt></li>
%%% <li><tt>State = term()</tt></li>
%%% <li><tt>StartFunc = {M,F,A}</tt></li>
%%% <li><tt>M = F = atom()</tt></li>
%%% <li><tt>A = [term()]</tt></li>
%%% </ul>
%%% The callback module may optionally export this function
%%% to overide the default method used to start a dialogue
%%% handler (DHA).</p>
%%% <p>StartFunc defines the function call used to start the DHA
%%% process. It should be a module-function-arguments tuple
%%% <tt>{M,F,A}</tt> used as <tt>apply(M,F,A)</tt>.</p>
%%% <p>The start function must create and link to the child process,
%%% and should return <tt>{ok, Child}</tt> where <tt>Child</tt> is
%%% the pid of the child process.</p>
%%% <p>See the description of StartFunc in the supervisor module.</p>
%%%
%%% @end
%%%
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
-module(tcap_tco_server).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.7 $').
-behaviour(gen_server).
% export the gen_server interface
-export([start/3, start/4, start_link/3, start_link/4,
call/2, call/3, multi_call/2, multi_call/3, multi_call/4,
cast/2, abcast/2, abcast/3, reply/2, enter_loop/4, enter_loop/5]).
% export the gen_server call backs
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
% behaviour modules must export this function
-export([behaviour_info/1]).
%% define what callbacks users must export
%%
%% @hidden
behaviour_info(callbacks) ->
gen_server:behaviour_info(callbacks)
% add the tcap_tco_server required callbacks
++ [{send_primitive, 2}, {start_transaction, 2}, {start_dialogue, 2}];
behaviour_info(Other) ->
gen_server:behaviour_info(Other).
-include("TCAPMessages.hrl").
-include("tcap.hrl").
-include("sccp.hrl").
-record(state, {supervisor, module, ext_state}).
%%----------------------------------------------------------------------
%% The gen_server call backs
%%----------------------------------------------------------------------
%% @hidden
init([Sup, Module, Args]) ->
process_flag(trap_exit, true),
case Module:init(Args) of
{ok, ExtState} ->
NewState = #state{supervisor = Sup, module = Module, ext_state = ExtState},
{ok, NewState};
{ok, ExtState, Timeout} ->
NewState = #state{supervisor = Sup, module = Module, ext_state = ExtState},
{ok, NewState, Timeout};
{stop, Reason} ->
{stop, Reason};
ignore ->
ignore;
Other ->
Other
end.
%% @hidden
%%
% assign a new dialogue ID
handle_call(dialogueID, From, State) ->
{reply, new_tid(), State};
% shutdown the server
handle_call(stop, _From, State) ->
{stop, shutdown, ok, State};
% unknown request
handle_call(Request, From, State) ->
Module = State#state.module,
case Module:handle_call(Request, From, State#state.ext_state) of
{reply, Reply, ExtState} ->
{reply, Reply, State#state{ext_state = ExtState}};
{reply, Reply, ExtState, Timeout} ->
{reply, Reply, State#state{ext_state = ExtState}, Timeout};
{noreply, ExtState} ->
{noreply, State#state{ext_state = ExtState}};
{noreply, ExtState, Timeout} ->
{noreply, State#state{ext_state = ExtState}, Timeout};
{stop, Reason, Reply, ExtState} ->
{stop, Reason, Reply, State#state{ext_state = ExtState}};
{stop, Reason, ExtState} ->
{stop, Reason, State#state{ext_state = ExtState}};
Other ->
Other
end.
%% @spec (Request, State) -> Result
%% Info = term()
%% State = term()
%% Result = {noreply, NewState} | {noreply, NewState, Timeout}
%% | {stop, Reason, NewState}
%% | {primitive, Primitive, NewState}
%% NewState = term()
%% Timeout = int() | infinity
%% Reason = term()
%% Primitive = {'N', 'UNITDATA', indication, SccpParams} |
%% {'N', 'NOTICE', indication, SccpParams}
%%
%% @doc Receive a message sent with <tt>gen_server:cast/2</tt>.
%%
%% <p>A user callback module may return an SCCP service primitive
%% to TCO for processing with the return value
%% <tt>{primitive, Primitive, NewState}</tt>.</p>
%%
%% @see //stdlib/gen_server:handle_cast/2
%%
%% @end
%%
% service primitive indications from the network layer
%
% reference: Figure A.3/Q.774 (sheet 1 of 4)
handle_cast({'N', 'UNITDATA', indication, UdataParams}, State)
when is_record(UdataParams, 'N-UNITDATA') ->
case 'TR':decode('TCMessage', UdataParams#'N-UNITDATA'.userData) of
{ok, {unidirectional, TPDU}} ->
case 'TR':decode('Unidirectional', TPDU) of
{ok, Unidirectional} ->
% Create a Dialogue Handler (DHA)
DialogueID = new_tid(),
StartFunc = get_start(dialogue, DialogueID, State),
ChildSpec = {DialogueID, StartFunc, temporary, 4000, worker, [tcap_dha_fsm]},
{ok, DHA} = supervisor:start_child(State#state.supervisor, ChildSpec),
% TR-UNI indication CSL <- TSL
UserData = #'TR-user-data'{dialoguePortion = Unidirectional#'Unidirectional'.dialoguePortion,
componentPortion = Unidirectional#'Unidirectional'.components},
TrParams = #'TR-UNI'{qos =
destAddress = UdataParams#'N-UNITDATA'.calledAddress,
origAddress = UdataParams#'N-UNITDATA'.callingAddress,
userData = UserData},
gen_fsm:send_event(DHA, {'TR', 'UNI', indication, TrParams}),
{noreply, State};
{error, Reason} ->
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
error_logger:error_report(["Syntax error in received N-UNI", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {'begin', TPDU}} ->
case 'TR':decode('Begin', TPDU) of
{ok, Begin} ->
% Assign local transaction ID
TransactionID = new_tid(),
StartFunc = get_start(transaction, TransactionID, State),
ChildSpec = {TransactionID, StartFunc, temporary, infinity, supervisor, [tcap_tsm_fsm]},
% Is TID = no TID?
% Note: The assignment of the ID above just gets the next available
% value and doesn't ensure that it is not in use (unlikely)
% or that there are enough resources available. The real
% test is in whether the start succeeds.
case supervisor:start_child(State#state.supervisor, ChildSpec) of
{ok, TSM} ->
% Created a Transaction State Machine (TSM)
TsmParams = UdataParams#'N-UNITDATA'{userData = Begin},
% BEGIN received TSM <- TCO
gen_fsm:send_event(TSM, {'BEGIN', received, TsmParams});
_Other ->
% TID = no TID
% Build ABORT message (P-Abort Cause = Resource Limitation)
Abort = {abort, #'Abort'{dtid = TPDU#'Begin'.otid,
reason = {'p-abortCause', resourceLimitation}}},
NewTPDU = list_to_binary('TCMessage':encode('TCMessage', Abort)),
SccpParams = #'N-UNITDATA'{calledAddress = UdataParams#'N-UNITDATA'.callingAddress,
callingAddress = UdataParams#'N-UNITDATA'.calledAddress,
sequenceControl = false, returnOption = false, importance = none,
userData = NewTPDU},
% TR-UNI request TSL -> SCCP
Module = State#state.module,
Module:send_primitive({'N', 'UNITDATA', request, SccpParams}, State#state.ext_state),
error_logger:error_report(["Unable to create TSM for received N-BEGIN",
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}])
end,
{noreply, State};
{error, Reason} ->
% TODO
% is OTID derivable?
% Build ABORT message with appropraite P-Abort Cause value
% N-UNITDATA request TSL -> SCCP
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (4)
error_logger:error_report(["Syntax error in received N-BEGIN", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {continue, TPDU}} ->
case 'TR':decode('Continue', TPDU) of
{ok, Continue} ->
% DTID assigned?
case catch ets:lookup_element(transaction, TPDU#'Continue'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-CONTINUE",
{dtid, TPDU#'End'.dtid},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
% TODO
% Build ABORT message with appropriate P-Abort Cause values
% N-UNITDATA request TSL -> SCCP
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (4)
{noreply, State};
TSM ->
TsmParams = UdataParams#'N-UNITDATA'{userData = Continue},
% CONTINUE received TSM <- TCO
gen_fsm:send_event(TSM, {'CONTINUE', received, TsmParams}),
{noreply, State}
end;
{error, Reason} ->
% TODO
% OTID derivable?
% DTID assigned?
% Build ABORT message with appropraite P-Abort Cause value
% N-UNITDATA request TSL -> SCCP
% Local Abort TSM <- TCO
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (2)
error_logger:error_report(["Syntax error in received N-CONTINUE", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {'end', TPDU}} ->
case 'TR':decode('End', TPDU) of
{ok, End} ->
% DTID assigned?
case catch ets:lookup(transaction, TPDU#'End'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-END",
{dtid, TPDU#'End'.dtid},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
{noreply, State};
TSM ->
TsmParams = UdataParams#'N-UNITDATA'{userData = End},
% END received TSM <- TCO
gen_fsm:send_event(TSM, {'END', received, TsmParams}),
{noreply, State}
end;
{error, Reason} ->
% TODO
% DTID assigned?
% Local Abort TSM <- TCO
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (5)
error_logger:error_report(["Syntax error in received N-END", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {abort, TPDU}} ->
case 'TR':decode('Abort', TPDU) of
{ok, Abort} ->
% DTID assigned?
case catch ets:lookup(transaction, TPDU#'Abort'.dtid, 2) of
{error, _Reason} ->
error_logger:error_report(["DTID not found in received N-ABORT",
{dtid, TPDU#'Abort'.dtid},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (3)
{noreply, State};
TSM ->
TsmParams = UdataParams#'N-UNITDATA'{userData = Abort},
% Abort received TSM <- TCO
gen_fsm:send_event(TSM, {'ABORT', received, TsmParams}),
{noreply, State}
end;
{error, Reason} ->
% TODO
% DTID assigned?
% Local Abort TSM <- TCO
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (5)
error_logger:error_report(["Syntax error in received N-ABORT", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
{ok, {error, Reason}} ->
% TODO
% Message type unknown
% OTID derivable?
% DTID assigned?
% Build ABORT message with appropraite P-Abort Cause value
% N-UNITDATA request TSL -> SCCP
% Local Abort TSM <- TCO
% Discard received message
% reference: Figure A.3/Q/774 (sheet 4 of 4) label (2)
error_logger:error_report(["Unknown TCMessage received", {error, Reason},
{caller, UdataParams#'N-UNITDATA'.callingAddress},
{called, UdataParams#'N-UNITDATA'.calledAddress}]),
{noreply, State}
end;
handle_cast({'N', 'NOTICE', indication, NoticeParams}, State) ->
% Extract the originating transactionID
case 'TR':decode('TCMessage', NoticeParams#'N-NOTICE'.userData) of
{ok, {'begin', TPDU}} ->
case 'TR':decode('Begin', TPDU) of
{ok, Begin} ->
TransactionID = Begin#'Begin'.otid;
_ ->
TransactionID = undefined
end;
{ok, {continue, TPDU}} ->
case 'TR':decode('Continue', TPDU) of
{ok, Continue} ->
TransactionID = Continue#'Continue'.otid;
_ ->
TransactionID = undefined
end;
_ ->
TransactionID = undefined
end,
% TR-NOTICE indication CSL <- TSL
% reference: Figure A.3/Q.774 (sheet 2 of 4)
% The CSL is a null layer for this indication so it becomes
% TC-NOTICE indication TCU <- TSL
% reference: Figure A.5/Q.774 (sheet 7 of 11)
% reference: Figure A.3/Q.774 (sheet 10 of 11)
TcParams = #'TC-NOTICE'{
dialogueID = TransactionID,
origAddress = NoticeParams#'N-NOTICE'.callingAddress,
destAddress = NoticeParams#'N-NOTICE'.calledAddress,
reportCause = NoticeParams#'N-NOTICE'.reason},
% TODO: fixme!!! gen_fsm:send_event(State#state.usap, {'TC', 'NOTICE', indication, TcParams}),
{noreply, State};
%%
%% service primitive requests from the TR-User
%% reference: Figure A.3/Q.774 (sheets 2&3 of 4)
handle_cast({'TR', 'UNI', request, UniParams}, State)
when is_record(UniParams, 'TR-UNI') ->
% Assemble TR-portion of UNI message
{SequenceControl, ReturnOption, Importance} = UniParams#'TR-UNI'.qos,
DialoguePortion = (UniParams#'TR-UNI'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (UniParams#'TR-UNI'.userData)#'TR-user-data'.componentPortion,
TPDU = 'TR':encode('TCMessage', {unidirectional, #'Unidirectional'{
dialoguePortion = DialoguePortion, components = ComponentPortion}}),
SccpParams = #'N-UNITDATA'{calledAddress = UniParams#'TR-UNI'.destAddress,
callingAddress = UniParams#'TR-UNI'.origAddress,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = Importance, userData = TPDU},
Module = State#state.module,
Module:send_primitive({'N', 'UNITDATA', request, SccpParams}, State#state.ext_state),
{noreply, State};
handle_cast({'TR', 'BEGIN', request, BeginParams}, State)
when is_record(BeginParams, 'TR-BEGIN') ->
% Create a Transaction State Machine (TSM)
OTID = BeginParams#'TR-BEGIN'.transactionID,
ChildName = list_to_atom("tsm_" ++ integer_to_list(OTID)),
{ok, {M, F, A, Mods}} = application:get_env(start_tsm),
% TDODO: fixme!!! StartFunc = get_start(transaction, OTID, State),
% ChildSpec = {ChildName, StartFunc, temporary, infinity, worker, [tcap_tsm_fsm]},
% {ok, TSM} = supervisor:start_child(State#state.supervisor, ChildSpec),
% gen_fsm:send_event(TSM, {'BEGIN', transaction, BeginParams}),
{noreply, State};
handle_cast({'TR', 'CONTINUE', request, ContParams}, State)
when is_record(ContParams, 'TR-CONTINUE') ->
TransactionID = ContParams#'TR-CONTINUE'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'CONTINUE', transaction, ContParams}),
{noreply, State};
handle_cast({'TR', 'END', request, EndParams}, State)
when is_record(EndParams, 'TR-END') ->
TransactionID = EndParams#'TR-END'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'END', transaction, EndParams}),
{noreply, State};
handle_cast({'TR', 'U-ABORT', request, AbortParams}, State)
when is_record(AbortParams, 'TR-U-ABORT') ->
TransactionID = AbortParams#'TR-U-ABORT'.transactionID,
TSM = ets:lookup_element(transaction, TransactionID, 2),
gen_fsm:send_event(TSM, {'ABORT', transaction, AbortParams}),
{noreply, State};
%
% The TSM sends us a message as it's last action so
% we can remove the supervisor child specification
%
handle_cast({'tsm-stopped', SupRef}, State) ->
supervisor:delete_child(State#state.supervisor, SupRef),
% reference: Figure A.3/Q/774 (sheet 2 of 4)
{noreply, State};
% unrecognized request
handle_cast(Request, State) ->
Module = State#state.module,
case Module:handle_cast(Request, State#state.ext_state) of
{noreply, ExtState} ->
{noreply, State#state{ext_state = ExtState}};
{noreply, ExtState, Timeout} ->
{noreply, State#state{ext_state = ExtState}, Timeout};
{primitive, Primitive, ExtState} ->
handle_cast(Primitive, State#state{ext_state = ExtState});
{stop, Reason, ExtState} ->
{stop, Reason, State#state{ext_state = ExtState}};
Other ->
Other
end.
%% @spec (Info, State) -> Result
%% Info = timeout | term()
%% State = term()
%% Result = {noreply, NewState} | {noreply, NewState, Timeout}
%% | {stop, Reason, NewState}
%% | {primitive, Primitive, NewState}
%% NewState = term()
%% Timeout = int() | infinity
%% Reason = term()
%% Primitive = {'N', 'UNITDATA', indication, SccpParams} |
%% {'N', 'NOTICE', indication, SccpParams}
%%
%% @doc Receive a message sent with '!'.
%%
%% <p>A user callback module may return an SCCP service primitive
%% to TCO for processing with the return value
%% <tt>{primitive, Primitive, NewState}</tt>.</p>
%%
%% @see //stdlib/gen_server:handle_info/2
%%
handle_info({'EXIT', _Pid, Reason}, State) ->
{stop, Reason, State};
handle_info(Info, State) ->
Module = State#state.module,
case Module:handle_info(Info, State#state.ext_state) of
{noreply, ExtState} ->
{noreply, State#state{ext_state = ExtState}};
{noreply, ExtState, Timeout} ->
{noreply, State#state{ext_state = ExtState}, Timeout};
{primitive, Primitive, ExtState} ->
handle_cast(Primitive, State#state{ext_state = ExtState});
{stop, Reason, ExtState} ->
{stop, Reason, State#state{ext_state = ExtState}};
Other ->
Other
end.
%% @hidden
terminate(Reason, State) ->
Module = State#state.module,
Module:terminate(Reason, State#state.ext_state).
%% @hidden
code_change(OldVersion, statename, State, Extra) ->
Module = State#state.module,
case Module:code_change(OldVersion, State#state.ext_state, Extra) of
{ok, ExtState} ->
{ok, State#state{ext_state = ExtState}};
Other ->
Other
end.
%%----------------------------------------------------------------------
%% internal functions
%%----------------------------------------------------------------------
%% @hidden
%%
%% get the next originating transaction id from the global counter
%%
%% NOTE: we are simply assuming that when the counter rolls over the last
%% transaction to have this ID is long gone (4.2 billion IDs)
%%
%% reference: Figure A.3 bis/Q.774
new_tid() ->
ets:update_counter(transaction, transactionID, {2, 1, 16#ffffffff, 0}).
get_start(dialogue, DialogueID, State) ->
Module = State#state.module,
case erlang:function_exported(Module, start_dialogue, 1) of
true ->
Module:start_dialogue(DialogueID, State#state.ext_state);
false ->
StartUserFun = fun(CSL) -> Module:start_user(CSL, DialogueID, State#state.ext_state) end,
StartArgs = [DialogueID, self(), StartUserFun],
{gen_fsm, start_link, [tcap_dha_fsm, StartArgs, []]}
end;
get_start(in_transaction, TransactionID, State) ->
Module = State#state.module,
case erlang:function_exported(Module, start_transaction, 1) of
true ->
Module:start_transaction(TransactionID, State#state.ext_state);
false ->
SendFun = fun(P) -> Module:send_primitive(P, State#state.ext_state) end,
StartDHA = get_start(dialogue, TransactionID, State),
StartArgs = [TransactionID, SendFun, StartDHA],
{gen_fsm, start_link, [tcap_dha_fsm, StartArgs, []]}
end;
get_start(out_transaction, TransactionID, State) ->
Module = State#state.module,
case erlang:function_exported(Module, start_transaction, 1) of
true ->
Module:start_transaction(TransactionID, State#state.ext_state);
false ->
SendFun = fun(P) -> Module:send_primitive(P, State#state.ext_state) end,
StartDHA = get_start(dialogue, TransactionID, State),
StartArgs = [TransactionID, SendFun, StartDHA],
{gen_fsm, start_link, [tcap_dha_fsm, StartArgs, []]}
end.
%%----------------------------------------------------------------------
%% The gen_server API functions
%%----------------------------------------------------------------------
%% @hidden
start(Module, Args, Options) ->
gen_server:start(?MODULE, [Module, Args], Options).
%% @hidden
start(ServerRef, Module, Args, Options) ->
gen_fsm:start(ServerRef, ?MODULE, [Module, Args], Options).
%% @hidden
start_link(Module, Args, Options) ->
gen_fsm:start_link(?MODULE, [Module, Args], Options).
%% @hidden
start_link(ServerRef, Module, Args, Options) ->
gen_fsm:start_link(ServerRef, ?MODULE, [Module, Args], Options).
%% @hidden
call(ServerRef, Request) ->
gen_server:call(ServerRef, Request).
%% @hidden
call(ServerRef, Request, Timeout) ->
gen_server:call(ServerRef, Request, Timeout).
%% @hidden
multi_call(Name, Request) ->
gen_server:multi_call(Name, Request).
%% @hidden
multi_call(Nodes, Name, Request) ->
gen_server:multi_call(Nodes, Name, Request).
%% @hidden
multi_call(Nodes, Name, Request, Timeout) ->
gen_server:multi_call(Nodes, Name, Request, Timeout).
%% @hidden
cast(ServerRef, Request) ->
gen_server:cast(ServerRef, Request).
%% @hidden
abcast(Name, Request) ->
gen_server:abcast(Name, Request).
%% @hidden
abcast(Nodes, Name, Request) ->
gen_server:abcast(Nodes, Name, Request).
%% @hidden
reply(Client, Reply) ->
gen_server:reply(Client, Reply).
%% @hidden
enter_loop(Module, Options, State, ServerName, Timeout) ->
gen_server:enter_loop(Module, Options, State, ServerName, Timeout).
%% @hidden
enter_loop(Module, Options, State, Timeout) ->
gen_server:enter_loop(Module, Options, State, Timeout).
% enter_loop(Module, Options, State, ServerName) ->
% gen_server:enter_loop(Module, Options, State, ServerName).

View File

@ -0,0 +1,405 @@
%%% $Id: tcap_tsm_fsm.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Transaction State Machine (TCM) functional block within the
%%% transaction sub-layer of ITU TCAP.
%%%
%%% @reference ITU-T Q.774 (06/97) Annex A Transaction capabilities SDLs
%%%
%%% @private
%%%
-module(tcap_tsm_fsm).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
-behaviour(gen_fsm).
%% call backs needed for gen_fsm behaviour
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
terminate/3, code_change/4]).
%% transaction_fsm state callbacks
-export([idle/2, initiation_sent/2, initiation_received/2, active/2]).
%% record definitions for TR-User primitives
-include("tcap.hrl").
%% record definitions for N-User primitives
-include("sccp.hrl").
%% record definitions for TCAP messages
-include("TCAPMessages.hrl").
%% the transaction_fsm state data
-record(state, {nsap, usap, tco, supervisor, supref, localTID, remoteTID,
local_address, remote_address, dha}).
%%----------------------------------------------------------------------
%% The gen_fsm call backs
%%----------------------------------------------------------------------
%% initialize the server
init({NSAP, USAP, TID, Supervisor, SupRef, TCO}) ->
%% store our process identifier in the global transaction ID table
ets:insert(transaction, {TID, self()}),
process_flag(trap_exit, true),
{ok, idle, #state{nsap = NSAP, usap = USAP, localTID = TID, supervisor = Supervisor,
supref = SupRef, tco = TCO}}.
%%%
%%% idle state handler
%%%
%% started by remote
%% reference: Figure A.4/Q.774 (sheet 1 of 5)
idle({'BEGIN', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
%% Store remote address and remote TID
NewState = State#state{remote_address = SccpParms#'N-UNITDATA'.callingAddress,
remoteTID = (SccpParms#'N-UNITDATA'.userData)#'Begin'.otid},
{ok, Begin} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% Start a Dialogue Handler (DHA)
SupId = list_to_atom("dha_sup_" ++ integer_to_list(State#state.localTID)),
StartFunc = {supervisor, start_link,
[dialogue_sup, [{State#state.usap, State#state.localTID, self()}]]},
ChildSpec = {SupId, StartFunc, permanent, infinity, supervisor, [dialogue_sup]},
{ok, DHA} = supervisor:start_child(State#state.supervisor, ChildSpec),
QOS = {SccpParms#'N-UNITDATA'.sequenceControl, SccpParms#'N-UNITDATA'.returnOption},
UserData = #'TR-user-data'{dialoguePortion = Begin#'Begin'.dialoguePortion,
componentPortion = Begin#'Begin'.components},
TrParms = #'TR-BEGIN'{qos = QOS,
destAddress = SccpParms#'N-UNITDATA'.calledAddress,
origAddress = SccpParms#'N-UNITDATA'.callingAddress,
transactionID = State#state.localTID,
userData = UserData},
%% TR-BEGIN CSL <- TSL
gen_fsm:send_event(DHA, {'TR', 'BEGIN', indication, TrParms}),
{next_state, initiation_received, NewState#state{dha = DHA}};
%% started by TR-User
%% reference: Figure A.4/Q.774 (sheet 1 of 5)
idle({'BEGIN', transaction, BeginParms}, State)
when is_record(BeginParms, 'TR-BEGIN') ->
%% Store local address
%% NOTE - This may be provided by TC-user or be implicitly associated with
%% the access point at which the N-UNITDATA primitive is issued.
NewState = State#state{local_address = BeginParms#'TR-BEGIN'.origAddress},
DialoguePortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (BeginParms#'TR-BEGIN'.userData)#'TR-user-data'.componentPortion,
Begin = #'Begin'{otid = State#state.localTID, dialoguePortion = DialoguePortion,
components = ComponentPortion},
%% Assemble TR-portion of BEGIN message
TPDU = list_to_binary('TR':encode('TCMessage', {'begin', Begin})),
{SequenceControl, ReturnOption} = BeginParms#'TR-BEGIN'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = BeginParms#'TR-BEGIN'.destAddress,
callingAddress = BeginParms#'TR-BEGIN'.origAddress,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(NewState#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, initiation_sent, NewState}.
%%%
%%% initiation_received state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue from TR-User
initiation_received({'CONTINUE', transaction, ContParms}, State)
when is_record(ContParms, 'TR-CONTINUE') ->
%% Store new local address if it is provided by User
case ContParms#'TR-CONTINUE'.origAddress of
undefined ->
NewState = State;
NewAddress ->
NewState = State#state{local_address = NewAddress}
end,
DialoguePortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion,
Continue = #'Continue'{otid = State#state.localTID, dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of CONTINUE message
TPDU = list_to_binary('TR':encode('TCMessage', {continue, Continue})),
{SequenceControl, ReturnOption} = ContParms#'TR-CONTINUE'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = NewState#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(NewState#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, active, NewState};
%% End from TR-User (prearranged)
initiation_received({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END'),
EndParms#'TR-END'.termination == prearranged ->
{stop, normal, State};
%% End from TR-User (not prearranged)
initiation_received({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
DialoguePortion = (EndParms#'TR-END'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion,
End = #'End'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of END message
TPDU = list_to_binary('TR':encode('TCMessage', {'end', End})),
{SequenceControl, ReturnOption} = EndParms#'TR-END'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State};
%% Abort from TR-User
initiation_received({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
Cause = (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion,
Abort = #'Abort'{reason = {'u-abortCause', Cause}},
%% Assemble TR-portion of ABORT message
TPDU = list_to_binary('TR':encode('TCMessage', {abort, Abort})),
{SequenceControl, ReturnOption} = AbortParms#'TR-U-ABORT'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State}.
%%%
%%% initiation_sent state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue from remote
initiation_sent({'CONTINUE', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
%% Store remote address and remote TID
OTID = (SccpParms#'N-UNITDATA'.userData)#'Begin'.otid,
NewState = State#state{ remote_address
= SccpParms#'N-UNITDATA'.callingAddress, remoteTID = OTID},
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Continue} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = Continue#'Continue'.dialoguePortion,
componentPortion = Continue #'Continue'.components},
TrParms = #'TR-CONTINUE'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(NewState#state.dha, {'TR', 'CONTINUE', indication, TrParms}),
{next_state, active, NewState};
%% End from remote
initiation_sent({'END', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, End} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = End#'End'.dialoguePortion,
componentPortion = End#'End'.components},
TrParms = #'TR-END'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'END', indication, TrParms}),
{stop, normal, State};
%% Abort from remote
initiation_sent({'ABORT', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Abort} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% TR-U-ABORT?
case Abort#'Abort'.reason of
{'p-abortCause', Cause} ->
TrParms = #'TR-P-ABORT'{qos = QOS,
transactionID = State#state.localTID,
pAbort = Cause},
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms});
{'u-abortCause', Cause} ->
UserData = #'TR-user-data'{dialoguePortion = Cause},
TrParms = #'TR-U-ABORT'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'U-ABORT', indication, TrParms})
end,
{stop, normal, State};
%% Local Abort
initiation_sent({'local-abort', received, Cause}, State) ->
TrParms = #'TR-P-ABORT'{pAbort = Cause},
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms}),
{stop, normal, State};
%% End from TR-User
initiation_sent({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
{stop, normal, State};
%% Abort from TR-User
initiation_sent({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
%% Purely local action
{stop, normal, State}.
%%%
%%% active state handler
%%%
%%% reference: Figure A.4/Q.774 (sheet 2 of 5)
%% Continue received from remote
active({'CONTINUE', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Continue} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = Continue#'Continue'.dialoguePortion,
componentPortion = Continue#'Continue'.components},
TrParms = #'TR-CONTINUE'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
gen_fsm:send_event(State#state.dha, {'TR', 'CONTINUE', indication, TrParms}),
{next_state, active, State};
%% Continue from TR-User
active({'CONTINUE', transaction, ContParms}, State)
when is_record(ContParms, 'TR-CONTINUE') ->
DialoguePortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (ContParms#'TR-CONTINUE'.userData)#'TR-user-data'.componentPortion,
Continue = #'Continue'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of CONTINUE message
TPDU = list_to_binary('TR':encode('TCMessage', {continue, Continue})),
{SequenceControl, ReturnOption} = ContParms#'TR-CONTINUE'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{next_state, active, State};
%% End from remote
active({'END', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, End} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
UserData = #'TR-user-data'{dialoguePortion = End#'End'.dialoguePortion,
componentPortion = End#'End'.components},
TrParms = #'TR-END'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
%% TR-END indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'END', indication, TrParms}),
{stop, normal, State};
%% End from TR-User (prearranged)
active({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END'),
EndParms#'TR-END'.termination == prearranged ->
{stop, normal, State};
%% End from TR-User (not prearranged)
active({'END', transaction, EndParms}, State)
when is_record(EndParms, 'TR-END') ->
DialoguePortion = (EndParms#'TR-END'.userData)#'TR-user-data'.dialoguePortion,
ComponentPortion = (EndParms#'TR-END'.userData)#'TR-user-data'.componentPortion,
End = #'End'{dialoguePortion = DialoguePortion, components = ComponentPortion},
%% Assemble TR-portion of END message
TPDU = list_to_binary('TR':encode('TCMessage', {'end', End})),
{SequenceControl, ReturnOption} = EndParms#'TR-END'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State};
%% Abort received from remote
active({'ABORT', received, SccpParms}, State)
when is_record(SccpParms, 'N-UNITDATA') ->
QOS = {SccpParms#'N-UNITDATA'.sequenceControl,
SccpParms#'N-UNITDATA'.returnOption},
{ok, Abort} = 'TR':decode('TCMessage', SccpParms#'N-UNITDATA'.userData),
%% TR-U-ABORT?
case Abort#'Abort'.reason of
{'p-abortCause', Cause} -> % No
TrParms = #'TR-P-ABORT'{qos = QOS,
transactionID = State#state.localTID,
pAbort = Cause},
%% TR-P-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms});
{'u-abortCause', Cause} -> % Yes
UserData = #'TR-user-data'{dialoguePortion = Cause},
TrParms = #'TR-U-ABORT'{qos = QOS,
transactionID = State#state.localTID,
userData = UserData},
%% TR-U-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'U-ABORT', indication, TrParms})
end,
{stop, normal, State};
%% Local Abort
active({'local-abort', received, Cause}, State) ->
TrParms = #'TR-P-ABORT'{qos = {false, false},
transactionID = State#state.localTID, pAbort= Cause},
%% TR-P-ABORT indication CSL <- TSL
gen_fsm:send_event(State#state.dha, {'TR', 'P-ABORT', indication, TrParms}),
{stop, normal, State};
%% Abort from TR-User
active({'ABORT', transaction, AbortParms}, State)
when is_record(AbortParms, 'TR-U-ABORT') ->
Cause = (AbortParms#'TR-U-ABORT'.userData)#'TR-user-data'.dialoguePortion,
Abort = #'Abort'{reason = {'u-abortCause', Cause}},
%% Assemble TR-portion of ABORT message
TPDU = list_to_binary('TR':encode('TCMessage', {abort, Abort})),
{SequenceControl, ReturnOption} = AbortParms#'TR-U-ABORT'.qos,
SccpParms = #'N-UNITDATA'{calledAddress = State#state.remote_address,
callingAddress = State#state.local_address,
sequenceControl = SequenceControl, returnOption = ReturnOption,
importance = none, userData = TPDU},
%% N-UNITDATA request TSL -> SCCP
gen_fsm:send_event(State#state.nsap, {'N', 'UNITDATA', request, SccpParms}),
{stop, normal, State}.
%% handle an event sent using gen_fsm:send_all_state_event/2
handle_event(Event, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Event]),
{next_state, StateName, State}.
%% handle an event sent using gen_fsm:sync_send_all_state_event/2,3
handle_sync_event(Event, _From, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Event]),
{next_state, StateName, State}.
%% handle any other message
handle_info(Info, StateName, State) ->
error_logger:format("transaction_fsm (~w) received unexpected message: ~w~n", [Info]),
{next_state, StateName, State}.
%% handle a shutdown request
terminate(_Reason, _StateName, State) ->
ets:delete(transaction, State#state.localTID),
%% signal TCO that we are stopping
gen_server:cast(State#state.supervisor, {'tsm-stopped', State#state.supref}).
%% handle updating state data due to a code replacement
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.

40
TCAP/src/Makefile Normal file
View File

@ -0,0 +1,40 @@
## $Id: Makefile,v 1.5 2005/02/10 05:20:17 vances Exp $
EBIN = ../ebin
ERL = erl
ERLC = erlc
EMULATOR = beam
ERLCFLAGS = -b $(EMULATOR) -o $(EBIN) -W -v +warn_unused_vars
$(EBIN)/%.$(EMULATOR):%.erl
$(ERLC) $(ERLCFLAGS) $<
BEAMS = $(EBIN)/tcap.$(EMULATOR) $(EBIN)/tcap_app.$(EMULATOR) \
$(EBIN)/tcap_sup.$(EMULATOR) \
$(EBIN)/tcap_sap_sup.$(EMULATOR) \
$(EBIN)/tcap_transaction_sup.$(EMULATOR) \
$(EBIN)/tcap_dialogue_sup.$(EMULATOR) \
$(EBIN)/tcap_components_sup.$(EMULATOR) \
$(EBIN)/tcap_invocation_sup.$(EMULATOR)
.PHONY: default
default: all
.PHONY: all
all: $(BEAMS) itu ansi
.PHONY: itu
itu:
cd itu && $(MAKE)
.PHONY: ansi
ansi:
cd ansi && $(MAKE)
.PHONY: clean
clean:
- rm -f $(BEAMS)
cd itu && $(MAKE) $@
cd ansi && $(MAKE) $@

109
TCAP/src/tcap.erl Normal file
View File

@ -0,0 +1,109 @@
%%% $Id: tcap.erl,v 1.10 2011/03/07 17:21:09 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc Transaction Capabilities Application Part
%%% <p>This module implements the user's API to the TCAP protocol
%%% stack application.Transaction Capabilities are </p>
%%%
%%% @reference <a href="index.html">TCAP User's Guide</a>
%%%
-module(tcap).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.10 $').
%% our published API functions
-export([start/0, stop/0]).
-export([open/3, close/1]).
%-export([start_tsl/3]).
-export([dialogueID/1, transactionID/1]).
%% @type tcap_options(). TCAP layer options
%% <p>A list of one or more of the following tuples.</p>
%% <dl>
%% <dt><tt>{variant, Variant}</tt></dt><dd><tt>itu | ansi</tt></dd>
%% </dl>
%% @end
%%----------------------------------------------------------------------
%% The API functions
%%----------------------------------------------------------------------
%% @spec () -> Result
%% Result = ok | {error, Reason}
%% Reason = term()
%%
%% @equiv application:start(tcap)
%%
start() ->
application:start(tcap).
%% @spec () -> Result
%% Result = ok | {error, Reason}
%% Reason = term()
%%
%% @equiv application:stop(tcap)
%%
stop() ->
application:stop(tcap).
%% @spec (TSL::pid(), TCU::pid(), Args) -> CSL
%% Args = [term()]
%% CSL = {DHA, CCO}
%% DHA = pid()
%% CCO = pid()
%%
%% @doc Start a new component sublayer (CSL).
%% <p>Called by the TC-User to initialize the TCAP layer for a new
%% dialogue.</p>
%%
%% <p><tt>TSL</tt> is the pid returned from a previous call to
%% <a href="#open-3"><tt>open/3</tt></a>.</p>
%%
%% <p><tt>TCU</tt> is the pid of the TC-User.</p>
%%
%% <p>Returns <tt>{DHA, CCO}</tt>; the pids of the dialogue handler
%% and component coordinator in the component sublayer.</p>.
%%
open(TSL, TCU, Args) ->
gen_server:call(TSL, {start_dialogue, TCU, Args}).
%% @spec (TSL::pid()) -> ok
%%
%% @doc Close a TCAP service layer.
%%
%% <p><tt>TSL</tt> is the pid returned in a previous call to
%% <a href="#open-3"><tt>open/3</tt></a>.</p>
%%
close(TSL) when is_pid(TSL) ->
gen_server:call(TSL, close).
%% @spec (TSL::pid()) -> tid()
%%
%% @doc Assign a new dialogue ID.
%%
%% <p><tt>TSL</tt> is the pid returned in a previous call to
%% <a href="#open-3"><tt>open/3</tt></a>.</p>
%%
dialogueID(TSL) when is_pid(TSL) ->
gen_server:call(TSL, dialogueID).
%% @equiv dialogueID/0
%%
transactionID(TSL) when is_pid(TSL) ->
dialogueID(TSL).

81
TCAP/src/tcap_app.erl Normal file
View File

@ -0,0 +1,81 @@
%%% $Id: tcap_app.erl,v 1.3 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2004-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc TCAP application callback module.
%%%
%%% @reference <a href="index.html">TCAP User's Guide</a>
%%%
%%% @private
-module(tcap_app).
-copyright('Copyright (c) 2004-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.3 $').
%% export application behaviour callbacks
-export([start/2, start_phase/3, prep_stop/1, stop/1, config_change/3]).
%% @spec(StartType, StartArgs::term()) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}
%% StartType = normal | {takeover,Node} | {failover,Node}
%% Node = node()
%% Pid = pid()
%% State = term()
%% Reason = term()
%%
%% @equiv //kernel/application:start/3
%%
start(normal, StartArgs) ->
ets:new(transaction, [named_table, public]),
{ok, SupRef} = application:get_env(supref),
supervisor:start_link(SupRef, tcap_sup, StartArgs).
%% @spec(Phase::atom(), StartType, PhaseArgs::term()) -> ok | {error, Reason}
%% StartType = normal | {takeover,Node} | {failover,Node}
%% Node = node()
%% Reason = term()
%%
%% @equiv //kernel/application:start_phase/3
%%
start_phase(_Phase, _StartType, _PhaseArgs) ->
ok.
%% @spec(State::term()) -> NewState
%% NewState = term()
%%
%% @equiv //kernel/application:prep_stop/1
%%
prep_stop(State) ->
State.
%% @spec(State) -> ok
%%
%% @equiv //kernel/application:stop/1
%%
stop(_State) ->
ok.
%% @spec(Changed, New, Removed) ->
%% Changed = [{Par,Val}]
%% New = [{Par,Val}]
%% Removed = [Par]
%% Par = atom()
%% Val = term()
%%
%% @equiv //kernel/application:config_change/3
%%
config_change(_Changed, _New, _Removed) ->
ok.

View File

@ -0,0 +1,33 @@
%%% $Id: tcap_components_sup.erl,v 1.2 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
-module(tcap_components_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.2 $').
-behaviour(supervisor).
%% call backs needed for supervisor behaviour
-export([init/1]).
init([USAP, ID]) ->
Name = list_to_atom("cco_" ++ integer_to_list(ID)),
StartArgs = [tcap_cco_server, [USAP, ID, self()], []],
StartFunc = {gen_fsm, start_link, StartArgs},
ChildSpec = {Name, StartFunc, temporary, 4000, worker,
[tcap_cco_server]},
{ok,{{one_for_all, 0, 1}, [ChildSpec]}}.

View File

@ -0,0 +1,40 @@
%%% $Id: tcap_dialogue_sup.erl,v 1.2 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
-module(tcap_dialogue_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.2 $').
-behaviour(supervisor).
%% call backs needed for supervisor behaviour
-export([init/1]).
%% when started from TCO
init({USAP, LocalTID, TCO, SupId}) ->
StartArgs = [tcap_dha_fsm, [{USAP, LocalTID, TCO, SupId, self()}], []],
StartFunc = {gen_fsm, start_link, StartArgs},
ChildSpec = {dha, StartFunc, permanent, 4000, worker,
[tcap_dha_fsm]},
{ok,{{one_for_all, 0, 1}, [ChildSpec]}};
%% when started from TSM
init({USAP, LocalTID, TCO}) ->
StartArgs = [tcap_dha_fsm, [{USAP, LocalTID, TCO, self()}], []],
StartFunc = {gen_fsm, start_link, StartArgs},
ChildSpec = {dha, StartFunc, permanent, 4000, worker,
[tcap_dha_fsm]},
{ok,{{one_for_all, 0, 1}, [ChildSpec]}}.

View File

@ -0,0 +1,33 @@
%%% $Id: tcap_invocation_sup.erl,v 1.2 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
-module(tcap_invocation_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.2 $').
-behaviour(supervisor).
%% call backs needed for supervisor behaviour
-export([init/1]).
init([USAP, InvokeID]) ->
Name = list_to_atom("ism_" ++ integer_to_list(InvokeID)),
StartArgs = [tcap_ism_fsm, [USAP, InvokeID], []],
StartFunc = {gen_fsm, start_link, StartArgs},
ChildSpec = {Name, StartFunc, temporary, 4000, worker,
[tcap_ism_sup]},
{ok,{{one_for_all, 0, 1}, [ChildSpec]}}.

45
TCAP/src/tcap_sap_sup.erl Normal file
View File

@ -0,0 +1,45 @@
%%% $Id: tcap_sap_sup.erl,v 1.5 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc TCAP service access point supervisor.
%%%
%%% @reference <a href="index.html">TCAP User's Guide</a>
%%%
%%% @private
-module(tcap_sap_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.5 $').
-behaviour(supervisor).
-export([init/1]).
%% @spec(StartArgs::term()) -> Result = {ok,{{RestartStrategy,MaxR,MaxT},[ChildSpec]}} | ignore
%% RestartStrategy = one_for_all | one_for_one | rest_for_one | simple_one_for_one
%% MaxR = MaxT = int()>=0
%% ChildSpec = child_spec()
%%
%% @see supervisor:init/1
%%
init([Module, Args, Options]) when is_list(Args), is_list(Options) ->
% Name = list_to_atom("tcap_ssn" ++ integer_to_list(SSN)),
StartArgs = [Module, [self()] ++ Args, Options],
StartFunc = {gen_server, start_link, StartArgs},
ChildSpec = {tco, StartFunc, permanent, 4000, worker, [Module, tcap_tco_server]},
{ok,{{one_for_one, 10, 60}, [ChildSpec]}}.

44
TCAP/src/tcap_sup.erl Normal file
View File

@ -0,0 +1,44 @@
%%% $Id: tcap_sup.erl,v 1.2 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
%%%
%%% @doc TCAP application top level supervisor.
%%%
%%% @reference <a href="index.html">TCAP User's Guide</a>
%%%
%%% @private
-module(tcap_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.2 $').
-behaviour(supervisor).
%% call backs needed for supervisor behaviour
-export([init/1]).
%% @spec(StartArgs::term()) -> Result = {ok,{{RestartStrategy,MaxR,MaxT},[ChildSpec]}} | ignore
%% RestartStrategy = one_for_all | one_for_one | rest_for_one | simple_one_for_one
%% MaxR = MaxT = int()>=0
%% ChildSpec = child_spec()
%%
%% @equiv //stdlib/supervisor:init/1
%%
init(_StartArgs) ->
StartMod = tcap_sap_sup,
StartFunc = {supervisor, start_link, [StartMod]},
ChildSpec = {sap_sup, StartFunc, permanent, infinity, supervisor, [StartMod]},
{ok,{{simple_one_for_one, 10, 60}, ChildSpec}}.

View File

@ -0,0 +1,32 @@
%%% $Id: tcap_transaction_sup.erl,v 1.2 2005/08/04 09:33:17 vances Exp $
%%%---------------------------------------------------------------------
%%% @copyright 2004-2005 Motivity Telecom Inc.
%%% @author Vance Shipley <vances@motivity.ca> [http://www.motivity.ca]
%%% @end
%%%
%%% Copyright Motivity Telecom Inc. 2003-2005
%%%
%%% All rights reserved. No part of this computer program(s) may be
%%% used, reproduced, stored in any retrieval system, or transmitted,
%%% in any form or by any means, electronic, mechanical, photocopying,
%%% recording, or otherwise without prior written permission of
%%% Motivity Telecom Inc.
%%%---------------------------------------------------------------------
-module(tcap_transaction_sup).
-copyright('Copyright (c) 2003-2005 Motivity Telecom Inc.').
-author('vances@motivity.ca').
-vsn('$Revision: 1.2 $').
-behaviour(supervisor).
%% call backs needed for supervisor behaviour
-export([init/1]).
init({NSAP, USAP, TID, SupRef}) ->
Name = list_to_atom("tsm_" ++ integer_to_list(TID)),
StartArgs = [tcap_tsm_fsm, [NSAP, USAP, TID, self(), SupRef], []],
StartFunc = {gen_fsm, start_link, StartArgs},
ChildSpec = {Name, StartFunc, permanent, 1000, worker, [tcap_tsm_fsm]},
{ok,{{one_for_all, 0, 1}, [ChildSpec]}}.