/* * Read thread */ static void * iptv_file_thread ( void *aux ) { iptv_mux_t *im = aux; file_priv_t *fp = im->im_data; ssize_t r; int fd = fp->fd, pause = 0; char buf[32*1024]; off_t off = 0; int64_t mono; int e; #if defined(PLATFORM_DARWIN) fcntl(fd, F_NOCACHE, 1); #endif pthread_mutex_lock(&iptv_lock); while (!fp->shutdown && fd > 0) { while (!fp->shutdown && pause) { mono = mclk() + sec2mono(1); do { e = tvh_cond_timedwait(&fp->cond, &iptv_lock, mono); if (e == ETIMEDOUT) break; } while (ERRNO_AGAIN(e)); } if (fp->shutdown) break; pause = 0; pthread_mutex_unlock(&iptv_lock); r = read(fd, buf, sizeof(buf)); pthread_mutex_lock(&iptv_lock); if (r == 0) break; if (r < 0) { if (ERRNO_AGAIN(errno)) continue; break; } sbuf_append(&im->mm_iptv_buffer, buf, r); if (iptv_input_recv_packets(im, r) == 1) pause = 1; #ifndef PLATFORM_DARWIN #if !ENABLE_ANDROID posix_fadvise(fd, off, r, POSIX_FADV_DONTNEED); #endif #endif off += r; } pthread_mutex_unlock(&iptv_lock); return NULL; }
int tcp_read_timeout(int fd, void *buf, size_t len, int timeout) { int x, tot = 0; struct pollfd fds; assert(timeout > 0); fds.fd = fd; fds.events = POLLIN; fds.revents = 0; while(tot != len) { x = poll(&fds, 1, timeout); if(x == 0) return ETIMEDOUT; if(x == -1) { if (!tvheadend_running) return ECONNRESET; if (ERRNO_AGAIN(errno)) continue; return errno; } x = recv(fd, buf + tot, len - tot, MSG_DONTWAIT); if(x == -1) { if(ERRNO_AGAIN(errno)) continue; return errno; } if(x == 0) return ECONNRESET; tot += x; } return 0; }
void tvh_safe_usleep(int64_t us) { int64_t r; if (us <= 0) return; do { r = tvh_usleep(us); if (r < 0) { if (ERRNO_AGAIN(-r)) continue; break; } us = r; } while (r > 0); }
static int download_file(download_t *dn, const char *filename) { int fd, res; struct stat st; char *data, *last_url; ssize_t r; off_t off; fd = tvh_open(filename, O_RDONLY, 0); if (fd < 0) { tvherror(dn->log, "unable to open file '%s': %s", filename, strerror(errno)); return -1; } if (fstat(fd, &st) || st.st_size == 0) { tvherror(dn->log, "unable to stat file '%s': %s", filename, strerror(errno)); close(fd); return -1; } data = malloc(st.st_size+1); off = 0; do { r = read(fd, data + off, st.st_size - off); if (r < 0) { if (ERRNO_AGAIN(errno)) continue; break; } off += r; } while (off != st.st_size); close(fd); if (off == st.st_size) { data[off] = '\0'; last_url = strrchr(filename, '/'); if (last_url) last_url++; res = dn->process(dn->aux, last_url, NULL, data, off); } else { res = -1; } free(data); return res; }
/* * Write data (retry on EAGAIN) */ static ssize_t _write ( int fd, const void *buf, size_t count ) { ssize_t r; size_t n = 0; while ( n < count ) { r = write(fd, buf+n, count-n); if (r == -1) { if (ERRNO_AGAIN(errno)) continue; else return -1; } n += r; } return count == n ? n : -1; }
/* * Read data */ static ssize_t iptv_rtsp_read ( iptv_mux_t *im ) { rtsp_priv_t *rp = im->im_data; udp_multirecv_t *um = &rp->um; ssize_t r; uint8_t buf[1500]; /* RTCP - ignore all incoming packets for now */ do { r = recv(im->mm_iptv_fd2, buf, sizeof(buf), MSG_DONTWAIT); } while (r > 0); r = iptv_rtp_read(im, um, iptv_rtp_header_callback); if (r < 0 && ERRNO_AGAIN(errno)) r = 0; return r; }
static void spawn_pipe_read( th_pipe_t *p, char **_buf, int level ) { char *buf = *_buf, *s; size_t len; int r; if (buf == NULL) { buf = malloc(SPAWN_PIPE_READ_SIZE); buf[0] = '\0'; buf[SPAWN_PIPE_READ_SIZE - 1] = 0; *_buf = buf; } while (1) { len = strlen(buf); r = read(p->rd, buf + len, SPAWN_PIPE_READ_SIZE - 1 - len); if (r < 1) { if (errno == EAGAIN) break; if (ERRNO_AGAIN(errno)) continue; break; } buf[len + r] = '\0'; tvhlog_hexdump("spawn", buf + len, r); while (1) { s = buf; while (*s && *s != '\n' && *s != '\r') s++; if (*s == '\0') break; *s++ = '\0'; if (buf[0]) tvhlog(level, "spawn", "%s", buf); memmove(buf, s, strlen(s) + 1); } if (strlen(buf) == SPAWN_PIPE_READ_SIZE - 1) { tvherror("spawn", "pipe buffer full"); buf[0] = '\0'; } } }
int64_t tvh_usleep(int64_t us) { #if defined(PLATFORM_DARWIN) return usleep(us); #else struct timespec ts; int64_t val; int r; if (us <= 0) return 0; ts.tv_sec = us / 1000000LL; ts.tv_nsec = (us % 1000000LL) * 1000LL; r = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, &ts); val = (ts.tv_sec * 1000000LL) + ((ts.tv_nsec + 500LL) / 1000LL); if (ERRNO_AGAIN(r)) return val; return r ? -r : 0; #endif }
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 spawn_pipe_write( th_pipe_t *p, const char *fmt, va_list ap ) { char buf[512], *s = buf; int r; vsnprintf(buf, sizeof(buf), fmt, ap); while (*s) { r = write(p->wr, s, strlen(s)); if (r < 0) { if (errno == EAGAIN) break; if (ERRNO_AGAIN(errno)) continue; break; } if (!r) break; s += r; } }
int64_t tvh_usleep_abs(int64_t us) { #if defined(PLATFORM_DARWIN) /* Convert to relative wait */ int64_t now = getmonoclock(); int64_t relative = us - now; return tvh_usleep(relative); #else struct timespec ts; int64_t val; int r; if (us <= 0) return 0; ts.tv_sec = us / 1000000LL; ts.tv_nsec = (us % 1000000LL) * 1000LL; r = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, &ts); val = (ts.tv_sec * 1000000LL) + ((ts.tv_nsec + 500LL) / 1000LL); if (ERRNO_AGAIN(r)) return val; return r ? -r : 0; #endif }
int tvh_write(int fd, const void *buf, size_t len) { time_t next = dispatch_clock + 25; ssize_t c; while (len) { c = write(fd, buf, len); if (c < 0) { if (ERRNO_AGAIN(errno)) { if (dispatch_clock > next) break; usleep(100); continue; } break; } len -= c; buf += c; } return len ? 1 : 0; }
int tvh_write(int fd, const void *buf, size_t len) { int64_t limit = mclk() + sec2mono(25); ssize_t c; while (len) { c = write(fd, buf, len); if (c < 0) { if (ERRNO_AGAIN(errno)) { if (mclk() > limit) break; tvh_safe_usleep(100); continue; } break; } len -= c; buf += c; } return len ? 1 : 0; }
int udp_write( udp_connection_t *uc, const void *buf, size_t len, struct sockaddr_storage *storage ) { int r; if (storage == NULL) storage = &uc->ip; while (len) { r = sendto(uc->fd, buf, len, 0, (struct sockaddr*)storage, storage->ss_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); if (r < 0) { if (ERRNO_AGAIN(errno)) { tvh_safe_usleep(100); continue; } break; } len -= r; buf += r; } return len; }
static ssize_t _read_buf ( timeshift_file_t *tsf, int fd, void *buf, size_t size ) { ssize_t r; size_t ret; if (tsf && tsf->ram) { if (tsf->roff == tsf->woff) return 0; if (tsf->roff + size > tsf->woff) return -1; pthread_mutex_lock(&tsf->ram_lock); memcpy(buf, tsf->ram + tsf->roff, size); tsf->roff += size; pthread_mutex_unlock(&tsf->ram_lock); return size; } else { ret = 0; while (size > 0) { r = read(tsf ? tsf->rfd : fd, buf, size); if (r < 0) { if (ERRNO_AGAIN(errno)) continue; tvhtrace(LS_TIMESHIFT, "read errno %d", errno); return -1; } if (r > 0) { size -= r; ret += r; buf += r; } if (r == 0) return 0; } if (ret > 0 && tsf) tsf->roff += ret; return ret; } }
static void * tvhdhomerun_device_discovery_thread( void *aux ) { struct hdhomerun_discover_device_t result_list[MAX_HDHOMERUN_DEVICES]; int numDevices, brk; while (tvheadend_is_running()) { 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 ) { pthread_mutex_lock(&global_lock); tvhdhomerun_device_t *existing = tvhdhomerun_device_find(cDev->device_id); if ( tvheadend_is_running() ) { if ( !existing ) { tvhinfo(LS_TVHDHOMERUN,"Found HDHomerun device %08x with %d tuners", cDev->device_id, cDev->tuner_count); tvhdhomerun_device_create(cDev); } else if ( ((struct sockaddr_in *)&existing->hd_info.ip_address)->sin_addr.s_addr != htonl(cDev->ip_addr) ) { struct sockaddr_storage detected_dev_addr; memset(&detected_dev_addr, 0, sizeof(detected_dev_addr)); detected_dev_addr.ss_family = AF_INET; ((struct sockaddr_in *)&detected_dev_addr)->sin_addr.s_addr = htonl(cDev->ip_addr); char existing_ip[64]; tcp_get_str_from_ip(&existing->hd_info.ip_address, existing_ip, sizeof(existing_ip)); char detected_ip[64]; tcp_get_str_from_ip(&detected_dev_addr, detected_ip, sizeof(detected_ip)); tvhinfo(LS_TVHDHOMERUN,"HDHomerun device %08x switched IPs from %s to %s, updating", cDev->device_id, existing_ip, detected_ip); tvhdhomerun_device_destroy(existing); tvhdhomerun_device_create(cDev); } } pthread_mutex_unlock(&global_lock); } } } pthread_mutex_lock(&tvhdhomerun_discovery_lock); brk = 0; if (tvheadend_is_running()) { brk = tvh_cond_timedwait(&tvhdhomerun_discovery_cond, &tvhdhomerun_discovery_lock, mclk() + sec2mono(15)); brk = !ERRNO_AGAIN(brk) && brk != ETIMEDOUT; } pthread_mutex_unlock(&tvhdhomerun_discovery_lock); if (brk) break; } return NULL; }
int tcp_connect(const char *hostname, int port, const char *bindaddr, char *errbuf, size_t errbufsize, int timeout) { int fd, r, res, err; struct addrinfo *ai; char portstr[6]; socklen_t errlen = sizeof(err); snprintf(portstr, 6, "%u", port); res = getaddrinfo(hostname, portstr, NULL, &ai); if (res != 0) { snprintf(errbuf, errbufsize, "%s", gai_strerror(res)); return -1; } fd = tvh_socket(ai->ai_family, SOCK_STREAM, 0); if(fd == -1) { snprintf(errbuf, errbufsize, "Unable to create socket: %s", strerror(errno)); freeaddrinfo(ai); return -1; } /** * Switch to nonblocking */ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) { if (bindaddr && bindaddr[0] != '\0') { struct sockaddr_storage ip; memset(&ip, 0, sizeof(ip)); ip.ss_family = ai->ai_family; if (inet_pton(AF_INET, bindaddr, IP_IN_ADDR(ip)) <= 0 || bind(fd, (struct sockaddr *)&ip, IP_IN_ADDRLEN(ip)) < 0) { snprintf(errbuf, errbufsize, "Cannot bind to IPv%s addr '%s'", ai->ai_family == AF_INET6 ? "6" : "4", bindaddr); freeaddrinfo(ai); return -1; } } } else { snprintf(errbuf, errbufsize, "Invalid protocol family"); freeaddrinfo(ai); return -1; } r = connect(fd, ai->ai_addr, ai->ai_addrlen); freeaddrinfo(ai); if(r == -1) { /* timeout < 0 - do not wait at all */ if(errno == EINPROGRESS && timeout < 0) { err = 0; } else if(errno == EINPROGRESS) { tvhpoll_event_t ev; tvhpoll_t *efd; efd = tvhpoll_create(1); memset(&ev, 0, sizeof(ev)); ev.events = TVHPOLL_OUT; ev.fd = fd; ev.data.ptr = &fd; tvhpoll_add(efd, &ev, 1); /* minimal timeout is one second */ if (timeout < 1) timeout = 0; while (1) { if (!tvheadend_running) { errbuf[0] = '\0'; tvhpoll_destroy(efd); close(fd); return -1; } r = tvhpoll_wait(efd, &ev, 1, timeout * 1000); if (r > 0) break; if (r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); tvhpoll_destroy(efd); close(fd); return -1; } if (!ERRNO_AGAIN(errno)) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(errno)); tvhpoll_destroy(efd); close(fd); return -1; } } tvhpoll_destroy(efd); getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); close(fd); return -1; } fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); /* Set the keep-alive active */ err = 1; setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&err, errlen); return fd; }