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