Summary
- RFC 3261 identified a SIP dialog with Call-ID, a local tag and a remote tag. The tags reverse roles at the peer, because each endpoint sees its own contribution as local.
- One forked INVITE could create several early or confirmed dialogs. They shared the caller's Call-ID and tag, while each respondent supplied a different To-tag that completed a distinct dialog name.
- The dialog then carried sequence, route and target state across later transactions. Its identifier correlated context; it did not authenticate a person, identify a media stream or guarantee that one human “call” meant one dialog.
One invitation came back as several relationships
Internet telephony inherited a word that sounded singular: call. A caller chose one address, sent one invitation and expected one conversation. The network underneath was already less tidy. A proxy could send that INVITE to a desk phone, a soft client and a gateway at the same time. More than one destination could ring. More than one could answer. The originating user agent needed to know which later ACK, update or BYE belonged to which responding peer.
A transaction identifier could not carry that burden. The initial INVITE transaction had a job: correlate one request, its retransmissions and its responses while that exchange was in progress. A successful response opened a longer problem. New requests would start new transactions. Either endpoint could become the sender. Routes learned during setup might have to remain in the path. A device could advertise a new contact address while the relationship continued.
SIP therefore needed a name for remembered context, not merely for one message exchange.
The first standards-track version, RFC 2543 in March 1999, called that continuing relationship a call leg. It identified a leg through Call-ID, To and From. It already understood the fork problem: when a request might reach several user-agent servers, each response needed a To-tag so the caller could distinguish the respondents. Multiple responses to one INVITE could therefore represent distinct call legs.
But the construction still carried its history in the address fields. A From tag was optional. Route construction was underspecified. The terms “call” and “call leg” encouraged an application story to stand in for a protocol state machine. Three years later, SIP 2.0 made the boundary much sharper.
The caller supplied only half the name
RFC 3261, published in June 2002, replaced the call leg with the dialog. Its definition was intentionally modest: a peer-to-peer SIP relationship between two user agents that persists for some time. It gave messages an interpretive context, ordered requests in each direction and supplied the information needed to route new requests between the peers.
At either user agent, the dialog identifier contained three components: the Call-ID, a local tag and a remote tag. The identifier was directional. Alice's local tag was Bob's remote tag; Bob's local tag was Alice's remote tag. The endpoints agreed on the two opaque values without pretending that “local” and “remote” were globally fixed labels.
An initial dialog-forming request carried a Call-ID and a From-tag. RFC 3261 described this as half a dialog identifier. A qualifying response added a To-tag. Seen by the initiating user agent, the From-tag became the local tag and the response's To-tag became the remote tag. Seen by the responder, the orientation reversed.
This division of labour was the answer to forking. Every branch of the invitation inherited the caller's Call-ID and From-tag. Each responding endpoint contributed its own To-tag. The caller could receive several responses bearing the same Call-ID and its own tag, yet keep their state apart because the remote tags differed.
Call-ID alone was therefore deliberately insufficient. It grouped related signaling without collapsing all respondents into one peer relationship. Nor were the tags human names. RFC 3261 required generated tags to be globally unique and cryptographically random with at least 32 bits of randomness, but described them as opaque tokens for making unique dialog identifiers. Randomness reduced accidental ambiguity. It did not authenticate Alice, authorize Bob or prove that either display name represented a person.
Ringing could already have a name
The dialog did not always wait for a final answer. For an INVITE, a provisional response from 101 through 199 with a To-tag created an early dialog. The user agent could now keep state associated with that particular respondent while the invitation was still unresolved. A 2xx final response moved the matching dialog into the confirmed state. A failure response, or no successful response on that path, ended the early dialog under the core rules.
Forking made this more than terminology. A caller could hold several early dialogs at once: one endpoint ringing, another reporting progress, a third already rejecting the invitation. The dialogs shared the initiating half of their identifiers but had distinct responder tags. More than one 2xx could even arrive, leaving the user agent with more than one confirmed dialog to acknowledge and then resolve according to the application's chosen outcome.
That mechanism sits next to, but is not the same as, reliable provisional response. PRACK and its RSeq/RAck sequence answer whether an important provisional response was received in order. Dialog tags answer whose peer context the response and later requests belong to. Reliability can operate inside an early dialog because the dialog already has a name; it does not create that name by itself.
The same separation applies to a Via branch. A branch value identifies transaction work and supports retransmission matching. The dialog tuple survives after that branch's transaction has completed and appears across new transactions. Treating one as the other would make an implementation either forget long-lived state too early or merge separate message exchanges into a single transaction.
The name guarded more than a pair of header fields
Once created, a dialog stored the information required to construct and interpret later requests. RFC 3261 listed the identifier, local and remote sequence numbers, local and remote URIs, the remote target, a secure flag and an ordered route set.
The sequence numbers gave each direction its own order. A user agent incremented its local CSeq when it generated new in-dialog requests, subject to the method-specific exceptions. The peer remembered the remote value and could reject a lower, out-of-order request. A gap was not automatically an error: an intermediary might have challenged an earlier attempt that never reached the final recipient. The purpose was ordered evidence, not a promise that every integer would appear.
The route set answered which proxies had asked to remain on the signaling path. A user-agent server learned it from Record-Route values in the request. The client learned the same path from the response in reverse order. RFC 3665 turned the rules into worked call flows: the same Call-ID and two tags recur across ACK, BYE and responses, while Route headers carry the selected proxies on subsequent requests.
The remote target answered a different question: which contact address currently represented the peer. It began with the Contact URI supplied during dialog creation. A successful target-refresh request could change it. For an INVITE-created dialog, RFC 3261 defined re-INVITE as the core target-refresh method; extensions could define others for other dialog types.
The distinction mattered. A device could move its reachable contact without acquiring a new dialog identity. The remote target changed; the Call-ID and tags did not. The route set also stayed fixed. A new Contact was not permission to erase the Record-Route path that intermediaries had established.
The three pieces therefore answered three different operational questions. The dialog tuple said which continuing context. The route set said through which retained intermediaries. The remote target said toward which current peer address. Their coexistence prevented mobility, routing policy and identity correlation from being compressed into one convenient but overloaded string.
A dialog could host new transactions without becoming the media
After establishment, either peer could initiate a new transaction within the dialog. The sender was the UAC for that transaction and the recipient the UAS, regardless of which roles they held during the original INVITE. The continuing relationship was symmetrical enough to outlive the client/server roles of one exchange.
Media negotiation occupied another layer. RFC 3264 defined SDP offer and answer as a way to agree on streams, codecs, addresses and ports. It assumed a higher-layer context, such as SIP, to associate successive exchanges. Later offers could add a stream, remove one, change a port or select different formats while the dialog continued.
A confirmed SIP dialog consequently did not prove that audio packets reached a listener. It did not name an RTP source, certify a codec outcome or measure call quality. It organized signaling context. The media session could change inside that context, and evidence of media delivery had to come from the media plane.
Lifetime also needed its own rule. RFC 4028 added negotiated session timers and periodic re-INVITE or UPDATE refreshes. It explicitly allowed different intervals—or no timer—on different dialogs created by one INVITE. A refresh was a new transaction in an existing context. Success extended the session; failure to refresh could lead to BYE. Possession of the dialog tuple was not a perpetual lease on remote state.
One dialog was not always one application relationship
Extensions exposed a final ambiguity. An INVITE created an invite usage, but an in-dialog SUBSCRIBE or REFER could create additional usages that shared the same dialog. RFC 5057 catalogued the resulting complexity. Those usages shared Call-ID, tags, sequence state, route set, contacts, remote target and secure flag, while keeping usage-specific state such as subscription duration.
Normal termination of one usage therefore need not erase the others. A BYE could end the invite usage while an event subscription remained. Conversely, ending a subscription did not necessarily terminate the invite usage. The shared dialog was a signaling container, not an assertion that every application relationship within it had one lifetime.
RFC 6665 made the boundary concrete for event notification. SUBSCRIBE and NOTIFY use dialog state, but the Event field participates in matching the particular subscription. A forked SUBSCRIBE can establish independent dialogs that are refreshed separately. The Call-ID/tag tuple tells an endpoint which common dialog context it is in; it is not the complete key for every use made of that context.
This is why the apparently simple three-part name mattered. It let SIP keep a peer relationship stable while transactions began and ended, contacts moved, routes remained, media changed and applications layered more state on top. Its strength came not from claiming to identify everything, but from identifying exactly one level of the system.
Member Briefing
Deeper Profile Context
Sign in with the right membership level to unlock the full briefing and source notes.
Only for Strategic Circle
Strategic Circle
Open to all readers. Unlock profile briefings after joining and signing in.
Join Strategic CircleOnly for Leadership Alliance
Leadership Alliance
For qualified IP-asset owners and management; sign in to unlock alliance briefings.
Join Leadership Alliance
