blob: 4a9be682ace7de1cd4d391ff65140ac2bbf25c98 [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file ack.c SIP Session ACK
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_ack {
22 struct le he;
23 struct tmr tmr;
24 struct sa dst;
25 struct sip_request *req;
26 struct sip_dialog *dlg;
27 struct mbuf *mb;
28 enum sip_transp tp;
29 uint32_t cseq;
30};
31
32
33static void destructor(void *arg)
34{
35 struct sipsess_ack *ack = arg;
36
37 hash_unlink(&ack->he);
38 tmr_cancel(&ack->tmr);
39 mem_deref(ack->req);
40 mem_deref(ack->dlg);
41 mem_deref(ack->mb);
42}
43
44
45static void tmr_handler(void *arg)
46{
47 struct sipsess_ack *ack = arg;
48
49 mem_deref(ack);
50}
51
52
53static int send_handler(enum sip_transp tp, const struct sa *src,
54 const struct sa *dst, struct mbuf *mb, void *arg)
55{
56 struct sipsess_ack *ack = arg;
57 (void)src;
58
59 mem_deref(ack->mb);
60 ack->mb = mem_ref(mb);
61 ack->dst = *dst;
62 ack->tp = tp;
63
64 tmr_start(&ack->tmr, 64 * SIP_T1, tmr_handler, ack);
65
66 return 0;
67}
68
69
70static void resp_handler(int err, const struct sip_msg *msg, void *arg)
71{
72 struct sipsess_ack *ack = arg;
73 (void)err;
74 (void)msg;
75
76 mem_deref(ack);
77}
78
79
80int sipsess_ack(struct sipsess_sock *sock, struct sip_dialog *dlg,
81 uint32_t cseq, struct sip_auth *auth,
82 const char *ctype, struct mbuf *desc)
83{
84 struct sipsess_ack *ack;
85 int err;
86
87 ack = mem_zalloc(sizeof(*ack), destructor);
88 if (!ack)
89 return ENOMEM;
90
91 hash_append(sock->ht_ack,
92 hash_joaat_str(sip_dialog_callid(dlg)),
93 &ack->he, ack);
94
95 ack->dlg = mem_ref(dlg);
96 ack->cseq = cseq;
97
98 err = sip_drequestf(&ack->req, sock->sip, false, "ACK", dlg, cseq,
99 auth, send_handler, resp_handler, ack,
100 "%s%s%s"
101 "Content-Length: %zu\r\n"
102 "\r\n"
103 "%b",
104 desc ? "Content-Type: " : "",
105 desc ? ctype : "",
106 desc ? "\r\n" : "",
107 desc ? mbuf_get_left(desc) : (size_t)0,
108 desc ? mbuf_buf(desc) : NULL,
109 desc ? mbuf_get_left(desc) : (size_t)0);
110 if (err)
111 goto out;
112
113 out:
114 if (err)
115 mem_deref(ack);
116
117 return err;
118}
119
120
121static bool cmp_handler(struct le *le, void *arg)
122{
123 struct sipsess_ack *ack = le->data;
124 const struct sip_msg *msg = arg;
125
126 if (!sip_dialog_cmp(ack->dlg, msg))
127 return false;
128
129 if (ack->cseq != msg->cseq.num)
130 return false;
131
132 return true;
133}
134
135
136int sipsess_ack_again(struct sipsess_sock *sock, const struct sip_msg *msg)
137{
138 struct sipsess_ack *ack;
139
140 ack = list_ledata(hash_lookup(sock->ht_ack,
141 hash_joaat_pl(&msg->callid),
142 cmp_handler, (void *)msg));
143 if (!ack)
144 return ENOENT;
145
146 return sip_send(sock->sip, NULL, ack->tp, &ack->dst, ack->mb);
147}