blob: 4c3aa6f243edf3e290e908aac07bf5947c599f9c [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file sipsess/reply.c SIP Session Reply
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <re_types.h>
7#include <re_mem.h>
8#include <re_mbuf.h>
9#include <re_sa.h>
10#include <re_list.h>
11#include <re_hash.h>
12#include <re_fmt.h>
13#include <re_uri.h>
14#include <re_tmr.h>
15#include <re_msg.h>
16#include <re_sip.h>
17#include <re_sipsess.h>
18#include "sipsess.h"
19
20
21struct sipsess_reply {
22 struct le le;
23 struct tmr tmr;
24 struct tmr tmrg;
25 const struct sip_msg *msg;
26 struct mbuf *mb;
27 struct sipsess *sess;
28 bool awaiting_answer;
29 uint32_t seq;
30 uint32_t txc;
31};
32
33
34static void destructor(void *arg)
35{
36 struct sipsess_reply *reply = arg;
37
38 list_unlink(&reply->le);
39 tmr_cancel(&reply->tmr);
40 tmr_cancel(&reply->tmrg);
41 mem_deref((void *)reply->msg);
42 mem_deref(reply->mb);
43}
44
45
46static void tmr_handler(void *arg)
47{
48 struct sipsess_reply *reply = arg;
49 struct sipsess *sess = reply->sess;
50
51 mem_deref(reply);
52
53 /* wait for all pending ACKs */
54 if (sess->replyl.head)
55 return;
56
57 /* we want to send bye */
58 sess->established = true;
59
60 if (!sess->terminated)
61 sipsess_terminate(sess, ETIMEDOUT, NULL);
62 else
63 mem_deref(sess);
64}
65
66
67static void retransmit_handler(void *arg)
68{
69 struct sipsess_reply *reply = arg;
70
71 (void)sip_send(reply->sess->sip, reply->msg->sock, reply->msg->tp,
72 &reply->msg->src, reply->mb);
73
74 reply->txc++;
75 tmr_start(&reply->tmrg, MIN(SIP_T1<<reply->txc, SIP_T2),
76 retransmit_handler, reply);
77}
78
79
80int sipsess_reply_2xx(struct sipsess *sess, const struct sip_msg *msg,
81 uint16_t scode, const char *reason, struct mbuf *desc,
82 const char *fmt, va_list *ap)
83{
84 struct sipsess_reply *reply;
85 struct sip_contact contact;
86 int err = ENOMEM;
87
88 reply = mem_zalloc(sizeof(*reply), destructor);
89 if (!reply)
90 goto out;
91
92 list_append(&sess->replyl, &reply->le, reply);
93 reply->seq = msg->cseq.num;
94 reply->msg = mem_ref((void *)msg);
95 reply->sess = sess;
96
97 sip_contact_set(&contact, sess->cuser, &msg->dst, msg->tp);
98
99 err = sip_treplyf(&sess->st, &reply->mb, sess->sip,
100 msg, true, scode, reason,
101 "%H"
102 "%v"
103 "%s%s%s"
104 "Content-Length: %zu\r\n"
105 "\r\n"
106 "%b",
107 sip_contact_print, &contact,
108 fmt, ap,
109 desc ? "Content-Type: " : "",
110 desc ? sess->ctype : "",
111 desc ? "\r\n" : "",
112 desc ? mbuf_get_left(desc) : (size_t)0,
113 desc ? mbuf_buf(desc) : NULL,
114 desc ? mbuf_get_left(desc) : (size_t)0);
115
116 if (err)
117 goto out;
118
119 tmr_start(&reply->tmr, 64 * SIP_T1, tmr_handler, reply);
120 tmr_start(&reply->tmrg, SIP_T1, retransmit_handler, reply);
121
122 if (!mbuf_get_left(msg->mb) && desc) {
123 reply->awaiting_answer = true;
124 sess->awaiting_answer = true;
125 }
126
127 out:
128 if (err) {
129 sess->st = mem_deref(sess->st);
130 mem_deref(reply);
131 }
132
133 return err;
134}
135
136
137static bool cmp_handler(struct le *le, void *arg)
138{
139 struct sipsess_reply *reply = le->data;
140 const struct sip_msg *msg = arg;
141
142 return msg->cseq.num == reply->seq;
143}
144
145
146int sipsess_reply_ack(struct sipsess *sess, const struct sip_msg *msg,
147 bool *awaiting_answer)
148{
149 struct sipsess_reply *reply;
150
151 reply = list_ledata(list_apply(&sess->replyl, false, cmp_handler,
152 (void *)msg));
153 if (!reply)
154 return ENOENT;
155
156 *awaiting_answer = reply->awaiting_answer;
157
158 mem_deref(reply);
159
160 return 0;
161}