Exemple #1
0
void janus_sdp_free(janus_sdp *sdp) {
	if(!sdp)
		return;
	g_free(sdp->o_name);
	g_free(sdp->o_addr);
	g_free(sdp->s_name);
	g_free(sdp->c_addr);
	GList *temp = sdp->attributes;
	while(temp) {
		janus_sdp_attribute *a = (janus_sdp_attribute *)temp->data;
		janus_sdp_attribute_destroy(a);
		temp = temp->next;
	}
	g_list_free(sdp->attributes);
	sdp->attributes = NULL;
	temp = sdp->m_lines;
	while(temp) {
		janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
		janus_sdp_mline_destroy(m);
		temp = temp->next;
	}
	g_list_free(sdp->m_lines);
	sdp->m_lines = NULL;
	g_free(sdp);
}
Exemple #2
0
/* Internal frees */
static void janus_sdp_free(const janus_refcount *sdp_ref) {
	janus_sdp *sdp = janus_refcount_containerof(sdp_ref, janus_sdp, ref);
	/* This SDP instance can be destroyed, free all the resources */
	g_free(sdp->o_name);
	g_free(sdp->o_addr);
	g_free(sdp->s_name);
	g_free(sdp->c_addr);
	GList *temp = sdp->attributes;
	while(temp) {
		janus_sdp_attribute *a = (janus_sdp_attribute *)temp->data;
		janus_sdp_attribute_destroy(a);
		temp = temp->next;
	}
	g_list_free(sdp->attributes);
	sdp->attributes = NULL;
	temp = sdp->m_lines;
	while(temp) {
		janus_sdp_mline *m = (janus_sdp_mline *)temp->data;
		janus_sdp_mline_destroy(m);
		temp = temp->next;
	}
	g_list_free(sdp->m_lines);
	sdp->m_lines = NULL;
	g_free(sdp);
}
Exemple #3
0
int janus_sdp_mline_remove(janus_sdp *sdp, janus_sdp_mtype type) {
	if(sdp == NULL)
		return -1;
	GList *ml = sdp->m_lines;
	while(ml) {
		janus_sdp_mline *m = (janus_sdp_mline *)ml->data;
		if(m->type == type) {
			/* Found! */
			sdp->m_lines = g_list_remove(sdp->m_lines, m);
			janus_sdp_mline_destroy(m);
			return 0;
		}
		ml = ml->next;
	}
	/* If we got here, we couldn't the m-line */
	return -2;
}
Exemple #4
0
janus_sdp *janus_sdp_parse(const char *sdp, char *error, size_t errlen) {
	if(!sdp)
		return NULL;
	if(strstr(sdp, "v=") != sdp) {
		if(error)
			g_snprintf(error, errlen, "Invalid SDP (doesn't start with v=)");
		return NULL;
	}
	janus_sdp *imported = g_malloc0(sizeof(janus_sdp));
	g_atomic_int_set(&imported->destroyed, 0);
	janus_refcount_init(&imported->ref, janus_sdp_free);
	imported->o_ipv4 = TRUE;
	imported->c_ipv4 = TRUE;

	gboolean success = TRUE;
	janus_sdp_mline *mline = NULL;

	gchar **parts = g_strsplit(sdp, strstr(sdp, "\r\n") ? "\r\n" : "\n", -1);
	if(parts) {
		int index = 0;
		char *line = NULL;
		while(success && (line = parts[index]) != NULL) {
			if(*line == '\0') {
				index++;
				continue;
			}
			if(strlen(line) < 3) {
				if(error)
					g_snprintf(error, errlen, "Invalid line (%zu bytes): %s", strlen(line), line);
				success = FALSE;
				break;
			}
			if(*(line+1) != '=') {
				if(error)
					g_snprintf(error, errlen, "Invalid line (2nd char is not '='): %s", line);
				success = FALSE;
				break;
			}
			char c = *line;
			if(mline == NULL) {
				/* Global stuff */
				switch(c) {
					case 'v': {
						if(sscanf(line, "v=%d", &imported->version) != 1) {
							if(error)
								g_snprintf(error, errlen, "Invalid v= line: %s", line);
							success = FALSE;
							break;
						}
						break;
					}
					case 'o': {
						if(imported->o_name || imported->o_addr) {
							if(error)
								g_snprintf(error, errlen, "Multiple o= lines: %s", line);
							success = FALSE;
							break;
						}
						char name[256], addrtype[6], addr[256];
						if(sscanf(line, "o=%255s %"SCNu64" %"SCNu64" IN %5s %255s",
								name, &imported->o_sessid, &imported->o_version, addrtype, addr) != 5) {
							if(error)
								g_snprintf(error, errlen, "Invalid o= line: %s", line);
							success = FALSE;
							break;
						}
						if(!strcasecmp(addrtype, "IP4"))
							imported->o_ipv4 = TRUE;
						else if(!strcasecmp(addrtype, "IP6"))
							imported->o_ipv4 = FALSE;
						else {
							if(error)
								g_snprintf(error, errlen, "Invalid o= line (unsupported protocol %s): %s", addrtype, line);
							success = FALSE;
							break;
						}
						imported->o_name = g_strdup(name);
						imported->o_addr = g_strdup(addr);
						break;
					}
					case 's': {
						if(imported->s_name) {
							if(error)
								g_snprintf(error, errlen, "Multiple s= lines: %s", line);
							success = FALSE;
							break;
						}
						imported->s_name = g_strdup(line+2);
						break;
					}
					case 't': {
						if(sscanf(line, "t=%"SCNu64" %"SCNu64, &imported->t_start, &imported->t_stop) != 2) {
							if(error)
								g_snprintf(error, errlen, "Invalid t= line: %s", line);
							success = FALSE;
							break;
						}
						break;
					}
					case 'c': {
						if(imported->c_addr) {
							if(error)
								g_snprintf(error, errlen, "Multiple global c= lines: %s", line);
							success = FALSE;
							break;
						}
						char addrtype[6], addr[256];
						if(sscanf(line, "c=IN %5s %255s", addrtype, addr) != 2) {
							if(error)
								g_snprintf(error, errlen, "Invalid c= line: %s", line);
							success = FALSE;
							break;
						}
						if(!strcasecmp(addrtype, "IP4"))
							imported->c_ipv4 = TRUE;
						else if(!strcasecmp(addrtype, "IP6"))
							imported->c_ipv4 = FALSE;
						else {
							if(error)
								g_snprintf(error, errlen, "Invalid c= line (unsupported protocol %s): %s", addrtype, line);
							success = FALSE;
							break;
						}
						imported->c_addr = g_strdup(addr);
						break;
					}
					case 'a': {
						janus_sdp_attribute *a = g_malloc0(sizeof(janus_sdp_attribute));
						janus_refcount_init(&a->ref, janus_sdp_attribute_free);
						line += 2;
						char *semicolon = strchr(line, ':');
						if(semicolon == NULL) {
							a->name = g_strdup(line);
							a->value = NULL;
						} else {
							if(*(semicolon+1) == '\0') {
								janus_sdp_attribute_destroy(a);
								if(error)
									g_snprintf(error, errlen, "Invalid a= line: %s", line);
								success = FALSE;
								break;
							}
							*semicolon = '\0';
							a->name = g_strdup(line);
							a->value = g_strdup(semicolon+1);
							a->direction = JANUS_SDP_DEFAULT;
							*semicolon = ':';
							if(strstr(line, "/sendonly"))
								a->direction = JANUS_SDP_SENDONLY;
							else if(strstr(line, "/recvonly"))
								a->direction = JANUS_SDP_RECVONLY;
							if(strstr(line, "/inactive"))
								a->direction = JANUS_SDP_INACTIVE;
						}
						imported->attributes = g_list_append(imported->attributes, a);
						break;
					}
					case 'm': {
						janus_sdp_mline *m = g_malloc0(sizeof(janus_sdp_mline));
						g_atomic_int_set(&m->destroyed, 0);
						janus_refcount_init(&m->ref, janus_sdp_mline_free);
						/* Start with media type, port and protocol */
						char type[32];
						char proto[64];
						if(strlen(line) > 200) {
							janus_sdp_mline_destroy(m);
							if(error)
								g_snprintf(error, errlen, "Invalid m= line (too long): %zu", strlen(line));
							success = FALSE;
							break;
						}
						if(sscanf(line, "m=%31s %"SCNu16" %63s %*s", type, &m->port, proto) != 3) {
							janus_sdp_mline_destroy(m);
							if(error)
								g_snprintf(error, errlen, "Invalid m= line: %s", line);
							success = FALSE;
							break;
						}
						m->type = janus_sdp_parse_mtype(type);
						m->type_str = g_strdup(type);
						m->proto = g_strdup(proto);
						m->direction = JANUS_SDP_SENDRECV;
						m->c_ipv4 = TRUE;
						if(m->port > 0) {
							/* Now let's check the payload types/formats */
							gchar **mline_parts = g_strsplit(line+2, " ", -1);
							if(!mline_parts) {
								janus_sdp_mline_destroy(m);
								if(error)
									g_snprintf(error, errlen, "Invalid m= line (no payload types/formats): %s", line);
								success = FALSE;
								break;
							}
							int mindex = 0;
							while(mline_parts[mindex]) {
								if(mindex < 3) {
									/* We've parsed these before */
									mindex++;
									continue;
								}
								/* Add string fmt */
								m->fmts = g_list_append(m->fmts, g_strdup(mline_parts[mindex]));
								/* Add numeric payload type */
								int ptype = atoi(mline_parts[mindex]);
								m->ptypes = g_list_append(m->ptypes, GINT_TO_POINTER(ptype));
								mindex++;
							}
							g_strfreev(mline_parts);
							if(m->fmts == NULL || m->ptypes == NULL) {
								janus_sdp_mline_destroy(m);
								if(error)
									g_snprintf(error, errlen, "Invalid m= line (no payload types/formats): %s", line);
								success = FALSE;
								break;
							}
						}
						/* Append to the list of m-lines */
						imported->m_lines = g_list_append(imported->m_lines, m);
						/* From now on, we parse this m-line */
						mline = m;
						break;
					}
					default:
						JANUS_LOG(LOG_WARN, "Ignoring '%c' property\n", c);
						break;
				}
			} else {
				/* m-line stuff */
				switch(c) {
					case 'c': {
						if(mline->c_addr) {
							if(error)
								g_snprintf(error, errlen, "Multiple m-line c= lines: %s", line);
							success = FALSE;
							break;
						}
						char addrtype[6], addr[256];
						if(sscanf(line, "c=IN %5s %255s", addrtype, addr) != 2) {
							if(error)
								g_snprintf(error, errlen, "Invalid c= line: %s", line);
							success = FALSE;
							break;
						}
						if(!strcasecmp(addrtype, "IP4"))
							mline->c_ipv4 = TRUE;
						else if(!strcasecmp(addrtype, "IP6"))
							mline->c_ipv4 = FALSE;
						else {
							if(error)
								g_snprintf(error, errlen, "Invalid c= line (unsupported protocol %s): %s", addrtype, line);
							success = FALSE;
							break;
						}
						mline->c_addr = g_strdup(addr);
						break;
					}
					case 'b': {
						if(mline->b_name) {
							if(error)
								g_snprintf(error, errlen, "Multiple m-line b= lines: %s", line);
							success = FALSE;
							break;
						}
						line += 2;
						char *semicolon = strchr(line, ':');
						if(semicolon == NULL || (*(semicolon+1) == '\0')) {
							if(error)
								g_snprintf(error, errlen, "Invalid b= line: %s", line);
							success = FALSE;
							break;
						}
						*semicolon = '\0';
						mline->b_name = g_strdup(line);
						mline->b_value = atol(semicolon+1);
						*semicolon = ':';
						break;
					}
					case 'a': {
						janus_sdp_attribute *a = g_malloc0(sizeof(janus_sdp_attribute));
						janus_refcount_init(&a->ref, janus_sdp_attribute_free);
						line += 2;
						char *semicolon = strchr(line, ':');
						if(semicolon == NULL) {
							/* Is this a media direction attribute? */
							janus_sdp_mdirection direction = janus_sdp_parse_mdirection(line);
							if(direction != JANUS_SDP_INVALID) {
								janus_sdp_attribute_destroy(a);
								mline->direction = direction;
								break;
							}
							a->name = g_strdup(line);
							a->value = NULL;
						} else {
							if(*(semicolon+1) == '\0') {
								janus_sdp_attribute_destroy(a);
								if(error)
									g_snprintf(error, errlen, "Invalid a= line: %s", line);
								success = FALSE;
								break;
							}
							*semicolon = '\0';
							a->name = g_strdup(line);
							a->value = g_strdup(semicolon+1);
							a->direction = JANUS_SDP_DEFAULT;
							*semicolon = ':';
							if(strstr(line, "/sendonly"))
								a->direction = JANUS_SDP_SENDONLY;
							else if(strstr(line, "/recvonly"))
								a->direction = JANUS_SDP_RECVONLY;
							if(strstr(line, "/inactive"))
								a->direction = JANUS_SDP_INACTIVE;
						}
						mline->attributes = g_list_append(mline->attributes, a);
						break;
					}
					case 'm': {
						/* Current m-line ended, back to global parsing */
						mline = NULL;
						continue;
					}
					default:
						JANUS_LOG(LOG_WARN, "Ignoring '%c' property (m-line)\n", c);
						break;
				}
			}
			index++;
		}
		g_strfreev(parts);
	}
	/* FIXME Do a last check: is all the stuff that's supposed to be there available? */
	if(success && (imported->o_name == NULL || imported->o_addr == NULL || imported->s_name == NULL || imported->m_lines == NULL)) {
		success = FALSE;
		if(error)
			g_snprintf(error, errlen, "Missing mandatory lines (o=, s= or m=)");
	}
	/* If something wrong happened, free and return a failure */
	if(!success) {
		if(error)
			JANUS_LOG(LOG_ERR, "%s\n", error);
		janus_sdp_destroy(imported);
		imported = NULL;
	}
	return imported;
}