1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Helper functions to skip white spaces, find tokens, find separators and free
29  * memory.
30  */
31 
32 #include <stdio.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <sdp.h>
39 
40 #include "sdp_parse.h"
41 #include "commp_util.h"
42 
43 void
sdp_free_origin(sdp_origin_t * origin)44 sdp_free_origin(sdp_origin_t *origin)
45 {
46 	if (origin != NULL) {
47 		if (origin->o_username != NULL)
48 			free(origin->o_username);
49 		if (origin->o_nettype != NULL)
50 			free(origin->o_nettype);
51 		if (origin->o_addrtype != NULL)
52 			free(origin->o_addrtype);
53 		if (origin->o_address != NULL)
54 			free(origin->o_address);
55 		free(origin);
56 	}
57 }
58 
59 void
sdp_free_key(sdp_key_t * key)60 sdp_free_key(sdp_key_t *key)
61 {
62 	if (key != NULL) {
63 		if (key->k_method != NULL)
64 			free(key->k_method);
65 		if (key->k_enckey != NULL)
66 			free(key->k_enckey);
67 		free(key);
68 	}
69 }
70 
71 void
sdp_free_zone(sdp_zone_t * zone)72 sdp_free_zone(sdp_zone_t *zone)
73 {
74 	sdp_zone_t	*next_zone;
75 
76 	while (zone != NULL) {
77 		next_zone = zone->z_next;
78 		if (zone->z_offset != NULL)
79 			free(zone->z_offset);
80 		free(zone);
81 		zone = next_zone;
82 	}
83 }
84 
85 void
sdp_free_list(sdp_list_t * list)86 sdp_free_list(sdp_list_t *list)
87 {
88 	sdp_list_t	*next_list;
89 
90 	while (list != NULL) {
91 		next_list = list->next;
92 		if (list->value != NULL)
93 			free(list->value);
94 		free(list);
95 		list = next_list;
96 	}
97 }
98 
99 void
sdp_free_media(sdp_media_t * media)100 sdp_free_media(sdp_media_t *media)
101 {
102 	sdp_media_t	*next_media;
103 
104 	while (media != NULL) {
105 		next_media = media->m_next;
106 		if (media->m_name != NULL)
107 			free(media->m_name);
108 		if (media->m_proto != NULL)
109 			free(media->m_proto);
110 		if (media->m_format != NULL)
111 			sdp_free_list(media->m_format);
112 		if (media->m_info != NULL)
113 			free(media->m_info);
114 		if (media->m_conn != NULL)
115 			sdp_free_connection(media->m_conn);
116 		if (media->m_bw != NULL)
117 			sdp_free_bandwidth(media->m_bw);
118 		if (media->m_key != NULL)
119 			sdp_free_key(media->m_key);
120 		if (media->m_attr != NULL)
121 			sdp_free_attribute(media->m_attr);
122 		free(media);
123 		media = next_media;
124 	}
125 }
126 
127 void
sdp_free_attribute(sdp_attr_t * attr)128 sdp_free_attribute(sdp_attr_t *attr)
129 {
130 	sdp_attr_t	*next_attr;
131 
132 	while (attr != NULL) {
133 		next_attr = attr->a_next;
134 		if (attr->a_name != NULL)
135 			free(attr->a_name);
136 		if (attr->a_value != NULL)
137 			free(attr->a_value);
138 		free(attr);
139 		attr = next_attr;
140 	}
141 }
142 
143 void
sdp_free_connection(sdp_conn_t * conn)144 sdp_free_connection(sdp_conn_t *conn)
145 {
146 	sdp_conn_t	*next_conn;
147 
148 	while (conn != NULL) {
149 		next_conn = conn->c_next;
150 		if (conn->c_nettype != NULL)
151 			free(conn->c_nettype);
152 		if (conn->c_addrtype != NULL)
153 			free(conn->c_addrtype);
154 		if (conn->c_address != NULL)
155 			free(conn->c_address);
156 		free(conn);
157 		conn = next_conn;
158 	}
159 }
160 
161 void
sdp_free_bandwidth(sdp_bandwidth_t * bw)162 sdp_free_bandwidth(sdp_bandwidth_t *bw)
163 {
164 	sdp_bandwidth_t		*next_bw;
165 
166 	while (bw != NULL) {
167 		next_bw = bw->b_next;
168 		if (bw->b_type != NULL)
169 			free(bw->b_type);
170 		free(bw);
171 		bw = next_bw;
172 	}
173 }
174 
175 void
sdp_free_repeat(sdp_repeat_t * repeat)176 sdp_free_repeat(sdp_repeat_t *repeat)
177 {
178 	sdp_repeat_t	*next_repeat;
179 
180 	while (repeat != NULL) {
181 		next_repeat = repeat->r_next;
182 		sdp_free_list(repeat->r_offset);
183 		free(repeat);
184 		repeat = next_repeat;
185 	}
186 }
187 
188 void
sdp_free_time(sdp_time_t * time)189 sdp_free_time(sdp_time_t *time)
190 {
191 	sdp_time_t	*next_time;
192 
193 	while (time != NULL) {
194 		next_time = time->t_next;
195 		sdp_free_repeat(time->t_repeat);
196 		free(time);
197 		time = next_time;
198 	}
199 }
200 
201 void
sdp_free_session(sdp_session_t * session)202 sdp_free_session(sdp_session_t *session)
203 {
204 	if (session == NULL)
205 		return;
206 	if (session->s_origin != NULL)
207 		sdp_free_origin(session->s_origin);
208 	if (session->s_name != NULL)
209 		free(session->s_name);
210 	if (session->s_info != NULL)
211 		free(session->s_info);
212 	if (session->s_uri != NULL)
213 		free(session->s_uri);
214 	if (session->s_email != NULL)
215 		sdp_free_list(session->s_email);
216 	if (session->s_phone != NULL)
217 		sdp_free_list(session->s_phone);
218 	if (session->s_conn != NULL)
219 		sdp_free_connection(session->s_conn);
220 	if (session->s_bw != NULL)
221 		sdp_free_bandwidth(session->s_bw);
222 	if (session->s_time != NULL)
223 		sdp_free_time(session->s_time);
224 	if (session->s_zone != NULL)
225 		sdp_free_zone(session->s_zone);
226 	if (session->s_key != NULL)
227 		sdp_free_key(session->s_key);
228 	if (session->s_attr != NULL)
229 		sdp_free_attribute(session->s_attr);
230 	if (session->s_media != NULL)
231 		sdp_free_media(session->s_media);
232 	free(session);
233 }
234 
235 /*
236  * Adds text of a given length to a linked list. If the list is NULL to
237  * start with it builds the new list
238  */
239 int
add_value_to_list(sdp_list_t ** list,const char * value,int len,boolean_t text)240 add_value_to_list(sdp_list_t **list, const char *value, int len, boolean_t text)
241 {
242 	sdp_list_t	*new = NULL;
243 	sdp_list_t	*tmp = NULL;
244 
245 	new = malloc(sizeof (sdp_list_t));
246 	if (new == NULL)
247 		return (ENOMEM);
248 	new->next = NULL;
249 	if (text)
250 		new->value = (char *)calloc(1, len + 1);
251 	else
252 		new->value = (uint64_t *)calloc(1, sizeof (uint64_t));
253 	if (new->value == NULL) {
254 		free(new);
255 		return (ENOMEM);
256 	}
257 	if (text) {
258 		(void) strncpy(new->value, value, len);
259 	} else {
260 		if (commp_time_to_secs((char *)value, (char *)(value +
261 		    len), new->value) != 0) {
262 			sdp_free_list(new);
263 			return (EINVAL);
264 		}
265 	}
266 	if (*list == NULL) {
267 		*list = new;
268 	} else {
269 		tmp = *list;
270 		while (tmp->next != NULL)
271 			tmp = tmp->next;
272 		tmp->next = new;
273 	}
274 	return (0);
275 }
276 
277 /*
278  * Given a linked list converts it to space separated string.
279  */
280 int
sdp_list_to_str(sdp_list_t * list,char ** buf,boolean_t text)281 sdp_list_to_str(sdp_list_t *list, char **buf, boolean_t text)
282 {
283 	int 		size = 0;
284 	int 		wrote = 0;
285 	sdp_list_t	*tmp;
286 	char		*ret;
287 	char		c[1];
288 
289 	if (list == NULL) {
290 		*buf = NULL;
291 		return (EINVAL);
292 	}
293 	tmp = list;
294 	while (list != NULL) {
295 		if (text)
296 			size += strlen((char *)list->value);
297 		else
298 			size += snprintf(c, 1, "%lld",
299 			    *(uint64_t *)list->value);
300 		size++;
301 		list = list->next;
302 	}
303 	list = tmp;
304 	if (size > 0) {
305 		*buf = calloc(1, size + 1);
306 		if (*buf == NULL)
307 			return (ENOMEM);
308 		ret = *buf;
309 		while (list != NULL) {
310 			if (text) {
311 				wrote = snprintf(ret, size, "%s ",
312 				    (char *)list->value);
313 			} else {
314 				wrote = snprintf(ret, size, "%lld ",
315 				    *(uint64_t *)list->value);
316 			}
317 			ret = ret + wrote;
318 			size = size - wrote;
319 			list = list->next;
320 		}
321 	} else {
322 		return (EINVAL);
323 	}
324 	return (0);
325 }
326 
327 /*
328  * Given a space separated string, converts it into linked list. SDP field
329  * repeat and media can have undefined number of offsets or formats
330  * respectively. We need to capture it in a linked list.
331  */
332 int
sdp_str_to_list(sdp_list_t ** list,const char * buf,int len,boolean_t text)333 sdp_str_to_list(sdp_list_t **list, const char *buf, int len, boolean_t text)
334 {
335 	const char	*begin;
336 	const char	*current;
337 	const char	*end;
338 	int		ret = 0;
339 
340 	if (len == 0)
341 		return (EINVAL);
342 	current = buf;
343 	end = current + len;
344 	/* takes care of strings with just spaces */
345 	if (commp_skip_white_space(&current, end) != 0)
346 		return (EINVAL);
347 	while (current < end) {
348 		(void) commp_skip_white_space(&current, end);
349 		begin = current;
350 		while (current < end) {
351 			if (isspace(*current))
352 				break;
353 			++current;
354 		}
355 		if (current != begin) {
356 			if ((ret = add_value_to_list(list, begin,
357 			    current - begin, text)) != 0) {
358 				sdp_free_list(*list);
359 				*list = NULL;
360 				return (ret);
361 			}
362 		}
363 	}
364 	return (0);
365 }
366