1
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
osmo-st-network/m2ua/M2UAMSG.st

234 lines
5.5 KiB
Smalltalk

"
(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: M2UAMSG [
| msg_class msg_type tags |
<category: 'OsmoNetwork-M2UA'>
<comment: 'I can parse a M2UA message from the wire, allow you
to see the class, type and include tags. In C the structure will
look like this:
struct m2ua_common_hdr {
uint8_t version;
uint8_t spare;
uint8_t msg_class;
uint8_t msg_type;
uint32_t msg_length;
uint8_t data[0];
} __attribute__((packed));
struct m2ua_parameter_hdr {
uint16_t tag;
uint16_t len;
uint8_t data[0];
} __attribute__((packed));
'>
M2UAMSG class >> parseFrom: aMsg [
<category: 'parsing'>
self logDataContext: aMsg area: #m2ua.
^ self new
parseFrom: aMsg readStream;
yourself.
]
M2UAMSG class >> fromClass: aClass type: aType [
<category: 'parsing'>
^ self new
instVarNamed: #msg_class put: aClass;
instVarNamed: #msg_type put: aType;
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
]
msgType [
<category: 'accessing'>
^ 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'>
self tags do: [:each |
(each isTag: aTag) ifTrue: [
^ each
]
].
^ aBlock value
]
tags [
<category: 'private'>
^ tags ifNil: [tags := OrderedCollection new]
]
parseFrom: 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.
]
writeOn: aMsg [
| tag_data |
<category: 'private'>
"Create the tag data"
tag_data := MessageBuffer new.
self tags do: [:each |
each writeOn: tag_data
].
aMsg putByte: M2UAConstants version.
aMsg putByte: M2UAConstants spare.
aMsg putByte: msg_class.
aMsg putByte: msg_type.
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
]
]