int bb_socketio_push(struct bb_session *bbs, char type, char *buf, size_t len) { char *message = bb_alloc(4 + len); if (!message) { bb_error("malloc()"); return -1; } message[0] = type; message[1] = ':'; message[2] = ':'; message[3] = ':'; memcpy(message+4, buf, len); if (bbs->sio_realtime) { return bb_websocket_reply(bbs, message, len+4); } struct bb_socketio_message *last_bbsm=NULL,*bbsm = bbs->sio_queue; while(bbsm) { last_bbsm = bbsm; bbsm = bbsm->next; } bbsm = bb_alloc(sizeof(struct bb_socketio_message)); if (!bbsm) { bb_free(message, len+4); bb_error("malloc()"); return -1; } memset(bbsm, 0, sizeof(struct bb_socketio_message)); bbsm->buf = message; bbsm->len = 4+len; if (last_bbsm) { last_bbsm->next = bbsm; } else { bbs->sio_queue = bbsm; } //is a poller attached to the session ? if (bbs->sio_poller) { ev_feed_event(blastbeat.loop, &bbs->death_timer, EV_TIMER); } return 0; }
static int cache_header_value_cb(http_parser *parser, const char *buf, size_t len) { struct bb_cache_item *bbci = (struct bb_cache_item *) parser->data; if (bbci->headers_len + len > MAX_HEADERS_SIZE) return -1; int pos = bbci->headers_count-1; if (!bbci->last_was_value) { bbci->headers[pos].value = bb_alloc(len); if (!bbci->headers[pos].value) { return -1; } memcpy(bbci->headers[pos].value, buf, len); bbci->headers[pos].vallen = len; bbci->headers_len+=len; } else { char *tmp_buf = bb_realloc(bbci->headers[pos].value, bbci->headers[pos].vallen, len); if (!tmp_buf) { return -1; } bbci->headers[pos].value = tmp_buf; memcpy(bbci->headers[pos].value + bbci->headers[pos].vallen, buf, len); bbci->headers[pos].vallen += len; bbci->headers_len+=len; } bbci->last_was_value = 1; return 0; }
static int cache_header_field_cb(http_parser *parser, const char *buf, size_t len) { struct bb_cache_item *bbci = (struct bb_cache_item *) parser->data; if (bbci->headers_len + len > MAX_HEADERS_SIZE) return -1; if (bbci->last_was_value) { if (bbci->headers_count + 1 > blastbeat.max_headers) return -1; struct bb_http_header *bbhh = bb_realloc(bbci->headers, sizeof(struct bb_http_header)*bbci->headers_count, sizeof(struct bb_http_header)); if (!bbhh) { return -1; } bbci->headers_len += sizeof(struct bb_http_header); // is it the first header ? if (bbci->headers_count == 0) { bbci->http_end_of_first_line = (char *) buf-2; } bbci->headers = bbhh; int pos = bbci->headers_count; bbci->headers_count++; bbci->headers[pos].value = NULL; bbci->headers[pos].vallen = 0; bbci->headers[pos].keylen = 0; bbci->headers[pos].key = bb_alloc(len); if (!bbci->headers[pos].key) { return -1; } memcpy(bbci->headers[pos].key, buf, len); bbci->headers[pos].keylen = len; bbci->headers_len += len; } else { int pos = bbci->headers_count-1; char *tmp_buf = bb_realloc(bbci->headers[pos].key, bbci->headers[pos].keylen, len); if (!tmp_buf) { return -1; } bbci->headers[pos].key = tmp_buf; memcpy(bbci->headers[pos].key + bbci->headers[pos].keylen, buf, len); bbci->headers[pos].keylen += len; bbci->headers_len+= len; } bbci->last_was_value = 0; return 0; }
/* bb_finalize: finish the basic block b ending at cp. If there is more code (cp+step < lp), return a new basic block to hold it. If link is true, make b a predecessor of the new basic block. */ static inline i_bb_t bb_finalize (i_bb_t b, icode_t cp, icode_t lp, unsigned step, unsigned link) { assert(!b->init); b->init = 1; b->t = cp; if (cp+step < lp) { i_bb_t newbb = bb_alloc(); newbb->h = cp + step; b->lnext = newbb; newbb->lprev = b; if (link) bb_linkbb(b, newbb); return newbb; } return b; }
int bb_socketio_send(struct bb_session *bbs, char *buf, size_t len) { char *cl = bb_alloc(MAX_CONTENT_LENGTH); if (!cl) { bb_error("unable to allocate memory for socket.io message: malloc()"); return -1; } int chunk_len = snprintf(cl, MAX_CONTENT_LENGTH, "%llu\r\n\r\n", (unsigned long long) len); if (bb_wq_push(bbs, (char *)message_headers, strlen(message_headers), 0)) return -1; if (bb_wq_push(bbs, (char *)cl, chunk_len, BB_WQ_FREE)) return -1; if (bb_wq_push(bbs, (char *)buf, len, BB_WQ_FREE)) return -1; return 0; }
i_bb_t i_bb_new (unsigned maxlen, i_bb_t lprev) { i_bb_t b = bb_alloc(); if (lprev) { lprev->lnext = b; b->lprev = lprev; if (lprev == i_fg_tail) i_fg_tail = b; } else { b->lnext = i_fg_root; i_fg_root->lprev = b; i_fg_root = b; } NEW(i_ip, maxlen); i_buf = i_ip; i_lim = i_buf+maxlen; return b; }
static int bb_ssl_servername(SSL *ssl,int *ad, void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_NOACK; struct bb_connection *bbc = SSL_get_ex_data(ssl, blastbeat.ssl_index); struct bb_acceptor *bba = bbc->acceptor; size_t servername_len = strlen(servername); struct bb_virtualhost *vhost = NULL; struct bb_hostname *bbhn = NULL; if (bba->addr.in4.sin_port != htons(443) && !strchr(servername, ':')) { size_t port_len = strlen(bba->port_str); char *new_sn = bb_alloc(servername_len+port_len); if (!new_sn) return SSL_TLSEXT_ERR_NOACK; memcpy(new_sn, servername, servername_len); memcpy(new_sn + servername_len, bba->port_str, port_len); vhost = bb_vhost_get(new_sn, servername_len+port_len, &bbhn); bb_free(new_sn, servername_len+port_len); } else { vhost = bb_vhost_get((char *)servername, servername_len, &bbhn); } if (!vhost) return SSL_TLSEXT_ERR_NOACK; // per vhost-context is required to decrypt keys sent by dealers if (!vhost->ctx) return SSL_TLSEXT_ERR_NOACK; // prefer dealer-defined context if (bbhn->ctx) { SSL_set_SSL_CTX(ssl, bbhn->ctx); return SSL_TLSEXT_ERR_OK; } SSL_set_SSL_CTX(ssl, vhost->ctx); return SSL_TLSEXT_ERR_OK; }
void i_fg_build (void) { unsigned i; i_puint32 cp = i_buf; /* Start of code to analyze */ i_puint32 lp = i_lim; /* End of code to analyze */ i_uint32 op; /* Current opcode */ i_bb_t b; /* Current basic block */ num_bb = 0; b = bb_alloc(); b->h = cp; if (i_ralloctype == RA_EZ) { i_fg_root = i_fg_tail = b; b->t = lp - i_isize; return; } i_calls_cur = i_calls_lim = 0; NEW0(lbl2bb, i_lab_cur); NEW(fwdrefs, i_nbb); fwdref_cur = 0; i_fg_root = b; do { assert(b && !b->init); op = get_op(cp); switch(i_op2class[op]) { case I_BOP: case I_BOPF: case I_MOPR: case I_MOPRF: assert(!isimmed(op)); markuse(b, get_rs(cp)); markuse(b, get_rs2(cp)); markdef(b, get_rd(cp)); break; case I_BOPI: case I_MOPRI: case I_MOPRIF: assert(isimmed(op)); markuse(b, get_rs(cp)); markdef(b, get_rd(cp)); break; case I_MOPW: case I_MOPWF: assert(!isimmed(op)); markuse(b, get_rd(cp)); markuse(b, get_rs(cp)); markuse(b, get_rs2(cp)); break; case I_MOPWI: case I_MOPWIF: assert(isimmed(op)); markuse(b, get_rd(cp)); markuse(b, get_rs(cp)); break; case I_UOP: case I_UOPF: assert(!isimmed(op)); markuse(b, get_rs(cp)); markdef(b, get_rd(cp)); break; case I_UOPI: assert(isimmed(op)); markdef(b, get_rd(cp)); break; case I_SET: case I_SETF: markdef(b, get_rd(cp)); break; case I_LEA: case I_LEAF: SCLASS(get_rs(cp)) = STACK; markuse(b, get_rs(cp)); markdef(b, get_rd(cp)); break; case I_RET: case I_RETF: if (op != i_op_retv) markuse(b, get_rd(cp)); case I_RETI: b = bb_finalize(b, cp, lp, i_isize, false); break; case I_BR: case I_BRF: markuse(b, get_rs2(cp)); case I_BRI: markuse(b, get_rs(cp)); bb_linklbl(b, get_rd(cp)); b = bb_finalize(b, cp, lp, i_isize, true); break; case I_CALL: case I_CALLF: markuse(b, get_rs(cp)); case I_CALLI: case I_CALLIF: if (op != i_op_callv && op != i_op_callvi) markdef(b, get_rd(cp)); markcall(cp); b = bb_finalize(b, cp, lp, 2*i_isize, true); cp += i_isize; /* Calls are 2x as long as other insns */ break; case I_ARG: case I_ARGF: markuse(b, get_rd(cp)); break; case I_JMP: assert(get_rd(cp) < num_i); markuse(b, get_rd(cp)); b = bb_finalize(b, cp, lp, i_isize, false); break; case I_JMPI: bb_linklbl(b, get_imm(cp)); b = bb_finalize(b, cp, lp, i_isize, false); break; case I_MISC: switch (op) { case i_op_lbl: if (cp > b->h) /* If not at head of current block ... */ /* ... make this the head of a new block */ b = bb_finalize(b, cp-i_isize, lp, i_isize, true); lbl2bb[get_rd(cp)] = b; break; default: /* refmul, refdiv, self, nop */ break; } break; default: assert(0); } } while ((cp += i_isize) < lp); i_fg_tail = b; for (i = 0; i < fwdref_cur; i++) bb_linkbb(fwdrefs[i].src, lbl2bb[fwdrefs[i].dst]); #ifndef NDEBUG for (i = 0, b = i_fg_root; b; b = b->lnext) i++; assert(i == num_bb); #endif }
/* here we run 2 parsers: the first one will split options key expires flags\r\n if key is right and the body is present (an empty body, means: destroy the item) the second one will run a http parser, if it is valid the cache_item is added to the hashtable */ void bb_cache_store(struct bb_session *bbs, char *buf, size_t len, int frag) { if (bbs->vhost->cache_size == 0) return; // check for space if (bbs->vhost->allocated_cache + (sizeof(struct bb_cache_item) + len) > bbs->vhost->cache_size) { fprintf(stderr,"!!! cache for virtualhost \"%.*s\" is full !!!\n", (int) bbs->vhost->len, bbs->vhost->name); return; } // 0->key 1->expires 2->flags 3->uninteresting 4->end int status = 0; uint32_t cht_pos; char *key = buf; char *expires = NULL; char *flags = NULL; size_t keylen = 0; size_t expires_len = 0; size_t flags_len = 0; size_t i; for(i=0;i<len;i++) { if (buf[i] == ' ') { if (status == 0) { keylen = i; status = 1; } else if (status == 1) { expires_len = i; status = 2;} else if (status == 2) { flags_len = i; status = 3;} } else if (buf[i] == '\n') { if (status == 4) break; if (status == 0) { keylen = i; status = 1; } else if (status == 1) { expires_len = i; status = 2;} else if (status == 2) { flags_len = i; status = 3;} break; } else if (buf[i] == '\r') { if (status == 4) break; if (status == 0) { keylen = i; status = 1; } else if (status == 1) { expires_len = i; status = 2;} else if (status == 2) { flags_len = i; status = 3;} status = 4; } else { if (status == 1 && !expires) { expires = buf+i; } else if (status == 2 && !flags) { flags = buf+i;} } } if (keylen == 0) return; // fix size if (expires_len > 0) { expires_len -= expires-buf; } if (flags_len > 0) { flags_len -= flags-buf; } uint64_t expires_num = bb_str2num(expires, expires_len); uint32_t flags_num = bb_str2num(flags, flags_len); struct bb_cache_item *already = bb_cache_get(bbs->vhost, key, keylen, frag); if (already) { // empty body, destroy the item if (len-(i+1) <= 0) { bb_cache_destroy(already); return ; } // by default ignore updates if (flags_num == 0) return; bb_cache_destroy(already); } char *http_buf = buf+(i+1); size_t http_buf_len = len-(i+1); struct bb_cache_item *bbci = bb_alloc(sizeof(struct bb_cache_item)); if (!bbci) { return; } memset(bbci, 0, sizeof(struct bb_cache_item)); if (frag) { bbci->body = bb_alloc(http_buf_len); if (!bbci->body) { goto clear; } memcpy(bbci->body, http_buf, http_buf_len); bbci->body_len = http_buf_len; goto store; } http_parser parser; http_parser_init(&parser, HTTP_RESPONSE); bbci->last_was_value = 1; parser.data = bbci; int res = http_parser_execute(&parser, &bb_http_cache_parser_settings, http_buf, http_buf_len); if (!bbci->valid && res != http_buf_len) goto clear; bbci->status[0] = (parser.status_code/100) + '0'; bbci->status[1] = ((parser.status_code%100)/10) + '0'; bbci->status[2] = ((parser.status_code%100)%10) + '0'; memcpy(bbci->protocol, http_buf, 8); bbci->http_first_line_len = bbci->http_end_of_first_line-http_buf; bbci->http_first_line = bb_alloc(bbci->http_first_line_len); if (!bbci->http_first_line) { goto clear; } memcpy(bbci->http_first_line, http_buf, bbci->http_first_line_len); store: // get the hash cht_pos = djb2_hash_cache(key, keylen, bbs->vhost->cht_size); // get the ht entry struct bb_cache_entry *bbce = &bbs->vhost->cache[cht_pos]; bbci->key = bb_alloc(keylen); if (!bbci->key) { goto clear; } memcpy(bbci->key, key, keylen); bbci->keylen = keylen; bbci->frag = frag; bbci->entry = bbce; bbci->next = NULL; bbci->len = sizeof(struct bb_cache_item) + bbci->body_len + bbci->http_first_line_len + keylen + bbci->headers_len; bbci->expires_num = expires_num; bbci->vhost = bbs->vhost; // append cache item to entry if (!bbce->head) { bbci->prev = NULL; bbce->head = bbci; } else { bbci->prev = bbce->tail; bbce->tail->next = bbci; } bbce->tail = bbci; if (expires_num > 0) { ev_timer_init(&bbci->expires, cache_expires_cb, expires_num, 0.0); ev_timer_start(blastbeat.loop, &bbci->expires); } bbs->vhost->allocated_cache += bbci->len; blastbeat.cache_memory += bbci->len; return; clear: bb_cache_clear(bbci); }