public static interface SipMessage.Builder<T extends SipMessage>
SipMessage
you will end up with a SipMessage.Builder
.
The pattern of the SipMessage
builders is that you can specify the various
headers, request-uri, body etc through the withXXX-methods and then upon build time,
the builder will call out to any registered functions (as registered through the onXXX-methods)
allowing the application to make any last minute changes.
In a real SIP stack there are headers within a SipMessage
that typically needs to be
manipulated before being sent out over the network. One such header is the ViaHeader
where
the transport layer typically has the responsibility to fill out the ip and port from which the
message was sent as well as specify the transport used.
The idea is as follows: everything within this SIP library is immutable, which includes SipRequest
and SipResponse
s but if you build a stack, the stack may actually need to change headers
before creating the "final" version of the SipMessage
which is then sent out over the network.
The typical use case is of course the ViaHeader
where it typically isn't known by the application
which protocol, or interface of the stack will be used. This is only known at the time the message
is about to be sent out and will (should) be filled out by the transport layer. Therefore, if you build
a stack you probably want to pass down a SipMessage.Builder
to be "sent" all the way down to the transport layer
which will
All callback as registered through the various onXXXX-methods allow for multiple callbacks to be registered.
They are called in reverse order from the order of registration.
TODO: don't think I will do this anymore. If you add the same header via an of the three methods then
TODO: that header will be included three times. I.e., if you call withHeaderBuilder and withHeader and
TODO: the same header also exists in the template then it will be included that many times.
Order of precedence where the top one "wins" over the others:
Builder#withFromHeader(AddressParametersHeader.Builder)
method then that builder will be used even if this builder is based off
another SipMessage
(which then serves as a "template")
TODO: add and/or clarify how headers are treated in general, i.e.:
A header can be added to the final SipMessage
that is being built via 1 out of 3 ways:
SipMessage
we are using as a template
for constructing this new sip message.onHeader(Function)
io.pkts.packet.sip.SipMessage.Builder#onHeaderBuilder(Consumer)
default boolean isSipRequestBuilder()
default boolean isSipResponseBuilder()
default SipMessage.Builder<SipRequest> toSipRequestBuilder()
default SipMessage.Builder<SipResponse> toSipResponseBuilder()
SipMessage.Builder<T> withNoDefaults()
ToHeader
- the request-uri will be used to construct the to-header
in the case of a request. For a response you have to supply itCSeqHeader
- a new CSeq header will be added where the
method is the same as this message and the sequence number is set to 1CallIdHeader
- a new random call-id will be addedMaxForwardsHeader
- if we are building a request, a max forwards of 70 will be addedContentLengthHeader
- Will be added if there is a body
on the message and the length set to the correct length.SipMessage
you are then responsible for adding
the mandatory headers to this builder (unless you don't care of course
because perhaps you are building a test tool meant to torture test
a SIP server).SipMessage.Builder<T> onHeader(java.util.function.Function<SipHeader,SipHeader> f) throws IllegalStateException
SipMessage
you have a chance to change the value of that header. You do so
by registering a function that accepts a SipHeader
as an argument and that
returns a SipHeader
, which is the header that will be pushed onto the new
SipMessage
. If you do not want to include the header, then simply return
null and the header will be dropped.
If you wish to leave the header un-touched, then simply return it has is.
Also note that the following headers have explicit "on" methods (they are considered
to be "system" headers):
The reason is simply because these are typically manipulated before
copying them over to a new request or response (e.g., Max Forwards is decremented,
CSeq may increase etc) and therefore it makes life easier if those headers are
"down casted" to their specific types.f
- IllegalStateException
- in case a function already had been registered with
this builder.SipMessage.Builder<T> withHeader(SipHeader header)
SipMessage
used as a template, then those headers will
TODO: this is essentially an "add header" so should it be called that?
TODO: and then should there be a set version? Just goes bad with a fluent
TODO: naming.header
- SipMessage.Builder<T> withHeaders(List<SipHeader> headers)
SipMessage.Builder<T> withPushHeader(SipHeader header)
SipMessage.Builder<T> onFromHeader(java.util.function.Consumer<AddressParametersHeader.Builder<FromHeader>> f)
SipMessage.Builder<T> withFromHeader(FromHeader from)
FromHeader
to be used by the new SipMessage
. If there already
is a FromHeader
present, either through a template or because this method
has been called previously, that value will be overwritten.from
- SipMessage.Builder<T> withFromHeader(String from)
SipMessage.Builder<T> onToHeader(java.util.function.Consumer<AddressParametersHeader.Builder<ToHeader>> f)
SipMessage.Builder<T> withToHeader(ToHeader to)
SipMessage.Builder<T> withToHeader(String to)
SipMessage.Builder<T> onContactHeader(java.util.function.Consumer<AddressParametersHeader.Builder<ContactHeader>> f)
SipMessage.Builder<T> withContactHeader(ContactHeader contact)
SipMessage.Builder<T> onCSeqHeader(java.util.function.Consumer<CSeqHeader.Builder> f)
SipMessage.Builder<T> withCSeqHeader(CSeqHeader cseq)
SipMessage.Builder<T> onMaxForwardsHeader(java.util.function.Consumer<MaxForwardsHeader.Builder> f)
SipMessage.Builder<T> withMaxForwardsHeader(MaxForwardsHeader maxForwards)
SipMessage.Builder<T> withCallIdHeader(CallIdHeader callID)
SipMessage.Builder<T> onTopMostRouteHeader(java.util.function.Consumer<AddressParametersHeader.Builder<RouteHeader>> f)
onRouteHeader(Consumer)
f
- SipMessage.Builder<T> onRouteHeader(java.util.function.Consumer<AddressParametersHeader.Builder<RouteHeader>> f)
onTopMostRouteHeader(Consumer)
is called instead)f
- SipMessage.Builder<T> withRouteHeader(RouteHeader route)
withRouteHeaders(RouteHeader...)
.
If you want to push a Route header to a potentially already existing list
of Record Route headers, then use withTopMostRouteHeader(RouteHeader)
route
- SipMessage.Builder<T> withRouteHeaders(RouteHeader... routes)
routes
- SipMessage.Builder<T> withRouteHeaders(List<RouteHeader> routes)
SipMessage.Builder<T> withTopMostRouteHeader(RouteHeader route)
route
- SipMessage.Builder<T> withPoppedRoute()
RouteHeader
via the method
withTopMostRouteHeader(RouteHeader)
followed
by this method, then the route you just added will be removed again. Order is important!
Note: if you actually wanted to know the value of that RouteHeader
then you should
really have checked it on the SipMessage
you received and not on the builder
object.SipMessage.Builder<T> withNoRoutes()
RouteHeader
s
that e.g. were automatically copied from another SipRequest
that was
used as a template. A common scenario is that you are building a B2BUA acting
as the border police to your network and you simply cannot trust incoming requests
and as such, you should not honor externally pushed routes, since if you did, an
attacker could by-pass your next hop by forcing the request to go to somewhere else.SipMessage.Builder<T> onTopMostRecordRouteHeader(java.util.function.Consumer<AddressParametersHeader.Builder<RecordRouteHeader>> f)
onRecordRouteHeader(Consumer)
f
- SipMessage.Builder<T> onRecordRouteHeader(java.util.function.Consumer<AddressParametersHeader.Builder<RecordRouteHeader>> f)
onTopMostRecordRouteHeader(Consumer)
is called instead)f
- SipMessage.Builder<T> withRecordRouteHeader(RecordRouteHeader recordRoute)
withRecordRouteHeaders(RecordRouteHeader...)
.
If you want to push a Record Route header to a potentially already existing list
of Record Route headers, then userecordRoute
- SipMessage.Builder<T> withRecordRouteHeaders(RecordRouteHeader... recordRoute)
recordRoute
- SipMessage.Builder<T> withRecordRouteHeaders(List<RecordRouteHeader> recordRoute)
SipMessage.Builder<T> withTopMostRecordRouteHeader(RecordRouteHeader recordRoute)
recordRoute
- SipMessage.Builder<T> onRequestURI(java.util.function.Function<SipURI,SipURI> f)
f
- SipMessage.Builder<T> onTopMostViaHeader(java.util.function.Consumer<ViaHeader.Builder> f)
io.pkts.packet.sip.SipMessage.Builder#onViaHeader(Consumer)
consumerf
- SipMessage.Builder<T> onViaHeader(java.util.function.BiConsumer<Integer,ViaHeader.Builder> f)
onTopMostViaHeader(Consumer)
.
I.e., Let's say you have the following message (request or response, same same):
...
Via: SIP/2.0/TCP 12.13.14.15;branch=z9hG4bK-asdf
Via: SIP/2.0/UDP 60.61.62.63;branch=z9hG4bK-1234
Via: SIP/2.0/UDP 96.97.98.99;branch=z9hG4bK-wxyz
...
onTopMostViaHeader(Consumer)
will be called.
onViaHeader(BiConsumer)
will be called where the index will
be '1' since this is the second via on the list and we of course start counting
at zero.
onViaHeader(BiConsumer)
will be called where the index will
be '2' since this is the third via on the list and so on...
f
- SipMessage.Builder<T> withViaHeader(ViaHeader via)
withViaHeaders(ViaHeader...)
.
If you want to push a Via header to a potentially already existing list
of Via headers, then use withTopMostViaHeader(ViaHeader)
.via
- SipMessage.Builder<T> withViaHeaders(ViaHeader... vias)
vias
- SipMessage.Builder<T> withViaHeaders(List<ViaHeader> vias)
vias
- SipMessage.Builder<T> withTopMostViaHeader(ViaHeader via)
via
- SipMessage.Builder<T> withTopMostViaHeader()
ViaHeader
will have to be filled out by the stack at some
later point, which is when the message is about to be sent, so when you create
the message you don't have all the details just yet. However, just to create
a new Via with bogus information only to be re-written later by registering
a function with onTopMostViaHeader(Consumer)
is rather silly
so therefore you can just indicate that you want a new top-most via header
but you will fill out all details later.
NOTE: if you do NOT register a function to handle this "empty" Via-header
through the method onTopMostViaHeader(Consumer)
things will
blow up later with you try to build this message.SipMessage.Builder<T> withPoppedVia()
ViaHeader
through the method
withTopMostViaHeader(ViaHeader)
followed
by this method, then the Via you just added will be removed again. Order is important!
Note: if you actually wanted to know the value of that ViaHeader
then you should
really have checked it on the SipMessage
you received and not on the builder
object.SipMessage.Builder<T> withBody(Buffer body)
T build()
SipMessage.Builder<T> onCommit(java.util.function.Consumer<SipMessage> f)
SipMessage
has been fully built and created the "end result"
will be conveyed to the registered function. It is utterly important
that the function returns as quickly as possible since the build method
will not be able to return until the call to this function has been completed.f
- Copyright © 2021. All Rights Reserved.