/* * Parse SDP message. */ PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool, char *buf, pj_size_t len, pjmedia_sdp_session **p_sdp) { pj_scanner scanner; pjmedia_sdp_session *session; pjmedia_sdp_media *media = NULL; void *attr; pjmedia_sdp_conn *conn; pj_str_t dummy; int cur_name = 254; parse_context ctx; PJ_USE_EXCEPTION; ctx.last_error = PJ_SUCCESS; init_sdp_parser(); pj_scan_init(&scanner, buf, len, 0, &on_scanner_error); session = pj_pool_calloc(pool, 1, sizeof(pjmedia_sdp_session)); PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); PJ_TRY { while (!pj_scan_is_eof(&scanner)) { cur_name = *scanner.curptr; switch (cur_name) { case 'a': attr = parse_attr(pool, &scanner, &ctx); if (attr) { if (media) { media->attr[media->attr_count++] = attr; } else { session->attr[session->attr_count++] = attr; } } break; case 'o': parse_origin(&scanner, session, &ctx); break; case 's': parse_generic_line(&scanner, &session->name, &ctx); break; case 'c': conn = pj_pool_calloc(pool, 1, sizeof(*conn)); parse_connection_info(&scanner, conn, &ctx); if (media) { media->conn = conn; } else { session->conn = conn; } break; case 't': parse_time(&scanner, session, &ctx); break; case 'm': media = pj_pool_calloc(pool, 1, sizeof(*media)); parse_media(&scanner, media, &ctx); session->media[ session->media_count++ ] = media; break; case 'v': parse_version(&scanner, &ctx); break; case 13: /* Allow empty newline at the end of the message */ pj_scan_get_char(&scanner); /* Continue below */ case 10: pj_scan_get_char(&scanner); if (!pj_scan_is_eof(&scanner)) { on_scanner_error(&scanner); } break; default: if (cur_name >= 'a' && cur_name <= 'z') parse_generic_line(&scanner, &dummy, &ctx); else { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } break; } } ctx.last_error = PJ_SUCCESS; } PJ_CATCH(SYNTAX_ERROR) { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(ctx.last_error, errmsg, sizeof(errmsg)); PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s", scanner.line, pj_scan_get_col(&scanner), errmsg)); session = NULL; pj_assert(ctx.last_error != PJ_SUCCESS); } PJ_END; pj_scan_fini(&scanner); *p_sdp = session; return ctx.last_error; }
/* * Parse SDP message. */ PJ_DEF(pj_status_t) pjmedia_sdp_parse( pj_pool_t *pool, char *buf, pj_size_t len, pjmedia_sdp_session **p_sdp) { pj_scanner scanner; pjmedia_sdp_session *session; pjmedia_sdp_media *media = NULL; pjmedia_sdp_attr *attr; pjmedia_sdp_conn *conn; pjmedia_sdp_bandw *bandw; pj_str_t dummy; int cur_name = 254; parse_context ctx; PJ_USE_EXCEPTION; ctx.last_error = PJ_SUCCESS; init_sdp_parser(); pj_scan_init(&scanner, buf, len, 0, &on_scanner_error); session = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session); PJ_ASSERT_RETURN(session != NULL, PJ_ENOMEM); /* Ignore leading newlines */ while (*scanner.curptr=='\r' || *scanner.curptr=='\n') pj_scan_get_char(&scanner); PJ_TRY { while (!pj_scan_is_eof(&scanner)) { cur_name = *scanner.curptr; switch (cur_name) { case 'a': attr = parse_attr(pool, &scanner, &ctx); if (attr) { if (media) { if (media->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_media_add_attr(media, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media attribute, " "attribute is ignored")); } else { if (session->attr_count < PJMEDIA_MAX_SDP_ATTR) pjmedia_sdp_session_add_attr(session, attr); else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session attribute" ", attribute is ignored")); } } break; case 'o': parse_origin(&scanner, session, &ctx); break; case 's': parse_generic_line(&scanner, &session->name, &ctx); break; case 'c': conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn); parse_connection_info(&scanner, conn, &ctx); if (media) { media->conn = conn; } else { session->conn = conn; } break; case 't': parse_time(&scanner, session, &ctx); break; case 'm': media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media); parse_media(&scanner, media, &ctx); if (session->media_count < PJMEDIA_MAX_SDP_MEDIA) session->media[ session->media_count++ ] = media; else PJ_PERROR(2,(THIS_FILE, PJ_ETOOMANY, "Error adding media, media is ignored")); break; case 'v': parse_version(&scanner, &ctx); break; case 13: case 10: pj_scan_get_char(&scanner); /* Allow empty newlines at the end of the message */ while (!pj_scan_is_eof(&scanner)) { if (*scanner.curptr != 13 && *scanner.curptr != 10) { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } pj_scan_get_char(&scanner); } break; case 'b': bandw = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_bandw); parse_bandwidth_info(&scanner, bandw, &ctx); if (media) { if (media->bandw_count < PJMEDIA_MAX_SDP_BANDW) media->bandw[media->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding media bandwidth " "info, info is ignored")); } else { if (session->bandw_count < PJMEDIA_MAX_SDP_BANDW) session->bandw[session->bandw_count++] = bandw; else PJ_PERROR(2, (THIS_FILE, PJ_ETOOMANY, "Error adding session bandwidth " "info, info is ignored")); } break; default: if (cur_name >= 'a' && cur_name <= 'z') parse_generic_line(&scanner, &dummy, &ctx); else { ctx.last_error = PJMEDIA_SDP_EINSDP; on_scanner_error(&scanner); } break; } } ctx.last_error = PJ_SUCCESS; } PJ_CATCH_ANY { char errmsg[PJ_ERR_MSG_SIZE]; pj_strerror(ctx.last_error, errmsg, sizeof(errmsg)); PJ_LOG(4, (THIS_FILE, "Error parsing SDP in line %d col %d: %s", scanner.line, pj_scan_get_col(&scanner), errmsg)); session = NULL; pj_assert(ctx.last_error != PJ_SUCCESS); } PJ_END; pj_scan_fini(&scanner); if (session) apply_media_direction(session); *p_sdp = session; return ctx.last_error; }
int sdp_parse(str *body, GQueue *sessions) { char *b, *end, *value, *line_end, *next_line; struct sdp_session *session = NULL; struct sdp_media *media = NULL; const char *errstr; struct sdp_attributes *attrs; struct sdp_attribute *attr; str *adj_s; GQueue *attr_queue; b = body->s; end = str_end(body); while (b && b < end - 1) { #ifdef TERMINATE_SDP_AT_BLANK_LINE if (b[0] == '\n' || b[0] == '\r') { body->len = b - body->s; break; } #endif errstr = "Missing '=' sign"; if (b[1] != '=') goto error; value = &b[2]; line_end = memchr(value, '\n', end - value); if (!line_end) { /* assume missing LF at end of body */ line_end = end; next_line = NULL; } else { next_line = line_end + 1; if (line_end[-1] == '\r') line_end--; } switch (b[0]) { case 'v': errstr = "Error in v= line"; if (line_end != value + 1) goto error; if (value[0] != '0') goto error; session = g_slice_alloc0(sizeof(*session)); g_queue_init(&session->media_streams); attrs_init(&session->attributes); g_queue_push_tail(sessions, session); media = NULL; session->s.s = b; session->rr = session->rs = -1; break; case 'o': errstr = "o= line found within media section"; if (media) goto error; errstr = "Error parsing o= line"; if (parse_origin(value, line_end, &session->origin)) goto error; break; case 'm': media = g_slice_alloc0(sizeof(*media)); media->session = session; attrs_init(&media->attributes); errstr = "Error parsing m= line"; if (parse_media(value, line_end, media)) goto error; g_queue_push_tail(&session->media_streams, media); media->s.s = b; media->rr = media->rs = -1; break; case 'c': errstr = "Error parsing c= line"; if (parse_connection(value, line_end, media ? &media->connection : &session->connection)) goto error; break; case 'a': attr = g_slice_alloc0(sizeof(*attr)); attr->full_line.s = b; attr->full_line.len = next_line ? (next_line - b) : (line_end - b); attr->line_value.s = value; attr->line_value.len = line_end - value; if (parse_attribute(attr)) { g_slice_free1(sizeof(*attr), attr); break; } attrs = media ? &media->attributes : &session->attributes; g_queue_push_tail(&attrs->list, attr); /* g_hash_table_insert(attrs->name_hash, &attr->name, attr); */ if (!g_hash_table_lookup(attrs->id_hash, &attr->attr)) g_hash_table_insert(attrs->id_hash, &attr->attr, attr); /* if (attr->key.s) g_hash_table_insert(attrs->name_hash, &attr->key, attr); */ /* attr_queue = g_hash_table_lookup(attrs->name_lists_hash, &attr->name); if (!attr_queue) g_hash_table_insert(attrs->name_lists_hash, &attr->name, (attr_queue = g_queue_new())); g_queue_push_tail(attr_queue, attr); */ attr_queue = g_hash_table_lookup(attrs->id_lists_hash, &attr->attr); if (!attr_queue) g_hash_table_insert(attrs->id_lists_hash, &attr->attr, (attr_queue = g_queue_new())); g_queue_push_tail(attr_queue, attr); break; case 'b': /* RR:0 */ if (line_end - value < 4) break; if (!memcmp(value, "RR:", 3)) *(media ? &media->rr : &session->rr) = (line_end - value == 4 && value[3] == '0') ? 0 : 1; else if (!memcmp(value, "RS:", 3)) *(media ? &media->rs : &session->rs) = (line_end - value == 4 && value[3] == '0') ? 0 : 1; break; case 's': case 'i': case 'u': case 'e': case 'p': case 't': case 'r': case 'z': case 'k': break; default: errstr = "Unknown SDP line type found"; goto error; } errstr = "SDP doesn't start with a session definition"; if (!session) goto error; adj_s = media ? &media->s : &session->s; adj_s->len = (next_line ? : end) - adj_s->s; b = next_line; } return 0; error: ilog(LOG_WARNING, "Error parsing SDP at offset %li: %s", (long) (b - body->s), errstr); sdp_free(sessions); return -1; }
int main(int argc, char **argv) { int i, c, ret, errflag = 0; char s[6]; while ((c = getopt_long(argc, argv, "A:F:p:lrRvVw?", longopts, 0)) != EOF) switch (c) { case 'A': nway_advertise = parse_media(optarg); break; case 'F': fixed_speed = parse_media(optarg); break; case 'p': override_phy = atoi(optarg); break; case 'r': opt_restart++; break; case 'R': opt_reset++; break; case 'v': verbose++; break; case 'V': opt_version++; break; case 'w': opt_watch++; break; case 'l': opt_log++; break; case '?': errflag++; } /* Check for a few inappropriate option combinations */ if (opt_watch) verbose = 0; if (errflag || (fixed_speed & (fixed_speed-1)) || (fixed_speed && (opt_restart || nway_advertise))) { fprintf(stderr, usage, argv[0]); return 2; } if (opt_version) printf(version); /* Open a basic socket. */ if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { perror("socket"); exit(-1); } /* No remaining args means show all interfaces. */ if (optind == argc) { ret = 1; for (i = 0; i < MAX_ETH; i++) { sprintf(s, "eth%d", i); ret &= do_one_xcvr(skfd, s, 1); } if (ret) fprintf(stderr, "no MII interfaces found\n"); } else { ret = 0; for (i = optind; i < argc; i++) { ret |= do_one_xcvr(skfd, argv[i], 0); } } if (opt_watch && (ret == 0)) { while (1) { sleep(1); if (optind == argc) { for (i = 0; i < MAX_ETH; i++) { sprintf(s, "eth%d", i); watch_one_xcvr(skfd, s, i); } } else { for (i = optind; i < argc; i++) watch_one_xcvr(skfd, argv[i], i-optind); } } } close(skfd); return ret; }