1*5306Sgm209912 /*
2*5306Sgm209912 * CDDL HEADER START
3*5306Sgm209912 *
4*5306Sgm209912 * The contents of this file are subject to the terms of the
5*5306Sgm209912 * Common Development and Distribution License (the "License").
6*5306Sgm209912 * You may not use this file except in compliance with the License.
7*5306Sgm209912 *
8*5306Sgm209912 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5306Sgm209912 * or http://www.opensolaris.org/os/licensing.
10*5306Sgm209912 * See the License for the specific language governing permissions
11*5306Sgm209912 * and limitations under the License.
12*5306Sgm209912 *
13*5306Sgm209912 * When distributing Covered Code, include this CDDL HEADER in each
14*5306Sgm209912 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5306Sgm209912 * If applicable, add the following below this CDDL HEADER, with the
16*5306Sgm209912 * fields enclosed by brackets "[]" replaced with your own identifying
17*5306Sgm209912 * information: Portions Copyright [yyyy] [name of copyright owner]
18*5306Sgm209912 *
19*5306Sgm209912 * CDDL HEADER END
20*5306Sgm209912 */
21*5306Sgm209912
22*5306Sgm209912 /*
23*5306Sgm209912 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24*5306Sgm209912 * Use is subject to license terms.
25*5306Sgm209912 */
26*5306Sgm209912
27*5306Sgm209912 #pragma ident "%Z%%M% %I% %E% SMI"
28*5306Sgm209912
29*5306Sgm209912 /*
30*5306Sgm209912 * Contains implementation of various interfaces exported by library
31*5306Sgm209912 */
32*5306Sgm209912
33*5306Sgm209912 #include <stdio.h>
34*5306Sgm209912 #include <assert.h>
35*5306Sgm209912 #include <errno.h>
36*5306Sgm209912 #include <stdlib.h>
37*5306Sgm209912 #include <string.h>
38*5306Sgm209912 #include <ctype.h>
39*5306Sgm209912 #include <sdp.h>
40*5306Sgm209912
41*5306Sgm209912 #include "sdp_parse.h"
42*5306Sgm209912 #include "commp_util.h"
43*5306Sgm209912
44*5306Sgm209912 #define FIELD_EQUALS_CRLF_LEN 4 /* first two characters and CRLF */
45*5306Sgm209912
46*5306Sgm209912 #define SDP_ATTR_TO_STR(m_attr) { \
47*5306Sgm209912 while ((m_attr) != NULL) { \
48*5306Sgm209912 if ((m_attr)->a_value != NULL) { \
49*5306Sgm209912 wrote = snprintf(buf, len, "a=%s%c%s%s", \
50*5306Sgm209912 (m_attr)->a_name, COMMP_COLON, (m_attr)-> \
51*5306Sgm209912 a_value, COMMP_CRLF); \
52*5306Sgm209912 } else { \
53*5306Sgm209912 wrote = snprintf(buf, len, "a=%s%s", (m_attr)-> \
54*5306Sgm209912 a_name, COMMP_CRLF); \
55*5306Sgm209912 } \
56*5306Sgm209912 len = len - wrote; \
57*5306Sgm209912 buf = buf + wrote; \
58*5306Sgm209912 (m_attr) = (m_attr)->a_next; \
59*5306Sgm209912 } \
60*5306Sgm209912 }
61*5306Sgm209912
62*5306Sgm209912 #define SDP_KEY_TO_STR(m_key) { \
63*5306Sgm209912 if ((m_key) != NULL) { \
64*5306Sgm209912 if ((m_key)->k_enckey != NULL) { \
65*5306Sgm209912 wrote = snprintf(buf, len, "k=%s%c%s%s", \
66*5306Sgm209912 (m_key)->k_method, COMMP_COLON, (m_key)-> \
67*5306Sgm209912 k_enckey, COMMP_CRLF); \
68*5306Sgm209912 } else { \
69*5306Sgm209912 wrote = snprintf(buf, len, "k=%s%s", (m_key)-> \
70*5306Sgm209912 k_method, COMMP_CRLF); \
71*5306Sgm209912 } \
72*5306Sgm209912 len = len - wrote; \
73*5306Sgm209912 buf = buf + wrote; \
74*5306Sgm209912 } \
75*5306Sgm209912 }
76*5306Sgm209912
77*5306Sgm209912 #define SDP_BANDWIDTH_TO_STR(m_bw) { \
78*5306Sgm209912 while ((m_bw) != NULL) { \
79*5306Sgm209912 wrote = snprintf(buf, len, "b=%s%c%llu%s", (m_bw)-> \
80*5306Sgm209912 b_type, COMMP_COLON, (m_bw)->b_value, COMMP_CRLF); \
81*5306Sgm209912 len = len - wrote; \
82*5306Sgm209912 buf = buf + wrote; \
83*5306Sgm209912 (m_bw) = (m_bw)->b_next; \
84*5306Sgm209912 } \
85*5306Sgm209912 }
86*5306Sgm209912
87*5306Sgm209912 #define SDP_INFORMATION_TO_STR(m_info) { \
88*5306Sgm209912 if ((m_info) != NULL) { \
89*5306Sgm209912 wrote = snprintf(buf, len, "i=%s%s", (m_info), COMMP_CRLF); \
90*5306Sgm209912 len = len - wrote; \
91*5306Sgm209912 buf = buf + wrote; \
92*5306Sgm209912 } \
93*5306Sgm209912 }
94*5306Sgm209912
95*5306Sgm209912 #define SDP_CONNECTION_TO_STR(m_conn) { \
96*5306Sgm209912 while ((m_conn) != NULL) { \
97*5306Sgm209912 if (strcasecmp((m_conn)->c_addrtype, \
98*5306Sgm209912 COMMP_ADDRTYPE_IP4) == 0) { \
99*5306Sgm209912 if ((m_conn)->c_addrcount > 1) { \
100*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s/%d/%d" \
101*5306Sgm209912 "%s", (m_conn)->c_nettype, (m_conn)-> \
102*5306Sgm209912 c_addrtype, (m_conn)->c_address, (m_conn)->\
103*5306Sgm209912 c_ttl, (m_conn)->c_addrcount, COMMP_CRLF); \
104*5306Sgm209912 } else if ((m_conn)->c_addrcount == 1) { \
105*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \
106*5306Sgm209912 (m_conn)->c_nettype, (m_conn)->c_addrtype, \
107*5306Sgm209912 (m_conn)->c_address, (m_conn)->c_ttl, \
108*5306Sgm209912 COMMP_CRLF); \
109*5306Sgm209912 } else { \
110*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s%s", \
111*5306Sgm209912 (m_conn)->c_nettype, (m_conn)->c_addrtype, \
112*5306Sgm209912 (m_conn)->c_address, COMMP_CRLF); \
113*5306Sgm209912 } \
114*5306Sgm209912 } else if (strcasecmp((m_conn)->c_addrtype, \
115*5306Sgm209912 COMMP_ADDRTYPE_IP6) == 0) { \
116*5306Sgm209912 if ((m_conn)->c_addrcount <= 1) { \
117*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s%s", \
118*5306Sgm209912 (m_conn)->c_nettype, (m_conn)->c_addrtype, \
119*5306Sgm209912 (m_conn)->c_address, COMMP_CRLF); \
120*5306Sgm209912 } else { \
121*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \
122*5306Sgm209912 (m_conn)->c_nettype, (m_conn)->c_addrtype, \
123*5306Sgm209912 (m_conn)->c_address, (m_conn)->c_addrcount,\
124*5306Sgm209912 COMMP_CRLF); \
125*5306Sgm209912 } \
126*5306Sgm209912 } else { \
127*5306Sgm209912 wrote = snprintf(buf, len, "c=%s %s %s%s", (m_conn)-> \
128*5306Sgm209912 c_nettype, (m_conn)->c_addrtype, (m_conn)-> \
129*5306Sgm209912 c_address, COMMP_CRLF); \
130*5306Sgm209912 } \
131*5306Sgm209912 len = len - wrote; \
132*5306Sgm209912 buf = buf + wrote; \
133*5306Sgm209912 (m_conn) = (m_conn)->c_next; \
134*5306Sgm209912 } \
135*5306Sgm209912 }
136*5306Sgm209912
137*5306Sgm209912 #define SDP_ADD_KEY(d_key, s_key) { \
138*5306Sgm209912 if ((s_key) != NULL) { \
139*5306Sgm209912 if (sdp_add_key(&(d_key), (s_key)->k_method, \
140*5306Sgm209912 (s_key)->k_enckey) != 0) { \
141*5306Sgm209912 sdp_free_session(new_sess); \
142*5306Sgm209912 return (NULL); \
143*5306Sgm209912 } \
144*5306Sgm209912 } \
145*5306Sgm209912 }
146*5306Sgm209912
147*5306Sgm209912 #define SDP_ADD_ATTRIBUTE(d_attr, s_attr) { \
148*5306Sgm209912 while ((s_attr) != NULL) { \
149*5306Sgm209912 if (sdp_add_attribute(&(d_attr), (s_attr)->a_name, \
150*5306Sgm209912 (s_attr)->a_value) != 0) { \
151*5306Sgm209912 sdp_free_session(new_sess); \
152*5306Sgm209912 return (NULL); \
153*5306Sgm209912 } \
154*5306Sgm209912 (s_attr) = (s_attr)->a_next; \
155*5306Sgm209912 } \
156*5306Sgm209912 }
157*5306Sgm209912
158*5306Sgm209912 #define SDP_ADD_BANDWIDTH(d_bw, s_bw) { \
159*5306Sgm209912 while ((s_bw) != NULL) { \
160*5306Sgm209912 if (sdp_add_bandwidth(&(d_bw), (s_bw)->b_type, \
161*5306Sgm209912 (s_bw)->b_value) != 0) { \
162*5306Sgm209912 sdp_free_session(new_sess); \
163*5306Sgm209912 return (NULL); \
164*5306Sgm209912 } \
165*5306Sgm209912 (s_bw) = (s_bw)->b_next; \
166*5306Sgm209912 } \
167*5306Sgm209912 }
168*5306Sgm209912
169*5306Sgm209912 #define SDP_ADD_CONNECTION(d_conn, s_conn) { \
170*5306Sgm209912 while ((s_conn) != NULL) { \
171*5306Sgm209912 if (sdp_add_connection(&(d_conn), (s_conn)->c_nettype, \
172*5306Sgm209912 (s_conn)->c_addrtype, (s_conn)->c_address, \
173*5306Sgm209912 (s_conn)->c_ttl, (s_conn)->c_addrcount) != 0) { \
174*5306Sgm209912 sdp_free_session(new_sess); \
175*5306Sgm209912 return (NULL); \
176*5306Sgm209912 } \
177*5306Sgm209912 (s_conn) = (s_conn)->c_next; \
178*5306Sgm209912 } \
179*5306Sgm209912 }
180*5306Sgm209912
181*5306Sgm209912 #define SDP_LEN_CONNECTION(m_conn) { \
182*5306Sgm209912 while ((m_conn) != NULL) { \
183*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN; \
184*5306Sgm209912 len += strlen((m_conn)->c_nettype); \
185*5306Sgm209912 len += strlen((m_conn)->c_addrtype) + 1; \
186*5306Sgm209912 len += strlen((m_conn)->c_address) + 1; \
187*5306Sgm209912 len += snprintf(buf, 1, "%u", (m_conn)->c_ttl) + 1; \
188*5306Sgm209912 len += snprintf(buf, 1, "%d", (m_conn)->c_addrcount) + 1; \
189*5306Sgm209912 (m_conn) = (m_conn)->c_next; \
190*5306Sgm209912 } \
191*5306Sgm209912 }
192*5306Sgm209912
193*5306Sgm209912 #define SDP_LEN_BANDWIDTH(m_bw) { \
194*5306Sgm209912 while ((m_bw) != NULL) { \
195*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN; \
196*5306Sgm209912 len += strlen((m_bw)->b_type); \
197*5306Sgm209912 len += snprintf(buf, 1, "%llu", (m_bw)->b_value) + 1; \
198*5306Sgm209912 (m_bw) = (m_bw)->b_next; \
199*5306Sgm209912 } \
200*5306Sgm209912 }
201*5306Sgm209912
202*5306Sgm209912 #define SDP_LEN_KEY(m_key) { \
203*5306Sgm209912 if ((m_key) != NULL) { \
204*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN; \
205*5306Sgm209912 len += strlen((m_key)->k_method); \
206*5306Sgm209912 if ((m_key)->k_enckey != NULL) \
207*5306Sgm209912 len += strlen((m_key)->k_enckey) + 1; \
208*5306Sgm209912 } \
209*5306Sgm209912 }
210*5306Sgm209912
211*5306Sgm209912 #define SDP_LEN_ATTRIBUTE(m_attr) { \
212*5306Sgm209912 while ((m_attr) != NULL) { \
213*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN; \
214*5306Sgm209912 len += strlen((m_attr)->a_name); \
215*5306Sgm209912 if ((m_attr)->a_value != NULL) \
216*5306Sgm209912 len += strlen((m_attr)->a_value) + 1; \
217*5306Sgm209912 (m_attr) = (m_attr)->a_next; \
218*5306Sgm209912 } \
219*5306Sgm209912 }
220*5306Sgm209912
221*5306Sgm209912 /*
222*5306Sgm209912 * Given a media list and media name ("audio", "video", et al), it searches
223*5306Sgm209912 * the list for that media. Returns NULL if media not present.
224*5306Sgm209912 */
225*5306Sgm209912 sdp_media_t *
sdp_find_media(sdp_media_t * media,const char * name)226*5306Sgm209912 sdp_find_media(sdp_media_t *media, const char *name)
227*5306Sgm209912 {
228*5306Sgm209912 if (media == NULL || name == NULL || (strlen(name) == 0)) {
229*5306Sgm209912 return (NULL);
230*5306Sgm209912 }
231*5306Sgm209912 while (media != NULL) {
232*5306Sgm209912 if (media->m_name != NULL) {
233*5306Sgm209912 if (strcasecmp(name, media->m_name) == 0)
234*5306Sgm209912 return (media);
235*5306Sgm209912 }
236*5306Sgm209912 media = media->m_next;
237*5306Sgm209912 }
238*5306Sgm209912 return (media);
239*5306Sgm209912 }
240*5306Sgm209912
241*5306Sgm209912 /*
242*5306Sgm209912 * Given a attribute list and name of the attribute ("rtpmap", "fmtp", et al),
243*5306Sgm209912 * this API searches the list for that attribute. Returns NULL if not found.
244*5306Sgm209912 */
245*5306Sgm209912 sdp_attr_t *
sdp_find_attribute(sdp_attr_t * attr,const char * name)246*5306Sgm209912 sdp_find_attribute(sdp_attr_t *attr, const char *name)
247*5306Sgm209912 {
248*5306Sgm209912 if (attr == NULL || name == NULL || (strlen(name) == 0)) {
249*5306Sgm209912 return (NULL);
250*5306Sgm209912 }
251*5306Sgm209912 while (attr != NULL) {
252*5306Sgm209912 if (attr->a_name != NULL) {
253*5306Sgm209912 if (strcasecmp(attr->a_name, name) == 0)
254*5306Sgm209912 return (attr);
255*5306Sgm209912 }
256*5306Sgm209912 attr = attr->a_next;
257*5306Sgm209912 }
258*5306Sgm209912 return (attr);
259*5306Sgm209912 }
260*5306Sgm209912
261*5306Sgm209912 /*
262*5306Sgm209912 * Given a media list and a format number, this API will return the rtpmap
263*5306Sgm209912 * attribute matching the format number.
264*5306Sgm209912 */
265*5306Sgm209912 sdp_attr_t *
sdp_find_media_rtpmap(sdp_media_t * media,const char * format)266*5306Sgm209912 sdp_find_media_rtpmap(sdp_media_t *media, const char *format)
267*5306Sgm209912 {
268*5306Sgm209912 sdp_attr_t *attr = NULL;
269*5306Sgm209912 char *tmp = NULL;
270*5306Sgm209912
271*5306Sgm209912 if (media == NULL || format == NULL || (strlen(format) == 0)) {
272*5306Sgm209912 return (NULL);
273*5306Sgm209912 }
274*5306Sgm209912 attr = media->m_attr;
275*5306Sgm209912 while (attr != NULL) {
276*5306Sgm209912 if (attr->a_name != NULL && (strcasecmp(attr->a_name,
277*5306Sgm209912 SDP_RTPMAP) == 0)) {
278*5306Sgm209912 if (attr->a_value != NULL) {
279*5306Sgm209912 tmp = attr->a_value;
280*5306Sgm209912 while (isspace(*tmp))
281*5306Sgm209912 ++tmp;
282*5306Sgm209912 if (strncasecmp(tmp, format,
283*5306Sgm209912 strlen(format)) == 0) {
284*5306Sgm209912 return (attr);
285*5306Sgm209912 }
286*5306Sgm209912 }
287*5306Sgm209912 }
288*5306Sgm209912 attr = attr->a_next;
289*5306Sgm209912 }
290*5306Sgm209912 return (attr);
291*5306Sgm209912 }
292*5306Sgm209912
293*5306Sgm209912 /*
294*5306Sgm209912 * Adds origin field to the session.
295*5306Sgm209912 * o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
296*5306Sgm209912 */
297*5306Sgm209912 int
sdp_add_origin(sdp_session_t * session,const char * name,uint64_t id,uint64_t ver,const char * nettype,const char * addrtype,const char * address)298*5306Sgm209912 sdp_add_origin(sdp_session_t *session, const char *name, uint64_t id,
299*5306Sgm209912 uint64_t ver, const char *nettype, const char *addrtype,
300*5306Sgm209912 const char *address)
301*5306Sgm209912 {
302*5306Sgm209912 sdp_origin_t *origin;
303*5306Sgm209912 int ret = 0;
304*5306Sgm209912
305*5306Sgm209912 if (session == NULL || name == NULL || nettype == NULL ||
306*5306Sgm209912 addrtype == NULL || address == NULL) {
307*5306Sgm209912 return (EINVAL);
308*5306Sgm209912 }
309*5306Sgm209912 if (session->s_origin != NULL)
310*5306Sgm209912 return (EPROTO);
311*5306Sgm209912 origin = calloc(1, sizeof (sdp_origin_t));
312*5306Sgm209912 if (origin == NULL)
313*5306Sgm209912 return (ENOMEM);
314*5306Sgm209912 origin->o_id = id;
315*5306Sgm209912 origin->o_version = ver;
316*5306Sgm209912 if ((ret = commp_add_str(&origin->o_username, name, strlen(name))) != 0)
317*5306Sgm209912 goto err_ret;
318*5306Sgm209912 if ((ret = commp_add_str(&origin->o_nettype, nettype,
319*5306Sgm209912 strlen(nettype))) != 0) {
320*5306Sgm209912 goto err_ret;
321*5306Sgm209912 }
322*5306Sgm209912 if ((ret = commp_add_str(&origin->o_addrtype, addrtype,
323*5306Sgm209912 strlen(addrtype))) != 0) {
324*5306Sgm209912 goto err_ret;
325*5306Sgm209912 }
326*5306Sgm209912 if ((ret = commp_add_str(&origin->o_address, address,
327*5306Sgm209912 strlen(address))) != 0) {
328*5306Sgm209912 goto err_ret;
329*5306Sgm209912 }
330*5306Sgm209912 session->s_origin = origin;
331*5306Sgm209912 return (ret);
332*5306Sgm209912 err_ret:
333*5306Sgm209912 sdp_free_origin(origin);
334*5306Sgm209912 return (ret);
335*5306Sgm209912 }
336*5306Sgm209912
337*5306Sgm209912 /*
338*5306Sgm209912 * Adds session name field to the session.
339*5306Sgm209912 * s=<session name>
340*5306Sgm209912 */
341*5306Sgm209912 int
sdp_add_name(sdp_session_t * session,const char * name)342*5306Sgm209912 sdp_add_name(sdp_session_t *session, const char *name)
343*5306Sgm209912 {
344*5306Sgm209912 if (session == NULL || name == NULL)
345*5306Sgm209912 return (EINVAL);
346*5306Sgm209912 if (session->s_name != NULL)
347*5306Sgm209912 return (EPROTO);
348*5306Sgm209912 return (commp_add_str(&session->s_name, name, strlen(name)));
349*5306Sgm209912 }
350*5306Sgm209912
351*5306Sgm209912 /*
352*5306Sgm209912 * Adds session information field to the session or media section of SDP.
353*5306Sgm209912 * i=<session description>
354*5306Sgm209912 */
355*5306Sgm209912 int
sdp_add_information(char ** information,const char * value)356*5306Sgm209912 sdp_add_information(char **information, const char *value)
357*5306Sgm209912 {
358*5306Sgm209912 if (information == NULL || value == NULL)
359*5306Sgm209912 return (EINVAL);
360*5306Sgm209912 if (*information != NULL)
361*5306Sgm209912 return (EPROTO);
362*5306Sgm209912 return (commp_add_str(information, value, strlen(value)));
363*5306Sgm209912 }
364*5306Sgm209912
365*5306Sgm209912 /*
366*5306Sgm209912 * Adds uri field to the session.
367*5306Sgm209912 * u=<uri>
368*5306Sgm209912 */
369*5306Sgm209912 int
sdp_add_uri(sdp_session_t * session,const char * uri)370*5306Sgm209912 sdp_add_uri(sdp_session_t *session, const char *uri)
371*5306Sgm209912 {
372*5306Sgm209912 if (session == NULL || uri == NULL)
373*5306Sgm209912 return (EINVAL);
374*5306Sgm209912 if (session->s_uri != NULL)
375*5306Sgm209912 return (EPROTO);
376*5306Sgm209912 return (commp_add_str(&session->s_uri, uri, strlen(uri)));
377*5306Sgm209912 }
378*5306Sgm209912
379*5306Sgm209912 /*
380*5306Sgm209912 * Adds email address field to the session.
381*5306Sgm209912 * e=<email-address>
382*5306Sgm209912 */
383*5306Sgm209912 int
sdp_add_email(sdp_session_t * session,const char * email)384*5306Sgm209912 sdp_add_email(sdp_session_t *session, const char *email)
385*5306Sgm209912 {
386*5306Sgm209912 if (session == NULL || email == NULL || (strlen(email) == 0))
387*5306Sgm209912 return (EINVAL);
388*5306Sgm209912 return (add_value_to_list(&session->s_email, email, strlen(email),
389*5306Sgm209912 B_TRUE));
390*5306Sgm209912 }
391*5306Sgm209912
392*5306Sgm209912 /*
393*5306Sgm209912 * Adds phone number field to the session.
394*5306Sgm209912 * p=<phone-number>
395*5306Sgm209912 */
396*5306Sgm209912 int
sdp_add_phone(sdp_session_t * session,const char * phone)397*5306Sgm209912 sdp_add_phone(sdp_session_t *session, const char *phone)
398*5306Sgm209912 {
399*5306Sgm209912 if (session == NULL || phone == NULL || (strlen(phone) == 0))
400*5306Sgm209912 return (EINVAL);
401*5306Sgm209912 return (add_value_to_list(&session->s_phone, phone, strlen(phone),
402*5306Sgm209912 B_TRUE));
403*5306Sgm209912 }
404*5306Sgm209912
405*5306Sgm209912 /*
406*5306Sgm209912 * Adds connection field to the session or media section of SDP
407*5306Sgm209912 * c=<nettype> <addrtype> <connection-address>[/ttl]/<number of addresses>
408*5306Sgm209912 */
409*5306Sgm209912 int
sdp_add_connection(sdp_conn_t ** conn,const char * nettype,const char * addrtype,const char * address,uint8_t ttl,int addrcount)410*5306Sgm209912 sdp_add_connection(sdp_conn_t **conn, const char *nettype, const char *addrtype,
411*5306Sgm209912 const char *address, uint8_t ttl, int addrcount)
412*5306Sgm209912 {
413*5306Sgm209912 sdp_conn_t *tmp;
414*5306Sgm209912 sdp_conn_t *new_conn;
415*5306Sgm209912 int ret = 0;
416*5306Sgm209912
417*5306Sgm209912 if (conn == NULL || nettype == NULL || addrtype == NULL ||
418*5306Sgm209912 address == NULL) {
419*5306Sgm209912 return (EINVAL);
420*5306Sgm209912 }
421*5306Sgm209912 new_conn = calloc(1, sizeof (sdp_conn_t));
422*5306Sgm209912 if (new_conn == NULL)
423*5306Sgm209912 return (ENOMEM);
424*5306Sgm209912 new_conn->c_ttl = ttl;
425*5306Sgm209912 new_conn->c_addrcount = addrcount;
426*5306Sgm209912 if ((ret = commp_add_str(&new_conn->c_nettype, nettype,
427*5306Sgm209912 strlen(nettype))) != 0) {
428*5306Sgm209912 goto err_ret;
429*5306Sgm209912 }
430*5306Sgm209912 if ((ret = commp_add_str(&new_conn->c_addrtype, addrtype,
431*5306Sgm209912 strlen(addrtype))) != 0) {
432*5306Sgm209912 goto err_ret;
433*5306Sgm209912 }
434*5306Sgm209912 if ((ret = commp_add_str(&new_conn->c_address, address,
435*5306Sgm209912 strlen(address))) != 0) {
436*5306Sgm209912 goto err_ret;
437*5306Sgm209912 }
438*5306Sgm209912 if (*conn == NULL) {
439*5306Sgm209912 *conn = new_conn;
440*5306Sgm209912 } else {
441*5306Sgm209912 tmp = *conn;
442*5306Sgm209912 while (tmp->c_next != NULL)
443*5306Sgm209912 tmp = tmp->c_next;
444*5306Sgm209912 tmp->c_next = new_conn;
445*5306Sgm209912 }
446*5306Sgm209912 return (ret);
447*5306Sgm209912 err_ret:
448*5306Sgm209912 sdp_free_connection(new_conn);
449*5306Sgm209912 return (ret);
450*5306Sgm209912 }
451*5306Sgm209912
452*5306Sgm209912 /*
453*5306Sgm209912 * Adds bandwidth field to the session or media section of SDP.
454*5306Sgm209912 * b=<bwtype>:<bandwidth>
455*5306Sgm209912 */
456*5306Sgm209912 int
sdp_add_bandwidth(sdp_bandwidth_t ** bw,const char * type,uint64_t value)457*5306Sgm209912 sdp_add_bandwidth(sdp_bandwidth_t **bw, const char *type, uint64_t value)
458*5306Sgm209912 {
459*5306Sgm209912 sdp_bandwidth_t *new_bw;
460*5306Sgm209912 sdp_bandwidth_t *tmp;
461*5306Sgm209912 int ret = 0;
462*5306Sgm209912
463*5306Sgm209912 if (bw == NULL || type == NULL)
464*5306Sgm209912 return (EINVAL);
465*5306Sgm209912 new_bw = calloc(1, sizeof (sdp_bandwidth_t));
466*5306Sgm209912 if (new_bw == NULL)
467*5306Sgm209912 return (ENOMEM);
468*5306Sgm209912 new_bw->b_value = value;
469*5306Sgm209912 if ((ret = commp_add_str(&new_bw->b_type, type, strlen(type))) != 0) {
470*5306Sgm209912 free(new_bw);
471*5306Sgm209912 return (ret);
472*5306Sgm209912 }
473*5306Sgm209912 if (*bw == NULL) {
474*5306Sgm209912 *bw = new_bw;
475*5306Sgm209912 } else {
476*5306Sgm209912 tmp = *bw;
477*5306Sgm209912 while (tmp->b_next != NULL)
478*5306Sgm209912 tmp = tmp->b_next;
479*5306Sgm209912 tmp->b_next = new_bw;
480*5306Sgm209912 }
481*5306Sgm209912 return (ret);
482*5306Sgm209912 }
483*5306Sgm209912
484*5306Sgm209912 /*
485*5306Sgm209912 * Adds time field to the session
486*5306Sgm209912 * t=<start-time> <stop-time>
487*5306Sgm209912 */
488*5306Sgm209912 int
sdp_add_time(sdp_session_t * session,uint64_t starttime,uint64_t stoptime,sdp_time_t ** time)489*5306Sgm209912 sdp_add_time(sdp_session_t *session, uint64_t starttime, uint64_t stoptime,
490*5306Sgm209912 sdp_time_t **time)
491*5306Sgm209912 {
492*5306Sgm209912 sdp_time_t *new_time;
493*5306Sgm209912 sdp_time_t *tmp;
494*5306Sgm209912
495*5306Sgm209912 if (time != NULL)
496*5306Sgm209912 *time = NULL;
497*5306Sgm209912 if (session == NULL) {
498*5306Sgm209912 return (EINVAL);
499*5306Sgm209912 }
500*5306Sgm209912 new_time = calloc(1, sizeof (sdp_time_t));
501*5306Sgm209912 if (new_time == NULL) {
502*5306Sgm209912 return (ENOMEM);
503*5306Sgm209912 }
504*5306Sgm209912 new_time->t_start = starttime;
505*5306Sgm209912 new_time->t_stop = stoptime;
506*5306Sgm209912 tmp = session->s_time;
507*5306Sgm209912 if (tmp == NULL)
508*5306Sgm209912 session->s_time = new_time;
509*5306Sgm209912 else {
510*5306Sgm209912 while (tmp->t_next != NULL)
511*5306Sgm209912 tmp = tmp->t_next;
512*5306Sgm209912 tmp->t_next = new_time;
513*5306Sgm209912 }
514*5306Sgm209912 if (time != NULL)
515*5306Sgm209912 *time = new_time;
516*5306Sgm209912 return (0);
517*5306Sgm209912 }
518*5306Sgm209912
519*5306Sgm209912 /*
520*5306Sgm209912 * Adds repeat field to the time structure of session
521*5306Sgm209912 * r=<repeat interval> <active duration> <offsets from start-time>
522*5306Sgm209912 */
523*5306Sgm209912 int
sdp_add_repeat(sdp_time_t * time,uint64_t interval,uint64_t duration,const char * offset)524*5306Sgm209912 sdp_add_repeat(sdp_time_t *time, uint64_t interval, uint64_t duration,
525*5306Sgm209912 const char *offset)
526*5306Sgm209912 {
527*5306Sgm209912 sdp_repeat_t *tmp;
528*5306Sgm209912 sdp_repeat_t *new_repeat;
529*5306Sgm209912 int ret = 0;
530*5306Sgm209912
531*5306Sgm209912 if (time == NULL || offset == NULL)
532*5306Sgm209912 return (EINVAL);
533*5306Sgm209912 new_repeat = calloc(1, sizeof (sdp_repeat_t));
534*5306Sgm209912 if (new_repeat == NULL)
535*5306Sgm209912 return (ENOMEM);
536*5306Sgm209912 new_repeat->r_interval = interval;
537*5306Sgm209912 new_repeat->r_duration = duration;
538*5306Sgm209912 if ((ret = sdp_str_to_list(&new_repeat->r_offset, offset,
539*5306Sgm209912 strlen(offset), B_FALSE)) != 0) {
540*5306Sgm209912 goto err_ret;
541*5306Sgm209912 }
542*5306Sgm209912 tmp = time->t_repeat;
543*5306Sgm209912 if (tmp == NULL) {
544*5306Sgm209912 time->t_repeat = new_repeat;
545*5306Sgm209912 } else {
546*5306Sgm209912 while (tmp->r_next != NULL)
547*5306Sgm209912 tmp = tmp->r_next;
548*5306Sgm209912 tmp->r_next = new_repeat;
549*5306Sgm209912 }
550*5306Sgm209912 return (ret);
551*5306Sgm209912 err_ret:
552*5306Sgm209912 sdp_free_repeat(new_repeat);
553*5306Sgm209912 return (ret);
554*5306Sgm209912 }
555*5306Sgm209912
556*5306Sgm209912 /*
557*5306Sgm209912 * Adds time zone field to the session
558*5306Sgm209912 * z=<adjustment time> <offset> <adjustment time> <offset> ....
559*5306Sgm209912 */
560*5306Sgm209912 int
sdp_add_zone(sdp_session_t * session,uint64_t time,const char * offset)561*5306Sgm209912 sdp_add_zone(sdp_session_t *session, uint64_t time, const char *offset)
562*5306Sgm209912 {
563*5306Sgm209912 sdp_zone_t *new_zone;
564*5306Sgm209912 sdp_zone_t *tmp;
565*5306Sgm209912 int ret = 0;
566*5306Sgm209912
567*5306Sgm209912 if (session == NULL || offset == NULL)
568*5306Sgm209912 return (EINVAL);
569*5306Sgm209912 new_zone = calloc(1, sizeof (sdp_zone_t));
570*5306Sgm209912 if (new_zone == NULL)
571*5306Sgm209912 return (ENOMEM);
572*5306Sgm209912 new_zone->z_time = time;
573*5306Sgm209912 if ((ret = commp_add_str(&new_zone->z_offset, offset,
574*5306Sgm209912 strlen(offset))) != 0) {
575*5306Sgm209912 free(new_zone);
576*5306Sgm209912 return (ret);
577*5306Sgm209912 }
578*5306Sgm209912 tmp = session->s_zone;
579*5306Sgm209912 if (tmp == NULL) {
580*5306Sgm209912 session->s_zone = new_zone;
581*5306Sgm209912 } else {
582*5306Sgm209912 while (tmp->z_next != NULL) {
583*5306Sgm209912 tmp = tmp->z_next;
584*5306Sgm209912 }
585*5306Sgm209912 tmp->z_next = new_zone;
586*5306Sgm209912 }
587*5306Sgm209912 return (ret);
588*5306Sgm209912 }
589*5306Sgm209912
590*5306Sgm209912 /*
591*5306Sgm209912 * Adds key field to session or media section of SDP.
592*5306Sgm209912 * k=<method>
593*5306Sgm209912 * k=<method>:<encryption key>
594*5306Sgm209912 */
595*5306Sgm209912 int
sdp_add_key(sdp_key_t ** key,const char * method,const char * enckey)596*5306Sgm209912 sdp_add_key(sdp_key_t **key, const char *method, const char *enckey)
597*5306Sgm209912 {
598*5306Sgm209912 int ret = 0;
599*5306Sgm209912
600*5306Sgm209912 if (key == NULL || method == NULL)
601*5306Sgm209912 return (EINVAL);
602*5306Sgm209912 if (*key != NULL)
603*5306Sgm209912 return (EPROTO);
604*5306Sgm209912 *key = calloc(1, sizeof (sdp_key_t));
605*5306Sgm209912 if (*key == NULL)
606*5306Sgm209912 return (ENOMEM);
607*5306Sgm209912 if ((ret = commp_add_str(&((*key)->k_method), method,
608*5306Sgm209912 strlen(method))) != 0) {
609*5306Sgm209912 goto err_ret;
610*5306Sgm209912 }
611*5306Sgm209912 if (enckey != NULL) {
612*5306Sgm209912 if ((ret = commp_add_str(&((*key)->k_enckey), enckey,
613*5306Sgm209912 strlen(enckey))) != 0) {
614*5306Sgm209912 goto err_ret;
615*5306Sgm209912 }
616*5306Sgm209912 }
617*5306Sgm209912 return (ret);
618*5306Sgm209912 err_ret:
619*5306Sgm209912 sdp_free_key(*key);
620*5306Sgm209912 *key = NULL;
621*5306Sgm209912 return (ret);
622*5306Sgm209912 }
623*5306Sgm209912
624*5306Sgm209912 /*
625*5306Sgm209912 * Adds attribute field to session or media section of SDP.
626*5306Sgm209912 * a=<attribute>
627*5306Sgm209912 * a=<attribute>:<value>
628*5306Sgm209912 */
629*5306Sgm209912 int
sdp_add_attribute(sdp_attr_t ** attr,const char * name,const char * value)630*5306Sgm209912 sdp_add_attribute(sdp_attr_t **attr, const char *name, const char *value)
631*5306Sgm209912 {
632*5306Sgm209912 sdp_attr_t *tmp;
633*5306Sgm209912 sdp_attr_t *new_attr;
634*5306Sgm209912 int ret = 0;
635*5306Sgm209912
636*5306Sgm209912 if (attr == NULL || name == NULL)
637*5306Sgm209912 return (EINVAL);
638*5306Sgm209912 new_attr = calloc(1, sizeof (sdp_attr_t));
639*5306Sgm209912 if (new_attr == NULL)
640*5306Sgm209912 return (ENOMEM);
641*5306Sgm209912 if ((ret = commp_add_str(&new_attr->a_name, name, strlen(name))) != 0)
642*5306Sgm209912 goto err_ret;
643*5306Sgm209912 if (value != NULL) {
644*5306Sgm209912 if ((ret = commp_add_str(&new_attr->a_value, value,
645*5306Sgm209912 strlen(value))) != 0) {
646*5306Sgm209912 goto err_ret;
647*5306Sgm209912 }
648*5306Sgm209912 }
649*5306Sgm209912 tmp = *attr;
650*5306Sgm209912 if (tmp == NULL) {
651*5306Sgm209912 *attr = new_attr;
652*5306Sgm209912 } else {
653*5306Sgm209912 while (tmp->a_next != NULL)
654*5306Sgm209912 tmp = tmp->a_next;
655*5306Sgm209912 tmp->a_next = new_attr;
656*5306Sgm209912 }
657*5306Sgm209912 return (ret);
658*5306Sgm209912 err_ret:
659*5306Sgm209912 sdp_free_attribute(new_attr);
660*5306Sgm209912 return (ret);
661*5306Sgm209912 }
662*5306Sgm209912
663*5306Sgm209912 /*
664*5306Sgm209912 * Adds media field to the session.
665*5306Sgm209912 * m=<media> <port>[/portcount] <proto> <fmt> ...
666*5306Sgm209912 */
667*5306Sgm209912 int
sdp_add_media(sdp_session_t * session,const char * name,uint_t port,int portcount,const char * protocol,const char * fmt,sdp_media_t ** media)668*5306Sgm209912 sdp_add_media(sdp_session_t *session, const char *name, uint_t port,
669*5306Sgm209912 int portcount, const char *protocol, const char *fmt, sdp_media_t **media)
670*5306Sgm209912 {
671*5306Sgm209912 sdp_media_t *tmp;
672*5306Sgm209912 sdp_media_t *new_media;
673*5306Sgm209912 int ret = 0;
674*5306Sgm209912
675*5306Sgm209912 if (media != NULL)
676*5306Sgm209912 *media = NULL;
677*5306Sgm209912 if (session == NULL || name == NULL || protocol == NULL ||
678*5306Sgm209912 portcount <= 0 || fmt == NULL) {
679*5306Sgm209912 return (EINVAL);
680*5306Sgm209912 }
681*5306Sgm209912 new_media = calloc(1, sizeof (sdp_media_t));
682*5306Sgm209912 if (new_media == NULL) {
683*5306Sgm209912 return (ENOMEM);
684*5306Sgm209912 }
685*5306Sgm209912 new_media->m_session = session;
686*5306Sgm209912 new_media->m_port = port;
687*5306Sgm209912 new_media->m_portcount = portcount;
688*5306Sgm209912 if ((ret = commp_add_str(&new_media->m_name, name, strlen(name))) != 0)
689*5306Sgm209912 goto err_ret;
690*5306Sgm209912 if ((ret = commp_add_str(&new_media->m_proto, protocol,
691*5306Sgm209912 strlen(protocol))) != 0) {
692*5306Sgm209912 goto err_ret;
693*5306Sgm209912 }
694*5306Sgm209912 if ((ret = sdp_str_to_list(&new_media->m_format, fmt,
695*5306Sgm209912 strlen(fmt), B_TRUE)) != 0) {
696*5306Sgm209912 goto err_ret;
697*5306Sgm209912 }
698*5306Sgm209912 tmp = session->s_media;
699*5306Sgm209912 if (tmp == NULL) {
700*5306Sgm209912 session->s_media = new_media;
701*5306Sgm209912 } else {
702*5306Sgm209912 while (tmp->m_next != NULL)
703*5306Sgm209912 tmp = tmp->m_next;
704*5306Sgm209912 tmp->m_next = new_media;
705*5306Sgm209912 }
706*5306Sgm209912 if (media != NULL)
707*5306Sgm209912 *media = new_media;
708*5306Sgm209912 return (0);
709*5306Sgm209912 err_ret:
710*5306Sgm209912 sdp_free_media(new_media);
711*5306Sgm209912 return (ret);
712*5306Sgm209912 }
713*5306Sgm209912
714*5306Sgm209912 /*
715*5306Sgm209912 * This internal API is required by sdp_session_to_str(). It determines the
716*5306Sgm209912 * length of buffer that is required to hold the session. Since the RFC does
717*5306Sgm209912 * not limit the size of various sub-fields in the field. We need to scan
718*5306Sgm209912 * through the structure to determine the length.
719*5306Sgm209912 */
720*5306Sgm209912 int
sdp_get_length(const sdp_session_t * session)721*5306Sgm209912 sdp_get_length(const sdp_session_t *session)
722*5306Sgm209912 {
723*5306Sgm209912 int len = 0;
724*5306Sgm209912 char buf[1];
725*5306Sgm209912 sdp_list_t *list;
726*5306Sgm209912 sdp_conn_t *conn;
727*5306Sgm209912 sdp_bandwidth_t *bw;
728*5306Sgm209912 sdp_zone_t *zone;
729*5306Sgm209912 sdp_time_t *time;
730*5306Sgm209912 sdp_repeat_t *repeat;
731*5306Sgm209912 sdp_attr_t *attr;
732*5306Sgm209912 sdp_media_t *media;
733*5306Sgm209912
734*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
735*5306Sgm209912 len += snprintf(buf, 1, "%d", session->s_version);
736*5306Sgm209912 if (session->s_origin != NULL) {
737*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
738*5306Sgm209912 len += strlen(session->s_origin->o_username);
739*5306Sgm209912 len += snprintf(buf, 1, "%llu", session->s_origin->o_id) + 1;
740*5306Sgm209912 len += snprintf(buf, 1, "%llu", session->s_origin->o_version)
741*5306Sgm209912 + 1;
742*5306Sgm209912 len += strlen(session->s_origin->o_nettype) + 1;
743*5306Sgm209912 len += strlen(session->s_origin->o_addrtype) + 1;
744*5306Sgm209912 len += strlen(session->s_origin->o_address) + 1;
745*5306Sgm209912 }
746*5306Sgm209912 if (session->s_name != NULL)
747*5306Sgm209912 len += strlen(session->s_name) + FIELD_EQUALS_CRLF_LEN;
748*5306Sgm209912 if (session->s_info != NULL)
749*5306Sgm209912 len += strlen(session->s_info) + FIELD_EQUALS_CRLF_LEN;
750*5306Sgm209912 if (session->s_uri != NULL)
751*5306Sgm209912 len += strlen(session->s_uri) + FIELD_EQUALS_CRLF_LEN;
752*5306Sgm209912 list = session->s_email;
753*5306Sgm209912 while (list != NULL) {
754*5306Sgm209912 len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN;
755*5306Sgm209912 list = list->next;
756*5306Sgm209912 }
757*5306Sgm209912 list = session->s_phone;
758*5306Sgm209912 while (list != NULL) {
759*5306Sgm209912 len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN;
760*5306Sgm209912 list = list->next;
761*5306Sgm209912 }
762*5306Sgm209912 conn = session->s_conn;
763*5306Sgm209912 SDP_LEN_CONNECTION(conn);
764*5306Sgm209912 bw = session->s_bw;
765*5306Sgm209912 SDP_LEN_BANDWIDTH(bw);
766*5306Sgm209912 time = session->s_time;
767*5306Sgm209912 while (time != NULL) {
768*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
769*5306Sgm209912 len += snprintf(buf, 1, "%llu", time->t_start);
770*5306Sgm209912 len += snprintf(buf, 1, "%llu", time->t_stop) + 1;
771*5306Sgm209912 repeat = time->t_repeat;
772*5306Sgm209912 while (repeat != NULL) {
773*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
774*5306Sgm209912 len += snprintf(buf, 1, "%llu", repeat->r_interval);
775*5306Sgm209912 len += snprintf(buf, 1, "%llu", repeat->r_duration) + 1;
776*5306Sgm209912 list = repeat->r_offset;
777*5306Sgm209912 while (list != NULL) {
778*5306Sgm209912 len += snprintf(buf, 1, "%llu",
779*5306Sgm209912 *(uint64_t *)list->value) + 1;
780*5306Sgm209912 list = list->next;
781*5306Sgm209912 }
782*5306Sgm209912 repeat = repeat->r_next;
783*5306Sgm209912 }
784*5306Sgm209912 time = time->t_next;
785*5306Sgm209912 }
786*5306Sgm209912 if (session->s_zone != NULL)
787*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
788*5306Sgm209912 zone = session->s_zone;
789*5306Sgm209912 while (zone != NULL) {
790*5306Sgm209912 len += snprintf(buf, 1, "%llu", zone->z_time) + 1;
791*5306Sgm209912 len += strlen(zone->z_offset) + 1;
792*5306Sgm209912 zone = zone->z_next;
793*5306Sgm209912 }
794*5306Sgm209912 SDP_LEN_KEY(session->s_key);
795*5306Sgm209912 attr = session->s_attr;
796*5306Sgm209912 SDP_LEN_ATTRIBUTE(attr);
797*5306Sgm209912 media = session->s_media;
798*5306Sgm209912 while (media != NULL) {
799*5306Sgm209912 len += FIELD_EQUALS_CRLF_LEN;
800*5306Sgm209912 len += strlen(media->m_name);
801*5306Sgm209912 len += snprintf(buf, 1, "%u", media->m_port) + 1;
802*5306Sgm209912 len += snprintf(buf, 1, "%d", media->m_portcount) + 1;
803*5306Sgm209912 len += strlen(media->m_proto) + 1;
804*5306Sgm209912 list = media->m_format;
805*5306Sgm209912 while (list != NULL) {
806*5306Sgm209912 len += strlen((char *)list->value) + 1;
807*5306Sgm209912 list = list->next;
808*5306Sgm209912 }
809*5306Sgm209912 if (media->m_info != NULL)
810*5306Sgm209912 len += strlen(media->m_info) + FIELD_EQUALS_CRLF_LEN;
811*5306Sgm209912 conn = media->m_conn;
812*5306Sgm209912 SDP_LEN_CONNECTION(conn);
813*5306Sgm209912 bw = media->m_bw;
814*5306Sgm209912 SDP_LEN_BANDWIDTH(bw);
815*5306Sgm209912 SDP_LEN_KEY(media->m_key);
816*5306Sgm209912 attr = media->m_attr;
817*5306Sgm209912 SDP_LEN_ATTRIBUTE(attr);
818*5306Sgm209912 media = media->m_next;
819*5306Sgm209912 }
820*5306Sgm209912 return (len);
821*5306Sgm209912 }
822*5306Sgm209912
823*5306Sgm209912 /*
824*5306Sgm209912 * Given a session structure it clones (deep copy) and returns the cloned copy
825*5306Sgm209912 */
826*5306Sgm209912 sdp_session_t *
sdp_clone_session(const sdp_session_t * session)827*5306Sgm209912 sdp_clone_session(const sdp_session_t *session)
828*5306Sgm209912 {
829*5306Sgm209912 sdp_session_t *new_sess;
830*5306Sgm209912 sdp_origin_t *origin;
831*5306Sgm209912 sdp_list_t *list;
832*5306Sgm209912 sdp_time_t *time;
833*5306Sgm209912 sdp_time_t *new_time;
834*5306Sgm209912 sdp_repeat_t *repeat;
835*5306Sgm209912 sdp_media_t *media;
836*5306Sgm209912 sdp_media_t *new_media;
837*5306Sgm209912 sdp_conn_t *conn;
838*5306Sgm209912 sdp_bandwidth_t *bw;
839*5306Sgm209912 sdp_attr_t *attr;
840*5306Sgm209912 sdp_zone_t *zone;
841*5306Sgm209912 char *offset = NULL;
842*5306Sgm209912 char *format = NULL;
843*5306Sgm209912
844*5306Sgm209912 if (session == NULL)
845*5306Sgm209912 return (NULL);
846*5306Sgm209912 new_sess = calloc(1, sizeof (sdp_session_t));
847*5306Sgm209912 if (new_sess == NULL)
848*5306Sgm209912 return (NULL);
849*5306Sgm209912 new_sess->sdp_session_version = session->sdp_session_version;
850*5306Sgm209912 new_sess->s_version = session->s_version;
851*5306Sgm209912 origin = session->s_origin;
852*5306Sgm209912 if (origin != NULL && (sdp_add_origin(new_sess, origin->o_username,
853*5306Sgm209912 origin->o_id, origin->o_version, origin->o_nettype, origin->
854*5306Sgm209912 o_addrtype, origin->o_address) != 0)) {
855*5306Sgm209912 goto err_ret;
856*5306Sgm209912 }
857*5306Sgm209912 if (session->s_name != NULL && sdp_add_name(new_sess, session->
858*5306Sgm209912 s_name) != 0) {
859*5306Sgm209912 goto err_ret;
860*5306Sgm209912 }
861*5306Sgm209912 if (session->s_info != NULL && sdp_add_information(&new_sess->
862*5306Sgm209912 s_info, session->s_info) != 0) {
863*5306Sgm209912 goto err_ret;
864*5306Sgm209912 }
865*5306Sgm209912 if (session->s_uri != NULL && sdp_add_uri(new_sess, session->
866*5306Sgm209912 s_uri) != 0) {
867*5306Sgm209912 goto err_ret;
868*5306Sgm209912 }
869*5306Sgm209912 list = session->s_email;
870*5306Sgm209912 while (list != NULL) {
871*5306Sgm209912 if (sdp_add_email(new_sess, (char *)list->value) != 0)
872*5306Sgm209912 goto err_ret;
873*5306Sgm209912 list = list->next;
874*5306Sgm209912 }
875*5306Sgm209912 list = session->s_phone;
876*5306Sgm209912 while (list != NULL) {
877*5306Sgm209912 if (sdp_add_phone(new_sess, (char *)list->value) != 0)
878*5306Sgm209912 goto err_ret;
879*5306Sgm209912 list = list->next;
880*5306Sgm209912 }
881*5306Sgm209912 conn = session->s_conn;
882*5306Sgm209912 SDP_ADD_CONNECTION(new_sess->s_conn, conn);
883*5306Sgm209912 bw = session->s_bw;
884*5306Sgm209912 SDP_ADD_BANDWIDTH(new_sess->s_bw, bw);
885*5306Sgm209912 time = session->s_time;
886*5306Sgm209912 while (time != NULL) {
887*5306Sgm209912 if (sdp_add_time(new_sess, time->t_start, time->t_stop,
888*5306Sgm209912 &new_time) != 0) {
889*5306Sgm209912 goto err_ret;
890*5306Sgm209912 }
891*5306Sgm209912 repeat = time->t_repeat;
892*5306Sgm209912 while (repeat != NULL) {
893*5306Sgm209912 if (sdp_list_to_str(repeat->r_offset, &offset,
894*5306Sgm209912 B_FALSE) != 0) {
895*5306Sgm209912 goto err_ret;
896*5306Sgm209912 }
897*5306Sgm209912 if (sdp_add_repeat(new_time, repeat->r_interval,
898*5306Sgm209912 repeat->r_duration, offset) != 0) {
899*5306Sgm209912 free(offset);
900*5306Sgm209912 goto err_ret;
901*5306Sgm209912 }
902*5306Sgm209912 free(offset);
903*5306Sgm209912 repeat = repeat->r_next;
904*5306Sgm209912 }
905*5306Sgm209912 time = time->t_next;
906*5306Sgm209912 }
907*5306Sgm209912 zone = session->s_zone;
908*5306Sgm209912 while (zone != NULL) {
909*5306Sgm209912 if (sdp_add_zone(new_sess, zone->z_time, zone->z_offset) != 0)
910*5306Sgm209912 goto err_ret;
911*5306Sgm209912 zone = zone->z_next;
912*5306Sgm209912 }
913*5306Sgm209912 SDP_ADD_KEY(new_sess->s_key, session->s_key);
914*5306Sgm209912 attr = session->s_attr;
915*5306Sgm209912 SDP_ADD_ATTRIBUTE(new_sess->s_attr, attr);
916*5306Sgm209912 media = session->s_media;
917*5306Sgm209912 while (media != NULL) {
918*5306Sgm209912 if (sdp_list_to_str(media->m_format, &format, B_TRUE) != 0)
919*5306Sgm209912 goto err_ret;
920*5306Sgm209912 if (sdp_add_media(new_sess, media->m_name,
921*5306Sgm209912 media->m_port, media->m_portcount, media->m_proto,
922*5306Sgm209912 format, &new_media) != 0) {
923*5306Sgm209912 free(format);
924*5306Sgm209912 goto err_ret;
925*5306Sgm209912 }
926*5306Sgm209912 free(format);
927*5306Sgm209912 if (media->m_info != NULL) {
928*5306Sgm209912 if (sdp_add_information(&new_media->m_info,
929*5306Sgm209912 media->m_info) != 0) {
930*5306Sgm209912 goto err_ret;
931*5306Sgm209912 }
932*5306Sgm209912 }
933*5306Sgm209912 conn = media->m_conn;
934*5306Sgm209912 SDP_ADD_CONNECTION(new_media->m_conn, conn);
935*5306Sgm209912 bw = media->m_bw;
936*5306Sgm209912 SDP_ADD_BANDWIDTH(new_media->m_bw, bw);
937*5306Sgm209912 SDP_ADD_KEY(new_media->m_key, media->m_key);
938*5306Sgm209912 attr = media->m_attr;
939*5306Sgm209912 SDP_ADD_ATTRIBUTE(new_media->m_attr, attr);
940*5306Sgm209912 new_media->m_session = new_sess;
941*5306Sgm209912 media = media->m_next;
942*5306Sgm209912 }
943*5306Sgm209912 return (new_sess);
944*5306Sgm209912 err_ret:
945*5306Sgm209912 sdp_free_session(new_sess);
946*5306Sgm209912 return (NULL);
947*5306Sgm209912 }
948*5306Sgm209912
949*5306Sgm209912 /*
950*5306Sgm209912 * should i check if individual members are NULL, if not snprintf
951*5306Sgm209912 * will core dump.
952*5306Sgm209912 */
953*5306Sgm209912 /*
954*5306Sgm209912 * Given a session structure, this API converts it into character
955*5306Sgm209912 * buffer, which will be used as a payload later on.
956*5306Sgm209912 */
957*5306Sgm209912 char *
sdp_session_to_str(const sdp_session_t * session,int * error)958*5306Sgm209912 sdp_session_to_str(const sdp_session_t *session, int *error)
959*5306Sgm209912 {
960*5306Sgm209912 char *ret = NULL;
961*5306Sgm209912 char *buf = NULL;
962*5306Sgm209912 int len = 0;
963*5306Sgm209912 int s_len = 0;
964*5306Sgm209912 int wrote = 0;
965*5306Sgm209912 sdp_origin_t *origin;
966*5306Sgm209912 sdp_list_t *list;
967*5306Sgm209912 sdp_conn_t *conn;
968*5306Sgm209912 sdp_attr_t *attr;
969*5306Sgm209912 sdp_bandwidth_t *bw;
970*5306Sgm209912 sdp_time_t *time;
971*5306Sgm209912 sdp_repeat_t *repeat;
972*5306Sgm209912 sdp_zone_t *zone;
973*5306Sgm209912 sdp_media_t *media;
974*5306Sgm209912
975*5306Sgm209912 if (error != NULL)
976*5306Sgm209912 *error = 0;
977*5306Sgm209912 if (session == NULL) {
978*5306Sgm209912 if (error != NULL)
979*5306Sgm209912 *error = EINVAL;
980*5306Sgm209912 return (NULL);
981*5306Sgm209912 }
982*5306Sgm209912 s_len = sdp_get_length(session);
983*5306Sgm209912 ret = malloc(s_len + 1);
984*5306Sgm209912 if (ret == NULL) {
985*5306Sgm209912 if (error != NULL)
986*5306Sgm209912 *error = ENOMEM;
987*5306Sgm209912 return (NULL);
988*5306Sgm209912 }
989*5306Sgm209912 buf = ret;
990*5306Sgm209912 len = s_len + 1;
991*5306Sgm209912 wrote = snprintf(buf, len, "v=%d%s", session->s_version, COMMP_CRLF);
992*5306Sgm209912 len = len - wrote;
993*5306Sgm209912 buf = buf + wrote;
994*5306Sgm209912 origin = session->s_origin;
995*5306Sgm209912 if (origin != NULL) {
996*5306Sgm209912 wrote = snprintf(buf, len, "o=%s %llu %llu %s %s %s%s",
997*5306Sgm209912 origin->o_username, origin->o_id, origin->o_version,
998*5306Sgm209912 origin->o_nettype, origin->o_addrtype, origin->o_address,
999*5306Sgm209912 COMMP_CRLF);
1000*5306Sgm209912 len = len - wrote;
1001*5306Sgm209912 buf = buf + wrote;
1002*5306Sgm209912 }
1003*5306Sgm209912 if (session->s_name != NULL) {
1004*5306Sgm209912 wrote = snprintf(buf, len, "s=%s%s", session->s_name,
1005*5306Sgm209912 COMMP_CRLF);
1006*5306Sgm209912 len = len - wrote;
1007*5306Sgm209912 buf = buf + wrote;
1008*5306Sgm209912 }
1009*5306Sgm209912 SDP_INFORMATION_TO_STR(session->s_info);
1010*5306Sgm209912 if (session->s_uri != NULL) {
1011*5306Sgm209912 wrote = snprintf(buf, len, "u=%s%s", session->s_uri,
1012*5306Sgm209912 COMMP_CRLF);
1013*5306Sgm209912 len = len - wrote;
1014*5306Sgm209912 buf = buf + wrote;
1015*5306Sgm209912 }
1016*5306Sgm209912 list = session->s_email;
1017*5306Sgm209912 while (list != NULL) {
1018*5306Sgm209912 wrote = snprintf(buf, len, "e=%s%s", (char *)list->value,
1019*5306Sgm209912 COMMP_CRLF);
1020*5306Sgm209912 len = len - wrote;
1021*5306Sgm209912 buf = buf + wrote;
1022*5306Sgm209912 list = list->next;
1023*5306Sgm209912 }
1024*5306Sgm209912 list = session->s_phone;
1025*5306Sgm209912 while (list != NULL) {
1026*5306Sgm209912 wrote = snprintf(buf, len, "p=%s%s", (char *)list->value,
1027*5306Sgm209912 COMMP_CRLF);
1028*5306Sgm209912 len = len - wrote;
1029*5306Sgm209912 buf = buf + wrote;
1030*5306Sgm209912 list = list->next;
1031*5306Sgm209912 }
1032*5306Sgm209912 conn = session->s_conn;
1033*5306Sgm209912 SDP_CONNECTION_TO_STR(conn);
1034*5306Sgm209912 bw = session->s_bw;
1035*5306Sgm209912 SDP_BANDWIDTH_TO_STR(bw);
1036*5306Sgm209912 time = session->s_time;
1037*5306Sgm209912 while (time != NULL) {
1038*5306Sgm209912 wrote = snprintf(buf, len, "t=%llu %llu%s", time->t_start,
1039*5306Sgm209912 time->t_stop, COMMP_CRLF);
1040*5306Sgm209912 len = len - wrote;
1041*5306Sgm209912 buf = buf + wrote;
1042*5306Sgm209912 repeat = time->t_repeat;
1043*5306Sgm209912 while (repeat != NULL) {
1044*5306Sgm209912 wrote = snprintf(buf, len, "r=%llu %llu", repeat->
1045*5306Sgm209912 r_interval, repeat->r_duration);
1046*5306Sgm209912 len = len - wrote;
1047*5306Sgm209912 buf = buf + wrote;
1048*5306Sgm209912 list = repeat->r_offset;
1049*5306Sgm209912 while (list != NULL) {
1050*5306Sgm209912 wrote = snprintf(buf, len, " %llu",
1051*5306Sgm209912 *(uint64_t *)list->value);
1052*5306Sgm209912 len = len - wrote;
1053*5306Sgm209912 buf = buf + wrote;
1054*5306Sgm209912 list = list->next;
1055*5306Sgm209912 }
1056*5306Sgm209912 wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1057*5306Sgm209912 len = len - wrote;
1058*5306Sgm209912 buf = buf + wrote;
1059*5306Sgm209912 repeat = repeat->r_next;
1060*5306Sgm209912 }
1061*5306Sgm209912 time = time->t_next;
1062*5306Sgm209912 }
1063*5306Sgm209912 zone = session->s_zone;
1064*5306Sgm209912 if (zone != NULL) {
1065*5306Sgm209912 wrote = snprintf(buf, len, "z=%llu %s", zone->z_time,
1066*5306Sgm209912 zone->z_offset);
1067*5306Sgm209912 len = len - wrote;
1068*5306Sgm209912 buf = buf + wrote;
1069*5306Sgm209912 zone = zone->z_next;
1070*5306Sgm209912 while (zone != NULL) {
1071*5306Sgm209912 wrote = snprintf(buf, len, " %llu %s", zone->z_time,
1072*5306Sgm209912 zone->z_offset);
1073*5306Sgm209912 len = len - wrote;
1074*5306Sgm209912 buf = buf + wrote;
1075*5306Sgm209912 zone = zone->z_next;
1076*5306Sgm209912 }
1077*5306Sgm209912 wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1078*5306Sgm209912 len = len - wrote;
1079*5306Sgm209912 buf = buf + wrote;
1080*5306Sgm209912 }
1081*5306Sgm209912 SDP_KEY_TO_STR(session->s_key);
1082*5306Sgm209912 attr = session->s_attr;
1083*5306Sgm209912 SDP_ATTR_TO_STR(attr);
1084*5306Sgm209912 media = session->s_media;
1085*5306Sgm209912 while (media != NULL) {
1086*5306Sgm209912 if (media->m_portcount == 1) {
1087*5306Sgm209912 wrote = snprintf(buf, len, "m=%s %d %s", media->m_name,
1088*5306Sgm209912 media->m_port, media->m_proto);
1089*5306Sgm209912 } else {
1090*5306Sgm209912 wrote = snprintf(buf, len, "m=%s %d/%d %s", media->
1091*5306Sgm209912 m_name, media->m_port, media->m_portcount, media->
1092*5306Sgm209912 m_proto);
1093*5306Sgm209912 }
1094*5306Sgm209912 len = len - wrote;
1095*5306Sgm209912 buf = buf + wrote;
1096*5306Sgm209912 list = media->m_format;
1097*5306Sgm209912 while (list != NULL) {
1098*5306Sgm209912 wrote = snprintf(buf, len, " %s", (char *)list->value);
1099*5306Sgm209912 len = len - wrote;
1100*5306Sgm209912 buf = buf + wrote;
1101*5306Sgm209912 list = list->next;
1102*5306Sgm209912 }
1103*5306Sgm209912 wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1104*5306Sgm209912 len = len - wrote;
1105*5306Sgm209912 buf = buf + wrote;
1106*5306Sgm209912 SDP_INFORMATION_TO_STR(media->m_info);
1107*5306Sgm209912 conn = media->m_conn;
1108*5306Sgm209912 SDP_CONNECTION_TO_STR(conn);
1109*5306Sgm209912 bw = media->m_bw;
1110*5306Sgm209912 SDP_BANDWIDTH_TO_STR(bw);
1111*5306Sgm209912 SDP_KEY_TO_STR(media->m_key);
1112*5306Sgm209912 attr = media->m_attr;
1113*5306Sgm209912 SDP_ATTR_TO_STR(attr);
1114*5306Sgm209912 media = media->m_next;
1115*5306Sgm209912 }
1116*5306Sgm209912 assert(len >= 1);
1117*5306Sgm209912 *buf = '\0';
1118*5306Sgm209912 return (ret);
1119*5306Sgm209912 }
1120*5306Sgm209912
1121*5306Sgm209912 /*
1122*5306Sgm209912 * Given a session structure and the field ('v', 'o', 's', et al), this API
1123*5306Sgm209912 * deletes the corresponding structure element. It frees the memory and sets the
1124*5306Sgm209912 * pointer to NULL
1125*5306Sgm209912 */
1126*5306Sgm209912 int
sdp_delete_all_field(sdp_session_t * session,const char field)1127*5306Sgm209912 sdp_delete_all_field(sdp_session_t *session, const char field)
1128*5306Sgm209912 {
1129*5306Sgm209912 if (session == NULL)
1130*5306Sgm209912 return (EINVAL);
1131*5306Sgm209912 switch (field) {
1132*5306Sgm209912 case SDP_ORIGIN_FIELD:
1133*5306Sgm209912 sdp_free_origin(session->s_origin);
1134*5306Sgm209912 session->s_origin = NULL;
1135*5306Sgm209912 break;
1136*5306Sgm209912 case SDP_NAME_FIELD:
1137*5306Sgm209912 free(session->s_name);
1138*5306Sgm209912 session->s_name = NULL;
1139*5306Sgm209912 break;
1140*5306Sgm209912 case SDP_INFO_FIELD:
1141*5306Sgm209912 free(session->s_info);
1142*5306Sgm209912 session->s_info = NULL;
1143*5306Sgm209912 break;
1144*5306Sgm209912 case SDP_URI_FIELD:
1145*5306Sgm209912 free(session->s_uri);
1146*5306Sgm209912 session->s_uri = NULL;
1147*5306Sgm209912 break;
1148*5306Sgm209912 case SDP_EMAIL_FIELD:
1149*5306Sgm209912 sdp_free_list(session->s_email);
1150*5306Sgm209912 session->s_email = NULL;
1151*5306Sgm209912 break;
1152*5306Sgm209912 case SDP_PHONE_FIELD:
1153*5306Sgm209912 sdp_free_list(session->s_phone);
1154*5306Sgm209912 session->s_phone = NULL;
1155*5306Sgm209912 break;
1156*5306Sgm209912 case SDP_CONNECTION_FIELD:
1157*5306Sgm209912 sdp_free_connection(session->s_conn);
1158*5306Sgm209912 session->s_conn = NULL;
1159*5306Sgm209912 break;
1160*5306Sgm209912 case SDP_BANDWIDTH_FIELD:
1161*5306Sgm209912 sdp_free_bandwidth(session->s_bw);
1162*5306Sgm209912 session->s_bw = NULL;
1163*5306Sgm209912 break;
1164*5306Sgm209912 case SDP_TIME_FIELD:
1165*5306Sgm209912 sdp_free_time(session->s_time);
1166*5306Sgm209912 session->s_time = NULL;
1167*5306Sgm209912 break;
1168*5306Sgm209912 case SDP_ZONE_FIELD:
1169*5306Sgm209912 sdp_free_zone(session->s_zone);
1170*5306Sgm209912 session->s_zone = NULL;
1171*5306Sgm209912 break;
1172*5306Sgm209912 case SDP_KEY_FIELD:
1173*5306Sgm209912 sdp_free_key(session->s_key);
1174*5306Sgm209912 session->s_key = NULL;
1175*5306Sgm209912 break;
1176*5306Sgm209912 case SDP_ATTRIBUTE_FIELD:
1177*5306Sgm209912 sdp_free_attribute(session->s_attr);
1178*5306Sgm209912 session->s_attr = NULL;
1179*5306Sgm209912 break;
1180*5306Sgm209912 case SDP_MEDIA_FIELD:
1181*5306Sgm209912 sdp_free_media(session->s_media);
1182*5306Sgm209912 session->s_media = NULL;
1183*5306Sgm209912 break;
1184*5306Sgm209912 default:
1185*5306Sgm209912 return (EINVAL);
1186*5306Sgm209912 }
1187*5306Sgm209912 return (0);
1188*5306Sgm209912 }
1189*5306Sgm209912
1190*5306Sgm209912 /*
1191*5306Sgm209912 * Given a media structure and the field ('i', 'b', 'c', et al), this API
1192*5306Sgm209912 * deletes the corresponding structure element. It frees the memory and sets
1193*5306Sgm209912 * the pointer to NULL.
1194*5306Sgm209912 */
1195*5306Sgm209912 int
sdp_delete_all_media_field(sdp_media_t * media,const char field)1196*5306Sgm209912 sdp_delete_all_media_field(sdp_media_t *media, const char field)
1197*5306Sgm209912 {
1198*5306Sgm209912 if (media == NULL)
1199*5306Sgm209912 return (EINVAL);
1200*5306Sgm209912 switch (field) {
1201*5306Sgm209912 case SDP_INFO_FIELD:
1202*5306Sgm209912 free(media->m_info);
1203*5306Sgm209912 media->m_info = NULL;
1204*5306Sgm209912 break;
1205*5306Sgm209912 case SDP_CONNECTION_FIELD:
1206*5306Sgm209912 sdp_free_connection(media->m_conn);
1207*5306Sgm209912 media->m_conn = NULL;
1208*5306Sgm209912 break;
1209*5306Sgm209912 case SDP_BANDWIDTH_FIELD:
1210*5306Sgm209912 sdp_free_bandwidth(media->m_bw);
1211*5306Sgm209912 media->m_bw = NULL;
1212*5306Sgm209912 break;
1213*5306Sgm209912 case SDP_KEY_FIELD:
1214*5306Sgm209912 sdp_free_key(media->m_key);
1215*5306Sgm209912 media->m_key = NULL;
1216*5306Sgm209912 break;
1217*5306Sgm209912 case SDP_ATTRIBUTE_FIELD:
1218*5306Sgm209912 sdp_free_attribute(media->m_attr);
1219*5306Sgm209912 media->m_attr = NULL;
1220*5306Sgm209912 break;
1221*5306Sgm209912 default:
1222*5306Sgm209912 return (EINVAL);
1223*5306Sgm209912 }
1224*5306Sgm209912 return (0);
1225*5306Sgm209912 }
1226*5306Sgm209912
1227*5306Sgm209912 /*
1228*5306Sgm209912 * Given a media list and the media, this API deletes that media from the
1229*5306Sgm209912 * list. It frees the memory corresponding to that media.
1230*5306Sgm209912 */
1231*5306Sgm209912 int
sdp_delete_media(sdp_media_t ** l_media,sdp_media_t * media)1232*5306Sgm209912 sdp_delete_media(sdp_media_t **l_media, sdp_media_t *media)
1233*5306Sgm209912 {
1234*5306Sgm209912 sdp_media_t *cur;
1235*5306Sgm209912 sdp_media_t *prev;
1236*5306Sgm209912
1237*5306Sgm209912 if (l_media == NULL || *l_media == NULL || media == NULL)
1238*5306Sgm209912 return (EINVAL);
1239*5306Sgm209912 cur = *l_media;
1240*5306Sgm209912 prev = NULL;
1241*5306Sgm209912 while (cur != NULL && cur != media) {
1242*5306Sgm209912 prev = cur;
1243*5306Sgm209912 cur = cur->m_next;
1244*5306Sgm209912 }
1245*5306Sgm209912 if (cur == NULL)
1246*5306Sgm209912 return (EINVAL);
1247*5306Sgm209912 if (cur == *l_media)
1248*5306Sgm209912 *l_media = cur->m_next;
1249*5306Sgm209912 else
1250*5306Sgm209912 prev->m_next = cur->m_next;
1251*5306Sgm209912 cur->m_next = NULL;
1252*5306Sgm209912 sdp_free_media(cur);
1253*5306Sgm209912 return (0);
1254*5306Sgm209912 }
1255*5306Sgm209912
1256*5306Sgm209912 /*
1257*5306Sgm209912 * Given an attribute list and an attribute, this API deletes that attribue
1258*5306Sgm209912 * from the list. It frees the memory corresponding to that attribute.
1259*5306Sgm209912 */
1260*5306Sgm209912 int
sdp_delete_attribute(sdp_attr_t ** l_attr,sdp_attr_t * attr)1261*5306Sgm209912 sdp_delete_attribute(sdp_attr_t **l_attr, sdp_attr_t *attr)
1262*5306Sgm209912 {
1263*5306Sgm209912 sdp_attr_t *cur;
1264*5306Sgm209912 sdp_attr_t *prev;
1265*5306Sgm209912
1266*5306Sgm209912 if (l_attr == NULL || *l_attr == NULL || attr == NULL)
1267*5306Sgm209912 return (EINVAL);
1268*5306Sgm209912 cur = *l_attr;
1269*5306Sgm209912 prev = NULL;
1270*5306Sgm209912 while (cur != NULL && cur != attr) {
1271*5306Sgm209912 prev = cur;
1272*5306Sgm209912 cur = cur->a_next;
1273*5306Sgm209912 }
1274*5306Sgm209912 if (cur == NULL)
1275*5306Sgm209912 return (EINVAL);
1276*5306Sgm209912 if (cur == *l_attr)
1277*5306Sgm209912 *l_attr = cur->a_next;
1278*5306Sgm209912 else
1279*5306Sgm209912 prev->a_next = cur->a_next;
1280*5306Sgm209912 cur->a_next = NULL;
1281*5306Sgm209912 sdp_free_attribute(cur);
1282*5306Sgm209912 return (0);
1283*5306Sgm209912 }
1284*5306Sgm209912
1285*5306Sgm209912 /*
1286*5306Sgm209912 * Allocates a new sdp session structure and assigns a version number to it.
1287*5306Sgm209912 * Currently one version is defined and it is 1. This will be useful in future
1288*5306Sgm209912 * in the unlikely need to change the structure.
1289*5306Sgm209912 */
1290*5306Sgm209912 sdp_session_t *
sdp_new_session()1291*5306Sgm209912 sdp_new_session()
1292*5306Sgm209912 {
1293*5306Sgm209912 sdp_session_t *session = NULL;
1294*5306Sgm209912
1295*5306Sgm209912 session = calloc(1, sizeof (sdp_session_t));
1296*5306Sgm209912 if (session != NULL)
1297*5306Sgm209912 session->sdp_session_version = SDP_SESSION_VERSION_1;
1298*5306Sgm209912 return (session);
1299*5306Sgm209912 }
1300