/* * FILE: sdp.c * AUTHOR: Ivan R. Judson * * The routines in this file implement parsing and construction of data * that's compliant with the Session Description Protocol, as specified * in RFC draft-ietf-mmusic-sdp-new-08. * * $Revision: 1.2 $ * $Date: 2003/05/28 11:36:50 $ * * Copyright (c) 2002 Argonne National Laboratory/University of Chicago * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Mathematics and * Computer Science Division of Argonne National Laboratory. * 4. Neither the name of the University nor of the Department may be used * to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "config_unix.h" #include "config_win32.h" #include "debug.h" #include "memory.h" #include "sdp.h" int sdp_check_key(char keylist[], char *currentkey, char key) { char *tempkey = keylist; while(*tempkey != key) if(*tempkey != keylist[strlen(keylist)]) tempkey++; else return 0; if(tempkey >= currentkey) { currentkey = tempkey; return 1; } else { return 0; } } sdp_media * sdp_handle_session_key(sdp *session, char key, char *value) { sdp_media *media = NULL, *curr_media = NULL; sdp_repeat *repeat = NULL, *curr_repeat = NULL; sdp_timezone *timezone = NULL; sdp_network *network = NULL; sdp_bandwidth_modifier *bwm; sdp_attribute *attr, *curr_attr; sdp_encryption *encrypt; unsigned int n_char; switch (key) { case 'v': session->protocol_version = atoi(value); break; case 'o': network = xmalloc(sizeof(sdp_network)); memset (network, 0, sizeof(sdp_network)); sscanf(value, "%as %as %ld %as %as %as\n", &(session->username),&(session->session_id), &(session->version), &(network->network_type), &(network->address_type), &(network->address)); network->number_of_addresses = 1; session->network = network; break; case 's': session->name = xstrdup(value); break; case 'i': session->information = xstrdup(value); break; case 'u': session->uri = xstrdup(value); break; case 'e': session->email = xstrdup(value); break; case 'p': session->phone = xstrdup(value); break; case 'c': network = xmalloc(sizeof(sdp_network)); memset (network, 0, sizeof(sdp_network)); sscanf(value, "%as %as %as\n", &(network->network_type), &(network->address_type), &(network->address)); network->number_of_addresses = 1; if(session->network != NULL) session->network = network; else xfree(network); break; case 'b': bwm = xmalloc(sizeof(sdp_bandwidth_modifier)); memset (bwm, 0, sizeof(sdp_bandwidth_modifier)); sscanf(value, "%a[^:]:%a[^\n]", &(bwm->modifier), &(bwm->value)); if(session->bandwidth_modifier == NULL) session->bandwidth_modifier = bwm; else xfree(bwm); break; case 't': sscanf(value, "%ld %ld\n", &(session->start_time), &(session->stop_time)); break; case 'r': repeat = xmalloc(sizeof(sdp_repeat)); memset (repeat, 0, sizeof(sdp_repeat)); sscanf(value, "%as %as %as\n", &(repeat->interval), &(repeat->duration), &(repeat->offsets)); if(session->repeats == NULL) session->repeats = repeat; else { curr_repeat = session->repeats; while(curr_repeat != NULL) curr_repeat = curr_repeat->next; curr_repeat->next = repeat; } break; case 'z': /* This is icky but for now... */ timezone = xmalloc(sizeof(sdp_timezone)); memset(timezone, 0, sizeof(sdp_timezone)); sscanf(value, "%ld %ld", &(timezone->adjustment), &(timezone->offset)); session->timezones = timezone; break; case 'k': encrypt = xmalloc(sizeof(sdp_encryption)); memset(encrypt, 0, sizeof(sdp_encryption)); sscanf(value, "%a[^:]:%a[^\n]", &(encrypt->method), &(encrypt->key)); if(session->encryption == NULL) session->encryption = encrypt; else xfree(encrypt); break; case 'a': attr = xmalloc(sizeof(sdp_attribute)); memset(attr, 0, sizeof(sdp_attribute)); n_char = strcspn(value, ":"); attr->key = xmalloc(n_char+1); memset(attr->key, '\0', n_char+1); strncpy(attr->key, value, n_char); if(strlen(value) == n_char) attr->value = NULL; else { attr->value = xmalloc(strlen(value) - n_char + 1); memset(attr->value, '\0', strlen(value) - n_char + 1); strncpy(attr->value, value+n_char+1, strlen(value) - n_char); } if(session->attributes == NULL) session->attributes = attr; else { curr_attr = session->attributes; while(curr_attr->next != NULL) curr_attr = curr_attr->next; curr_attr->next = attr; } break; case 'm': media = xmalloc(sizeof(sdp_media)); memset(media, 0, sizeof(sdp_media)); sscanf(value, "%as %d %as %as\n", &(media->name), &(media->port), &(media->transport), &(media->format_list)); media->number_of_ports = 1; if(session->media == NULL) session->media = media; else { curr_media = session->media; while(curr_media->next != NULL) curr_media = curr_media->next; curr_media->next = media; } break; } return media; } sdp_media * sdp_handle_media_key(sdp_media *media, char key, char *value) { sdp_media *new_media; sdp_network *network; sdp_bandwidth_modifier *bwm; sdp_attribute *attr, *curr_attr; sdp_encryption *encrypt; unsigned int n_char; switch (key) { case 'i': media->information = xstrdup(value); break; case 'c': network = xmalloc(sizeof(sdp_network)); memset (network, 0, sizeof(sdp_network)); sscanf(value, "%as %as %as\n", &(network->network_type), &(network->address_type), &(network->address)); network->number_of_addresses = 1; if(media->network == NULL) media->network = network; else xfree(network); break; case 'b': bwm = xmalloc(sizeof(sdp_bandwidth_modifier)); memset (bwm, 0, sizeof(sdp_bandwidth_modifier)); sscanf(value, "%as:%as\n", &(bwm->modifier), &(bwm->value)); if(media->bandwidth_modifier == NULL) media->bandwidth_modifier = bwm; else xfree(bwm); break; case 'k': encrypt = xmalloc(sizeof(sdp_encryption)); memset(encrypt, 0, sizeof(sdp_encryption)); sscanf(value, "%as:%as\n", &(encrypt->method), &(encrypt->key)); if(media->encryption == NULL) media->encryption = encrypt; else xfree(encrypt); break; case 'a': attr = xmalloc(sizeof(sdp_attribute)); memset(attr, 0, sizeof(sdp_attribute)); n_char = strcspn(value, ":"); attr->key = xmalloc(n_char+1); memset(attr->key, '\0', n_char+1); strncpy(attr->key, value, n_char); if(strlen(value) == n_char) attr->value = NULL; else { attr->value = xmalloc(strlen(value) - n_char + 1); memset(attr->value, '\0', strlen(value) - n_char + 1); strncpy(attr->value, value+n_char+1, strlen(value) - n_char); } if(media->attributes == NULL) media->attributes = attr; else { curr_attr = media->attributes; while(curr_attr->next != NULL) curr_attr = curr_attr->next; curr_attr->next = attr; } break; case 'm': new_media = xmalloc(sizeof(sdp_media)); memset(new_media, 0, sizeof(sdp_media)); sscanf(value, "%as %d %as %as\n", &(new_media->name), &(new_media->port), &(new_media->transport), &(new_media->format_list)); new_media->number_of_ports = 1; media->next = new_media; media = media->next; break; } return media; } sdp *sdp_parse(char *sdp_string) { static char sessionkeys[] = "vosiuepcbtrzkam"; static char mediakeys[] = "micbka"; static char *current_key; int goodkey = 0; sdp_media *media = NULL; char *line = NULL, key, *value = NULL; static char *pos; sdp *session = NULL; int n_char; if(sdp_string != NULL) { current_key = sessionkeys; session = xmalloc(sizeof(sdp)); memset (session, 0, sizeof(sdp)); session->original = xstrdup(sdp_string); pos = sdp_string; do { n_char = strcspn(pos, "\n"); line = xmalloc(n_char+1); memset(line, '\0', n_char+1); strncpy(line, pos, n_char); pos += n_char + 1; if(strchr(line, '=') != NULL) { key = line[0]; value = &(line[2]); if(media == NULL) { if((goodkey = sdp_check_key(sessionkeys, current_key, key)) == 1) media = sdp_handle_session_key(session, key, value); else printf("Bad Session Key!\n"); } else { if((goodkey = sdp_check_key(mediakeys, current_key, key)) == 1) media = sdp_handle_media_key(media, key, value); else printf("Bad Media Key!\n"); } } xfree(line); } while (n_char != 0); } return session; } void sdp_print(sdp *session) { if(session != NULL) { sdp_media *current_media = session->media; sdp_attribute *current_attribute = session->attributes; printf("Protocol Version: %d\n", session->protocol_version); printf("Username: %s\n", session->username); printf("Session ID: %s\n", session->session_id); printf("Version: %ld\n", session->version); printf("Name: %s\n", session->name); printf("Information: %s\n", session->information); printf("URI: %s\n", session->uri); printf("Email: %s\n", session->email); printf("Phone: %s\n", session->phone); printf("Start Time: %ld\n", session->start_time); printf("Stop Time: %ld\n", session->stop_time); if(session->network != NULL) { sdp_print_network(session->network); } if(session->bandwidth_modifier != NULL) { printf("Bandwidth Modifier\n"); printf("\tModifier: %s\n", session->bandwidth_modifier->modifier); printf("\tValue: %s\n", session->bandwidth_modifier->value); } printf("Session Attributes:\n"); while(current_attribute != NULL) { printf("\tAttribute: %s Value: %s\n", current_attribute->key, current_attribute->value); current_attribute = current_attribute->next; } current_media = session->media; while(current_media != NULL) { sdp_print_media(current_media); current_media = current_media->next; } } } void sdp_print_network(sdp_network *network) { printf("Network Information:\n"); printf("\tNetwork Type: %s\n", network->network_type); printf("\tAddress Type: %s\n", network->address_type); printf("\tAddress: %s\n", network->address); printf("\t# of Addresses: %d\n", network->number_of_addresses); } void sdp_print_media(sdp_media *media) { sdp_attribute *curr_attr = media->attributes; printf("Media Configuration:\n"); printf("\tName: %s\n", media->name); printf("\tPort: %d Number of Ports: %d\n", media->port, media->number_of_ports); if(media->network != NULL) { sdp_print_network(media->network); } printf("\tTransport: %s\n", media->transport); printf("\tInformation: %s\n", media->information); if(media->attributes != NULL) { printf("\tMedia Attributes:\n"); while(curr_attr != NULL) { printf("\t\tAttribute: %s Value: %s\n", curr_attr->key, curr_attr->value); curr_attr = curr_attr->next; } } } char * sdp_make(sdp *session) { sdp_timezone *tz; sdp_attribute *attr; sdp_media *media; char *sdp_string; sdp_string = xmalloc(4096); sprintf(sdp_string, "v=%d\n", session->protocol_version); sprintf(sdp_string, "%so=%s %s %ld", sdp_string, session->username, session->session_id, session->version); if(session->network != NULL) { sprintf(sdp_string, "%s %s %s %s\n", sdp_string, session->network->network_type, session->network->address_type, session->network->address); } sprintf(sdp_string, "%ss=%s\n", sdp_string, session->name); if(session->information != NULL) sprintf(sdp_string, "%si=%s\n", sdp_string, session->information); if(session->uri != NULL) sprintf(sdp_string, "%su=%s\n", sdp_string, session->uri); if(session->email != NULL) sprintf(sdp_string, "%se=%s\n", sdp_string, session->email); if(session->phone != NULL) sprintf(sdp_string, "%sp=%s\n", sdp_string, session->phone); if(session->network != NULL) sprintf(sdp_string, "%sc=%s %s %s\n", sdp_string, session->network->network_type, session->network->address_type, session->network->address); if(session->bandwidth_modifier != NULL) sprintf(sdp_string, "%sb=%s:%s\n", sdp_string, session->bandwidth_modifier->modifier, session->bandwidth_modifier->value); sprintf(sdp_string, "%st=%ld %ld\n", sdp_string, session->start_time, session->stop_time); if(session->timezones != NULL) { tz = session->timezones; sprintf(sdp_string, "%sz=%ld %ld", sdp_string, tz->adjustment, tz->offset); while(tz->next != NULL) { sprintf(sdp_string, "%s %ld %ld", sdp_string, tz->next->adjustment, tz->next->offset); tz = tz->next; } sprintf(sdp_string, "%s\n", sdp_string); } if(session->encryption != NULL) { if(session->encryption->key == NULL) sprintf(sdp_string, "%sk=%s\n", sdp_string, session->encryption->method); else sprintf(sdp_string, "%sk=%s:%s\n", sdp_string, session->encryption->method, session->encryption->key); } attr = session->attributes; while(attr != NULL) { sprintf(sdp_string, "%sa=%s:%s\n", sdp_string, attr->key, attr->value); attr = attr->next; } media = session->media; while(media != NULL) { if(media->number_of_ports > 1) sprintf(sdp_string, "%sm=%s %d/%d %s %s\n", sdp_string, media->name, media->port, media->number_of_ports, media->transport, media->format_list); else sprintf(sdp_string, "%sm=%s %d %s %s\n", sdp_string, media->name, media->port, media->transport, media->format_list); if(media->information != NULL) sprintf(sdp_string, "%si=%s\n", sdp_string, media->information); if(media->network != NULL) sprintf(sdp_string, "%sc=%s %s %s\n", sdp_string, media->network->network_type, media->network->address_type, media->network->address); if(media->bandwidth_modifier != NULL) sprintf(sdp_string, "%sb=%s:%s\n", sdp_string, media->bandwidth_modifier->modifier, media->bandwidth_modifier->value); if(media->encryption != NULL) { if(media->encryption->key == NULL) sprintf(sdp_string, "%sk=%s\n", sdp_string, media->encryption->method); else sprintf(sdp_string, "%sk=%s:%s\n", sdp_string, media->encryption->method, media->encryption->key); } attr = media->attributes; while(attr != NULL) { sprintf(sdp_string, "%sa=%s:%s\n", sdp_string, attr->key, attr->value); attr = attr->next; } media = media->next; } return sdp_string; } void sdp_free(sdp *session) { sdp_media *media, *cmedia; sdp_attribute *attr, *cattr; sdp_repeat *repeat, *crepeat; if(session->username != NULL) xfree(session->username); if(session->session_id != NULL) xfree(session->session_id); if(session->network != NULL) sdp_free_network(session->network); if(session->name != NULL) xfree(session->name); if(session->information != NULL) xfree(session->information); if(session->uri != NULL) xfree(session->uri); if(session->email != NULL) xfree(session->email); if(session->phone != NULL) xfree(session->phone); if(session->bandwidth_modifier != NULL) sdp_free_bandwidth_modifier(session->bandwidth_modifier); if(session->timezones != NULL) xfree(session->timezones); if(session->encryption != NULL) sdp_free_encryption(session->encryption); repeat = session->repeats; while(repeat != NULL) { crepeat = repeat; repeat = repeat->next; sdp_free_repeat(crepeat); } attr = session->attributes; while(attr != NULL) { cattr = attr; attr = attr->next; sdp_free_attribute(cattr); } media = session->media; while(media != NULL) { cmedia = media; media = media->next; sdp_free_media(cmedia); } if(session->original != NULL) xfree(session->original); xfree(session); } void sdp_free_network(sdp_network *network) { xfree(network->network_type); xfree(network->address_type); xfree(network->address); xfree(network); } void sdp_free_attribute(sdp_attribute *attr) { xfree(attr->key); if(attr->value != NULL) xfree(attr->value); xfree(attr); } void sdp_free_encryption(sdp_encryption *encr) { xfree(encr->method); xfree(encr->key); xfree(encr); } void sdp_free_bandwidth_modifier(sdp_bandwidth_modifier *bwm) { xfree(bwm->modifier); xfree(bwm->value); xfree(bwm); } void sdp_free_repeat(sdp_repeat *repeat) { xfree(repeat->interval); xfree(repeat->duration); xfree(repeat->offsets); xfree(repeat); } void sdp_free_media(sdp_media *media) { sdp_attribute *attr, *cattr; xfree(media->name); if(media->network != NULL) sdp_free_network(media->network); xfree(media->transport); xfree(media->format_list); if(media->information != NULL) xfree(media->information); if(media->bandwidth_modifier != NULL) sdp_free_bandwidth_modifier(media->bandwidth_modifier); if(media->encryption != NULL) sdp_free_encryption(media->encryption); attr = media->attributes; while(attr != NULL) { cattr = attr; attr = attr->next; sdp_free_attribute(cattr); } xfree(media); }