Exemple #1
0
static int hls_write(HTTPContext *c, uint8_t *data, int size)
{
	int inc = 0;
	uint8_t *ptr = NULL;
	HLS *s = &s_hls[c->hls_idx];

	if(!s->data){
		http_log("internal error i %d\n", c->hls_idx);
		return -1;
	}
	
	if(s->csize + size > s->msize){
		inc = 	(s->csize + size - s->msize + SEG_INC_SIZE)/SEG_INC_SIZE;
		ptr = av_realloc(s->data, inc*SEG_INC_SIZE + s->msize);
		if(ptr){
			s->data = ptr;
			s->msize += inc*SEG_INC_SIZE;
		}else{
			http_log("not enough mem  %d\n", inc);
			return -2;
		}
	}
	
	memcpy(s->data + s->csize, data, size);
	s->csize += size;
	c->hls_wpos += size;

	return 0;
}
static void new_connection(int server_fd)
{
    http_log("new connection!.\n");
    struct sockaddr_in from_addr;
    socklen_t len;
    int fd;
    RTSPContext *c = NULL;

    len = sizeof(from_addr);
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
                &len);
    if (fd < 0) {
        http_log("error during accept %s\n", strerror(errno));
        return;
    }

    if (nb_connections >= 100) {
     //   http_send_too_busy_reply(fd);
        goto fail;
    }

    /* add a new connection */
    c = av_mallocz(sizeof(RTSPContext));
    if (!c)
        goto fail;

    c->fd = fd;
    c->poll_entry = NULL;
    c->from_addr = from_addr;
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;

    c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + IOBUFFER_INIT_SIZE;
    c->next = first_rtsp_ctx;
    first_rtsp_ctx = c;
    nb_connections++;

    start_wait_request(c);
    return;
 fail:
    if (c) {
        av_free(c->buffer);
        av_free(c);
    }
    close(fd);
}
Exemple #3
0
void
http_request(http_t *ctx,
    const char *verb, const char *host, uint16_t port, const char *uri)
{
  http_log(ctx, "%s: host=\"%s\" uri=\"%s\"", __func__, host, uri);
  http_send_str(ctx, verb);
  http_send_str(ctx, " ");
  http_send_str(ctx, uri);
  http_send_line(ctx, " HTTP/1.1");

  http_send_str(ctx, "Host: ");
  http_send_str(ctx, host);
  if (port != HTTP_DEFAULT_PORT) {
    char buf[32], *p = buf;
    size_t size = sizeof buf;
    
    p = append_char(p, &size, ':');
    p = append_uint(p, &size, port);
    http_send_str(ctx, buf);
  }
  http_send_str(ctx, "\r\n");
  http_send_str(ctx, http_useragent_header);
  http_send_line(ctx, http_connection_header(ctx));
  http_send_extra_headers(ctx);
}
Exemple #4
0
static void log_connection(HTTPContext *c)
{
	//if(av_match_ext(c->url, "m3u8"))
    	http_log("%s:%u %d \"%s\" %lld %d %d\n",
             inet_ntoa(c->from_addr.sin_addr), ntohs(c->from_addr.sin_port), 
			 c->post, c->url,
			 c->data_count, c->http_error, nb_connections);
}
Exemple #5
0
static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs)
{
    static int print_prefix = 1;
    AVClass *avc = ptr ? *(AVClass**)ptr : NULL;
    if (level > av_log_get_level())
        return;
    if (print_prefix && avc)
        http_log("[%s @ %p]", avc->item_name(ptr), ptr);
    print_prefix = strstr(fmt, "\n") != NULL;
    http_vlog(fmt, vargs);
}
static void build_file_streams(void)
{
  iStream *stream, *stream_next;
  int i, ret;
  for(stream = first_stream; stream != NULL; stream = stream_next) {
    stream_next = stream->next;

    printf("filename = %s\n", stream->filename);
    printf("idx filename = %s\n", stream->idx_filename);
    if (!stream->filename[0] && !stream->idx_filename[0]) {
        http_log("Unspecified feed file for stream '%s' or idx file '%s'\n", stream->filename, stream->idx_filename);
    }
    else {
        /* find all the AVStreams inside and reference them in
           'stream' */
      //index parsing
      iIndexHeader *hdr = malloc(sizeof(*hdr));
      if (hdr < 0)
        printf("malloc error! of iIndexHeader \n");

      // error 처리 생략
      printf("start parse index file!!\n");
      iIndex *first_idx = start_parse_index_file(stream->idx_filename, hdr);

      if (first_idx == NULL) {
        http_log("%s Index file parsing error!!!\n", stream->idx_filename);
        return;
      }
      stream->idx_hdr = hdr;
      stream->first_idx = first_idx;
      stream->codec_name = hdr->encoding_format == 0 ? "H264" : "H265";
      stream->total_length = hdr->total_length;
      stream->bit_rate = hdr->bit_rate;
      stream->duration = hdr->duration;
    }
  }
}
Exemple #7
0
int flvsrv_sendHttpResp(FLVSRV_CTXT_T *pFlvCtxt) {
  int rc;
  FILE_OFFSET_T lenLive = 0;

  http_log(pFlvCtxt->pSd, pFlvCtxt->pReq, HTTP_STATUS_OK, lenLive);

  if((rc = http_resp_sendhdr(pFlvCtxt->pSd, pFlvCtxt->pReq->version, HTTP_STATUS_OK,
                   lenLive, CONTENT_TYPE_FLV, http_getConnTypeStr(pFlvCtxt->pReq->connType),
                   pFlvCtxt->pReq->cookie, NULL, NULL, NULL, NULL)) < 0) {
    pFlvCtxt->state = FLVSRV_STATE_ERROR;
    return rc;
  }

  return rc;
}
Exemple #8
0
static int sff_prepare_data(HTTPContext *c)
{
	SFF *sff = NULL;  
	AVPacket pkt = {0};

    switch(c->state) {
    case HTTPSTATE_SEND_DATA_HEADER:
		sff = sff_read(c, 1);
		if(!sff){
			printf("prepare no sff for %s\n", c->url);
			c->state = HTTPSTATE_WAIT_FEED;
			return 1;
		}
		c->buffer_ptr = sff->data;
        c->buffer_end = sff->data + sff->size;

        c->state = HTTPSTATE_SEND_DATA;
        c->last_packet_sent = 0;
        break;
    case HTTPSTATE_SEND_DATA:
		sff = sff_read(c, 2);
		if(!sff){
			//printf("2prepare no sff\n");
			c->state = HTTPSTATE_WAIT_FEED;
			return 1;
		}
		
		if(sff_parse(sff, &pkt)){
			printf("parse erro\n");
			return AVERROR(EAGAIN);
		}

		c->buffer_ptr = pkt.data;
		c->buffer_end = pkt.data + pkt.size;
		if(-1 == pkt.stream_index){
			c->state = HTTPSTATE_SEND_DATA_TRAILER;
		}

        break;
    default:
    case HTTPSTATE_SEND_DATA_TRAILER:
        c->last_packet_sent = 1;
		http_log("send trailer status\n");
		return -2;
        break;
    }
    return 0;
}
Exemple #9
0
int main(int argc, char **argv)
{
    //av_register_all();
    //avformat_network_init();
    unsetenv("http_proxy");  /* Kill the http_proxy */

	parse_config();
    signal(SIGPIPE, SIG_IGN);

    if (http_server() < 0) {
        http_log("Could not start server\n");
        exit(1);
    }

    return 0;
}
Exemple #10
0
/**
 *  @return
 *   -1 if a header was invalid (see http status for details)
 *    0 if all headers are successfully handled (end-of-header reached)
 */
