int SPDYF_handler_write_goaway (struct SPDY_Session *session) { struct SPDYF_Response_Queue *response_queue = session->response_queue_head; struct SPDYF_Control_Frame control_frame; size_t total_size; int last_good_stream_id; SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment"); memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame)); session->is_goaway_sent = true; total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header + 4 // last good stream id as "subheader" + 4; // status code as "subheader" if(NULL == (session->write_buffer = malloc(total_size))) { return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; control_frame.length = 8; // always for GOAWAY SPDYF_CONTROL_FRAME_HTON(&control_frame); //put frame headers to write buffer memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame); //put last good stream id to write buffer last_good_stream_id = HTON31(session->last_replied_to_stream_id); memcpy(session->write_buffer + session->write_buffer_offset, &last_good_stream_id, 4); session->write_buffer_offset += 4; //put "data" to write buffer. This is the status memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 4); session->write_buffer_offset += 4; //data is not freed by the destroy function so: //free(response_queue->data); //SPDYF_DEBUG("goaway sent: status %i", NTOH31(*(uint32_t*)(response_queue->data))); SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1"); SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2"); return SPDY_YES; }
void SPDYF_handler_ignore_frame (struct SPDY_Session *session) { struct SPDYF_Control_Frame *frame; SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status, "the function is called wrong"); frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; //handle subheaders if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status) { if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE) { session->status = SPDY_SESSION_STATUS_IGNORE_BYTES; return; } else session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY; } //handle body if(session->read_buffer_offset - session->read_buffer_beginning >= frame->length) { session->read_buffer_beginning += frame->length; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); } }
int SPDYF_handler_write_rst_stream (struct SPDY_Session *session) { struct SPDYF_Response_Queue *response_queue = session->response_queue_head; struct SPDYF_Control_Frame control_frame; size_t total_size; SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment"); memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame)); total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header + 4 // stream id as "subheader" + 4; // status code as "subheader" if(NULL == (session->write_buffer = malloc(total_size))) { return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; control_frame.length = 8; // always for RST_STREAM SPDYF_CONTROL_FRAME_HTON(&control_frame); //put frame headers to write buffer memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame); //put stream id to write buffer. This is the status memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8); session->write_buffer_offset += 8; //data is not freed by the destroy function so: //free(response_queue->data); //SPDYF_DEBUG("rst_stream sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32)); SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1"); SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2"); return SPDY_YES; }
int SPDYF_handler_write_window_update (struct SPDY_Session *session) { struct SPDYF_Response_Queue *response_queue = session->response_queue_head; struct SPDYF_Control_Frame control_frame; size_t total_size; SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment"); memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame)); total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header + 4 // stream id as "subheader" + 4; // delta-window-size as "subheader" if(NULL == (session->write_buffer = malloc(total_size))) { return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; control_frame.length = 8; // always for WINDOW_UPDATE SPDYF_CONTROL_FRAME_HTON(&control_frame); //put frame headers to write buffer memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame); //put stream id and delta-window-size to write buffer memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, 8); session->write_buffer_offset += 8; //SPDYF_DEBUG("window_update sent: id %i", NTOH31((((uint64_t)response_queue->data) & 0xFFFF0000) >> 32)); SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1"); SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2"); return SPDY_YES; }
int SPDYF_prepare_window_update (struct SPDY_Session *session, struct SPDYF_Stream * stream, int32_t delta_window_size) { struct SPDYF_Response_Queue *response_to_queue; struct SPDYF_Control_Frame *control_frame; uint32_t *data; SPDYF_ASSERT(NULL != stream, "stream cannot be NULL"); if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue)))) { return SPDY_NO; } memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue)); if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame)))) { free(response_to_queue); return SPDY_NO; } memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame)); if(NULL == (data = malloc(8))) { free(control_frame); free(response_to_queue); return SPDY_NO; } *(data) = HTON31(stream->stream_id); *(data + 1) = HTON31(delta_window_size); control_frame->control_bit = 1; control_frame->version = SPDY_VERSION; control_frame->type = SPDY_CONTROL_FRAME_TYPES_WINDOW_UPDATE; control_frame->flags = 0; response_to_queue->control_frame = control_frame; response_to_queue->process_response_handler = &SPDYF_handler_write_window_update; response_to_queue->data = data; response_to_queue->data_size = 8; response_to_queue->stream = stream; SPDYF_queue_response (response_to_queue, session, -1); return SPDY_YES; }
struct SPDYF_Response_Queue * SPDYF_response_queue_create(bool is_data, void *data, size_t data_size, struct SPDY_Response *response, struct SPDYF_Stream *stream, bool closestream, SPDYF_ResponseQueueResultCallback frqcb, void *frqcb_cls, SPDY_ResponseResultCallback rrcb, void *rrcb_cls) { struct SPDYF_Response_Queue *head = NULL; struct SPDYF_Response_Queue *prev; struct SPDYF_Response_Queue *response_to_queue; struct SPDYF_Control_Frame *control_frame; struct SPDYF_Data_Frame *data_frame; unsigned int i; bool is_last; SPDYF_ASSERT((! is_data) || ((0 == data_size) && (NULL != response->rcb)) || ((0 < data_size) && (NULL == response->rcb)), "either data or request->rcb must not be null"); if (is_data && (data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)) { //separate the data in more frames and add them to the queue prev=NULL; for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE) { is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >= data_size; if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue)))) goto free_and_fail; memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue)); if(0 == i) head = response_to_queue; if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame)))) { free(response_to_queue); goto free_and_fail; } memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame)); data_frame->control_bit = 0; data_frame->stream_id = stream->stream_id; if(is_last && closestream) data_frame->flags |= SPDY_DATA_FLAG_FIN; response_to_queue->data_frame = data_frame; response_to_queue->process_response_handler = &SPDYF_handler_write_data; response_to_queue->is_data = is_data; response_to_queue->stream = stream; if(is_last) { response_to_queue->frqcb = frqcb; response_to_queue->frqcb_cls = frqcb_cls; response_to_queue->rrcb = rrcb; response_to_queue->rrcb_cls = rrcb_cls; } response_to_queue->data = data + i; response_to_queue->data_size = is_last ? (data_size - 1) % SPDY_MAX_SUPPORTED_FRAME_SIZE + 1 : SPDY_MAX_SUPPORTED_FRAME_SIZE; response_to_queue->response = response; response_to_queue->prev = prev; if(NULL != prev) prev->next = response_to_queue; prev = response_to_queue; } return head; //for GOTO free_and_fail: while(NULL != head) { response_to_queue = head; head = head->next; free(response_to_queue->data_frame); free(response_to_queue); } return NULL; } //create only one frame for data, data with callback or control frame if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue)))) { return NULL; } memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue)); if(is_data) { if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame)))) { free(response_to_queue); return NULL; } memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame)); data_frame->control_bit = 0; data_frame->stream_id = stream->stream_id; if(closestream && NULL == response->rcb) data_frame->flags |= SPDY_DATA_FLAG_FIN; response_to_queue->data_frame = data_frame; response_to_queue->process_response_handler = &SPDYF_handler_write_data; } else { if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame)))) { free(response_to_queue); return NULL; } memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame)); control_frame->control_bit = 1; control_frame->version = SPDY_VERSION; control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY; if(closestream) control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN; response_to_queue->control_frame = control_frame; response_to_queue->process_response_handler = &SPDYF_handler_write_syn_reply; } response_to_queue->is_data = is_data; response_to_queue->stream = stream; response_to_queue->frqcb = frqcb; response_to_queue->frqcb_cls = frqcb_cls; response_to_queue->rrcb = rrcb; response_to_queue->rrcb_cls = rrcb_cls; response_to_queue->data = data; response_to_queue->data_size = data_size; response_to_queue->response = response; return response_to_queue; }
int SPDYF_session_read (struct SPDY_Session *session) { int bytes_read; bool reallocate; size_t actual_buf_size; if(SPDY_SESSION_STATUS_CLOSING == session->status || SPDY_SESSION_STATUS_FLUSHING == session->status) return SPDY_NO; //if the read buffer is full to the end, we need to reallocate space if (session->read_buffer_size == session->read_buffer_offset) { //but only if the state of the session requires it //i.e. no further proceeding is possible without reallocation reallocate = false; actual_buf_size = session->read_buffer_offset - session->read_buffer_beginning; switch(session->status) { case SPDY_SESSION_STATUS_WAIT_FOR_HEADER: case SPDY_SESSION_STATUS_IGNORE_BYTES: //we need space for a whole control frame header if(actual_buf_size < sizeof(struct SPDYF_Control_Frame)) reallocate = true; break; case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER: case SPDY_SESSION_STATUS_WAIT_FOR_BODY: //we need as many bytes as set in length field of the //header SPDYF_ASSERT(NULL != session->frame_handler_cls, "no frame for session"); if(session->frame_handler != &spdyf_handler_read_data) { if(actual_buf_size < ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length) reallocate = true; } else { if(actual_buf_size < ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length) reallocate = true; } break; case SPDY_SESSION_STATUS_CLOSING: case SPDY_SESSION_STATUS_FLUSHING: //nothing needed break; } if(reallocate) { //reuse the space in the buffer that was already read by the lib memmove(session->read_buffer, session->read_buffer + session->read_buffer_beginning, session->read_buffer_offset - session->read_buffer_beginning); session->read_buffer_offset -= session->read_buffer_beginning; session->read_buffer_beginning = 0; } else { //will read next time //TODO optimize it, memmove more often? return SPDY_NO; } } session->last_activity = SPDYF_monotonic_time(); //actual read from the TLS socket bytes_read = session->fio_recv(session, session->read_buffer + session->read_buffer_offset, session->read_buffer_size - session->read_buffer_offset); switch(bytes_read) { case SPDY_IO_ERROR_CLOSED: //The TLS connection was closed by the other party, clean //or not shutdown (session->socket_fd, SHUT_RD); session->read_closed = true; session->status = SPDY_SESSION_STATUS_CLOSING; return SPDY_YES; case SPDY_IO_ERROR_ERROR: //any kind of error in the TLS subsystem //try to prepare GOAWAY frame SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false); //try to flush the queue when write is called session->status = SPDY_SESSION_STATUS_FLUSHING; return SPDY_YES; case SPDY_IO_ERROR_AGAIN: //read or write should be called again; leave it for the //next time return SPDY_NO; //default: //something was really read from the TLS subsystem //just continue } session->read_buffer_offset += bytes_read; return SPDY_YES; }
int SPDYF_handler_write_data (struct SPDY_Session *session) { struct SPDYF_Response_Queue *response_queue = session->response_queue_head; struct SPDYF_Response_Queue *new_response_queue; size_t total_size; struct SPDYF_Data_Frame data_frame; ssize_t ret; bool more; SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment"); memcpy(&data_frame, response_queue->data_frame, sizeof(data_frame)); if(NULL == response_queue->response->rcb) { //standard response with data into the struct SPDYF_ASSERT(NULL != response_queue->data, "no data for the response"); total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header + response_queue->data_size; if(NULL == (session->write_buffer = malloc(total_size))) { return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; data_frame.length = response_queue->data_size; SPDYF_DATA_FRAME_HTON(&data_frame); //put SPDY headers to the writing buffer memcpy(session->write_buffer + session->write_buffer_offset,&data_frame,sizeof(struct SPDYF_Data_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame); //put data to the writing buffer memcpy(session->write_buffer + session->write_buffer_offset, response_queue->data, response_queue->data_size); session->write_buffer_offset += response_queue->data_size; } else { /* response with callbacks. The lib will produce more than 1 * data frames */ total_size = sizeof(struct SPDYF_Data_Frame) //SPDY header + SPDY_MAX_SUPPORTED_FRAME_SIZE; //max possible size if(NULL == (session->write_buffer = malloc(total_size))) { return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; ret = response_queue->response->rcb(response_queue->response->rcb_cls, session->write_buffer + sizeof(struct SPDYF_Data_Frame), response_queue->response->rcb_block_size, &more); if(ret < 0 || ret > response_queue->response->rcb_block_size) { free(session->write_buffer); session->write_buffer = NULL; //send RST_STREAM if(SPDY_YES == (ret = SPDYF_prepare_rst_stream(session, response_queue->stream, SPDY_RST_STREAM_STATUS_INTERNAL_ERROR))) { return SPDY_NO; } //else no memory //for now close session //TODO what? session->status = SPDY_SESSION_STATUS_CLOSING; return SPDY_NO; } if(0 == ret && more) { //the app couldn't write anything to buf but later will free(session->write_buffer); session->write_buffer = NULL; session->write_buffer_size = 0; if(NULL != response_queue->next) { //put the frame at the end of the queue //otherwise - head of line blocking session->response_queue_head = response_queue->next; session->response_queue_head->prev = NULL; session->response_queue_tail->next = response_queue; response_queue->prev = session->response_queue_tail; response_queue->next = NULL; session->response_queue_tail = response_queue; } return SPDY_YES; } if(more) { //create another response queue object to call the user cb again if(NULL == (new_response_queue = SPDYF_response_queue_create(true, NULL, 0, response_queue->response, response_queue->stream, false, response_queue->frqcb, response_queue->frqcb_cls, response_queue->rrcb, response_queue->rrcb_cls))) { //TODO send RST_STREAM //for now close session session->status = SPDY_SESSION_STATUS_CLOSING; free(session->write_buffer); session->write_buffer = NULL; return SPDY_NO; } //put it at second position on the queue new_response_queue->prev = response_queue; new_response_queue->next = response_queue->next; if(NULL == response_queue->next) { session->response_queue_tail = new_response_queue; } else { response_queue->next->prev = new_response_queue; } response_queue->next = new_response_queue; response_queue->frqcb = NULL; response_queue->frqcb_cls = NULL; response_queue->rrcb = NULL; response_queue->rrcb_cls = NULL; } else { data_frame.flags |= SPDY_DATA_FLAG_FIN; } data_frame.length = ret; SPDYF_DATA_FRAME_HTON(&data_frame); //put SPDY headers to the writing buffer memcpy(session->write_buffer + session->write_buffer_offset, &data_frame, sizeof(struct SPDYF_Data_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Data_Frame); session->write_buffer_offset += ret; session->write_buffer_size = session->write_buffer_offset; } //SPDYF_DEBUG("data sent: id %i", NTOH31(data_frame.stream_id)); SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1"); SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2"); return SPDY_YES; }
int SPDYF_session_accept(struct SPDY_Daemon *daemon) { int new_socket_fd; int ret; struct SPDY_Session *session = NULL; socklen_t addr_len; struct sockaddr *addr; #if HAVE_INET6 struct sockaddr_in6 addr6; addr = (struct sockaddr *)&addr6; addr_len = sizeof(addr6); #else struct sockaddr_in addr4; addr = (struct sockaddr *)&addr4; addr_len = sizeof(addr6); #endif new_socket_fd = accept (daemon->socket_fd, addr, &addr_len); if(new_socket_fd < 1) return SPDY_NO; if (NULL == (session = malloc (sizeof (struct SPDY_Session)))) { goto free_and_fail; } memset (session, 0, sizeof (struct SPDY_Session)); session->daemon = daemon; session->socket_fd = new_socket_fd; session->max_num_frames = daemon->max_num_frames; ret = SPDYF_io_set_session(session, daemon->io_subsystem); SPDYF_ASSERT(SPDY_YES == ret, "Somehow daemon->io_subsystem iswrong here"); //init TLS context, handshake will be done if(SPDY_YES != session->fio_new_session(session)) { goto free_and_fail; } //read buffer session->read_buffer_size = SPDYF_BUFFER_SIZE; if (NULL == (session->read_buffer = malloc (session->read_buffer_size))) { session->fio_close_session(session); goto free_and_fail; } //address of the client if (NULL == (session->addr = malloc (addr_len))) { session->fio_close_session(session); goto free_and_fail; } memcpy (session->addr, addr, addr_len); session->addr_len = addr_len; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; //init zlib context for the whole session if(SPDY_YES != SPDYF_zlib_deflate_init(&session->zlib_send_stream)) { session->fio_close_session(session); goto free_and_fail; } if(SPDY_YES != SPDYF_zlib_inflate_init(&session->zlib_recv_stream)) { session->fio_close_session(session); SPDYF_zlib_deflate_end(&session->zlib_send_stream); goto free_and_fail; } //add it to daemon's list DLL_insert(daemon->sessions_head,daemon->sessions_tail,session); session->last_activity = SPDYF_monotonic_time(); if(NULL != daemon->new_session_cb) daemon->new_session_cb(daemon->cls, session); return SPDY_YES; //for GOTO free_and_fail: /* something failed, so shutdown, close and free memory */ shutdown (new_socket_fd, SHUT_RDWR); (void)close (new_socket_fd); if(NULL != session) { if(NULL != session->addr) free (session->addr); if(NULL != session->read_buffer) free (session->read_buffer); free (session); } return SPDY_NO; }
/** * Handler for reading the full SYN_STREAM frame after we know that * the frame is such. * The function waits for the full frame and then changes status * of the session. New stream is created. * * @param session SPDY_Session whose read buffer is used. */ static void spdyf_handler_read_syn_stream (struct SPDY_Session *session) { size_t name_value_strm_size = 0; unsigned int compressed_data_size; int ret; void *name_value_strm = NULL; struct SPDYF_Control_Frame *frame; struct SPDY_NameValue *headers; SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status, "the function is called wrong"); frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; //handle subheaders if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status) { if(0 == frame->length) { //protocol error: incomplete frame //we just ignore it since there is no stream id for which to //send RST_STREAM //TODO maybe GOAWAY and closing session is appropriate SPDYF_DEBUG("zero long SYN_STREAM received"); session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); return; } if(SPDY_YES != SPDYF_stream_new(session)) { /* waiting for some more fields to create new stream or something went wrong, SPDYF_stream_new has handled the situation */ return; } session->current_stream_id = session->streams_head->stream_id; if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE) { //TODO no need to create stream if this happens session->status = SPDY_SESSION_STATUS_IGNORE_BYTES; return; } else session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY; } //handle body //start reading the compressed name/value pairs (http headers) compressed_data_size = frame->length //everything after length field - 10;//4B stream id, 4B assoc strem id, 2B priority, unused and slot if(session->read_buffer_offset - session->read_buffer_beginning < compressed_data_size) { // the full frame is not yet here, try later return; } if(compressed_data_size > 0 && SPDY_YES != SPDYF_zlib_inflate(&session->zlib_recv_stream, session->read_buffer + session->read_buffer_beginning, compressed_data_size, &name_value_strm, &name_value_strm_size)) { /* something went wrong on inflating, * the state of the stream for decompression is unknown * and we may not be able to read anything more received on * this session, * so it is better to close the session */ free(name_value_strm); free(frame); /* mark the session for closing and close it, when * everything on the output queue is already written */ session->status = SPDY_SESSION_STATUS_FLUSHING; SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_INTERNAL_ERROR, false); return; } if(0 == name_value_strm_size || 0 == compressed_data_size) { //Protocol error: send RST_STREAM if(SPDY_YES != SPDYF_prepare_rst_stream(session, session->streams_head, SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR)) { //no memory, try later to send RST return; } } else { ret = SPDYF_name_value_from_stream(name_value_strm, name_value_strm_size, &headers); if(SPDY_NO == ret) { //memory error, try later free(name_value_strm); return; } session->streams_head->headers = headers; //inform the application layer for the new stream received if(SPDY_YES != session->daemon->fnew_stream_cb(session->daemon->fcls, session->streams_head)) { //memory error, try later free(name_value_strm); return; } session->read_buffer_beginning += compressed_data_size; free(name_value_strm); } //SPDYF_DEBUG("syn_stream received: id %i", session->current_stream_id); //change state to wait for new frame session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); }
int SPDYF_handler_write_syn_reply (struct SPDY_Session *session) { struct SPDYF_Response_Queue *response_queue = session->response_queue_head; struct SPDYF_Stream *stream = response_queue->stream; struct SPDYF_Control_Frame control_frame; void *compressed_headers = NULL; size_t compressed_headers_size=0; size_t used_data=0; size_t total_size; uint32_t stream_id_nbo; SPDYF_ASSERT(NULL == session->write_buffer, "the function is called not in the correct moment"); memcpy(&control_frame, response_queue->control_frame, sizeof(control_frame)); if(SPDY_YES != SPDYF_zlib_deflate(&session->zlib_send_stream, response_queue->data, response_queue->data_size, &used_data, &compressed_headers, &compressed_headers_size)) { /* something went wrong on compressing, * the state of the stream for compression is unknown * and we may not be able to send anything more on * this session, * so it is better to close the session right now */ session->status = SPDY_SESSION_STATUS_CLOSING; free(compressed_headers); return SPDY_NO; } //TODO do we need this used_Data SPDYF_ASSERT(used_data == response_queue->data_size, "not everything was used by zlib"); total_size = sizeof(struct SPDYF_Control_Frame) //SPDY header + 4 // stream id as "subheader" + compressed_headers_size; if(NULL == (session->write_buffer = malloc(total_size))) { /* no memory * since we do not save the compressed data anywhere and * the sending zlib stream is already in new state, we must * close the session */ session->status = SPDY_SESSION_STATUS_CLOSING; free(compressed_headers); return SPDY_NO; } session->write_buffer_beginning = 0; session->write_buffer_offset = 0; session->write_buffer_size = total_size; control_frame.length = compressed_headers_size + 4; // compressed data + stream_id SPDYF_CONTROL_FRAME_HTON(&control_frame); //put frame headers to write buffer memcpy(session->write_buffer + session->write_buffer_offset,&control_frame,sizeof(struct SPDYF_Control_Frame)); session->write_buffer_offset += sizeof(struct SPDYF_Control_Frame); //put stream id to write buffer stream_id_nbo = HTON31(stream->stream_id); memcpy(session->write_buffer + session->write_buffer_offset, &stream_id_nbo, 4); session->write_buffer_offset += 4; //put compressed name/value pairs to write buffer memcpy(session->write_buffer + session->write_buffer_offset, compressed_headers, compressed_headers_size); session->write_buffer_offset += compressed_headers_size; SPDYF_ASSERT(0 == session->write_buffer_beginning, "bug1"); SPDYF_ASSERT(session->write_buffer_offset == session->write_buffer_size, "bug2"); //DEBUG CODE, break compression state to see what happens /* SPDYF_zlib_deflate(&session->zlib_send_stream, "1234567890", 10, &used_data, &compressed_headers, &compressed_headers_size); */ free(compressed_headers); session->last_replied_to_stream_id = stream->stream_id; //SPDYF_DEBUG("syn_reply sent: id %i", stream->stream_id); return SPDY_YES; }
/** * Handler for reading DATA frames. In requests they are used for POST * arguments. * * @param session SPDY_Session whose read buffer is used. */ static void spdyf_handler_read_data (struct SPDY_Session *session) { int ret; struct SPDYF_Data_Frame * frame; struct SPDYF_Stream * stream; SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status || SPDY_SESSION_STATUS_WAIT_FOR_BODY == session->status, "the function is called wrong"); //SPDYF_DEBUG("DATA frame received (POST?). Ignoring"); //SPDYF_SIGINT(""); frame = (struct SPDYF_Data_Frame *)session->frame_handler_cls; //handle subheaders if(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status) { if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE) { session->status = SPDY_SESSION_STATUS_IGNORE_BYTES; return; } else session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY; } //handle body if(session->read_buffer_offset - session->read_buffer_beginning >= frame->length) { stream = SPDYF_stream_find(frame->stream_id, session); if(NULL == stream || stream->is_in_closed || NULL == session->daemon->received_data_cb) { if(NULL == session->daemon->received_data_cb) SPDYF_DEBUG("No callback for DATA frame set; Ignoring DATA frame!"); //TODO send error? //TODO for now ignore frame session->read_buffer_beginning += frame->length; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); return; } ret = session->daemon->freceived_data_cb(session->daemon->cls, stream, session->read_buffer + session->read_buffer_beginning, frame->length, 0 == (SPDY_DATA_FLAG_FIN & frame->flags)); session->read_buffer_beginning += frame->length; stream->window_size -= frame->length; //TODO close in and send rst maybe SPDYF_ASSERT(SPDY_YES == ret, "Cancel POST data is not yet implemented"); if(SPDY_DATA_FLAG_FIN & frame->flags) { stream->is_in_closed = true; } else if(stream->window_size < SPDYF_INITIAL_WINDOW_SIZE / 2) { //very simple implementation of flow control //when the window's size is under the half of the initial value, //increase it again up to the initial value //prepare WINDOW_UPDATE if(SPDY_YES == SPDYF_prepare_window_update(session, stream, SPDYF_INITIAL_WINDOW_SIZE - stream->window_size)) { stream->window_size = SPDYF_INITIAL_WINDOW_SIZE; } //else: do it later } //SPDYF_DEBUG("data received: id %i", frame->stream_id); session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); } }
/** * Handler for reading RST_STREAM frames. After receiving the frame * the stream moves into closed state and status * of the session is changed. Frames, belonging to this stream, which * are still at the output queue, will be ignored later. * * @param session SPDY_Session whose read buffer is used. */ static void spdyf_handler_read_rst_stream (struct SPDY_Session *session) { struct SPDYF_Control_Frame *frame; uint32_t stream_id; int32_t status_int; //enum SPDY_RST_STREAM_STATUS status; //for debug struct SPDYF_Stream *stream; SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status, "the function is called wrong"); frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; if(0 != frame->flags || 8 != frame->length) { //this is a protocol error SPDYF_DEBUG("wrong RST_STREAM received"); //ignore as a large frame session->status = SPDY_SESSION_STATUS_IGNORE_BYTES; return; } if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length) { //not all fields are received //try later return; } memcpy(&stream_id, session->read_buffer + session->read_buffer_beginning, 4); stream_id = NTOH31(stream_id); session->read_buffer_beginning += 4; memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4); //status = ntohl(status_int); //for debug session->read_buffer_beginning += 4; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); //mark the stream as closed stream = session->streams_head; while(NULL != stream) { if(stream_id == stream->stream_id) { stream->is_in_closed = true; stream->is_out_closed = true; break; } stream = stream->next; } //SPDYF_DEBUG("Received RST_STREAM; status=%i; id=%i",status,stream_id); //do something according to the status //TODO /*switch(status) { case SPDY_RST_STREAM_STATUS_PROTOCOL_ERROR: break; }*/ }
/** * Handler for reading the GOAWAY frame after we know that * the frame is such. * The function waits for the full frame and then changes status * of the session. * * @param session SPDY_Session whose read buffer is used. */ static void spdyf_handler_read_goaway (struct SPDY_Session *session) { struct SPDYF_Control_Frame *frame; uint32_t last_good_stream_id; uint32_t status_int; enum SPDY_GOAWAY_STATUS status; SPDYF_ASSERT(SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER == session->status, "the function is called wrong"); frame = (struct SPDYF_Control_Frame *)session->frame_handler_cls; if(frame->length > SPDY_MAX_SUPPORTED_FRAME_SIZE) { //this is a protocol error/attack session->status = SPDY_SESSION_STATUS_IGNORE_BYTES; return; } if(0 != frame->flags || 8 != frame->length) { //this is a protocol error SPDYF_DEBUG("wrong GOAWAY received"); //anyway, it will be handled } if((session->read_buffer_offset - session->read_buffer_beginning) < frame->length) { //not all fields are received //try later return; } //mark that the session is almost closed session->is_goaway_received = true; if(8 == frame->length) { memcpy(&last_good_stream_id, session->read_buffer + session->read_buffer_beginning, 4); last_good_stream_id = NTOH31(last_good_stream_id); session->read_buffer_beginning += 4; memcpy(&status_int, session->read_buffer + session->read_buffer_beginning, 4); status = ntohl(status_int); session->read_buffer_beginning += 4; //TODO do something with last_good //SPDYF_DEBUG("Received GOAWAY; status=%i; lastgood=%i",status,last_good_stream_id); //do something according to the status //TODO switch(status) { case SPDY_GOAWAY_STATUS_OK: break; case SPDY_GOAWAY_STATUS_PROTOCOL_ERROR: break; case SPDY_GOAWAY_STATUS_INTERNAL_ERROR: break; } //SPDYF_DEBUG("goaway received: status %i", status); } session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(frame); }
void SPDYF_queue_response (struct SPDYF_Response_Queue *response_to_queue, struct SPDY_Session *session, int consider_priority) { struct SPDYF_Response_Queue *pos; struct SPDYF_Response_Queue *last; uint8_t priority; SPDYF_ASSERT(SPDY_YES != consider_priority || NULL != response_to_queue->stream, "called with consider_priority but no stream provided"); last = response_to_queue; while(NULL != last->next) { last = last->next; } if(SPDY_NO == consider_priority) { //put it at the end of the queue response_to_queue->prev = session->response_queue_tail; if (NULL == session->response_queue_head) session->response_queue_head = response_to_queue; else session->response_queue_tail->next = response_to_queue; session->response_queue_tail = last; return; } else if(-1 == consider_priority) { //put it at the head of the queue last->next = session->response_queue_head; if (NULL == session->response_queue_tail) session->response_queue_tail = last; else session->response_queue_head->prev = response_to_queue; session->response_queue_head = response_to_queue; return; } if(NULL == session->response_queue_tail) { session->response_queue_head = response_to_queue; session->response_queue_tail = last; return; } //search for the right position to put it pos = session->response_queue_tail; priority = response_to_queue->stream->priority; while(NULL != pos && pos->stream->priority > priority) { pos = pos->prev; } if(NULL == pos) { //put it on the head session->response_queue_head->prev = last; last->next = session->response_queue_head; session->response_queue_head = response_to_queue; } else if(NULL == pos->next) { //put it at the end response_to_queue->prev = pos; pos->next = response_to_queue; session->response_queue_tail = last; } else { response_to_queue->prev = pos; last->next = pos->next; pos->next = response_to_queue; last->next->prev = last; } }
int SPDYF_name_value_is_empty(struct SPDY_NameValue *container) { SPDYF_ASSERT(NULL != container, "NULL is not an empty container!"); return (NULL == container->name && NULL == container->value) ? SPDY_YES : SPDY_NO; }
/* Needed by testcase to be extern -- should this be in the header? */ _MHD_EXTERN ssize_t SPDYF_name_value_to_stream(struct SPDY_NameValue * container[], int num_containers, void **stream) { size_t size; int32_t num_pairs = 0; int32_t value_size; int32_t name_size; int32_t temp; unsigned int i; unsigned int offset; unsigned int value_offset; struct SPDY_NameValue * iterator; int j; size = 4; //for num pairs for(j=0; j<num_containers; ++j) { iterator = container[j]; while(iterator != NULL) { ++num_pairs; size += 4 + strlen(iterator->name); //length + string SPDYF_ASSERT(iterator->num_values>0, "num_values is 0"); size += 4; //value length for(i=0; i<iterator->num_values; ++i) { //if(NULL == iterator->value[i]) // continue; size += strlen(iterator->value[i]); // string if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL separator } iterator = iterator->next; } } if(NULL == (*stream = malloc(size))) { return -1; } //put num_pairs to the stream num_pairs = htonl(num_pairs); memcpy(*stream, &num_pairs, 4); offset = 4; //put all other headers to the stream for(j=0; j<num_containers; ++j) { iterator = container[j]; while(iterator != NULL) { name_size = strlen(iterator->name); temp = htonl(name_size); memcpy(*stream + offset, &temp, 4); offset += 4; strncpy(*stream + offset, iterator->name, name_size); offset += name_size; value_offset = offset; offset += 4; for(i=0; i<iterator->num_values; ++i) { if(i /*|| !strlen(iterator->value[0])*/) { memset(*stream + offset, 0, 1); ++offset; //if(!i) continue; } //else if(NULL != iterator->value[i]) //{ strncpy(*stream + offset, iterator->value[i], strlen(iterator->value[i])); offset += strlen(iterator->value[i]); //} } value_size = offset - value_offset - 4; value_size = htonl(value_size); memcpy(*stream + value_offset, &value_size, 4); iterator = iterator->next; } } SPDYF_ASSERT(offset == size,"offset is wrong"); return size; }
int SPDYF_session_idle (struct SPDY_Session *session) { size_t read_buffer_beginning; size_t frame_length; struct SPDYF_Control_Frame* control_frame; struct SPDYF_Data_Frame *data_frame; //prepare session for closing if timeout is used and already passed if(SPDY_SESSION_STATUS_CLOSING != session->status && session->daemon->session_timeout && (session->last_activity + session->daemon->session_timeout < SPDYF_monotonic_time())) { session->status = SPDY_SESSION_STATUS_CLOSING; //best effort for sending GOAWAY SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_OK, true); SPDYF_session_write(session,true); } switch(session->status) { //expect new frame to arrive case SPDY_SESSION_STATUS_WAIT_FOR_HEADER: session->current_stream_id = 0; //check if the whole frame header is already here //both frame types have the same length if(session->read_buffer_offset - session->read_buffer_beginning < sizeof(struct SPDYF_Control_Frame)) return SPDY_NO; /* check the first bit to see if it is data or control frame * and also if the version is supported */ if(0x80 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning) && SPDY_VERSION == *((uint8_t *)session->read_buffer + session->read_buffer_beginning + 1)) { //control frame if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame)))) { SPDYF_DEBUG("No memory"); return SPDY_NO; } //get frame headers memcpy(control_frame, session->read_buffer + session->read_buffer_beginning, sizeof(struct SPDYF_Control_Frame)); session->read_buffer_beginning += sizeof(struct SPDYF_Control_Frame); SPDYF_CONTROL_FRAME_NTOH(control_frame); session->status = SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER; //assign different frame handler according to frame type switch(control_frame->type){ case SPDY_CONTROL_FRAME_TYPES_SYN_STREAM: session->frame_handler = &spdyf_handler_read_syn_stream; break; case SPDY_CONTROL_FRAME_TYPES_GOAWAY: session->frame_handler = &spdyf_handler_read_goaway; break; case SPDY_CONTROL_FRAME_TYPES_RST_STREAM: session->frame_handler = &spdyf_handler_read_rst_stream; break; default: session->frame_handler = &SPDYF_handler_ignore_frame; } session->frame_handler_cls = control_frame; //DO NOT break the outer case } else if(0 == *(uint8_t *)(session->read_buffer + session->read_buffer_beginning)) { //needed for POST //data frame if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame)))) { SPDYF_DEBUG("No memory"); return SPDY_NO; } //get frame headers memcpy(data_frame, session->read_buffer + session->read_buffer_beginning, sizeof(struct SPDYF_Data_Frame)); session->read_buffer_beginning += sizeof(struct SPDYF_Data_Frame); SPDYF_DATA_FRAME_NTOH(data_frame); session->status = SPDY_SESSION_STATUS_WAIT_FOR_BODY; session->frame_handler = &spdyf_handler_read_data; session->frame_handler_cls = data_frame; //DO NOT brake the outer case } else { SPDYF_DEBUG("another protocol or version received!"); /* According to the draft the lib should send here * RST_STREAM with status UNSUPPORTED_VERSION. I don't * see any sense of keeping the session open since * we don't know how many bytes is the bogus "frame". * And the latter normally will be HTTP request. * */ //shutdown(session->socket_fd, SHUT_RD); session->status = SPDY_SESSION_STATUS_FLUSHING; SPDYF_prepare_goaway(session, SPDY_GOAWAY_STATUS_PROTOCOL_ERROR,false); //SPDYF_session_write(session,false); /* close connection since the client expects another protocol from us */ //SPDYF_session_close(session); return SPDY_YES; } //expect specific header fields after the standard header case SPDY_SESSION_STATUS_WAIT_FOR_SUBHEADER: if(NULL!=session->frame_handler) { read_buffer_beginning = session->read_buffer_beginning; //if everything is ok, the "body" will also be processed //by the handler session->frame_handler(session); if(SPDY_SESSION_STATUS_IGNORE_BYTES == session->status) { //check for larger than max supported frame if(session->frame_handler != &spdyf_handler_read_data) { frame_length = ((struct SPDYF_Control_Frame *)session->frame_handler_cls)->length; } else { frame_length = ((struct SPDYF_Data_Frame *)session->frame_handler_cls)->length; } //if(SPDY_MAX_SUPPORTED_FRAME_SIZE < frame_length) { SPDYF_DEBUG("received frame with unsupported size: %zu", frame_length); //the data being received must be ignored and //RST_STREAM sent //ignore bytes that will arive later session->read_ignore_bytes = frame_length + read_buffer_beginning - session->read_buffer_offset; //ignore what is already in read buffer session->read_buffer_beginning = session->read_buffer_offset; SPDYF_prepare_rst_stream(session, session->current_stream_id > 0 ? session->streams_head : NULL, //may be 0 here which is not good SPDY_RST_STREAM_STATUS_FRAME_TOO_LARGE); //actually the read buffer can be bigger than the //max supported size session->status = session->read_ignore_bytes ? SPDY_SESSION_STATUS_IGNORE_BYTES : SPDY_SESSION_STATUS_WAIT_FOR_HEADER; free(session->frame_handler_cls); } } } if(SPDY_SESSION_STATUS_IGNORE_BYTES != session->status) { break; } //ignoring data in read buffer case SPDY_SESSION_STATUS_IGNORE_BYTES: SPDYF_ASSERT(session->read_ignore_bytes > 0, "Session is in wrong state"); if(session->read_ignore_bytes > session->read_buffer_offset - session->read_buffer_beginning) { session->read_ignore_bytes -= session->read_buffer_offset - session->read_buffer_beginning; session->read_buffer_beginning = session->read_buffer_offset; } else { session->read_buffer_beginning += session->read_ignore_bytes; session->read_ignore_bytes = 0; session->status = SPDY_SESSION_STATUS_WAIT_FOR_HEADER; } break; //expect frame body (name/value pairs) case SPDY_SESSION_STATUS_WAIT_FOR_BODY: if(NULL!=session->frame_handler) session->frame_handler(session); break; case SPDY_SESSION_STATUS_FLUSHING: return SPDY_NO; //because of error the session needs to be closed case SPDY_SESSION_STATUS_CLOSING: //error should be already sent to the client SPDYF_session_close(session); return SPDY_YES; } return SPDY_YES; }