1 /*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25 /**@CFILE soa_asynch.c
26 *
27 * @brief Static implementation of Sofia SDP Offer/Answer Engine
28 *
29 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
30 *
31 * @date Created: Tue Aug 16 17:06:06 EEST 2005
32 */
33
34 #include "config.h"
35
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <assert.h>
41
42 struct soa_asynch_complete;
43
44 #define SU_MSG_ARG_T struct soa_asynch_completed
45
46 #include <sofia-sip/su_wait.h>
47 #include <sofia-sip/su_tag_class.h>
48 #include <sofia-sip/su_tag_class.h>
49 #include <sofia-sip/su_tagarg.h>
50 #include <sofia-sip/su_strlst.h>
51
52 #include "sofia-sip/soa.h"
53 #include <sofia-sip/sdp.h>
54 #include "sofia-sip/soa_session.h"
55
56 #define NONE ((void *)-1)
57 #define XXX assert(!"implemented")
58
59 typedef struct soa_asynch_session
60 {
61 soa_session_t sss_session[1];
62 }
63 soa_asynch_session_t;
64
65 struct soa_asynch_completed
66 {
67 soa_session_t *completed_session;
68 unsigned completed_terminated;
69 int (*completed_call)(soa_session_t *, soa_callback_f *);
70 };
71
72 static int soa_asynch_init(char const *, soa_session_t *, soa_session_t *);
73 static void soa_asynch_deinit(soa_session_t *);
74 static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags);
75 static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags);
76 static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss);
77 static int soa_asynch_generate_offer(soa_session_t *ss,
78 soa_callback_f *completed);
79 static int soa_asynch_generate_answer(soa_session_t *ss,
80 soa_callback_f *completed);
81 static int soa_asynch_process_answer(soa_session_t *ss,
82 soa_callback_f *completed);
83 static int soa_asynch_activate(soa_session_t *ss, char const *option);
84 static int soa_asynch_deactivate(soa_session_t *ss, char const *option);
85 static void soa_asynch_terminate(soa_session_t *ss, char const *option);
86
87 struct soa_session_actions const soa_asynch_actions =
88 {
89 (sizeof soa_asynch_actions),
90 sizeof (struct soa_asynch_session),
91 soa_asynch_init,
92 soa_asynch_deinit,
93 soa_asynch_set_params,
94 soa_asynch_get_params,
95 soa_asynch_get_paramlist,
96 soa_base_media_features,
97 soa_base_sip_require,
98 soa_base_sip_supported,
99 soa_base_remote_sip_features,
100 soa_base_set_capability_sdp,
101 soa_base_set_remote_sdp,
102 soa_base_set_local_sdp,
103 soa_asynch_generate_offer,
104 soa_asynch_generate_answer,
105 soa_asynch_process_answer,
106 soa_asynch_activate,
107 soa_asynch_deactivate,
108 soa_asynch_terminate
109 };
110
111 /* Initialize session */
soa_asynch_init(char const * name,soa_session_t * ss,soa_session_t * parent)112 static int soa_asynch_init(char const *name,
113 soa_session_t *ss,
114 soa_session_t *parent)
115 {
116 return soa_base_init(name, ss, parent);
117 }
118
soa_asynch_deinit(soa_session_t * ss)119 static void soa_asynch_deinit(soa_session_t *ss)
120 {
121 soa_base_deinit(ss);
122 }
123
soa_asynch_set_params(soa_session_t * ss,tagi_t const * tags)124 static int soa_asynch_set_params(soa_session_t *ss, tagi_t const *tags)
125 {
126 return soa_base_set_params(ss, tags);
127 }
128
soa_asynch_get_params(soa_session_t const * ss,tagi_t * tags)129 static int soa_asynch_get_params(soa_session_t const *ss, tagi_t *tags)
130 {
131 return soa_base_get_params(ss, tags);
132 }
133
soa_asynch_get_paramlist(soa_session_t const * ss)134 static tagi_t *soa_asynch_get_paramlist(soa_session_t const *ss)
135 {
136 return soa_base_get_paramlist(ss);
137 }
138
soa_asynch_completed(su_root_magic_t * magic,su_msg_r msg,struct soa_asynch_completed * arg)139 static void soa_asynch_completed(su_root_magic_t *magic,
140 su_msg_r msg,
141 struct soa_asynch_completed *arg)
142 {
143 soa_session_t *ss = arg->completed_session;
144
145 if (arg->completed_terminated == ss->ss_terminated) {
146 if (ss->ss_in_progress) {
147 soa_callback_f *completed = ss->ss_in_progress;
148 ss->ss_in_progress = NULL;
149
150 /* Update local activity */
151 if (arg->completed_call(ss, NULL) < 0)
152 /* XXX - Process error */;
153
154 completed(ss->ss_magic, ss);
155 }
156 }
157
158 soa_session_unref(ss);
159 }
160
soa_asynch_generate_offer(soa_session_t * ss,soa_callback_f * completed)161 static int soa_asynch_generate_offer(soa_session_t *ss,
162 soa_callback_f *completed)
163 {
164 sdp_session_t *sdp;
165 sdp_media_t *m;
166 uint16_t port = 5004;
167 su_msg_r msg;
168
169 if (ss->ss_user->ssd_sdp == NULL) {
170 if (ss->ss_caps->ssd_unparsed == NULL)
171 return soa_set_status(ss, 500, "No local session available");
172 }
173
174 if (ss->ss_user->ssd_sdp)
175 return 0; /* We are done */
176
177 /* Generate a dummy SDP offer based on our capabilities */
178 if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
179 return -1;
180 sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
181
182 for (m = sdp->sdp_media; m; m = m->m_next)
183 if (m->m_port == 0)
184 m->m_port = port, port += 2;
185
186 /* We pretend to be asynchronous */
187 if (su_msg_create(msg,
188 su_root_task(ss->ss_root),
189 su_root_task(ss->ss_root),
190 soa_asynch_completed,
191 sizeof (struct soa_asynch_completed)) == -1)
192 return soa_set_status(ss, 500, "Internal error");
193
194 su_msg_data(msg)->completed_session = soa_session_ref(ss);
195 su_msg_data(msg)->completed_terminated = ss->ss_terminated;
196 su_msg_data(msg)->completed_call = soa_base_generate_offer;
197
198 su_msg_send(msg);
199
200 ss->ss_in_progress = completed;
201
202 return 1; /* Indicate caller of async operation */
203 }
204
soa_asynch_generate_answer(soa_session_t * ss,soa_callback_f * completed)205 static int soa_asynch_generate_answer(soa_session_t *ss,
206 soa_callback_f *completed)
207 {
208 sdp_session_t *sdp;
209 sdp_media_t *m;
210 uint16_t port = 5004;
211 su_msg_r msg;
212
213 if (ss->ss_user->ssd_sdp == NULL) {
214 if (ss->ss_caps->ssd_unparsed == NULL)
215 return soa_set_status(ss, 500, "No local session available");
216 }
217
218 if (ss->ss_user->ssd_sdp)
219 return 0; /* We are done */
220
221 /* Generate a dummy SDP offer based on our capabilities */
222 if (soa_set_local_sdp(ss, ss->ss_caps->ssd_unparsed, -1) < 0)
223 return -1;
224 sdp = ss->ss_user->ssd_sdp; assert(ss->ss_user->ssd_sdp);
225
226 for (m = sdp->sdp_media; m; m = m->m_next)
227 if (m->m_port == 0)
228 m->m_port = port, port += 2;
229
230 /* We pretend to be asynchronous */
231 if (su_msg_create(msg,
232 su_root_task(ss->ss_root),
233 su_root_task(ss->ss_root),
234 soa_asynch_completed,
235 sizeof (struct soa_asynch_completed)) == -1)
236 return soa_set_status(ss, 500, "Internal error");
237
238 su_msg_data(msg)->completed_session = soa_session_ref(ss);
239 su_msg_data(msg)->completed_terminated = ss->ss_terminated;
240 su_msg_data(msg)->completed_call = soa_base_generate_answer;
241
242 su_msg_send(msg);
243
244 ss->ss_in_progress = completed;
245
246 return 1; /* Indicate caller of async operation */
247 }
248
soa_asynch_process_answer(soa_session_t * ss,soa_callback_f * completed)249 static int soa_asynch_process_answer(soa_session_t *ss,
250 soa_callback_f *completed)
251 {
252 su_msg_r msg;
253
254 /* We pretend to be asynchronous */
255 if (su_msg_create(msg,
256 su_root_task(ss->ss_root),
257 su_root_task(ss->ss_root),
258 soa_asynch_completed,
259 sizeof (struct soa_asynch_completed)) == -1)
260 return soa_set_status(ss, 500, "Internal error");
261
262 su_msg_data(msg)->completed_session = soa_session_ref(ss);
263 su_msg_data(msg)->completed_terminated = ss->ss_terminated;
264 su_msg_data(msg)->completed_call = soa_base_process_answer;
265
266 su_msg_send(msg);
267
268 ss->ss_in_progress = completed;
269
270 return 1; /* Indicate caller of async operation */
271 }
272
273
soa_asynch_activate(soa_session_t * ss,char const * option)274 static int soa_asynch_activate(soa_session_t *ss, char const *option)
275 {
276 return soa_base_activate(ss, option);
277 }
278
soa_asynch_deactivate(soa_session_t * ss,char const * option)279 static int soa_asynch_deactivate(soa_session_t *ss, char const *option)
280 {
281 return soa_base_deactivate(ss, option);
282 }
283
soa_asynch_terminate(soa_session_t * ss,char const * option)284 static void soa_asynch_terminate(soa_session_t *ss, char const *option)
285 {
286 ss->ss_in_progress = NULL;
287 soa_description_free(ss, ss->ss_user);
288 soa_base_terminate(ss, option);
289 }
290