int
http_process_headers(http_t *ctx, char *buf, size_t buf_size)
{
  RUNTIME_ASSERT(ctx);
  RUNTIME_ASSERT(HTTP_STATE_HEADERS == ctx->state);
  
  for (;;) {
    char *name, *value;
    
    name = value =  NULL;
    switch (http_parse_header(ctx, buf, buf_size, &name, &value)) {
    case -1:
      DBUG("http_parse_header() failed: %u \"%s\"",
        ctx->status_code, ctx->status_msg);
      return -1;
      
    case 0:
      RUNTIME_ASSERT(HTTP_STATE_BODY == ctx->state);
      return 0;

    case 1:
      break;

    default:
      RUNTIME_ASSERT(0);
      http_set_status(ctx, 500, "Internal Server Error");
      return -1;
    }

    RUNTIME_ASSERT(HTTP_STATE_HEADERS == ctx->state);
    RUNTIME_ASSERT(name);
    RUNTIME_ASSERT(value);

#if 0
    http_log(ctx, "name=\"%s\"; value=\"%s\"", name, value);
#endif
    
    if (0 != http_handle_header(ctx, name, value))
      break;
  }

  return -1;
}
Exemple #11
0
static int prepare_local_file(HTTPContext *c)
{/*return 1 if local file exist and can be read to buffer.*/
    int len;
	unsigned char tmp[64] = "";
	char prefix[32] = ".";
	int fd = -1;
	struct stat st = {0};

	snprintf(tmp, sizeof(tmp)-1, "%s/%s",  prefix, c->url);
	fd = open(tmp, O_RDONLY);
	if(fd < 0){
		return 0;
	}
	if((fstat(fd, &st) < 0) || (st.st_size > SIZE_MAX)){
		return 0;
	}
	
	c->pb_buffer = av_malloc(1024 + st.st_size);
	if(!c->pb_buffer){
        c->buffer_ptr = c->buffer;
        c->buffer_end = c->buffer;
		close(fd);
		return 0;
	}
	
	len = sprintf(c->pb_buffer, "HTTP/1.1 200 OK\r\n"
			"Content-type: %s;charset=UTF-8\r\n"
			"Content-Length: %u\r\n"
			"Connection: %s\r\n"
			"\r\n", 
			get_mine_type(c->url),
			(unsigned int)st.st_size, 
			(c->keep_alive ? "keep-alive" : "close") );

	len += read(fd, c->pb_buffer + len, st.st_size);
	close(fd);
	http_log("local file %s size %lld\n", c->url, st.st_size);

    c->buffer_ptr = c->pb_buffer;
    c->buffer_end = c->pb_buffer + len;
	return 1;
}
Exemple #12
0
int
http_read_response(http_t *ctx)
{
  char buf[BUFFERSIZE];
  char *p, *endptr;
  uint32_t code;
  ssize_t ret, size;
  int error;

  RUNTIME_ASSERT(ctx);
  RUNTIME_ASSERT(ctx->state == HTTP_STATE_REQUEST);
  
  ret = fifo_findchar(ctx->input, '\n', sizeof buf);
  if (ret < 0) {
    return 0;
  }
  if ((size_t) ret >= sizeof buf) {
    http_log(ctx, "HTTP response line is too long");
    return -1;
  }
  size = ret + 1;
  ret = fifo_read(ctx->input, buf, size);
  RUNTIME_ASSERT(ret > 0 && (size_t) ret <= sizeof buf);
  ret--;
  RUNTIME_ASSERT(buf[ret] == '\n');

  while (ret >= 0 && isspace((unsigned char) buf[ret]))
    buf[ret--] = '\0';

  http_log(ctx, "buf=\"%s\"", buf);
  
  p = http_parse_version(ctx, buf);
  if (!p) {
    http_log(ctx, "Not a HTTP reply: %s", buf);
    return -1;
  }
  if (!isspace((unsigned char) *p)) {
    http_log(ctx, "Missing space after HTTP/x.y: %s", buf);
    return -1;
  }

  p = skip_spaces(p);
  
  if (!isdigit((unsigned char) *p)) {
    http_log(ctx, "Invalid HTTP status code: %s", buf);
    return -1;
  }

  code = parse_uint32(p, &endptr, 10, &error);
  if (*endptr != '\0' && !isspace((unsigned char) *endptr)) {
    http_log(ctx, "Invalid HTTP status code: %s", buf);
    return -1;
  }
  if (code < 100 || code > 999) {
    http_log(ctx, "HTTP status code is out-of-range: %s", buf);
    return -1;
  }

  /* Don't care about the rest of the line */

  ctx->status_code = code;
  ctx->state = HTTP_STATE_HEADERS;
  return 0;
}
Exemple #13
0
static int hls_parse_request(HTTPContext *c, char *name, int is_first)
{
	int idx = -1, ret = 0;
	char *ext = NULL;
	HLS *s = NULL;

    ext = strrchr(name, '.');
	if(!ext){
		http_log("bad name %s\n", name);
		return -1;
	}	
	if(ext - name > sizeof(s_hls_name)-1){
		http_log("name %s too long\n", name);
		return -1;
	}
				
	if(!strcmp(ext, ".m3u8")){
		idx = S;
		
	}else if(!strcmp(ext, ".ts")){
		idx = ext[-1] - '0';//todo: S > 10 without get basename.
		if(!(0 <= idx && idx < S)){
			http_log("too large index %d\n", idx);
			return -1;
		}
	}
	
	if(-1 == idx){
		http_log("unkown name %s\n", name);
		return -1;
	}

	c->hls_idx = idx;
	s = &s_hls[idx];
	if(c->post){/*writer*/
		//todo: close http conn with same name
		
		//http_log("hls post c %p name %s:%d data %p size %d:%d\n", c, name, idx, s->data, s->msize, s->csize);

		if(!s->data){
			s->data = av_malloc(SEG_INC_SIZE);
			s->msize = SEG_INC_SIZE;
		}else{
			/*intended not to free*/
		}

		//todo: if someone is reading
		s->flag = 1;
		s->csize = 0;
		
		c->hls_wpos = 0; 
		c->http_error = 0;
		c->state = HTTPSTATE_RECEIVE_DATA;
	
		ret = 0;
	}else{/*reader*/
		if(is_first && (S == idx) && strncmp(s_hls_name, name, ext-name) ){
			hls_close();
			strncpy(s_hls_name, name, ext - name);
			s_hls_name[ext - name] = 0; 
			
			ret = 1; /*request switch*/ 	
		}

		c->hls_rpos = 0;
		c->http_error = 0;
		c->state = HTTPSTATE_SEND_HEADER;
	}
	
	return ret; 
}
Exemple #14
0
static void new_connection(int server_fd, int is_rtsp)
{
    struct sockaddr_in from_addr;
    socklen_t len;
    int fd;
    HTTPContext *c = NULL;
	int val;
	val = 0;

    len = sizeof(from_addr);
	memset(&from_addr, 0, len);
    fd = accept(server_fd, (struct sockaddr *)&from_addr,
                &len);
    if (fd < 0) {
        http_log("error during accept %s\n", strerror(errno));
        return;
    }
    if (ff_socket_nonblock(fd, 1) < 0)
        av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n");
	
	#if	0 /*prevent myself close_wait*/
	val = 1;
	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
	val = 5;
	setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val));
	val = 3;
	setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val));
	val = 2;
	setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val));
	#endif

    if (nb_connections >= nb_max_connections) {
        http_send_too_busy_reply(fd);
        goto fail;
    }

    /* add a new connection */
    c = av_mallocz(sizeof(HTTPContext));
    if (!c)
        goto fail;
    c->fd = fd;
    c->poll_entry = NULL;
    c->from_addr = from_addr;
    c->buffer_size = IOBUFFER_INIT_SIZE;
    c->buffer = av_malloc(c->buffer_size);
    if (!c->buffer)
        goto fail;

    c->next = first_http_ctx;
    first_http_ctx = c;
    nb_connections++;

	c->buffer_ptr = c->buffer;
    c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */
	c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
    c->state = HTTPSTATE_WAIT_REQUEST;
	c->hls_idx = -1;

    return;
 fail:
    if (c) {
        av_free(c->buffer);
        av_free(c);
    }
    closesocket(fd);
}
/* main loop of the Streaming server */
static int start_event_loop(void)
{
    int server_fd = 0, rtsp_server_fd = 0;
    int ret, delay;
    struct pollfd *poll_table, *poll_entry;
    RTSPContext *c, *c_next;

    if(!(poll_table = av_mallocz( 100 *sizeof(*poll_table)))) {
        http_log("Impossible to allocate a poll table handling %d connections.\n", 100);
        return -1;
    }

    if (my_rtsp_addr.sin_port) {
      rtsp_server_fd = socket_open_listen(&my_rtsp_addr);
      if (rtsp_server_fd < 0) {
        http_log("HTTP and RTSP disabled.\n");
        return -1;
      }
    }

    printf("%s started.\n", program_name);

    for(;;) {
        poll_entry = poll_table;
        if (rtsp_server_fd) {
            poll_entry->fd = rtsp_server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
        }

        /* wait for events on each HTTP handle */
        c = first_rtsp_ctx;
        //delay = 1000;
        delay = 10;
        while (c != NULL) {
            int fd;
            fd = c->fd;
            switch(c->state) {
            case RTSPSTATE_SEND_REPLY:
            case RTSPSTATE_SEND_PACKET:
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLOUT;
                poll_entry++;
                break;
            case RTPSTATE_SEND_DATA:
                /* for TCP, we output as much as we can
                 * (may need to put a limit) */
                if (strcmp(c->protocol, "RTP/UDP") == 0) {
                  fd = c->udp_fd;
                }
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLOUT;
                poll_entry++;
                break;
            case RTSPSTATE_WAIT_REQUEST:
                /* need to catch errors */
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLIN;/* Maybe this will work */
                poll_entry++;
                break;
            default:
                c->poll_entry = NULL;
                break;
            }
            c = c->next;
        }

        /* wait for an event on one connection. We poll at least every
           second to handle timeouts */
        do {
            ret = poll(poll_table, poll_entry - poll_table, delay);
            if (ret < 0) {
              printf ("poll errorr \n");
              return -1;
            }
        } while (ret < 0);

        cur_time = av_gettime() / 1000;

        /* now handle the events */
        for(c = first_rtsp_ctx; c != NULL; c = c_next) {
            c_next = c->next;
            if (handle_connection(c) < 0) {
              /* close and free the connection */
                close_connection(c);
            }
        }

        // 처음에  rtsp_server_fd로 셋팅했던 거. 로 포인터 값 변경.
        poll_entry = poll_table;
        if (rtsp_server_fd) {
            /* new RTSP connection request ? */
            if (poll_entry->revents & POLLIN)
                new_connection(rtsp_server_fd);
        }
    }
}
Exemple #16
0
static int http_server(void)
{
    int server_fd = 0;
	int ctrl_fd = 0, ctrl_fd2 = 0;
    int ret, delay;
    struct pollfd *poll_table, *poll_entry;
    HTTPContext *c, *c_next;
    if(!(poll_table = av_mallocz_array(nb_max_http_connections + 1, sizeof(*poll_table)))) {
        http_log("Impossible to allocate a poll table handling %d connections.\n", nb_max_http_connections);
        return -1;
    }

	#if defined(PLUGIN_DVB)
	ctrl_fd = ff_ctl_open(1234);
    if (ctrl_fd < 0) {
        av_free(poll_table);
        return -1;
    }
	#endif
	
    if (my_http_addr.sin_port) {
        server_fd = socket_open_listen(&my_http_addr);
        if (server_fd < 0) {
            av_free(poll_table);
            return -1;
        }
    }

    if ( !server_fd) {
        http_log("HTTP disabled.\n");
        av_free(poll_table);
        return -1;
    }
	
	#if defined(PLUGIN_SSDP)
	ssdp_fd = mcast_open(ssdp_ip, ssdp_port);
	if(ssdp_fd <= 0){
		http_log("ssdp disabled\n");
	}
	ssdp_notify(ssdp_fd, ssdp_ip, ssdp_port, "ssdp:alive");
	#endif
	
    http_log("FFserver started.\n");

    for(;;) {
        poll_entry = poll_table;
		
		#if defined(PLUGIN_DVB)
		if(ctrl_fd){
			poll_entry->fd = ctrl_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
		}
		if(ctrl_fd2){
			poll_entry->fd = ctrl_fd2;
			poll_entry->events = POLLIN;
			if(ctl_msg_pending() > 0){
				poll_entry->events |= POLLOUT;
			}
            poll_entry++;
		}
		#endif
		
        if (server_fd) {
            poll_entry->fd = server_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
        }
		
		#if defined(PLUGIN_SSDP)
		if(ssdp_fd){
			poll_entry->fd = ssdp_fd;
            poll_entry->events = POLLIN;
            poll_entry++;
		}
		#endif

        /* wait for events on each HTTP handle */
        c = first_http_ctx;
        delay = 1500;
        while (c != NULL) {
            int fd;
            fd = c->fd;
            switch(c->state) {
            case HTTPSTATE_SEND_HEADER:
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLOUT;
                poll_entry++;
                break;
            case HTTPSTATE_SEND_DATA_HEADER:
            case HTTPSTATE_SEND_DATA:
            case HTTPSTATE_SEND_DATA_TRAILER:
                /*for TCP, we output as much as we can*/
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLOUT;
                poll_entry++;
                break;
            case HTTPSTATE_WAIT_REQUEST:
            case HTTPSTATE_RECEIVE_DATA:
            case HTTPSTATE_WAIT_FEED:
                /* need to catch errors */
                c->poll_entry = poll_entry;
                poll_entry->fd = fd;
                poll_entry->events = POLLIN;/* Maybe this will work */
                poll_entry++;
                break;
            default:
                c->poll_entry = NULL;
                break;
            }
            c = c->next;
        }

        /* wait for an event on one connection. We poll at least every second to handle timeouts */
        do {
            ret = poll(poll_table, poll_entry - poll_table, delay);
            if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
                av_free(poll_table);
                return -1;
            }
        } while (ret < 0);

        cur_time = av_gettime() / 1000;

        /* now handle the events */
        for(c = first_http_ctx; c != NULL; c = c_next) {
            c_next = c->next;
            if (handle_connection(c) < 0) {
                log_connection(c);
                close_connection(c);
            }
        }

        poll_entry = poll_table;

		#if defined(PLUGIN_DVB)
		if(ctrl_fd){
			if(poll_entry->revents & POLLIN){
				ctrl_fd2 = ctl_msg_open(ctrl_fd);
			}
			poll_entry++;
		}
		if(ctrl_fd2 && poll_entry->fd == ctrl_fd2){
			if(poll_entry->revents & POLLIN){
				ctl_msg_recv();
				ff_ctl_recv(ctl_msg_cb);
			}else if(poll_entry->revents & POLLOUT){
				ctl_msg_send();
			}
			poll_entry++;
		}
		#endif
		if(poll_entry->fd != server_fd){
			printf("bad  entry\n");
		}
		
        if (server_fd) {
            if (poll_entry->revents & POLLIN)
                new_connection(server_fd, 0);
            poll_entry++;
        }
		
		#if defined(PLUGIN_SSDP)
		if (ssdp_fd) {
            if (poll_entry->revents & POLLIN)
                ssdp_response(ssdp_fd);
            poll_entry++;
        }
		#endif
	
    }
}
Exemple #17
0
static int handle_connection(HTTPContext *c)
{
    int len, ret;

    switch(c->state) {
    case HTTPSTATE_WAIT_REQUEST:
        /* timeout ? */
        if ((c->timeout - cur_time) < 0)
            return -1;
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        /* read the data */
    read_loop:
        len = recv(c->fd, c->buffer_ptr, 1, 0);
        if (len < 0) {
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR))
                return -1;
        } else if (len == 0) {
            if(!c->keep_alive)return -1;
        } else {
            /* search for end of request. */
            uint8_t *ptr;
            c->buffer_ptr += len;
            ptr = c->buffer_ptr;
            if ((ptr >= c->buffer + 2 && !memcmp(ptr-2, "\n\n", 2)) ||
                (ptr >= c->buffer + 4 && !memcmp(ptr-4, "\r\n\r\n", 4))) {
                /* request found : parse it and reply */
                ret = http_parse_request(c);
                if (ret < 0)
                    return -1;
            } else if (ptr >= c->buffer_end) {
                /* request too long: cannot do anything */
                return -1;
            } else goto read_loop;
        }
        break;

    case HTTPSTATE_SEND_HEADER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
            return -1;

        /* no need to write if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        len = send(c->fd, c->buffer_ptr, c->buffer_end - c->buffer_ptr, 0);
        if (len < 0) {
            if (ff_neterrno() != AVERROR(EAGAIN) &&
                ff_neterrno() != AVERROR(EINTR)) {
                goto close_conn;
            }
        } else {
            c->buffer_ptr += len;
            c->data_count += len;
            if (c->buffer_ptr >= c->buffer_end) {
                av_freep(&c->pb_buffer);
				if(c->keep_alive){
					memset(c->buffer, 0, c->buffer_size);
					c->buffer_ptr = c->buffer;
				    c->buffer_end = c->buffer + c->buffer_size - 1; 
					c->timeout = cur_time + HTTP_REQUEST_TIMEOUT;
				    c->state = HTTPSTATE_WAIT_REQUEST;
					c->hls_idx = -1;
					http_log("%u alive %s\n", ntohs(c->from_addr.sin_port), c->url);
					return 0;
				}
                /* if error, exit */
                if (c->http_error)
                    return -1;
                /* all the buffer was sent : synchronize to the incoming*/
                c->state = HTTPSTATE_SEND_DATA_HEADER;
                c->buffer_ptr = c->buffer_end = c->buffer;
            }
        }
        break;

    case HTTPSTATE_SEND_DATA:
    case HTTPSTATE_SEND_DATA_HEADER:
    case HTTPSTATE_SEND_DATA_TRAILER:
        if (c->poll_entry->revents & (POLLERR | POLLHUP))
			return -1;
        /* no need to read if no events */
        if (!(c->poll_entry->revents & POLLOUT))
            return 0;
        if (http_send_data(c) < 0)
			return -1;
        /* close connection if trailer sent */
        if (c->state == HTTPSTATE_SEND_DATA_TRAILER)
            return -1;
        break;
    case HTTPSTATE_RECEIVE_DATA:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLERR | POLLHUP)){
			HLS *s = NULL;
			if(c->hls_idx >= 0){
				s = &s_hls[c->hls_idx];
				s->flag = 2;
			}
				
			wake_others(c, HTTPSTATE_SEND_DATA_TRAILER); 
            return -1;
        }
        if (!(c->poll_entry->revents & POLLIN))
            return 0;
        if (http_receive_data(c) < 0)
            return -1;
        break;
    case HTTPSTATE_WAIT_FEED:
        /* no need to read if no events */
        if (c->poll_entry->revents & (POLLIN | POLLERR | POLLHUP)) /*19*/
            {printf("line %d: %x:%d\n", __LINE__, c->poll_entry->revents, get_socket_error(c->fd)); return -1;} 
        /* nothing to do, we'll be waken up by incoming feed packets */
        break;

    default:
        return -1;
    }
    return 0;

