int bb_socketio_message(struct bb_session *bbs, char *buf, size_t len) { if (bbs->sio_session) bbs = bbs->sio_session; if (len == 3 && buf[1] == ':' && buf[2] == ':') return 0; char *sio_body = find_third_colon(buf, len); if (!sio_body) return -1; size_t sio_len = len - (sio_body-buf); // forward socket.io message to the right session switch(buf[0]) { case '3': bb_zmq_send_msg(bbs->dealer, bbs, (char *) &bbs->uuid_part1, BB_UUID_LEN, "socket.io/msg", 13, sio_body, sio_len); break; case '4': bb_zmq_send_msg(bbs->dealer, bbs, (char *) &bbs->uuid_part1, BB_UUID_LEN, "socket.io/json", 14, sio_body, sio_len); break; case '5': bb_zmq_send_msg(bbs->dealer, bbs, (char *) &bbs->uuid_part1, BB_UUID_LEN, "socket.io/event", 15, sio_body, sio_len); break; default: fprintf(stderr,"SOCKET.IO MESSAGE TYPE: %c\n", buf[0]); return -1; } return 0; }
static void bb_session_clear(struct bb_session *bbs) { int i; struct bb_connection *bbc = bbs->connection; // remove the session from the hash table bb_sht_remove(bbs); struct bb_session_request *bbsr = bbs->requests_head; while(bbsr) { // in spdy mode, the first header is empty for(i=bbc->spdy;i<=bbsr->header_pos;i++) { free(bbsr->headers[i].key); free(bbsr->headers[i].value); } if (bbsr->uwsgi_buf) { free(bbsr->uwsgi_buf); } if (bbsr->websocket_message_queue) { free(bbsr->websocket_message_queue); } struct bb_session_request *tmp_bbsr = bbsr; bbsr = bbsr->next; free(tmp_bbsr); } // if linked to a dealer, send a 'end' message if (bbs->dealer) { bb_zmq_send_msg(bbs->dealer->identity, bbs->dealer->len, (char *) &bbs->uuid_part1, BB_UUID_LEN, "end", 3, "", 0); } }
static int bb_session_headers_complete(http_parser *parser) { //printf("headers parsed\n"); struct bb_session_request *bbsr = (struct bb_session_request *) parser->data; off_t i; //printf("%s %.*s HTTP/%d.%d\n", http_method_str(parser->method), (int) bbsr->headers[0].keylen, bbsr->headers[0].key, parser->http_major, parser->http_minor); /* for(i=1;i<=bbsr->header_pos;i++) { printf("%.*s: %.*s\n", (int) bbsr->headers[i].keylen, bbsr->headers[i].key, (int)bbsr->headers[i].vallen, bbsr->headers[i].value); } */ // ok get the Host header struct bb_http_header *bbhh = bb_http_req_header(bbsr, "Host", 4); if (!bbhh) { return -1; } if (!bbsr->bbs->dealer) { bbsr->bbs->dealer = bb_get_dealer(bbsr->bbs->acceptor, bbhh->value, bbhh->vallen); if (!bbsr->bbs->dealer) { return -1; } } if (parser->upgrade) { struct bb_http_header *bbhh = bb_http_req_header(bbsr, "Upgrade", 7); if (bbhh) { if (!bb_stricmp("websocket", 9, bbhh->value, bbhh->vallen)) { bbsr->type = BLASTBEAT_TYPE_WEBSOCKET; bb_send_websocket_handshake(bbsr); goto msg; } } } if (!http_should_keep_alive(parser)) { //printf("NO KEEP ALIVE !!!\n"); bbsr->close = 1; } msg: // now encode headers in a uwsgi packet and send it as "headers" message if (bb_uwsgi(bbsr)) { return -1; } bb_zmq_send_msg(bbsr->bbs->dealer->identity, bbsr->bbs->dealer->len, (char *) &bbsr->bbs->uuid_part1, BB_UUID_LEN, "uwsgi", 5, bbsr->uwsgi_buf, bbsr->uwsgi_pos); return 0; }
void bb_session_close(struct bb_session *bbs) { int i; ev_io_stop(blastbeat.loop, &bbs->reader.reader); ev_io_stop(blastbeat.loop, &bbs->writer.writer); if (bbs->ssl) { // this should be better managed, but why wasting resources ? // just ignore its return value SSL_shutdown(bbs->ssl); SSL_free(bbs->ssl); } close(bbs->fd); // remove the session from the hash table bb_sht_remove(bbs); struct bb_session_request *bbsr = bbs->requests_head; while(bbsr) { for(i=0;i<=bbsr->header_pos;i++) { free(bbsr->headers[i].key); free(bbsr->headers[i].value); } if (bbsr->uwsgi_buf) { free(bbsr->uwsgi_buf); } if (bbsr->websocket_message_queue) { free(bbsr->websocket_message_queue); } struct bb_session_request *tmp_bbsr = bbsr; bbsr = bbsr->next; free(tmp_bbsr); } struct bb_writer_item *bbwi = bbs->writer.head; while(bbwi) { struct bb_writer_item *old_bbwi = bbwi; bbwi = bbwi->next; if (old_bbwi->free_it) { free(old_bbwi->buf); } free(old_bbwi); } // if linked to a dealer, send a 'end' message if (bbs->dealer) { bb_zmq_send_msg(bbs->dealer->identity, bbs->dealer->len, (char *) &bbs->uuid_part1, BB_UUID_LEN, "end", 3, "", 0); } free(bbs); }
static int body_cb(http_parser *parser, const char *buf, size_t len) { struct bb_session_request *bbsr = (struct bb_session_request *) parser->data; // send a message as "body" bb_zmq_send_msg(bbsr->bbs->dealer->identity, bbsr->bbs->dealer->len, (char *) &bbsr->bbs->uuid_part1, BB_UUID_LEN, "body", 4, buf, len); return 0; }
void bb_zmq_receiver(struct ev_loop *loop, struct ev_io *w, int revents) { uint32_t zmq_events = 0; size_t opt_len = sizeof(uint32_t); for(;;) { int ret = zmq_getsockopt(blastbeat.router, ZMQ_EVENTS, &zmq_events, &opt_len); if (ret < 0) { perror("zmq_getsockopt()"); break; } if (zmq_events & ZMQ_POLLIN) { uint64_t more = 0; size_t more_size = sizeof(more); int headers = 0; int i; zmq_msg_t msg[4]; for(i=0;i<4;i++) { zmq_msg_init(&msg[i]); zmq_recv(blastbeat.router, &msg[i], ZMQ_NOBLOCK); if (zmq_getsockopt(blastbeat.router, ZMQ_RCVMORE, &more, &more_size)) { perror("zmq_getsockopt()"); break; } if (!more && i < 3) { break; } } // invalid message if (i != 4) goto next; // manage "pong" messages // message with uuid ? if (zmq_msg_size(&msg[1]) != BB_UUID_LEN) goto next; // dead/invalid session ? struct bb_session *bbs = bb_sht_get(zmq_msg_data(&msg[1])); if (!bbs) goto next; struct bb_session_request *bbsr = bbs->requests_tail; // no request running ? if (!bbsr) goto next; if (!strncmp(zmq_msg_data(&msg[2]), "body", zmq_msg_size(&msg[2]))) { if (bb_wq_push_copy(bbs,zmq_msg_data(&msg[3]), zmq_msg_size(&msg[3]), 1)) { bb_session_close(bbs); goto next; } bbsr->written_bytes += zmq_msg_size(&msg[2]); // if Content-Length is specified, check it... if (bbsr->content_length != ULLONG_MAX && bbsr->written_bytes >= bbsr->content_length && bbsr->close) { if (bb_wq_push_close(bbs)) bb_session_close(bbs); } goto next; } if (!strncmp(zmq_msg_data(&msg[2]), "websocket", zmq_msg_size(&msg[2]))) { if (bb_websocket_reply(bbsr, zmq_msg_data(&msg[3]), zmq_msg_size(&msg[3]))) bb_session_close(bbs); goto next; } if (!strncmp(zmq_msg_data(&msg[2]), "chunk", zmq_msg_size(&msg[2]))) { if (bb_manage_chunk(bbsr, zmq_msg_data(&msg[3]), zmq_msg_size(&msg[3]))) bb_session_close(bbs); goto next; } if (!strncmp(zmq_msg_data(&msg[2]), "headers", zmq_msg_size(&msg[2]))) { http_parser parser; http_parser_init(&parser, HTTP_RESPONSE); parser.data = bbsr; int res = http_parser_execute(&parser, &bb_http_response_parser_settings, zmq_msg_data(&msg[3]), zmq_msg_size(&msg[3])); // invalid headers ? if (res != zmq_msg_size(&msg[3])) { bb_session_close(bbs); goto next; } if (bb_wq_push_copy(bbs, zmq_msg_data(&msg[3]), zmq_msg_size(&msg[3]), 1)) bb_session_close(bbs); goto next; } if (!strncmp(zmq_msg_data(&msg[2]), "retry", zmq_msg_size(&msg[2]))) { if (bbs->hops >= blastbeat.max_hops) { bb_session_close(bbs); goto next; } bbs->dealer = bb_get_dealer(bbs->acceptor, bbs->dealer->vhost->name, bbs->dealer->vhost->len); if (!bbs->dealer) { bb_session_close(bbs); goto next; } bb_zmq_send_msg(bbs->dealer->identity, bbs->dealer->len, (char *) &bbs->uuid_part1, BB_UUID_LEN, "uwsgi", 5, bbsr->uwsgi_buf, bbsr->uwsgi_pos); bbs->hops++; goto next; } if (!strncmp(zmq_msg_data(&msg[2]), "end", zmq_msg_size(&msg[2]))) { if (bb_wq_push_close(bbs)) { bb_session_close(bbs); } goto next; } next: zmq_msg_close(&msg[0]); zmq_msg_close(&msg[1]); zmq_msg_close(&msg[2]); zmq_msg_close(&msg[3]); continue; } break; } }