} END_TEST /* TODO: find two headers with coliding hash and test it */ START_TEST(test_http_headers) { http_hdr_table *t; t = http_headers_init(); fail_if(http_header_parse(t, "") == 0); fail_if(http_header_parse(t, "field") == 0); fail_if(http_header_parse(t, "field\r\n") == 0); fail_if(http_header_parse(t, "field:") == 0); fail_if(http_header_parse(t, "field:\r\n") == 0); fail_if(http_header_parse(t, "field:value") == 0); fail_if(http_header_parse(t, ":value") == 0); fail_if(http_header_parse(t, ":value\r\n") == 0); fail_unless(http_header_parse(t, "Host: dsl.sk\r\n") == 0); assert_str(http_header_get(t, "Host"), "dsl.sk"); assert_str(http_header_get(t, "host"), "dsl.sk"); assert_str(http_header_get(t, "HOST"), "dsl.sk"); http_headers_destroy(t); } END_TEST
static void ssdp_response(struct http_header_list *args) { const char *url = http_header_get(args, "location"); const char *type = http_header_get(args, "st"); if(url != NULL && type != NULL) upnp_add_device(url, type, ssdp_maxage(args)); }
/* * Input: List of headers containing only X-Wap-Application-Id headers, values * being numeric application id codes. (Ppg module does coding of the header * value part of the X-WAP-Application-Id header). * Output: Octstr containing them in a byte list (one id per byte). * * Returns: Octstr containing headers, if succesfull, otherwise an empty * octstr. */ static Octstr *pack_appid_list(List *headers) { Octstr *appid_os, *header_name, *header_value; long i; size_t len; i = 0; appid_os = octstr_create(""); len = (size_t) list_len(headers); gw_assert(len); while (i < len) { http_header_get(headers, i, &header_name, &header_value); gw_assert(octstr_compare(header_name, octstr_imm("X-WAP-Application-Id")) == 0); octstr_format_append(appid_os, "%S", header_value); octstr_destroy(header_name); octstr_destroy(header_value); ++i; } return appid_os; }
static void ssdp_recv_notify(struct http_header_list *args) { const char *nts = http_header_get(args, "nts"); const char *url = http_header_get(args, "location"); const char *type = http_header_get(args, "nt"); if(nts == NULL || url == NULL) return; if(!strcasecmp(nts, "ssdp:alive") && type != NULL) upnp_add_device(url, type, ssdp_maxage(args)); if(!strcasecmp(nts, "ssdp:byebye")) upnp_del_device(url); }
static int ssdp_maxage(struct http_header_list *args) { int maxage = 1800; const char *cc = http_header_get(args, "cache-control"); if(cc != NULL && (cc = strstr(cc, "max-age")) != NULL && (cc = strchr(cc , '=')) != NULL) maxage = atoi(cc+1); return maxage; }
/* Removes hop-by-hop headers listed in section 13.5.1 of RFC 2616, and additionally removes any headers listed in the Connection header as described in section 14.10. */ int http_header_remove_hop_by_hop(struct http_header **header) { static const char *HOP_BY_HOP_HEADERS[] = { "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailers", "Transfer-Encoding", "Upgrade", }; char *connection; char **connection_tokens; size_t num_connection_tokens; unsigned int i; connection = http_header_get(*header, "Connection"); if (connection != NULL) { const char *p; p = read_token_list(connection, &connection_tokens, &num_connection_tokens); if (p == NULL) { free(connection); return 400; } if (*p != '\0') { free(connection); for (i = 0; i < num_connection_tokens; i++) free(connection_tokens[i]); free(connection_tokens); return 400; } free(connection); } else { connection_tokens = NULL; num_connection_tokens = 0; } for (i = 0; i < sizeof(HOP_BY_HOP_HEADERS) / sizeof(HOP_BY_HOP_HEADERS[0]); i++) *header = http_header_remove(*header, HOP_BY_HOP_HEADERS[i]); for (i = 0; i < num_connection_tokens; i++) *header = http_header_remove(*header, connection_tokens[i]); for (i = 0; i < num_connection_tokens; i++) free(connection_tokens[i]); free(connection_tokens); return 0; }
static void tmdb_handle_rate_limit(struct http_header_list *response_headers) { const char *retry = http_header_get(response_headers, "retry-after"); int waittime = 5; if(retry != NULL) waittime = atoi(retry) + 1; http_headers_free(response_headers); TMDB_TRACE("Rate limited - Throttling requests for %d seconds", waittime); hts_mutex_lock(&tmdb_mutex); tmdb_no_request_before = arch_get_ts() + waittime * 1000000; hts_mutex_unlock(&tmdb_mutex); }
void load_site_news(void) { #if ENABLE_WEBPOPUP struct http_header_list response_headers; buf_t *b; char errbuf[512]; b = fa_load("https://movian.tv/projects/movian/news.json", FA_LOAD_FLAGS(FA_DISABLE_AUTH | FA_COMPRESSION), FA_LOAD_RESPONSE_HEADERS(&response_headers), FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(b == NULL) { TRACE(TRACE_DEBUG, "News", "Unable to load news -- %s", errbuf); return; } const char *dateheader = http_header_get(&response_headers, "date"); if(dateheader == NULL) { buf_release(b); http_headers_free(&response_headers); return; } dateheader = mystrdupa(dateheader); http_headers_free(&response_headers); htsmsg_t *newsinfo = htsmsg_store_load("sitenews"); time_t no_news_before; if(newsinfo == NULL) newsinfo = htsmsg_create_map(); no_news_before = htsmsg_get_u32_or_default(newsinfo, "nothingbefore", 0); if(no_news_before == 0) { if(http_ctime(&no_news_before, dateheader)) { buf_release(b); htsmsg_release(newsinfo); return; } htsmsg_add_u32(newsinfo, "nothingbefore", no_news_before); htsmsg_store_save(newsinfo, "sitenews"); htsmsg_release(newsinfo); } htsmsg_t *doc = htsmsg_json_deserialize(buf_cstr(b)); buf_release(b); if(doc == NULL) { return; } hts_mutex_lock(&news_mutex); htsmsg_t *news = htsmsg_get_list(doc, "news"); if(news != NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, news) { htsmsg_t *entry; if((entry = htsmsg_get_map_by_field(f)) == NULL) continue; const char *title = htsmsg_get_str(entry, "title"); const char *created_on = htsmsg_get_str(entry, "created_on"); int id = htsmsg_get_u32_or_default(entry, "id", 0); if(created_on == NULL || title == NULL || id == 0) continue; time_t t; if(parse_created_on_time(&t, created_on)) continue; if(t < no_news_before) continue; char idstr[64]; snprintf(idstr, sizeof(idstr), "sitenews:%d", id); prop_t *p = add_news_locked(idstr, title, NULL, "Read more", idstr); if(p != NULL) { prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, open_news, p, PROP_TAG_ROOT, prop_create(p, "eventSink"), PROP_TAG_MUTEX, &news_mutex, NULL); } }
static int mm7eaif_receive(MmsBoxHTTPClientInfo *h) { MmsMsg *m = NULL; List *mh = NULL; int hstatus = HTTP_NO_CONTENT; List *rh = http_create_empty_headers(); List *rqh = http_create_empty_headers(); Octstr *reply_body = NULL, *value = NULL, *value2 = NULL; List *to = gwlist_create(), *hto = NULL; Octstr *subject = NULL, *otransid = NULL, *msgid = NULL; Octstr *hfrom = NULL, *rr_uri = NULL; time_t expiryt = -1, deliveryt = -1; Octstr *qf = NULL, *xver = NULL, *mmc_id = NULL, *qdir = NULL; int msize = h->body ? octstr_len(h->body) : 0; int dlr; int mtype; debug("mmsbox.mm7eaif.sendinterface", 0, " --> Enterred eaif send interface, blen=[%d] <--- ", msize); hfrom = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-From")); if (!h->body || /* A body is required, and must parse */ (m = mms_frombinary(h->body, hfrom ? hfrom : octstr_imm("anon@anon"))) == NULL) { http_header_add(rh, "Content-Type", "text/plain"); hstatus = HTTP_BAD_REQUEST; reply_body = octstr_format("Unexpected MMS message, no body?"); goto done; } /* XXXX handle delivery reports differently. */ mtype = mms_messagetype(m); mh = mms_message_headers(m); /* Now get sender and receiver data. * for now we ignore adaptation flags. */ mms_collect_envdata_from_msgheaders(mh, &to, &subject, &otransid, &expiryt, &deliveryt, DEFAULT_EXPIRE, -1, octstr_get_cstr(unified_prefix), strip_prefixes); if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL && gwlist_len(hto) > 0) { /* To address is in headers. */ int i, n; gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); to = gwlist_create(); for (i = 0, n = gwlist_len(hto); i < n; i++) { Octstr *h = NULL, *v = NULL; List *l; void *x; http_header_get(hto,i, &h, &v); l = http_header_split_value(v); while ((x = gwlist_extract_first(l)) != NULL) gwlist_append(to, x); gwlist_destroy(l, NULL); octstr_destroy(h); octstr_destroy(v); } } qdir = get_mmsbox_queue_dir(hfrom, to, h->m, &mmc_id); /* get routing info. */ switch(mtype) { case MMS_MSGTYPE_SEND_REQ: case MMS_MSGTYPE_RETRIEVE_CONF: /* Get Message ID */ if ((msgid = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-Message-Id"))) == NULL) msgid = http_header_value(mh, octstr_imm("Message-ID")); else mms_replace_header_value(m, "Message-ID", octstr_get_cstr(msgid)); /* replace it in the message.*/ value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report")); if (value && octstr_case_compare(value, octstr_imm("Yes")) == 0) dlr = 1; else dlr = 0; if (deliveryt < 0) deliveryt = time(NULL); if (expiryt < 0) expiryt = time(NULL) + DEFAULT_EXPIRE; if (hfrom == NULL) hfrom = http_header_value(mh, octstr_imm("From")); mms_remove_headers(m, "Bcc"); mms_remove_headers(m, "X-Mms-Delivery-Time"); mms_remove_headers(m, "X-Mms-Expiry"); mms_remove_headers(m, "X-Mms-Sender-Visibility"); MOD_SUBJECT(m, h->m, hfrom); /* Save it, put message id in header, return. */ qf = qfs->mms_queue_add(hfrom, to, subject, h->m->id, mmc_id, deliveryt, expiryt, m, NULL, NULL, NULL, NULL, NULL, NULL, dlr, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received", hfrom, to, msize, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; octstr_destroy(value); octstr_destroy(value2); break; case MMS_MSGTYPE_DELIVERY_IND: msgid = mms_get_header_value(m, octstr_imm("Message-ID")); value = mms_get_header_value(m, octstr_imm("X-Mms-Status")); value2 = mms_get_header_value(m, octstr_imm("X-Mbuni-Orig-Message-ID")); rr_uri = mmsbox_get_report_info(m, h->m, mmc_id, "delivery-report", value, rqh, NULL, 0, msgid); if (value2 && mmc_id == NULL) http_header_add(rqh, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(value2)); qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, rr_uri, NULL, rqh, 0, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("DeliveryReport", hfrom, to, -1, msgid, value, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; octstr_destroy(value); octstr_destroy(value2); break; case MMS_MSGTYPE_READ_ORIG_IND: msgid = mms_get_header_value(m, octstr_imm("Message-ID")); value = mms_get_header_value(m, octstr_imm("X-Mms-Read-Status")); value2 = mms_get_header_value(m, octstr_imm("X-Mbuni-Orig-Message-ID")); rr_uri = mmsbox_get_report_info(m, h->m, mmc_id, "read-report", value, rqh, NULL, 0, msgid); if (value2 && mmc_id == NULL) http_header_add(rqh, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(value2)); qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, rr_uri, NULL, rqh, 0, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received RR", hfrom, to, -1, msgid, value, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; octstr_destroy(value); octstr_destroy(value2); break; } done: xver = octstr_format(EAIF_VERSION, h->m->ver.major, h->m->ver.minor1); http_header_add(rh, "X-NOKIA-MMSC-Version", octstr_get_cstr(xver)); octstr_destroy(xver); http_send_reply(h->client, hstatus, rh, octstr_imm("")); http_destroy_headers(hto); http_destroy_headers(rqh); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(hfrom); octstr_destroy(subject); octstr_destroy(otransid); octstr_destroy(msgid); octstr_destroy(qf); octstr_destroy(mmc_id); octstr_destroy(rr_uri); http_destroy_headers(mh); mms_destroy(m); return http_status_class(hstatus) == HTTP_STATUS_SUCCESSFUL ? 0 : -1; }
/* * Attempt to read an envelope from queue file: * - opens and locks the file. * - if the lock succeeds, check that file hasn't changed since opening. If it has * return NULL (i.e. file is being processed elsewhere -- race condition), otherwise read it. * - If should block is 1, then does a potentially blocking attempt to lock the file. */ static MmsEnvelope *mms_queue_readenvelope(char *qf, char *mms_queuedir, int shouldblock) { Octstr *fname; int fd; Octstr *qdata, *s; ParseContext *p; MmsEnvelope *e; int okfile = 0; char subdir[64]; char realqf[QFNAMEMAX]; char xqf[QFNAMEMAX+64]; struct qfile_t *qfs; get_subdir(qf, subdir, realqf); /* break it down... */ fname = octstr_format( "%.128s/%s%s", mms_queuedir, subdir, realqf); strncpy(xqf, octstr_get_cstr(fname), sizeof xqf); #ifdef SunOS if ((fd = open(octstr_get_cstr(fname), O_RDWR)) < 0) { #else if ((fd = open(octstr_get_cstr(fname), O_RDONLY)) < 0) { #endif debug("",0,"mms_queue_readenvelope: could not open file %s", octstr_get_cstr(fname)); octstr_destroy(fname); return NULL; } else if (mm_lockfile(fd, octstr_get_cstr(fname), shouldblock) != 0) { debug("",0,"mms_queue_readenvelope: could not lock file %s", octstr_get_cstr(fname)); unlock_and_close(fd); octstr_destroy(fname); return NULL; } debug("",0,"locked and opened file: %s", octstr_get_cstr(fname)); e = mms_queue_create_envelope(NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, qf, NULL, sizeof (struct qfile_t), NULL); qfs = e->qfs_data; qfs->fd = fd; strncpy(qfs->name, realqf, sizeof qfs->name); strncpy(qfs->subdir, subdir, sizeof qfs->subdir); strncpy(qfs->dir, mms_queuedir, sizeof qfs->dir); qdata = octstr_read_file(octstr_get_cstr(fname)); octstr_destroy(fname); if (qdata == NULL) qdata = octstr_imm(""); p = parse_context_create(qdata); for (s = parse_get_line(p); s; s = parse_get_line(p)) { char *line = octstr_get_cstr(s); int ch = line[0]; char *res = line + 1; char *ptmp; switch (ch) { Octstr *t; MmsEnvelopeTo *to; case 'T': t = octstr_create(res); e->msgtype = mms_string_to_message_type(t); octstr_destroy(t); if (e->msgtype < 0) { e->msgtype = 0; error(0, "mms_queueread: Unknown MMS message type (%s) in file %s, skipped!\n", res, xqf); } break; case 'I': e->msgId = octstr_create(res); break; case 'i': strncpy(e->src_interface, res, sizeof e->src_interface); break; case 'F': e->from = octstr_create(res); if (mms_validate_address(e->from) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&e->from, NULL, NULL, 1); } break; case 'R': t = octstr_create(res); if (mms_validate_address(t) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&t, NULL, NULL, 1); } to = gw_malloc(sizeof *to); to->rcpt = t; to->process = 1; gwlist_append(e->to, to); break; case 'C': e->created = atol(res); break; case 'L': e->lasttry = atol(res); break; case 'D': e->sendt = atol(res); break; case 'X': e->expiryt = atol(res); break; case 'N': e->attempts = atol(res); break; case 'P': e->fromproxy = octstr_create(res); break; case 'M': e->mdata = octstr_create(res); break; case 'p': e->viaproxy = octstr_create(res); break; case 'S': e->msize = atol(res); break; case 's': e->subject = octstr_create(res); break; case 't': e->token = octstr_create(res); break; case 'f': e->lastaccess = atol(res); break; case 'b': e->bill.billed = 1; e->bill.amt = atof(res); break; case 'r': e->dlr = 1; break; case 'V': e->vaspid = octstr_create(res); break; case 'v': e->vasid = octstr_create(res); break; case 'U': e->url1 = octstr_create(res); break; case 'u': e->url2 = octstr_create(res); break; case 'H': if (e->hdrs == NULL) e->hdrs = http_create_empty_headers(); if ((ptmp = index(res, ':')) == NULL) error(0, "Incorrectly formatted line %s in queue file %s!", line, xqf); else { char *value = ptmp + 1; char hname[512]; int xlen = (ptmp - res < sizeof hname) ? ptmp - res : -1 + sizeof hname; strncpy(hname, res, xlen); hname[xlen] = 0; /* terminate it. */ http_header_add(e->hdrs, hname, value); } break; case '.': okfile = 1; break; default: error(0, "Unknown QF header %c in file %s!", ch, xqf); break; } octstr_destroy(s); if (okfile) break; /* We are done. */ } parse_context_destroy(p); octstr_destroy(qdata); /* We should properly validate the queue file here. */ if (!okfile) { free_envelope(e,0); e = NULL; error(0, "Corrupt queue control file: %s", xqf); } return e; } /* Updates envelope to queue file: * - opens temp file * - writes output to temp file, if not new else writes directly. * - renames temp file to queue file (if not new) * This function doesn't check that this envelope is useless (i.e. no recipients) * - If function returns -1, caller should check errno for error. */ static int writeenvelope(MmsEnvelope *e, int newenv) { Octstr *tfname = NULL; char *s; char buf[512]; int fd; int i, n; int res = 0; struct qfile_t *qfs = e ? e->qfs_data : NULL; gw_assert(e); if (newenv) fd = qfs->fd; else { tfname = octstr_format( "%s/%s%c%s.%d", qfs->dir, qfs->subdir, MTF, qfs->name + 1, random()); fd = open(octstr_get_cstr(tfname), O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0 ) { error(0, "mms_queueadd: Failed to open temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } else if (mm_lockfile(fd, octstr_get_cstr(tfname), 0) != 0) { /* Lock it. */ error(0, "mms_queueadd: Failed lock temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } } /* Write out. */ s = (char *)mms_message_type_to_cstr(e->msgtype); if (!s) { error(0, "mms_queuewrite: Unknown MMS message type %d! Skipped\n", e->msgtype); s = ""; } _putline(fd, "T", s); if (e->msgId) _putline(fd, "I", octstr_get_cstr(e->msgId)); if (e->src_interface[0]) _putline(fd, "i", e->src_interface); if (e->from) _putline(fd, "F", octstr_get_cstr(e->from)); if (e->to) n = gwlist_len(e->to); else n = 0; for (i = 0; i < n; i++) { MmsEnvelopeTo *to = gwlist_get(e->to, i); if (to->process) _putline(fd, "R", octstr_get_cstr(to->rcpt)); } /* Output headers if any. */ n = (e->hdrs) ? gwlist_len(e->hdrs) : 0; for (i = 0; i < n; i++) { Octstr *h = NULL, *v = NULL; http_header_get(e->hdrs, i, &h, &v); if (h && v) { Octstr *x = octstr_format("%s:%s", octstr_get_cstr(h), octstr_get_cstr(v)); _putline(fd, "H", octstr_get_cstr(x)); octstr_destroy(x); } if (h) octstr_destroy(h); if (v) octstr_destroy(v); } sprintf(buf, "%ld", e->created); _putline(fd, "C", buf); if (e->lasttry) { sprintf(buf, "%ld", e->lasttry); _putline(fd, "L", buf); } if (e->sendt) { sprintf(buf, "%ld", e->sendt); _putline(fd, "D", buf); } if (e->expiryt) { sprintf(buf, "%ld", e->expiryt); _putline(fd, "X", buf); } if (e->attempts) { sprintf(buf, "%ld", e->attempts); _putline(fd, "N", buf); } if (e->lastaccess) { sprintf(buf, "%ld", e->lastaccess); _putline(fd, "f", buf); } sprintf(buf, "%ld", e->msize); _putline(fd, "S", buf); if (e->fromproxy) _putline(fd, "P", octstr_get_cstr(e->fromproxy)); if (e->mdata) _putline(fd, "M", octstr_get_cstr(e->mdata)); if (e->subject) _putline(fd, "s", octstr_get_cstr(e->subject)); if (e->viaproxy) _putline(fd, "p", octstr_get_cstr(e->viaproxy)); if (e->token) _putline(fd, "t", octstr_get_cstr(e->token)); if (e->vaspid) _putline(fd, "V", octstr_get_cstr(e->vaspid)); if (e->vasid) _putline(fd, "v", octstr_get_cstr(e->vasid)); if (e->url1) _putline(fd, "U", octstr_get_cstr(e->url1)); if (e->url2) _putline(fd, "u", octstr_get_cstr(e->url2)); if (e->dlr) _putline(fd, "r", "Yes"); if (e->bill.billed) { sprintf(buf, "%.3f", e->bill.amt); _putline(fd,"b", buf); } _putline(fd, "", "."); fsync(fd); /* Sync data. */ if (!newenv) { /* An update */ Octstr *qfname; qfname = octstr_format("%s/%s%s", qfs->dir, qfs->subdir, qfs->name); if (rename(octstr_get_cstr(tfname), octstr_get_cstr(qfname)) < 0) { error(0, "mms_queuewrite: Failed to rename %s to %s: error = %s\n", octstr_get_cstr(qfname), octstr_get_cstr(tfname), strerror(errno)); unlock_and_close(fd); /* Close new one, keep old one. */ res = -1; } else { /* On success, new descriptor replaces old one and we close old one. */ unlock_and_close(qfs->fd); qfs->fd = fd; } octstr_destroy(qfname); } done: octstr_destroy(tfname); return res; }
/** * mc is set if packet arrived on our multicast listening socket */ static void ssdp_input(int fd, int mc) { char buf[2000]; int r, cmd, self; struct http_header_list args; uint32_t myaddr; const char *usn; struct sockaddr_in si; #if defined(IP_RECVDSTADDR) struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; char ctrl[500]; iov.iov_base = buf; iov.iov_len = sizeof(buf); msg.msg_name = (struct sockaddr *)&si; msg.msg_namelen = sizeof(struct sockaddr_in); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ctrl; msg.msg_controllen = sizeof(ctrl); r = recvmsg(fd, &msg, 0); if(r < 1) return; buf[r] = 0; myaddr = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg,cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { struct in_addr *ia = (struct in_addr *)CMSG_DATA(cmsg); myaddr = ntohl(ia->s_addr); break; } } #else socklen_t slen = sizeof(struct sockaddr_in); netif_t *ni; r = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&si, &slen); if(r < 1) return; buf[r] = 0; ni = net_get_interfaces(); myaddr = ni ? ni[0].ipv4 : 0; free(ni); #endif if(!myaddr) return; LIST_INIT(&args); cmd = ssdp_parse(buf, &args); usn = http_header_get(&args, "usn"); self = usn != NULL && !strncmp(usn, "uuid:", 5) && !strncmp(usn + 5, ssdp_uuid, strlen(ssdp_uuid)); if(!self) { if(cmd == SSDP_NOTIFY && mc) ssdp_recv_notify(&args); if(cmd == SSDP_RESPONSE && !mc) ssdp_response(&args); if(cmd == SSDP_SEARCH && mc) ssdp_send_all(ssdp_fdu, myaddr, &si, NULL); } http_headers_free(&args); }