close_conn:
    av_freep(&c->pb_buffer);
    return -1;
}
Exemple #18
0
/* parse HTTP request and prepare header */
static int http_parse_request(HTTPContext *c)
{
    char *q, msg[1024];
    const char *mime_type, *p;
	HTTPContext *ctx;
	int ret = 0, is_first = 0;
	const char *first_tag = "First-Request=0";
	RequestData rd = {{0}};

    p = c->buffer;
	while(get_line(msg, sizeof(msg), &p) > 0){
		ret = handle_line(c, msg, sizeof(msg), &rd);
		if(ret < 0)return ret;
	}
	is_first = !av_stristr(rd.cookie, first_tag);
	
	if(c->post && c->content_length 
		&& !av_match_ext(c->url, "m3u8")
		&& !av_match_ext(c->url, "ts")
		&& !av_match_ext(c->url, "flv")){
		c->post = 0;
		c->content_length = read_request_content(c, rd.content, sizeof(rd.content));
	}
	#if defined(PLUGIN_DVB)
	if(!c->post && !strcmp(c->url, "digitalDvb/allServiceType/getClientInfo")){
		uint32_t *ptr = (uint32_t*)rd.content, *ptr_end = (uint32_t*)(rd.content+sizeof(rd.content)-8);
		for(ctx = first_http_ctx; ctx; ctx = ctx->next) 
			if(!ctx->post && av_match_ext(ctx->url, "flv") )
			{/*todo: record hls*/
				if(ptr < ptr_end){
					int chid = -1;
					sscanf(ctx->url, "%d", &chid);
		
					*ptr++ = inet_addr(inet_ntoa(ctx->from_addr.sin_addr));
					*ptr++ = chid;

					printf("ip %s id %u %s\t", inet_ntoa(ctx->from_addr.sin_addr), chid, ctx->url);
				}
			}
	}
	#endif

    //http_log("New conn: %s:%u %d %s cookie:%s\n", inet_ntoa(c->from_addr.sin_addr), ntohs(c->from_addr.sin_port), c->post, c->url, rd.cookie);

	/*handle m3u8/ts request solely*/
	if(av_match_ext(c->url, "m3u8") 
			|| av_match_ext(c->url, "ts")){
		c->keep_alive = 0; 
		ret = hls_parse_request(c, c->url, is_first);
		if(ret < 0)goto send_error;
		else if(ret == 1){
			long chid = atoi(c->url);
			if(!(0 <= chid && chid <= 10000)){
				sprintf(msg, "bad request: %s-->%ld", c->url, chid);
				http_log("%s\n", msg);
				goto send_error;
			}
			#if defined(PLUGIN_DVB)
			ff_ctl_send_string(1, c->url, rd.content);
			#endif
			http_log("wait get %s\n", c->url);
		}
		if(c->state == HTTPSTATE_SEND_HEADER)
			goto send_header;
		return 0; /*end here*/
	}

	#if defined(PLUGIN_DVB)
	ret = plugin_dvb(c, &rd);
	if(ret < 0){
		goto send_error;
	}else if(ret > 0){
		return 0;
	}
	#endif

    /*handle feed request*/
    if (c->post) {
		ctx = find_feed(c->url);
		if(ctx && ctx != c){
			sprintf(msg, "file %s has been feeded", c->url);
			http_log("%s\n", msg);
			goto send_error;
		}
        c->http_error = 0;
        c->state = HTTPSTATE_RECEIVE_DATA;
        return 0; /*end here*/
	}else{
		if(prepare_local_file(c) > 0){
			c->http_error = 200;
			c->state = HTTPSTATE_SEND_HEADER;
			return 0; /*no need feed, send local files directly.*/
		}
		
		ctx = find_feed(c->url);
		if(!ctx){
			c->keep_alive = 0; 
			sprintf(msg, "wait to get %s", c->url);
			http_log("%s\n", msg);
			#if defined(PLUGIN_DVB)
			ff_ctl_send(2, c->url, strlen(c->url)+1, rd.content, sizeof(rd.content)); 
			#endif
		}else{
			ctx->sff_ref_cnt++;
		}
		c->feed_ctx = ctx; 
	}

send_header:
    /* prepare HTTP header */
    c->buffer[0] = 0;
    av_strlcatf(c->buffer, c->buffer_size, "HTTP/1.1 200 OK\r\n");
	mime_type =  get_mine_type(c->url);
    av_strlcatf(c->buffer, c->buffer_size, "Pragma: no-cache\r\n");
    av_strlcatf(c->buffer, c->buffer_size, "Content-Type: %s\r\n", mime_type);
	av_strlcatf(c->buffer, c->buffer_size, "Connection: %s\r\n", (c->keep_alive ? "keep-alive" : "close"));
	av_strlcatf(c->buffer, c->buffer_size, "Set-Cookie: %s; Path=/; Domain=%s\r\n", first_tag, rd.domain);
    av_strlcatf(c->buffer, c->buffer_size, "\r\n");

    q = c->buffer + strlen(c->buffer);

    /* prepare output buffer */
    c->http_error = 0;
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;

	#if 0
	if(S == c->hls_idx){
		HLS *s = &s_hls[c->hls_idx];
		char *ext = strrchr(c->url, '.');
		if(!(2 == s->flag && s->data && s->csize > 0)){/*not exist yet, fake one*/
			c->http_error = 200;
			c->buffer_end += sprintf(c->buffer_end, 
				"#EXTM3U\n"
				"#EXT-X-VERSION:3\n"
				"#EXT-X-TARGETDURATION:2\n"
				"#EXT-X-MEDIA-SEQUENCE:0\n"
				"#EXTINF:1.283989,\n"
				"%.*s0.ts\n", ext - c->url, c->url);
		}
	}
	#endif
    return 0;
 send_error:
	c->keep_alive = 0;
    c->http_error = 404;
    q = c->buffer;
    htmlstrip(msg);
    snprintf(q, c->buffer_size,
                  "HTTP/1.1 404 Not Found\r\n"
                  "Content-type: text/html\r\n"
                  "\r\n"
                  "<html>\n"
                  "<head><title>404 Not Found</title></head>\n"
                  "<body>%s</body>\n"
                  "</html>\n", msg);
    q += strlen(q);
    /* prepare output buffer */
    c->buffer_ptr = c->buffer;
    c->buffer_end = q;
    c->state = HTTPSTATE_SEND_HEADER;
    return 0;
}
Exemple #19
0
void show_help_default(const char *opt, const char *arg)
{
	http_log("dumpy default help\n");
}
Exemple #20
0
/**
 * Reads data from the http context buffer (decodes it if the transfer-
 * encoding isn't "identity") and transfers up to ``buflen'' bytes into
 * ``buf''. The http context MUST be in state HTTP_STATE_BODY.
 *
 * @returns (ssize_t) -1 on failure and sets errno. If errno is set to EAGAIN
 *          further data may be available later.
 *           
 *          If there's a transfer-encoding
 *          error, errno will be set to EIO. If (-1) is returned and errno
 *          has any other value than EAGAIN, the function MUST NOT be called
 *          again.
 */
