/** * httpserver_dispatcher: * @data: RequestData type pointer * @user_data: httpstreaming type pointer * * Process http request. * * Returns: positive value if have not completed the processing, for example live streaming. * 0 if have completed the processing. */ static GstClockTime httpstreaming_dispatcher (gpointer data, gpointer user_data) { RequestData *request_data = data; HTTPStreaming *httpstreaming = (HTTPStreaming *)user_data; gchar *buf; int i = 0, j, ret; Encoder *encoder; EncoderOutput *encoder_output; Channel *channel; RequestDataUserData *request_user_data; GstClockTime ret_clock_time; channel = get_channel (httpstreaming, request_data); switch (request_data->status) { case HTTP_REQUEST: GST_DEBUG ("new request arrived, socket is %d, uri is %s", request_data->sock, request_data->uri); encoder_output = get_encoder_output (httpstreaming, request_data); if (encoder_output == NULL) { buf = g_strdup_printf (http_404, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return 0; } else if ((request_data->parameters[0] == '\0') || (request_data->parameters[0] == 'b')) { /* default operator is play, ?bitrate= */ GST_ERROR ("Play %s.", request_data->uri); request_user_data = (RequestDataUserData *)g_malloc (sizeof (RequestDataUserData));//FIXME if (request_user_data == NULL) { GST_ERROR ("Internal Server Error, g_malloc for request_user_data failure."); buf = g_strdup_printf (http_500, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return 0; } if (*(encoder_output->head_addr) == *(encoder_output->tail_addr)) { GST_DEBUG ("%s unready.", request_data->uri); buf = g_strdup_printf (http_404, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return 0; } /* let send_chunk send new chunk. */ encoder = get_encoder (request_data->uri, httpstreaming->itvencoder->channel_array); request_user_data->encoder = encoder; request_user_data->chunk_size = 0; request_user_data->send_count = 2; request_user_data->chunk_size_str = g_strdup (""); request_user_data->chunk_size_str_len = 0; request_user_data->encoder_output = encoder_output; request_user_data->current_rap_addr = *(encoder_output->last_rap_addr); request_user_data->current_send_position = *(encoder_output->last_rap_addr) + 12; request_user_data->channel_age = channel->age; request_data->user_data = request_user_data; request_data->bytes_send = 0; buf = g_strdup_printf (http_chunked, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return gst_clock_get_time (httpstreaming->httpserver->system_clock) + GST_MSECOND; } else { buf = g_strdup_printf (http_404, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return 0; } break; case HTTP_CONTINUE: request_user_data = request_data->user_data; if ((request_user_data->channel_age != channel->age) || (*(channel->output->state) != GST_STATE_PLAYING)) { g_free (request_data->user_data); request_data->user_data = NULL; return 0; } encoder_output = request_user_data->encoder_output; if (request_user_data->current_send_position == *(encoder_output->tail_addr)) { /* no more stream, wait 10ms */ GST_DEBUG ("current:%llu == tail:%llu", request_user_data->current_send_position, encoder_output->tail_addr); return gst_clock_get_time (httpstreaming->httpserver->system_clock) + 500 * GST_MSECOND + g_random_int_range (1, 1000000); } ret_clock_time = send_chunk (encoder_output, request_data); if (ret_clock_time != GST_CLOCK_TIME_NONE) { return ret_clock_time + gst_clock_get_time (httpstreaming->httpserver->system_clock); } else { return GST_CLOCK_TIME_NONE; } case HTTP_FINISH: g_free (request_data->user_data); request_data->user_data = NULL; return 0; default: GST_ERROR ("Unknown status %d", request_data->status); buf = g_strdup_printf (http_400, PACKAGE_NAME, PACKAGE_VERSION); httpserver_write (request_data->sock, buf, strlen (buf)); g_free (buf); return 0; } }
static void thread_pool_func (gpointer data, gpointer user_data) { HTTPServer *http_server = (HTTPServer *)user_data; RequestData **request_data_pointer = data; RequestData *request_data = *request_data_pointer; gint ret; GstClockTime cb_ret; GST_DEBUG ("EVENT %d, status %d, sock %d", request_data->events, request_data->status, request_data->sock); g_mutex_lock (&(request_data->events_mutex)); if (request_data->events & (EPOLLHUP | EPOLLERR)) { request_data->status = HTTP_FINISH; request_data->events = 0; } else if (request_data->events & EPOLLOUT) { if ((request_data->status == HTTP_IDLE) || (request_data->status == HTTP_BLOCK)) { request_data->status = HTTP_CONTINUE; } request_data->events ^= EPOLLOUT; } else if (request_data->events & EPOLLIN) { if ((request_data->status == HTTP_IDLE) || (request_data->status == HTTP_BLOCK)) { /* in normal play status */ ret = read_request (request_data); if (ret < 0) { request_data->status = HTTP_FINISH; } else { GST_DEBUG ("Unexpected request arrived, ignore."); request_data->status = HTTP_CONTINUE; } } /* HTTP_REQUEST status */ request_data->events ^= EPOLLIN; } else if ((request_data->status == HTTP_IDLE) || (request_data->status == HTTP_BLOCK)) { /* no event, popup from idle queue or block queue */ request_data->status = HTTP_CONTINUE; } else { GST_WARNING ("warning!!! unprocessed event, sock %d status %d events %d", request_data->sock, request_data->status, request_data->events); } g_mutex_unlock (&(request_data->events_mutex)); if (request_data->status == HTTP_REQUEST) { ret = read_request (request_data); if (ret < 0) { request_data_release (http_server, request_data_pointer); return; } ret = parse_request (request_data); if (ret == 0) { /* parse complete, call back user function */ request_data->events ^= EPOLLIN; invoke_user_callback (http_server, request_data_pointer); } else if (ret == 1) { /* need read more data */ g_mutex_lock (&(http_server->block_queue_mutex)); g_queue_push_head (http_server->block_queue, request_data_pointer); g_mutex_unlock (&(http_server->block_queue_mutex)); return; } else if (ret == 2) { /* Not Implemented */ GST_WARNING ("Not Implemented, return is %d, sock is %d", ret, request_data->sock); gchar *buf = g_strdup_printf (http_501, PACKAGE_NAME, PACKAGE_VERSION); if (httpserver_write (request_data->sock, buf, strlen (buf)) != strlen (buf)) { GST_ERROR ("write sock %d error.", request_data->sock); } g_free (buf); request_data_release (http_server, request_data_pointer); } else { /* Bad Request */ GST_WARNING ("Bad request, return is %d, sock is %d", ret, request_data->sock); gchar *buf = g_strdup_printf (http_400, PACKAGE_NAME, PACKAGE_VERSION); if (httpserver_write (request_data->sock, buf, strlen (buf)) != strlen (buf)) { GST_ERROR ("write sock %d error.", request_data->sock); } g_free (buf); request_data_release (http_server, request_data_pointer); } } else if (request_data->status == HTTP_CONTINUE) { invoke_user_callback (http_server, request_data_pointer); } else if (request_data->status == HTTP_FINISH) { // FIXME: how about if have continue request in idle queue?? cb_ret = http_server->user_callback (request_data, http_server->user_data); GST_DEBUG ("request finish %d callback return %lu, send %lu", request_data->sock, cb_ret, request_data->bytes_send); if (cb_ret == 0) { g_mutex_lock (&(http_server->idle_queue_mutex)); g_tree_remove (http_server->idle_queue, &(request_data->wakeup_time)); g_mutex_unlock (&(http_server->idle_queue_mutex)); request_data_release (http_server, request_data_pointer); } } }