m2ua: Merge the ASP changes from Pharo to GST
This commit is contained in:
parent
372c2e0f0b
commit
6f7e0bcf8d
6
Makefile
6
Makefile
|
@ -45,7 +45,11 @@ UA = \
|
|||
ua/XUA.st
|
||||
|
||||
M2UA = \
|
||||
m2ua/M2UAConstants.st m2ua/M2UAMSG.st m2ua/M2UATag.st m2ua/M2UAStates.st
|
||||
m2ua/M2UAConstants.st m2ua/M2UAMSG.st m2ua/M2UATag.st m2ua/M2UAMessages.st \
|
||||
m2ua/M2UAStates.st m2ua/M2UAAspStateMachine.st \
|
||||
m2ua/M2UAApplicationServerProcess.st m2ua/M2UALayerManagement.st \
|
||||
m2ua/M2UAExamples.st m2ua/M2UATerminology.st m2ua/M2UATests.st
|
||||
|
||||
|
||||
OSMO = \
|
||||
osmo/LogAreaOsmo.st \
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
BlockClosure extend [
|
||||
value: arg1 value: arg2 value: arg3 value: arg4 [
|
||||
<category: '*OsmoNetwork'>
|
||||
"Evaluate the receiver passing arg1, arg2, arg3 and arg4 as the parameters"
|
||||
|
||||
<category: 'built ins'>
|
||||
<primitive: VMpr_BlockClosure_value>
|
||||
SystemExceptions.WrongArgumentCount signal
|
||||
]
|
||||
]
|
|
@ -0,0 +1,507 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UAApplicationServerProcess [
|
||||
| socket asp_active_block asp_down_block asp_inactive_block asp_up_block error_block notify_block sctp_confirm_block sctp_released_block sctp_restarted_block sctp_status_block established state t_ack lastMsg on_state_change as_state |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: 'I am a M2UA Application Server Process.
|
||||
|
||||
I have an internal state machine and a state and will be used by the
|
||||
M2UA Layer. I am written for the usage in a Media Gateway Controller
|
||||
and will also keep information about the Application Server itself.
|
||||
|
||||
If I need to be used on a Signalling Gateway (SG) I will need a dedicated
|
||||
M2UA Application Server class and state machine.
|
||||
|
||||
I can currently only manage a single interface. The specification allows
|
||||
a single ASP to send one ASPActive for one interface at a time.'>
|
||||
|
||||
M2UAApplicationServerProcess class >> initWith: aService [
|
||||
^self new
|
||||
socketService: aService;
|
||||
yourself
|
||||
]
|
||||
|
||||
M2UAApplicationServerProcess class >> new [
|
||||
^super new
|
||||
initialize;
|
||||
yourself
|
||||
]
|
||||
|
||||
onError: aBlock [
|
||||
"M-ERROR indication
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP or SGP reports that it has received an ERROR
|
||||
message from its peer."
|
||||
|
||||
<category: 'Primitives-LayerManagement'>
|
||||
error_block := aBlock
|
||||
]
|
||||
|
||||
onNotify: aBlock [
|
||||
"M-NOTIFY indication
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports that it has received a NOTIFY message
|
||||
from its peer."
|
||||
|
||||
<category: 'Primitives-LayerManagement'>
|
||||
notify_block := aBlock
|
||||
]
|
||||
|
||||
onSctpEstablished: aBlock [
|
||||
"M-SCTP_ESTABLISH confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP confirms to LM that it has established an SCTP association with an SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
sctp_confirm_block := aBlock
|
||||
]
|
||||
|
||||
onSctpReleased: aBlock [
|
||||
"M-SCTP_RELEASE confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP confirms to LM that it has released SCTP association with SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
sctp_released_block := aBlock
|
||||
]
|
||||
|
||||
onSctpRestarted: aBlock [
|
||||
"M-SCTP_RELEASE indication
|
||||
Direction: M2UA -> LM
|
||||
Purpose: SGP informs LM that ASP has released an SCTP association."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
sctp_restarted_block := aBlock
|
||||
]
|
||||
|
||||
onSctpStatus: aBlock [
|
||||
"M-SCTP_STATUS indication
|
||||
Direction: M2UA -> LM
|
||||
Purpose: M2UA reports status of SCTP association."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
sctp_status_block := aBlock
|
||||
]
|
||||
|
||||
sctpEstablish [
|
||||
"M-SCTP_ESTABLISH request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to establish an SCTP association with an SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
established := false.
|
||||
socket stop.
|
||||
socket start
|
||||
]
|
||||
|
||||
sctpRelease [
|
||||
"M-SCTP_RELEASE request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to release an SCTP association with SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
established := false.
|
||||
socket stop.
|
||||
t_ack ifNotNil: [t_ack cancel]
|
||||
]
|
||||
|
||||
sctpStatusRequest [
|
||||
"M-SCTP_STATUS request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests M2UA to report status of SCTP association."
|
||||
|
||||
<category: 'Primitives-LayerManagement-SCTP'>
|
||||
self notYetImplemented
|
||||
]
|
||||
|
||||
aspActive [
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
"M-ASP_ACTIVE request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to send an ASP ACTIVE message to the SGP."
|
||||
|
||||
| msg |
|
||||
self checkNextState: M2UAAspStateActive.
|
||||
msg := M2UAMSG new
|
||||
class: M2UAConstants clsASPTM;
|
||||
msgType: M2UAConstants asptmActiv;
|
||||
addTag: self createIdentIntTag;
|
||||
addTag: self createInfoTag;
|
||||
yourself.
|
||||
self send: msg
|
||||
]
|
||||
|
||||
aspDown [
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
"M-ASP_DOWN request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to stop its operation and send an ASP DOWN
|
||||
message to the SGP."
|
||||
|
||||
| msg |
|
||||
self checkNextState: M2UAAspStateDown.
|
||||
msg := M2UAMSG new
|
||||
class: M2UAConstants clsASPSM;
|
||||
msgType: M2UAConstants aspsmDown;
|
||||
addTag: self createAspIdentTag;
|
||||
addTag: self createInfoTag;
|
||||
yourself.
|
||||
self send: msg
|
||||
]
|
||||
|
||||
aspInactive [
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
"M-ASP_INACTIVE request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to send an ASP INACTIVE message to the SGP."
|
||||
|
||||
| msg |
|
||||
self checkNextState: M2UAAspStateInactive.
|
||||
msg := M2UAMSG new
|
||||
class: M2UAConstants clsASPTM;
|
||||
msgType: M2UAConstants asptmInactiv;
|
||||
addTag: self createIdentIntTag;
|
||||
addTag: self createInfoTag;
|
||||
yourself.
|
||||
self send: msg
|
||||
]
|
||||
|
||||
aspUp [
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
"M-ASP_UP request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to start its operation and send an ASP UP
|
||||
message to the SGP."
|
||||
|
||||
| msg |
|
||||
self checkNextState: M2UAAspStateInactive.
|
||||
msg := M2UAMSG new
|
||||
class: M2UAConstants clsASPSM;
|
||||
msgType: M2UAConstants aspsmUp;
|
||||
addTag: self createAspIdentTag;
|
||||
addTag: self createInfoTag;
|
||||
yourself.
|
||||
self send: msg
|
||||
]
|
||||
|
||||
onAspActive: aBlock [
|
||||
"M-ASP_ACTIVE confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports that is has received an ASP ACTIVE
|
||||
Acknowledgment message from the SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
asp_active_block := aBlock
|
||||
]
|
||||
|
||||
onAspDown: aBlock [
|
||||
"M-ASP_DOWN confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports that is has received an ASP DOWN Acknowledgment
|
||||
message from the SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
asp_down_block := aBlock
|
||||
]
|
||||
|
||||
onAspInactive: aBlock [
|
||||
"M-ASP_INACTIVE confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports that is has received an ASP INACTIVE
|
||||
Acknowledgment message from the SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
asp_inactive_block := aBlock
|
||||
]
|
||||
|
||||
onAspUp: aBlock [
|
||||
"M-ASP_UP confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports that it has received an ASP UP Acknowledgment
|
||||
message from the SGP."
|
||||
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
asp_up_block := aBlock
|
||||
]
|
||||
|
||||
onStateChange: aBlock [
|
||||
"A generic callback for all state changes"
|
||||
|
||||
<category: 'Primitives-LayerManagemennt-ASP'>
|
||||
on_state_change := aBlock
|
||||
]
|
||||
|
||||
deregisterLinkKey [
|
||||
"M-LINK_KEY_DEREG Request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to de-register Link Key with SG by sending
|
||||
DEREG REQ message."
|
||||
|
||||
<category: 'Primitives-LayerManagement-LinkKey'>
|
||||
self notYetImplemented
|
||||
]
|
||||
|
||||
onLinkKeyDeregistered: aBlock [
|
||||
"M-LINK_KEY_DEREG Confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports to LM that it has successfully received a
|
||||
DEREG RSP message from SG."
|
||||
|
||||
<category: 'Primitives-LayerManagement-LinkKey'>
|
||||
self notYetImplemented
|
||||
]
|
||||
|
||||
onLinkKeyRegistered: aBlock [
|
||||
"M-LINK_KEY_REG Confirm
|
||||
Direction: M2UA -> LM
|
||||
Purpose: ASP reports to LM that it has successfully received a REG
|
||||
RSP message from SG."
|
||||
|
||||
<category: 'Primitives-LayerManagement-LinkKey'>
|
||||
self notYetImplemented
|
||||
]
|
||||
|
||||
registerLinkKey [
|
||||
"M-LINK_KEY_REG Request
|
||||
Direction: LM -> M2UA
|
||||
Purpose: LM requests ASP to register Link Key with SG by sending REG
|
||||
REQ message."
|
||||
|
||||
<category: 'Primitives-LayerManagement-LinkKey'>
|
||||
self notYetImplemented
|
||||
]
|
||||
|
||||
hostname: aHostname port: aPort [
|
||||
"Select the SCTP hostname/port for the SG to connect to"
|
||||
|
||||
<category: 'configuration'>
|
||||
socket
|
||||
hostname: aHostname;
|
||||
port: aPort
|
||||
]
|
||||
|
||||
createAspIdentTag [
|
||||
<category: 'm2ua-tags'>
|
||||
^M2UATag initWith: M2UAConstants tagAspIdent data: #(1 2 3 4)
|
||||
]
|
||||
|
||||
createIdentIntTag [
|
||||
<category: 'm2ua-tags'>
|
||||
^M2UATag initWith: M2UAConstants tagIdentInt data: #(0 0 0 0)
|
||||
]
|
||||
|
||||
createInfoTag [
|
||||
<category: 'm2ua-tags'>
|
||||
^M2UATag initWith: M2UAConstants tagInfo
|
||||
data: 'Hello from Smalltalk' asByteArray
|
||||
]
|
||||
|
||||
callNotification: aBlock [
|
||||
"Inform the generic method first, then all the others"
|
||||
|
||||
<category: 'private'>
|
||||
on_state_change ifNotNil: [on_state_change value].
|
||||
aBlock ifNotNil: [aBlock value]
|
||||
]
|
||||
|
||||
checkNextState: nextState [
|
||||
"Check if nextState and state are compatible and if not
|
||||
throw an exception. TODO:"
|
||||
|
||||
<category: 'private'>
|
||||
self state = nextState
|
||||
ifTrue:
|
||||
[^self error: ('M2UA ASP already in state <1p>' expandMacrosWith: state)].
|
||||
(self state nextPossibleStates includes: nextState)
|
||||
ifFalse:
|
||||
[^self error: ('M2UA ASP illegal state transition from <1p> to <2p>.'
|
||||
expandMacrosWith: state
|
||||
with: nextState)]
|
||||
]
|
||||
|
||||
dispatchData: aByteArray [
|
||||
<category: 'private'>
|
||||
| msg |
|
||||
msg := M2UAMSG parseToClass: aByteArray.
|
||||
msg dispatchOnAsp: self
|
||||
]
|
||||
|
||||
dispatchNotification: aBlock [
|
||||
<category: 'private'>
|
||||
aBlock value
|
||||
]
|
||||
|
||||
internalReset [
|
||||
<category: 'private'>
|
||||
self socketService: socket
|
||||
]
|
||||
|
||||
moveToState: newState [
|
||||
<category: 'private'>
|
||||
((state nextPossibleStates includes: newState) or: [state = newState])
|
||||
ifFalse:
|
||||
[^self error: ('M2UA ASP Illegal state transition from <1p> to <2p>'
|
||||
expandMacrosWith: state
|
||||
with: newState)].
|
||||
|
||||
"TODO: general on entry, on exit"
|
||||
state := newState
|
||||
]
|
||||
|
||||
sctpConnected [
|
||||
<category: 'private'>
|
||||
"The connect was issued."
|
||||
|
||||
| wasEstablished |
|
||||
wasEstablished := established.
|
||||
established := true.
|
||||
state := M2UAAspStateDown.
|
||||
t_ack ifNotNil: [t_ack cancel].
|
||||
wasEstablished = true
|
||||
ifTrue: [sctp_confirm_block ifNotNil: [sctp_confirm_block value]]
|
||||
ifFalse: [sctp_restarted_block ifNotNil: [sctp_restarted_block value]]
|
||||
]
|
||||
|
||||
sctpReleased [
|
||||
"The SCTP connection has been released."
|
||||
|
||||
<category: 'private'>
|
||||
self moveToState: M2UAAspStateDown.
|
||||
established = true ifFalse: [^self].
|
||||
sctp_released_block ifNotNil: [sctp_released_block value]
|
||||
]
|
||||
|
||||
send: aMsg [
|
||||
"Forget about what we did before"
|
||||
|
||||
<category: 'private'>
|
||||
t_ack ifNotNil: [t_ack cancel].
|
||||
t_ack := TimerScheduler instance scheduleInSeconds: 2
|
||||
block:
|
||||
["Re-send the message"
|
||||
|
||||
self logNotice: ('<1p>:<2p> Sending message has timed out'
|
||||
expandMacrosWith: socket hostname
|
||||
with: socket port)
|
||||
area: #m2ua.
|
||||
self send: aMsg].
|
||||
socket nextPut: aMsg toMessage asByteArray
|
||||
]
|
||||
|
||||
initialize [
|
||||
<category: 'creation'>
|
||||
state := M2UAAspStateDown
|
||||
]
|
||||
|
||||
socketService: aService [
|
||||
<category: 'creation'>
|
||||
socket := aService.
|
||||
socket
|
||||
onSctpConnect: [self sctpConnected];
|
||||
onSctpReleased: [self sctpReleased];
|
||||
onSctpData:
|
||||
[:stream :assoc :ppid :data |
|
||||
ppid = 2
|
||||
ifFalse:
|
||||
[^self logNotice: 'M2UAApplicationServerProcess expecting PPID 2.'
|
||||
area: #m2ua].
|
||||
self dispatchData: data]
|
||||
]
|
||||
|
||||
handleAspActiveAck: aMsg [
|
||||
<category: 'dispatch'>
|
||||
t_ack cancel.
|
||||
self moveToState: M2UAAspStateActive.
|
||||
self callNotification: asp_active_block
|
||||
]
|
||||
|
||||
handleAspDownAck: aMsg [
|
||||
<category: 'dispatch'>
|
||||
t_ack cancel.
|
||||
as_state := nil.
|
||||
self moveToState: M2UAAspStateDown.
|
||||
self callNotification: asp_down_block
|
||||
]
|
||||
|
||||
handleAspInactiveAck: aMsg [
|
||||
<category: 'dispatch'>
|
||||
t_ack cancel.
|
||||
as_state := nil.
|
||||
self moveToState: M2UAAspStateInactive.
|
||||
self callNotification: asp_inactive_block
|
||||
]
|
||||
|
||||
handleAspUpAck: aMsg [
|
||||
<category: 'dispatch'>
|
||||
t_ack cancel.
|
||||
self moveToState: M2UAAspStateInactive.
|
||||
self callNotification: asp_inactive_block
|
||||
]
|
||||
|
||||
handleError: aMsg [
|
||||
"Cancel pending operations.. because something went wrong"
|
||||
|
||||
<category: 'dispatch'>
|
||||
t_ack cancel.
|
||||
error_block ifNotNil: [error_block value: aMsg]
|
||||
]
|
||||
|
||||
handleNotify: aMsg [
|
||||
<category: 'dispatch'>
|
||||
"Extract the status"
|
||||
|
||||
| tag type ident |
|
||||
tag := aMsg findTag: M2UAConstants tagStatus.
|
||||
tag ifNil: [^self].
|
||||
type := (tag data ushortAt: 1) swap16.
|
||||
ident := (tag data ushortAt: 3) swap16.
|
||||
type = M2UAConstants ntfyKindStateChange ifTrue: [as_state := ident].
|
||||
|
||||
"Inform our user about it"
|
||||
notify_block ifNotNil: [notify_block value: type value: ident]
|
||||
]
|
||||
|
||||
handleUnknownMessage: aMsg [
|
||||
"We got something we don't know. ignore it for now."
|
||||
|
||||
<category: 'dispatch'>
|
||||
|
||||
]
|
||||
|
||||
isASActive [
|
||||
<category: 'status'>
|
||||
^as_state = M2UAConstants ntfyStateASActive
|
||||
]
|
||||
|
||||
isASInactive [
|
||||
<category: 'status'>
|
||||
^as_state = M2UAConstants ntfyStateASInactive
|
||||
]
|
||||
|
||||
isASPending [
|
||||
<category: 'status'>
|
||||
^as_state = M2UAConstants ntfyStateASPending
|
||||
]
|
||||
|
||||
state [
|
||||
<category: 'accessing'>
|
||||
^state
|
||||
]
|
||||
]
|
|
@ -0,0 +1,106 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UAAspStateMachine [
|
||||
| state |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: 'I am the Application Server Process State machine. An
|
||||
pplication Server Process will create me to manage the state. My state
|
||||
machine is driven by calling the selectors from the events protocol.
|
||||
If you ask for an illegal state transition a DNU will be raised. Ath
|
||||
this point you should probably reset what you are doing and do proper
|
||||
error reporting.
|
||||
|
||||
This class is currently not used!'>
|
||||
|
||||
M2UAAspStateMachine class >> initialState [
|
||||
^M2UAAspStateDown
|
||||
]
|
||||
|
||||
M2UAAspStateMachine class >> new [
|
||||
^(self basicNew)
|
||||
initialize;
|
||||
yourself
|
||||
]
|
||||
|
||||
entered: aState [
|
||||
aState entered
|
||||
|
||||
"TODO notify users of the machine"
|
||||
]
|
||||
|
||||
initialize [
|
||||
state := self class initialState on: self
|
||||
]
|
||||
|
||||
left: aState [
|
||||
aState left
|
||||
|
||||
"TODO notify users of the machine"
|
||||
]
|
||||
|
||||
moveToState: aNewState [
|
||||
| oldState |
|
||||
oldState := state.
|
||||
state := (aNewState new)
|
||||
machine: self;
|
||||
yourself.
|
||||
self left: oldState.
|
||||
self entered: state
|
||||
]
|
||||
|
||||
state [
|
||||
^state class
|
||||
]
|
||||
|
||||
aspActive: anEvent [
|
||||
<category: 'events'>
|
||||
state onAspActive: anEvent
|
||||
]
|
||||
|
||||
aspDown: anEvent [
|
||||
<category: 'events'>
|
||||
state onAspDown: anEvent
|
||||
]
|
||||
|
||||
aspInactive: anEvent [
|
||||
<category: 'events'>
|
||||
state onAspInactive: anEvent
|
||||
]
|
||||
|
||||
aspUp: anEvent [
|
||||
<category: 'events'>
|
||||
state onAspUp: anEvent
|
||||
]
|
||||
|
||||
otherAspInAsOverrides: anEvent [
|
||||
<category: 'events'>
|
||||
state onOtherAspInAsOverrides: anEvent
|
||||
]
|
||||
|
||||
sctpCdi: anEvent [
|
||||
<category: 'events'>
|
||||
state onSctpCdi: anEvent
|
||||
]
|
||||
|
||||
sctpRi: anEvent [
|
||||
<category: 'events'>
|
||||
state onSctpRi: anEvent
|
||||
]
|
||||
]
|
|
@ -0,0 +1,42 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UAExamples [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
createAsp [
|
||||
"Create a SCTP network service"
|
||||
|
||||
| service asp manager |
|
||||
service := SCTPNetworkService new
|
||||
hostname: 'localhost';
|
||||
port: 2904;
|
||||
yourself.
|
||||
"Create the ASP"
|
||||
asp := M2UAApplicationServerProcess initWith: service.
|
||||
|
||||
"Create a Layer Management (LM) and start it"
|
||||
manager := M2UALayerManagement new
|
||||
applicationServerProcess: asp;
|
||||
targetState: M2UAAspStateActive;
|
||||
yourself.
|
||||
manager manage
|
||||
]
|
||||
]
|
|
@ -0,0 +1,127 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UALayerManagement [
|
||||
| targetState managedProcess |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: 'I am taking the LayerManagement control for an M2UAApplicationServiceProcess.
|
||||
|
||||
Currently you can tell me the ASP state this class should be in
|
||||
and I will react to to the events from the ASP.'>
|
||||
|
||||
applicationServerProcess: aProcess [
|
||||
<category: 'creation'>
|
||||
managedProcess := aProcess.
|
||||
managedProcess
|
||||
onSctpEstablished: [self sctpEstablished];
|
||||
onSctpRestarted: [self sctpEstablished];
|
||||
onError: [:msg | self m2uaError: msg];
|
||||
onNotify: [:type :ident | self m2uaNotify: type ident: ident];
|
||||
onAspActive: [self m2uaActive];
|
||||
onAspInactive: [self m2uaInactive];
|
||||
onAspDown: [self m2uaDown];
|
||||
onAspUp: [self m2uaUp]
|
||||
]
|
||||
|
||||
manage [
|
||||
"I begin to manage the process."
|
||||
|
||||
<category: 'creation'>
|
||||
managedProcess
|
||||
sctpRelease;
|
||||
sctpEstablish
|
||||
]
|
||||
|
||||
targetState: aState [
|
||||
"Use the M2UAAspState subclasses for the states"
|
||||
|
||||
<category: 'creation'>
|
||||
targetState := aState
|
||||
]
|
||||
|
||||
applicationServerProcess [
|
||||
<category: 'accessing'>
|
||||
^managedProcess
|
||||
]
|
||||
|
||||
m2uaActive [
|
||||
"E.g if the target state is already reached"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
managedProcess state = targetState ifTrue: [^self targetReached].
|
||||
targetState = M2UAAspStateInactive
|
||||
ifTrue: [managedProcess aspInactive]
|
||||
ifFalse: [managedProcess aspDown]
|
||||
]
|
||||
|
||||
m2uaDown [
|
||||
"E.g if the target state is already reached"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
managedProcess state = targetState ifTrue: [^self targetReached].
|
||||
|
||||
"There is only one way forward"
|
||||
managedProcess aspUp
|
||||
]
|
||||
|
||||
m2uaError: aMsg [
|
||||
<category: 'as-process-callbacks'>
|
||||
self logNotice: 'M2UA Error.' area: #m2ua
|
||||
]
|
||||
|
||||
m2uaInactive [
|
||||
"E.g if the target state is already reached"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
managedProcess state = targetState ifTrue: [^self targetReached].
|
||||
targetState = M2UAAspStateActive
|
||||
ifTrue: [managedProcess aspActive]
|
||||
ifFalse: [managedProcess aspDown]
|
||||
]
|
||||
|
||||
m2uaNotify: type ident: ident [
|
||||
"TODO: Check the type/ident"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
|
||||
]
|
||||
|
||||
m2uaUp [
|
||||
"E.g if the target state is already reached"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
managedProcess state = targetState ifTrue: [^self targetReached].
|
||||
targetState = M2UAAspStateActive
|
||||
ifTrue: [managedProcess aspActive]
|
||||
ifFalse: [managedProcess aspInactive]
|
||||
]
|
||||
|
||||
sctpEstablished [
|
||||
"E.g if the target state is already reached"
|
||||
|
||||
<category: 'as-process-callbacks'>
|
||||
managedProcess state = targetState ifTrue: [^self].
|
||||
"There is only one way forward"
|
||||
managedProcess aspUp
|
||||
]
|
||||
|
||||
targetReached [
|
||||
|
||||
]
|
||||
]
|
154
m2ua/M2UAMSG.st
154
m2ua/M2UAMSG.st
|
@ -57,6 +57,41 @@ struct m2ua_parameter_hdr {
|
|||
yourself.
|
||||
]
|
||||
|
||||
M2UAMSG class >> copyFrom: aMsg [
|
||||
<category: 'parsing'>
|
||||
^ self new
|
||||
msgClass: aMsg msgClass;
|
||||
msgType: aMsg msgType;
|
||||
tags: aMsg tags;
|
||||
yourself
|
||||
]
|
||||
|
||||
M2UAMSG class >> parseToClass: aMsg [
|
||||
<category: 'parsing'>
|
||||
"This will attempt to parse the message into one of the
|
||||
available subclasses."
|
||||
|
||||
| rawMsg msgClasses |
|
||||
rawMsg := self parseFrom: aMsg.
|
||||
|
||||
"A simple class based lookup"
|
||||
msgClasses :=
|
||||
{M2UAASPSMMessage.
|
||||
M2UAASPTMMessage.
|
||||
M2UAASPMGMTMessage}.
|
||||
msgClasses do:
|
||||
[:msgClass |
|
||||
rawMsg msgClass = msgClass messageClass
|
||||
ifTrue:
|
||||
[msgClass allSubclassesDo: [:class |
|
||||
class messageTag = rawMsg msgType
|
||||
ifTrue: [^class copyFrom: rawMsg]]]].
|
||||
|
||||
^self error: ('Unknown message class (<1p>) or message type (<2p>)'
|
||||
expandMacrosWith: rawMsg msgClass
|
||||
with: rawMsg msgType)
|
||||
]
|
||||
|
||||
msgClass [
|
||||
<category: 'accessing'>
|
||||
^ msg_class
|
||||
|
@ -67,6 +102,13 @@ struct m2ua_parameter_hdr {
|
|||
^ msg_type
|
||||
]
|
||||
|
||||
findTag: aTag [
|
||||
"I find a tag with a tag identifier"
|
||||
|
||||
<category: 'accessing'>
|
||||
^self findTag: aTag ifAbsent: [nil]
|
||||
]
|
||||
|
||||
findTag: aTag ifAbsent: aBlock [
|
||||
"I find a tag with a tag identifier"
|
||||
<category: 'accessing'>
|
||||
|
@ -85,42 +127,61 @@ struct m2ua_parameter_hdr {
|
|||
]
|
||||
|
||||
parseFrom: aStream [
|
||||
| version spare len end |
|
||||
<category: 'parsing'>
|
||||
|
||||
version := aStream next.
|
||||
version = M2UAConstants version ifFalse: [
|
||||
self logError:
|
||||
('M2UA version is wrong <1p>.' expandMacrosWith: version) area: #m2ua.
|
||||
self error: ('M2UA version is wrong <1p>.' expandMacrosWith: version).
|
||||
].
|
||||
|
||||
spare := aStream next.
|
||||
spare = M2UAConstants spare ifFalse: [
|
||||
self logError: ('M2UA spare is wrong <1p>.' expandMacrosWith: spare) area: #m2ua.
|
||||
self error: ('M2UA spare is wrong <1p>.' expandMacrosWith: spare).
|
||||
].
|
||||
|
||||
msg_class := aStream next.
|
||||
msg_type := aStream next.
|
||||
|
||||
len := ((aStream next: 4) uintAt: 1) swap32.
|
||||
aStream size - aStream position < (len - 8) ifTrue: [
|
||||
self logError: ('M2UA length is not plausible <1p> <2p>.'
|
||||
expandMacrosWith: len with: aStream size - aStream position)
|
||||
area: #m2ua.
|
||||
self error: ('M2UA length is not plausible <1p> <2p>.'
|
||||
expandMacrosWith: len with: aStream size - aStream position).
|
||||
].
|
||||
|
||||
tags := OrderedCollection new.
|
||||
end := aStream position + len - 8.
|
||||
|
||||
[aStream position < end] whileTrue: [
|
||||
tags add: (M2UATag fromStream: aStream)
|
||||
].
|
||||
<category: 'parsing'>
|
||||
| len |
|
||||
self parseVersion: aStream.
|
||||
self parseSpare: aStream.
|
||||
msg_class := aStream next.
|
||||
msg_type := aStream next.
|
||||
len := self parseLength: aStream.
|
||||
tags := self parseTags: aStream to: aStream position + len - 8
|
||||
]
|
||||
|
||||
parseLength: aStream [
|
||||
<category: 'parsing'>
|
||||
| len |
|
||||
len := ((aStream next: 4) uintAt: 1) swap32.
|
||||
aStream size - aStream position < (len - 8)
|
||||
ifTrue:
|
||||
[self
|
||||
logError: ('M2UA length is not plausible <1p> <2p>.' expandMacrosWith: len
|
||||
with: aStream size - aStream position)
|
||||
area: #m2ua.
|
||||
self
|
||||
error: ('M2UA length is not plausible <1p> <2p>.' expandMacrosWith: len
|
||||
with: aStream size - aStream position)].
|
||||
^len
|
||||
]
|
||||
|
||||
parseSpare: aStream [
|
||||
<category: 'parsing'>
|
||||
| spare |
|
||||
spare := aStream next.
|
||||
spare = M2UAConstants spare
|
||||
ifFalse:
|
||||
[self logError: ('M2UA spare is wrong <1p>.' expandMacrosWith: spare)
|
||||
area: #m2ua.
|
||||
self error: ('M2UA spare is wrong <1p>.' expandMacrosWith: spare)]
|
||||
]
|
||||
|
||||
parseTags: aStream to: end [
|
||||
<category: 'parsing'>
|
||||
tags := OrderedCollection new.
|
||||
[aStream position < end]
|
||||
whileTrue: [tags add: (M2UATag fromStream: aStream)].
|
||||
^tags
|
||||
]
|
||||
|
||||
parseVersion: aStream [
|
||||
<category: 'parsing'>
|
||||
| version |
|
||||
version := aStream next.
|
||||
version = M2UAConstants version
|
||||
ifFalse:
|
||||
[self logError: ('M2UA version is wrong <1p>.' expandMacrosWith: version)
|
||||
area: #m2ua.
|
||||
self error: ('M2UA version is wrong <1p>.' expandMacrosWith: version)]
|
||||
]
|
||||
addTag: aTag [
|
||||
<category: 'encoding'>
|
||||
self tags add: aTag.
|
||||
|
@ -143,5 +204,30 @@ struct m2ua_parameter_hdr {
|
|||
aMsg putLen32: tag_data size + 8.
|
||||
aMsg putByteArray: tag_data.
|
||||
]
|
||||
|
||||
class: aClass [
|
||||
<category: 'creation'>
|
||||
msg_class := aClass
|
||||
]
|
||||
|
||||
msgClass: aClass [
|
||||
<category: 'creation'>
|
||||
self class: aClass
|
||||
]
|
||||
|
||||
msgType: aType [
|
||||
<category: 'creation'>
|
||||
msg_type := aType
|
||||
]
|
||||
|
||||
tags: aTags [
|
||||
<category: 'creation'>
|
||||
tags := aTags
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleUnknownMessage: self
|
||||
]
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
"
|
||||
(C) 2011-2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
M2UAMSG subclass: M2UAASPSMMessage [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: 'Application Server Process State Maintenance (ASPSM) messages'>
|
||||
|
||||
M2UAASPSMMessage class >> messageClass [
|
||||
^M2UAConstants clsASPSM
|
||||
]
|
||||
]
|
||||
|
||||
M2UAMSG subclass: M2UAASPTMMessage [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAASPTMMessage class >> messageClass [
|
||||
^M2UAConstants clsASPTM
|
||||
]
|
||||
]
|
||||
|
||||
M2UAMSG subclass: M2UAASPMGMTMessage [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAASPMGMTMessage class >> messageClass [
|
||||
^M2UAConstants clsMgmt
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessHeartbeatAck [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessHeartbeatAck class >> messageTag [
|
||||
^M2UAConstants aspsmBeatAck
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessDown [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessDown class >> messageTag [
|
||||
^M2UAConstants aspsmDown
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspDown: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessHeartbeat [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessHeartbeat class >> messageTag [
|
||||
^M2UAConstants aspsmBeat
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessDownAck [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessDownAck class >> messageTag [
|
||||
^M2UAConstants aspsmDownAck
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspDownAck: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessUp [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessUp class >> messageTag [
|
||||
^M2UAConstants aspsmUp
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspUp: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPTMMessage subclass: M2UAApplicationServerProcessInactiveAck [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessInactiveAck class >> messageTag [
|
||||
^M2UAConstants asptmInactivAck
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspInactiveAck: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPTMMessage subclass: M2UAApplicationServerProcessActive [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessActive class >> messageTag [
|
||||
^M2UAConstants asptmActiv
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspActive: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPTMMessage subclass: M2UAApplicationServerProcessInactive [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessInactive class >> messageTag [
|
||||
^M2UAConstants asptmInactiv
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspInactive: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPMGMTMessage subclass: M2UAApplicationServerProcessNotify [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessNotify class >> messageTag [
|
||||
^M2UAConstants mgmtNtfy
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleNotify: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPMGMTMessage subclass: M2UAApplicationServerProcessError [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessError class >> messageTag [
|
||||
^M2UAConstants mgmtError
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleError: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPTMMessage subclass: M2UAApplicationServerProcessActiveAck [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessActiveAck class >> messageTag [
|
||||
^M2UAConstants asptmActivAck
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspActiveAck: self
|
||||
]
|
||||
]
|
||||
|
||||
M2UAASPSMMessage subclass: M2UAApplicationServerProcessUpAck [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAApplicationServerProcessUpAck class >> messageTag [
|
||||
^M2UAConstants aspsmUpAck
|
||||
]
|
||||
|
||||
dispatchOnAsp: anAsp [
|
||||
<category: 'm2ua-asp-dispatch'>
|
||||
anAsp handleAspUpAck: self
|
||||
]
|
||||
]
|
|
@ -42,6 +42,7 @@ STInST.RBProgramNodeVisitor subclass: M2UAStateMachineVisitor [
|
|||
|
||||
|
||||
Object subclass: M2UAStateBase [
|
||||
| machine |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: 'I am the base class of all M2UA state machines. My direct subclasses are state machines and their subclasses are the individual states that make up the statemachine.'>
|
||||
|
@ -82,6 +83,31 @@ Object subclass: M2UAStateBase [
|
|||
nextPutAll: '}';
|
||||
contents
|
||||
]
|
||||
|
||||
M2UAStateBase class >> on: aMachine [
|
||||
"Create a new state for a machine"
|
||||
|
||||
^self new
|
||||
machine: aMachine;
|
||||
yourself
|
||||
]
|
||||
|
||||
entered [
|
||||
"The state has been entered"
|
||||
]
|
||||
|
||||
left [
|
||||
"The state has been left"
|
||||
]
|
||||
|
||||
machine: aMachine [
|
||||
machine := aMachine
|
||||
]
|
||||
|
||||
moveToState: aNewState [
|
||||
<category: 'transition'>
|
||||
machine moveToState: aNewState
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
|
@ -147,6 +173,10 @@ M2UAStateBase subclass: M2UAAspState [
|
|||
|
||||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: 'I am the base class of the ASP State Machine from RFC 3331 on Page 61.'>
|
||||
|
||||
M2UAAspState class >> nextPossibleStates [
|
||||
^self subclassResponsibility
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
|
@ -156,6 +186,10 @@ M2UAAspState subclass: M2UAAspStateActive [
|
|||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAAspStateActive class >> nextPossibleStates [
|
||||
^ {M2UAAspStateInactive. M2UAAspStateDown}
|
||||
]
|
||||
|
||||
onAspDown: anEvent [
|
||||
<category: 'state-changes'>
|
||||
self moveToState: M2UAAspStateDown
|
||||
|
@ -189,6 +223,10 @@ M2UAAspState subclass: M2UAAspStateDown [
|
|||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAAspStateDown class >> nextPossibleStates [
|
||||
^{M2UAAspStateInactive}
|
||||
]
|
||||
|
||||
onAspUp: anEvent [
|
||||
<category: 'state-changes'>
|
||||
^self moveToState: M2UAAspStateInactive
|
||||
|
@ -202,6 +240,10 @@ M2UAAspState subclass: M2UAAspStateInactive [
|
|||
<category: 'OsmoNetwork-M2UA-States'>
|
||||
<comment: nil>
|
||||
|
||||
M2UAAspStateInactive class >> nextPossibleStates [
|
||||
^ {M2UAAspStateActive. M2UAAspStateDown}
|
||||
]
|
||||
|
||||
onAspActive: anEvent [
|
||||
<category: 'state-changes'>
|
||||
^self moveToState: M2UAAspStateActive
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
"
|
||||
(C) 2011-2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UATerminology [
|
||||
|
||||
<category: 'OsmoNetwork-M2UA'>
|
||||
<comment: 'I attempt to help with the terminology for M2UA.
|
||||
|
||||
M2UA is defined in IETF RFC 3331 and is actually from a family
|
||||
of closely related RFCs for M3UA, SUA, M2PA.
|
||||
|
||||
The whole idea is that one can adapt the M2UA layer from the classlic
|
||||
E1/T1 timeslots to the more modern SCTP (SIGTRAN). MTP3 and above will
|
||||
not notice the difference.
|
||||
|
||||
The communication for M2UA is between two systems, both should be
|
||||
configurable as either a client or server (listening for incoming SCTP
|
||||
connections).
|
||||
|
||||
In general the communication is between a Signalling Gateway
|
||||
(SG) and a Media Gateway Controller (MGC). In our world the MGC
|
||||
would is the MSC/HLR/VLR/AuC.
|
||||
|
||||
What makes things complicated is the cardinality of systems. There is
|
||||
an Application Server (AS), this can have multiple Application Server
|
||||
Processes (ASP) for one or multiple MTP links. While the RFC onlys
|
||||
says that the SG should the list of ASs in practice both ends need to
|
||||
do it.'>
|
||||
]
|
|
@ -0,0 +1,222 @@
|
|||
"
|
||||
(C) 2013 by Holger Hans Peter Freyther
|
||||
All Rights Reserved
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"
|
||||
|
||||
Object subclass: M2UAASMock [
|
||||
| socket |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA-Tests'>
|
||||
<comment: 'A simple mock'>
|
||||
|
||||
socketService: aSocket [
|
||||
<category: 'creation'>
|
||||
socket := aSocket
|
||||
]
|
||||
|
||||
handleAspActive: aMsg [
|
||||
<category: 'dispatch'>
|
||||
| ret |
|
||||
ret := M2UAMSG new
|
||||
msgClass: M2UAConstants clsASPTM;
|
||||
msgType: M2UAConstants asptmActivAck;
|
||||
yourself.
|
||||
socket sendToAsp: ret toMessage asByteArray
|
||||
]
|
||||
|
||||
handleAspDown: aMsg [
|
||||
<category: 'dispatch'>
|
||||
| ret |
|
||||
ret := M2UAMSG new
|
||||
msgClass: M2UAConstants clsASPSM;
|
||||
msgType: M2UAConstants aspsmDownAck;
|
||||
yourself.
|
||||
socket sendToAsp: ret toMessage asByteArray
|
||||
]
|
||||
|
||||
handleAspInactive: aMsg [
|
||||
<category: 'dispatch'>
|
||||
| ret |
|
||||
ret := M2UAMSG new
|
||||
msgClass: M2UAConstants clsASPTM;
|
||||
msgType: M2UAConstants asptmInactivAck;
|
||||
yourself.
|
||||
socket sendToAsp: ret toMessage asByteArray
|
||||
]
|
||||
|
||||
handleAspUp: aMsg [
|
||||
<category: 'dispatch'>
|
||||
| ret |
|
||||
ret := M2UAMSG new
|
||||
msgClass: M2UAConstants clsASPSM;
|
||||
msgType: M2UAConstants aspsmUpAck;
|
||||
yourself.
|
||||
socket sendToAsp: ret toMessage asByteArray
|
||||
]
|
||||
|
||||
onData: aData [
|
||||
| msg |
|
||||
msg := M2UAMSG parseToClass: aData.
|
||||
msg dispatchOnAsp: self
|
||||
]
|
||||
]
|
||||
|
||||
Object subclass: SCTPNetworkServiceMock [
|
||||
| on_connect on_released on_data as asp |
|
||||
|
||||
<category: 'OsmoNetwork-M2UA-Tests'>
|
||||
<comment: 'I mock SCTPand directly connect an AS with an ASP.'>
|
||||
|
||||
onSctpConnect: aBlock [
|
||||
<category: 'notification'>
|
||||
on_connect := aBlock
|
||||
]
|
||||
|
||||
applicationServer: anAs [
|
||||
<category: 'creation'>
|
||||
as := anAs
|
||||
]
|
||||
|
||||
applicationServerProcess: anAsp [
|
||||
<category: 'creation'>
|
||||
asp := anAsp
|
||||
]
|
||||
|
||||
onSctpData: aBlock [
|
||||
<category: 'creation'>
|
||||
on_data := aBlock
|
||||
]
|
||||
|
||||
onSctpReleased: aBlock [
|
||||
<category: 'creation'>
|
||||
on_released := aBlock
|
||||
]
|
||||
|
||||
hostname [
|
||||
<category: 'management'>
|
||||
^'localhost'
|
||||
]
|
||||
|
||||
port [
|
||||
<category: 'management'>
|
||||
^0
|
||||
]
|
||||
|
||||
start [
|
||||
"Nothing"
|
||||
|
||||
<category: 'management'>
|
||||
on_connect value
|
||||
]
|
||||
|
||||
stop [
|
||||
<category: 'management'>
|
||||
on_released value
|
||||
]
|
||||
|
||||
nextPut: aMsg [
|
||||
as onData: aMsg
|
||||
]
|
||||
|
||||
sendToAsp: aMsg [
|
||||
on_data
|
||||
value: nil
|
||||
value: nil
|
||||
value: 2
|
||||
value: aMsg
|
||||
]
|
||||
]
|
||||
|
||||
TestCase subclass: M2UAApplicationServerProcessTest [
|
||||
|
||||
<comment: 'A M2UAApplicationServerProcessTest is a test class for testing the behavior of M2UAApplicationServerProcess'>
|
||||
<category: 'OsmoNetwork-M2UA-Tests'>
|
||||
|
||||
testCreation [
|
||||
| asp |
|
||||
asp := M2UAApplicationServerProcess new
|
||||
onAspActive: [];
|
||||
onAspDown: [];
|
||||
onAspInactive: [];
|
||||
onAspUp: [];
|
||||
onStateChange: [];
|
||||
onError: [:msg | ];
|
||||
onNotify: [:type :ident | ];
|
||||
onSctpEstablished: [];
|
||||
onSctpReleased: [];
|
||||
onSctpRestarted: [];
|
||||
onSctpStatus: [];
|
||||
yourself
|
||||
]
|
||||
|
||||
testStateTransitions [
|
||||
| mock as asp |
|
||||
mock := SCTPNetworkServiceMock new.
|
||||
as := M2UAASMock new
|
||||
socketService: mock;
|
||||
yourself.
|
||||
asp := M2UAApplicationServerProcess initWith: mock.
|
||||
mock
|
||||
applicationServer: as;
|
||||
applicationServerProcess: asp.
|
||||
|
||||
"This works as the mock will handle this synchronously"
|
||||
self assert: asp state = M2UAAspStateDown.
|
||||
asp
|
||||
sctpEstablish;
|
||||
aspUp.
|
||||
self assert: asp state = M2UAAspStateInactive.
|
||||
|
||||
"Now bring it down and up again"
|
||||
asp aspDown.
|
||||
self assert: asp state = M2UAAspStateDown.
|
||||
asp
|
||||
aspUp;
|
||||
aspActive.
|
||||
self assert: asp state = M2UAAspStateActive.
|
||||
asp aspDown.
|
||||
self assert: asp state = M2UAAspStateDown.
|
||||
asp
|
||||
aspUp;
|
||||
aspActive;
|
||||
aspInactive.
|
||||
self assert: asp state = M2UAAspStateInactive.
|
||||
asp sctpRelease.
|
||||
self assert: asp state = M2UAAspStateDown
|
||||
]
|
||||
]
|
||||
|
||||
TestCase subclass: M2UAAspStateMachineTest [
|
||||
|
||||
<comment: 'A M2UAAspStateMachineTest is a test class for testing the behavior of M2UAAspStateMachine'>
|
||||
<category: 'OsmoNetwork-M2UA-Tests'>
|
||||
|
||||
testLegalTransitions [
|
||||
| machine |
|
||||
machine := M2UAAspStateMachine new.
|
||||
self assert: machine state = M2UAAspStateDown.
|
||||
machine aspUp: 'Link is up'.
|
||||
self assert: machine state = M2UAAspStateInactive.
|
||||
machine aspActive: 'Active'.
|
||||
self assert: machine state = M2UAAspStateActive.
|
||||
machine aspInactive: 'Inactive'.
|
||||
self assert: machine state = M2UAAspStateInactive.
|
||||
machine aspActive: 'Active'.
|
||||
self assert: machine state = M2UAAspStateActive.
|
||||
machine sctpCdi: 'Connection is gone'.
|
||||
self assert: machine state = M2UAAspStateDown
|
||||
]
|
||||
]
|
18
package.xml
18
package.xml
|
@ -9,6 +9,7 @@
|
|||
<prereq>Parser</prereq>
|
||||
|
||||
<filein>core/Extensions.st</filein>
|
||||
<filein>core/ExtensionsGST.st</filein>
|
||||
<filein>core/MessageStructure.st</filein>
|
||||
<filein>core/MessageBuffer.st</filein>
|
||||
<filein>core/LogAreas.st</filein>
|
||||
|
@ -28,10 +29,21 @@
|
|||
<filein>sccp/SCCPGlobalTitleTranslation.st</filein>
|
||||
<filein>mtp3/MTP3Messages.st</filein>
|
||||
<filein>ua/XUA.st</filein>
|
||||
|
||||
<filein>m2ua/M2UAConstants.st</filein>
|
||||
<filein>m2ua/M2UAStates.st</filein>
|
||||
<filein>m2ua/M2UATag.st</filein>
|
||||
<filein>m2ua/M2UAMSG.st</filein>
|
||||
<filein>m2ua/M2UAMessages.st</filein>
|
||||
<filein>m2ua/M2UAStates.st</filein>
|
||||
<filein>m2ua/M2UAAspStateMachine.st</filein>
|
||||
<filein>m2ua/M2UAApplicationServerProcess.st</filein>
|
||||
<filein>m2ua/M2UALayerManagement.st</filein>
|
||||
<filein>m2ua/M2UATerminology.st</filein>
|
||||
<filein>m2ua/M2UAExamples.st</filein>
|
||||
|
||||
|
||||
|
||||
<filein>osmo/LogAreaOsmo.st</filein>
|
||||
<filein>osmo/OsmoUDPSocket.st</filein>
|
||||
<filein>osmo/OsmoCtrlLogging.st</filein>
|
||||
|
@ -48,13 +60,16 @@
|
|||
<sunit>Osmo.IPAGSTTests</sunit>
|
||||
<sunit>Osmo.IPAMsgTests</sunit>
|
||||
<sunit>Osmo.MessageBufferTest</sunit>
|
||||
<sunit>Osmo.M2UAMSGTests</sunit>
|
||||
<sunit>Osmo.ISUPGeneratedTest</sunit>
|
||||
<sunit>Osmo.OsmoUDPSocketTest</sunit>
|
||||
<sunit>Osmo.TLVDescriptionTest</sunit>
|
||||
<sunit>Osmo.CtrlGrammarTest</sunit>
|
||||
<sunit>Osmo.CtrlParserTest</sunit>
|
||||
|
||||
<sunit>Osmo.M2UAMSGTests</sunit>
|
||||
<sunit>Osmo.M2UAApplicationServerProcessTest</sunit>
|
||||
<sunit>Osmo.M2UAAspStateMachineTest</sunit>
|
||||
|
||||
<sunit>Osmo.MTP3LabelTest</sunit>
|
||||
<sunit>Osmo.MTP3SLTAMSGTest</sunit>
|
||||
<sunit>Osmo.MTP3SLTMMSGTest</sunit>
|
||||
|
@ -66,6 +81,7 @@
|
|||
<filein>isup/ISUPTests.st</filein>
|
||||
<filein>ipa/IPATests.st</filein>
|
||||
<filein>osmo/OsmoCtrlGrammarTest.st</filein>
|
||||
<filein>m2ua/M2UATests.st</filein>
|
||||
<filein>mtp3/MTP3MessagesTests.st</filein>
|
||||
</test>
|
||||
</package>
|
||||
|
|
Reference in New Issue