static void satip_discovery_send_msearch(void *aux) { #define MSG "\ M-SEARCH * HTTP/1.1\r\n\ HOST: 239.255.255.250:1900\r\n\ MAN: \"ssdp:discover\"\r\n\ MX: 2\r\n\ ST: urn:ses-com:device:SatIPServer:1\r\n" int attempt = ((intptr_t)aux) % 10; htsbuf_queue_t q; /* UDP is not reliable - send this message three times */ if (attempt < 1 || attempt > 3) return; if (satip_discovery_service == NULL) return; htsbuf_queue_init(&q, 0); htsbuf_append(&q, MSG, sizeof(MSG)-1); htsbuf_qprintf(&q, "USER-AGENT: unix/1.0 UPnP/1.1 TVHeadend/%s\r\n", tvheadend_version); htsbuf_append(&q, "\r\n", 2); upnp_send(&q, NULL, 0); htsbuf_queue_flush(&q); gtimer_arm_ms(&satip_discovery_msearch_timer, satip_discovery_send_msearch, (void *)(intptr_t)(attempt + 1), attempt * 11); #undef MSG }
void linuxdvb_ca_enqueue_capmt(linuxdvb_ca_t *lca, uint8_t slot, const uint8_t *ptr, int len, uint8_t list_mgmt, uint8_t cmd_id) { linuxdvb_ca_capmt_t *lcc; int c = 1; if (!lca) return; if (lca->lca_capmt_query && cmd_id == CA_PMT_CMD_ID_OK_DESCRAMBLING) c = 2; while (c--) { lcc = calloc(1, sizeof(*lcc)); if (!lcc) return; lcc->data = malloc(len); lcc->len = len; lcc->slot = slot; lcc->list_mgmt = list_mgmt; lcc->cmd_id = (c ? CA_PMT_CMD_ID_QUERY : cmd_id); memcpy(lcc->data, ptr, len); TAILQ_INSERT_TAIL(&lca->lca_capmt_queue, lcc, lcc_link); tvhtrace("en50221", "%s CAPMT enqueued (%s)", ca_pmt_cmd_id2str(lcc->cmd_id), ca_pmt_list_mgmt2str(lcc->list_mgmt)); } gtimer_arm_ms(&lca->lca_capmt_queue_timer, linuxdvb_ca_process_capmt_queue, lca, 50); }
static int download_pipe(download_t *dn, const char *args) { char **argv = NULL; int r; download_pipe_close(dn); gtimer_disarm(&dn->pipe_read_timer); /* Arguments */ if (spawn_parse_args(&argv, 64, args, NULL)) { tvherror(dn->log, "pipe: unable to parse arguments (%s)", args); return -1; } /* Grab */ r = spawn_and_give_stdout(argv[0], argv, NULL, &dn->pipe_fd, &dn->pipe_pid, 1); spawn_free_args(argv); if (r < 0) { dn->pipe_fd = -1; dn->pipe_pid = 0; tvherror(dn->log, "pipe: cannot start (%s)", args); return -1; } fcntl(dn->pipe_fd, F_SETFL, fcntl(dn->pipe_fd, F_GETFL) | O_NONBLOCK); gtimer_arm_ms(&dn->pipe_read_timer, download_pipe_read, dn, 250); return 0; }
static void tvhdhomerun_discovery_timer_cb(void *aux) { struct hdhomerun_discover_device_t result_list[MAX_HDHOMERUN_DEVICES]; if (!tvheadend_running) return; int numDevices = hdhomerun_discover_find_devices_custom(0, HDHOMERUN_DEVICE_TYPE_TUNER, HDHOMERUN_DEVICE_ID_WILDCARD, result_list, MAX_HDHOMERUN_DEVICES); if (numDevices > 0) { while (numDevices > 0 ) { numDevices--; struct hdhomerun_discover_device_t* cDev = &result_list[numDevices]; if ( cDev->device_type == HDHOMERUN_DEVICE_TYPE_TUNER ) { if ( !tvhdhomerun_device_find(cDev->device_id) ) { tvhlog(LOG_INFO, "tvhdhomerun","Found HDHomerun device %08x with %d tuners", cDev->device_id, cDev->tuner_count); tvhdhomerun_device_create(cDev); } } } } // Do rediscovery every 30 seconds.. gtimer_arm_ms(&tvhdhomerun_discovery_timer, tvhdhomerun_discovery_timer_cb, NULL, 15*1000); }
static void linuxdvb_ca_monitor ( void *aux ) { linuxdvb_ca_t *lca = aux; ca_slot_info_t csi; int state; csi.num = 0; if (lca->lca_ca_fd >= 0) { if ((ioctl(lca->lca_ca_fd, CA_GET_SLOT_INFO, &csi)) != 0) { tvherror("linuxdvb", "failed to get CAM slot %u info [e=%s]", csi.num, strerror(errno)); } if (csi.flags & CA_CI_MODULE_READY) state = CA_SLOT_STATE_MODULE_READY; else if (csi.flags & CA_CI_MODULE_PRESENT) state = CA_SLOT_STATE_MODULE_PRESENT; else state = CA_SLOT_STATE_EMPTY; lca->lca_state_str = ca_slot_state2str(state); if (lca->lca_state != state) { tvhlog(LOG_INFO, "linuxdvb", "CAM slot %u status changed to %s", csi.num, lca->lca_state_str); idnode_notify_title_changed(&lca->lca_id, NULL); lca->lca_state = state; } if ((!lca->lca_en50221_thread_running) && (state == CA_SLOT_STATE_MODULE_READY)) { lca->lca_en50221_thread_running = 1; tvhthread_create(&lca->lca_en50221_thread, NULL, linuxdvb_ca_en50221_thread, lca); } else if (lca->lca_en50221_thread_running && (state != CA_SLOT_STATE_MODULE_READY)) { lca->lca_en50221_thread_running = 0; pthread_join(lca->lca_en50221_thread, NULL); } } gtimer_arm_ms(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, 250); }
linuxdvb_ca_t * linuxdvb_ca_create ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path) { linuxdvb_ca_t *lca; char id[6]; const char *uuid = NULL; lca = calloc(1, sizeof(linuxdvb_ca_t)); memset(lca, 0, sizeof(linuxdvb_ca_t)); lca->lca_number = number; lca->lca_ca_path = strdup(ca_path); lca->lca_ca_fd = -1; lca->lca_capmt_interval = 100; lca->lca_capmt_query_interval = 1200; /* Internal config ID */ snprintf(id, sizeof(id), "ca%u", number); if (conf) conf = htsmsg_get_map(conf, id); if (conf) uuid = htsmsg_get_str(conf, "uuid"); if (idnode_insert(&lca->lca_id, uuid, &linuxdvb_ca_class, 0)) { free(lca); return NULL; } if (conf) idnode_load(&lca->lca_id, conf); /* Adapter link */ lca->lca_adapter = la; LIST_INSERT_HEAD(&la->la_ca_devices, lca, lca_link); TAILQ_INIT(&lca->lca_capmt_queue); gtimer_arm_ms(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, 250); return lca; }
static void download_pipe_read(void *aux) { download_t *dn = aux; ssize_t len; char *s, *p; if (dn->pipe_fd < 0 || dn->pipe_pid == 0) return; while (1) { if (dn->pipe_sbuf.sb_ptr > 50*1024*1024) { errno = EMSGSIZE; goto failed; } sbuf_alloc(&dn->pipe_sbuf, 2048); len = sbuf_read(&dn->pipe_sbuf, dn->pipe_fd); if (len == 0) { s = dn->url ? strdupa(dn->url) : strdupa(""); p = strchr(s, ' '); if (p) *p = '\0'; p = strrchr(s, '/'); if (p) p++; sbuf_append(&dn->pipe_sbuf, "", 1); dn->process(dn->aux, p, NULL, (char *)dn->pipe_sbuf.sb_data, (size_t)dn->pipe_sbuf.sb_ptr); download_pipe_close(dn); return; } else if (len < 0) { if (ERRNO_AGAIN(errno)) break; failed: tvherror(dn->log, "pipe: read failed: %d", errno); download_pipe_close(dn); return; } } gtimer_arm_ms(&dn->pipe_read_timer, download_pipe_read, dn, 250); }
static void satip_discovery_service_received (uint8_t *data, size_t len, udp_connection_t *conn, struct sockaddr_storage *storage) { char *buf, *ptr, *saveptr; char *argv[10]; char *st = NULL; char *location = NULL; char *server = NULL; char *uuid = NULL; char *bootid = NULL; char *configid = NULL; char *deviceid = NULL; char sockbuf[128]; satip_discovery_t *d; int n, i; if (len > 8191 || satip_discoveries_count > 100) return; buf = alloca(len+1); memcpy(buf, data, len); buf[len] = '\0'; ptr = strtok_r(buf, "\r\n", &saveptr); /* Request decoder */ if (ptr) { if (http_tokenize(ptr, argv, 3, -1) != 3) return; if (conn->multicast) { if (strcmp(argv[0], "NOTIFY")) return; if (strcmp(argv[1], "*")) return; if (strcmp(argv[2], "HTTP/1.1")) return; } else { if (strcmp(argv[0], "HTTP/1.1")) return; if (strcmp(argv[1], "200")) return; } ptr = strtok_r(NULL, "\r\n", &saveptr); } /* Header decoder */ while (1) { if (ptr == NULL) break; if (http_tokenize(ptr, argv, 2, ':') == 2) { if (strcmp(argv[0], "ST") == 0) st = argv[1]; else if (strcmp(argv[0], "LOCATION") == 0) location = argv[1]; else if (strcmp(argv[0], "SERVER") == 0) server = argv[1]; else if (strcmp(argv[0], "BOOTID.UPNP.ORG") == 0) bootid = argv[1]; else if (strcmp(argv[0], "CONFIGID.UPNP.ORG") == 0) configid = argv[1]; else if (strcmp(argv[0], "DEVICEID.SES.COM") == 0) deviceid = argv[1]; else if (strcmp(argv[0], "USN") == 0) { n = http_tokenize(argv[1], argv, ARRAY_SIZE(argv), ':'); for (i = 0; i < n-1; i++) if (argv[i] && strcmp(argv[i], "uuid") == 0) { uuid = argv[++i]; break; } } } ptr = strtok_r(NULL, "\r\n", &saveptr); } /* Sanity checks */ if (st == NULL || strcmp(st, "urn:ses-com:device:SatIPServer:1")) goto add_uuid; if (uuid == NULL || strlen(uuid) < 16 || satip_server_match_uuid(uuid)) goto add_uuid; if (location == NULL || strncmp(location, "http://", 7)) goto add_uuid; if (bootid == NULL || configid == NULL || server == NULL) goto add_uuid; /* Forward information to next layer */ d = calloc(1, sizeof(satip_discovery_t)); if (inet_ntop(conn->ip.ss_family, IP_IN_ADDR(conn->ip), sockbuf, sizeof(sockbuf)) == NULL) { satip_discovery_destroy(d, 0); return; } d->myaddr = strdup(sockbuf); d->location = strdup(location); d->server = strdup(server); d->uuid = strdup(uuid); d->bootid = strdup(bootid); d->configid = strdup(configid); d->deviceid = strdup(deviceid ? deviceid : ""); if (urlparse(d->location, &d->url)) { satip_discovery_destroy(d, 0); return; } pthread_mutex_lock(&global_lock); i = 1; if (!satip_discovery_find(d) && !satip_device_find(d->uuid)) { TAILQ_INSERT_TAIL(&satip_discoveries, d, disc_link); satip_discoveries_count++; gtimer_arm_ms(&satip_discovery_timerq, satip_discovery_timerq_cb, NULL, 250); i = 0; } pthread_mutex_unlock(&global_lock); if (i) /* duplicate */ satip_discovery_destroy(d, 0); return; add_uuid: if (deviceid == NULL || uuid == NULL) return; /* if new uuid was discovered, retrigger MSEARCH */ pthread_mutex_lock(&global_lock); if (!satip_device_find(uuid)) gtimer_arm(&satip_discovery_timer, satip_discovery_timer_cb, NULL, 5); pthread_mutex_unlock(&global_lock); }
void satip_device_destroy_later( satip_device_t *sd, int after ) { gtimer_arm_ms(&sd->sd_destroy_timer, satip_device_destroy_cb, sd, after); }
static void linuxdvb_ca_process_capmt_queue ( void *aux ) { linuxdvb_ca_t *lca = aux; linuxdvb_ca_capmt_t *lcc; struct section *section; struct section_ext *result; struct mpeg_pmt_section *pmt; uint8_t capmt[4096]; int size, i; lcc = TAILQ_FIRST(&lca->lca_capmt_queue); if (!lcc) return; if (!(section = section_codec(lcc->data, lcc->len))){ tvherror("en50221", "failed to decode PMT section"); goto done; } if (!(result = section_ext_decode(section, 0))){ tvherror("en50221", "failed to decode PMT ext_section"); goto done; } if (!(pmt = mpeg_pmt_section_codec(result))){ tvherror("en50221", "failed to decode PMT"); goto done; } size = en50221_ca_format_pmt(pmt, capmt, sizeof(capmt), 0, lcc->list_mgmt, lcc->cmd_id); if (size < 0) { tvherror("en50221", "Failed to format CAPMT"); } if (en50221_app_ca_pmt(lca->lca_ca_resource, lca->lca_ca_session_number, capmt, size)) { tvherror("en50221", "Failed to send CAPMT"); } tvhtrace("en50221", "%s CAPMT sent (%s)", ca_pmt_cmd_id2str(lcc->cmd_id), ca_pmt_list_mgmt2str(lcc->list_mgmt)); tvhlog_hexdump("en50221", capmt, size); done: i = (lcc->cmd_id == CA_PMT_CMD_ID_QUERY) ? lca->lca_capmt_query_interval : lca->lca_capmt_interval; TAILQ_REMOVE(&lca->lca_capmt_queue, lcc, lcc_link); free(lcc->data); free(lcc); if (!TAILQ_EMPTY(&lca->lca_capmt_queue)) { gtimer_arm_ms(&lca->lca_capmt_queue_timer, linuxdvb_ca_process_capmt_queue, lca, i); } }