ssize_t
http_read_body(http_t *ctx, char *buf, ssize_t buflen)
{
  ssize_t ret = 0, count = 0;
  uint64_t left;
  
  RUNTIME_ASSERT(ctx != NULL);
  RUNTIME_ASSERT(buf != NULL);
  RUNTIME_ASSERT(buflen >= 0);

  RUNTIME_ASSERT(ctx->sane);
  RUNTIME_ASSERT(ctx->state == HTTP_STATE_BODY);
  
  switch (ctx->encoding) {
  case HTTP_TRANSFER_ENCODING_IDENTITY:
    
    RUNTIME_ASSERT(ctx->content_length >= ctx->received);
    left = ctx->content_length - ctx->received;
    if (left == 0) {
      return 0;
    }

    RUNTIME_ASSERT(left > 0);
    ret = fifo_read(ctx->input, buf, MIN(left, (size_t) buflen));
    if (ret > 0) {
      ctx->received += ret;
    } else if (ret == 0) {
      errno = EAGAIN;
      return -1;
    }
    count = ret;
    break;

  case HTTP_TRANSFER_ENCODING_CHUNKED:

    while (!ctx->last_chunk && buflen > 0) {

      RUNTIME_ASSERT(ctx->content_length >= ctx->received);
      left = ctx->chunk_size - ctx->chunk_received;
      if (left > 0) {
        ret = fifo_read(ctx->input, buf, MIN(left, (size_t) buflen));
        if (ret > 0) {
          RUNTIME_ASSERT(ret <= buflen);
          ctx->chunk_received += ret;
          ctx->received += ret;
          buf += ret;
          buflen -= ret;
          count += ret;
        } else {
          if (ret == 0 && count == 0) {
            errno = EAGAIN;
            return -1;
          }
          return count;
        }
      } else {
        char chunk_intro[1024];
        ssize_t pos, size;
        uint64_t v;
        char *endptr;
        int error;

        /* If this isn't the first chunk, wait for trailing <CR><LF> */
        if (ctx->chunk_size > 0) {
          pos = fifo_findchar(ctx->input, '\n', sizeof chunk_intro);
          if (pos == (ssize_t) -1) {
            if (count > 0)
              return count;
            
            errno = EAGAIN;
            return -1;
          }

          RUNTIME_ASSERT(pos >= 0 && (size_t) pos < sizeof chunk_intro);
          size = fifo_read(ctx->input, chunk_intro, pos + 1);
          RUNTIME_ASSERT(size == pos + 1);
          RUNTIME_ASSERT(chunk_intro[pos] == '\n');
          chunk_intro[pos] = '\0';
        }
        RUNTIME_ASSERT(ctx->chunk_received == ctx->chunk_size);
        /* Mark the previous chunk as completely handled */
        ctx->chunk_sum_received += ctx->chunk_size;
        ctx->chunk_size = 0;
        ctx->chunk_received = 0;

        /* Determine the size of the next chunk */
        pos = fifo_findchar(ctx->input, '\n', sizeof chunk_intro);
        if (pos == (ssize_t) -1) {
          if (count > 0)
            return count;
          errno = EAGAIN;
          return -1;
        }
      
        RUNTIME_ASSERT(pos >= 0 && (size_t) pos < sizeof chunk_intro);
        size = fifo_read(ctx->input, chunk_intro, pos + 1);
        RUNTIME_ASSERT(size == pos + 1);
        RUNTIME_ASSERT(chunk_intro[pos] == '\n');
        chunk_intro[pos] = '\0';

        /* Read the chunk header and determine its size (hex value) */
        v = parse_uint64(chunk_intro, &endptr, 16, &error);
        if (
            (!v && error) ||
            (*endptr != '\0' && !isspace((unsigned char) *endptr))
        ) {
          errno = EIO;
          ctx->sane = false;
          return -1;
        }
        if (v == 0) {
          /* Only the last chunk has a zero length */
#if 1 
          http_log(ctx, "Last chunk reached");
#endif
          ctx->last_chunk = true;
          return count > 0 ? count : 0;
        }
#if 0 
        http_log(ctx, "chunk_size=%" PRIu64, v);
#endif
        ctx->chunk_size = v;
      }
    }
    break;

  default:
    RUNTIME_ASSERT(0);
  }

  return count;
}
Exemple #21
0
/**
 * Reads a single HTTP header line from ctx->input and parses it.
 * Header continuation is handled transparently. Trailing space characters
 * are discarded from the header line and the line is NUL-terminated.
 * 
 * @param ctx an initialized ``http_t'' in state HTTP_STATE_HEADERS.
 * @param buf a work buffer.
 * @param buf_size the size of buf; this defines the maximum length of
 *        headers that can be handled.
 *
 * @return
 *   -1 if a header was invalid (see http status for details).
 *    0 if the end-of-headers was reached.
 *    1 if a header was successfully parsed.
 */
int
http_read_header(http_t *ctx, char *buf, size_t buf_size)
{
  char *p;
  size_t size;
 
  RUNTIME_ASSERT(ctx);
  RUNTIME_ASSERT(buf);
  RUNTIME_ASSERT(buf_size > 0);
  RUNTIME_ASSERT(ctx->state == HTTP_STATE_HEADERS);

  p = buf;
  size = buf_size;

  for (;;) {
    ssize_t r;
    
    r = fifo_findchar(ctx->input, '\n', size);
    if ((ssize_t) -1 == r) {
      if ((size_t) fifo_fill(ctx->input) > size)
        DBUG("Header line is too long");
      else
        DBUG("Header line is not yet terminated");

      ctx->keep_alive = false;
      http_set_status(ctx, 413, "Request Entity Too Large");
      return -1;
    }

    RUNTIME_ASSERT(r >= 0 && (size_t) r < size);

    /* Make sure the headers don't contain any NUL characters */
    if ((ssize_t) -1 != fifo_findchar(ctx->input, '\0', r)) {
      ctx->keep_alive = false;
      http_set_status(ctx, 400, "Bad Request (NUL in Header)");
      return -1;
    }

    fifo_read(ctx->input, p, 1 + r);
    RUNTIME_ASSERT('\n' == p[r]);

    /* Discard trailing '\r' characters */
    for (/* NOTHING*/; r > 0; r--) {
      if ('\r' != p[r - 1])
        break;
    }
    
    RUNTIME_ASSERT('\n' == p[r] || '\r' == p[r]);
    p[r] = '\0';

    /* Check for a header continuation with HT (0x09) or a space (0x20) */
    if (
      0 != fifo_findchar(ctx->input, 0x09, 1) &&
      0 != fifo_findchar(ctx->input, 0x20, 1)
    ) {
     
      /* Discard all trailing spaces */
      if (isspace((unsigned char) p[r])) {
        while (r > 0 && isspace((unsigned char) p[r - 1]))
          r--;

        p[r] = '\0';
      }
    
      break;
    }

    p += r;
    size -= r;

    /* Discard all consecutive HT and SP characters */
    fifo_skip_chars(ctx->input, fifo_fill(ctx->input), "\x09\x20");

    /* Replace all skipped space by a single space character */
    if (size > 0) {
      *p++ = 0x20;
      size--;
    }
  }
 
  if (ctx->debug_dump_headers) {
    http_log(ctx, "\t%s", buf);
  }

  if ('\0' == *buf) {
    ctx->state = HTTP_STATE_BODY;
    return 0;
  }
  
  return 1;
}
Exemple #22
0
bool http_t::get( std::string&       result,
                  const std::string& url,
                  cache::behavior_t  caching,
                  const std::string& confirmation,
                  int                throttle_seconds )
{
    result.clear();

    std::string encoded_url;
    format( encoded_url, url );

    auto_lock_t lock( cache_mutex );

    url_cache_entry_t& entry = url_db[ encoded_url ];

    if ( HTTP_CACHE_DEBUG )
    {
        std::ofstream http_log( "simc_http_log.txt", std::ios::app );
        std::ostream::sentry s( http_log );
        if ( s )
        {
            http_log << cache::era() << ": get(\"" << url << "\") [";

            if ( entry.validated != cache::INVALID_ERA )
            {
                if ( entry.validated >= cache::era() )
                    http_log << "hot";
                else if ( caching != cache::CURRENT )
                    http_log << "warm";
                else
                    http_log << "cold";
                http_log << ": (" << entry.modified << ", " << entry.validated << ')';
            }
            else
                http_log << "miss";
            if ( caching != cache::ONLY &&
                    ( entry.validated == cache::INVALID_ERA ||
                      ( caching == cache::CURRENT && entry.validated < cache::era() ) ) )
                http_log << " download";
            http_log << "]\n";
        }
    }

    if ( entry.validated < cache::era() && ( caching == cache::CURRENT || entry.validated == cache::INVALID_ERA ) )
    {
        if ( caching == cache::ONLY )
            return false;

        util_t::printf( "@" );
        fflush( stdout );
        throttle( throttle_seconds );

        if ( ! download( entry, encoded_url ) )
            return false;

        if ( HTTP_CACHE_DEBUG && entry.modified < entry.validated )
        {
            std::ofstream http_log( "simc_http_log.txt", std::ios::app );
            http_log << cache::era() << ": Unmodified (" << entry.modified << ", " << entry.validated << ")\n";
        }

        if ( confirmation.size() && ( entry.result.find( confirmation ) == std::string::npos ) )
        {
            //util_t::printf( "\nsimulationcraft: HTTP failed on '%s'\n", url.c_str() );
            //util_t::printf( "%s\n", ( result.empty() ? "empty" : result.c_str() ) );
            //fflush( stdout );
            return false;
        }
    }

    result = entry.result;
    return true;
}