static void read_cb(int fd, int mask, void* user) { int fork_id = (int)user; fork_state* fs = get_fork(fork_id); assert(fd == fs->to_host_fd[0]); fs->has_yielded_reader = 0; if (mask & STD2_CALLBACK_ABORT) { assert(!"abort not implemented"); abort(); return; } buffer_reserve(&fs->in_buffer, 1024); int closed = read_buffer_append(fd, &fs->in_buffer, 1); /* If fd was closed, abort all returns. */ if (closed) { request* req; for (req = fs->first_request; req; req = req->next) std2_abort_return(req->return_id); return; } /* fd wasn't closed so yield new read callback. */ yield_callbacks(fork_id); if (!fs->return_processed) return; fprintf(stderr, "NAH\n"); if (buffer_avail(&fs->in_buffer) < 8) return; int ret_id = *(std2_int32*)buffer_cursor(&fs->in_buffer); int ret_size = *((std2_int32*)buffer_cursor(&fs->in_buffer) + 1); if (buffer_avail(&fs->in_buffer) < 8 + ret_size) return; fprintf(stderr, "std2: got return from fork, id %d, size %d\n", ret_id, ret_size); request* req; for (req = fs->first_request; req; req = req->next) if (req->id == ret_id) { fs->return_processed = 0; std2_continue_return(req->return_id, return_func, req); return; } fprintf(stderr, "std2: bad request id\n"); }
int main(int argc, char ** argv) { struct termios tio; struct buffer * data; struct pollfd pfd; size_t off; char line[MAX_LINELEN], *p, * cmd; int ret, fd, c; uint32_t capacity, nfuncs, counts_per_func, size, i, j, index, min; uint32_t * bitmaps[NR_BITMAPS], * hashes; uint32_t bitmap_diffs[NR_BITMAPS] = {10, 60, 600}; uint32_t bitmap_max[NR_BITMAPS] = {2, 10, 50}; struct taia timestamps[NR_BITMAPS], now, diff; double error_rate; while ((c = getopt(argc, argv, "c:e:h")) != -1) { switch (c) { case 'h': usage(argc > 0 ? argv[0] : "(unknown)"); break; case 'c': capacity = atoi(optarg); break; case 'e': error_rate = atof(optarg); break; } } if (argc-optind != NR_BITMAPS+1) { fprintf(stderr, "not enough (or too many) arguments supplied\n\n"); usage(argc > 0 ? argv[0] : "(unknown)"); } /* get the tresholds from the command line */ for (i=0;i<NR_BITMAPS;i++) { bitmap_diffs[i] = atoi(argv[optind+i]); printf("%i\n", bitmap_diffs[i]); } /* get the command which will be executed */ cmd = argv[optind+3]; /* calculate the bloom filter parameters */ capacity = CAPACITY; error_rate = ERROR_RATE; nfuncs = (int)ceil(log(1/error_rate) / log(2)); counts_per_func = (int) ceil(capacity * fabs(log(error_rate)) /(nfuncs * pow(log(2), 2))); size = nfuncs * counts_per_func * sizeof(uint32_t); debug("nfuncs: %u, counts_per_func: %u, size: %u, bits: %lu\n", nfuncs, counts_per_func, size, size/sizeof(uint32_t)); /* allocate all the bitmaps necessary and set timestamps */ taia_now(&now); for (i=0;i<NR_BITMAPS;i++) { bitmaps[i] = xmalloc(size); memcpy(&(timestamps[i]), &now, sizeof(struct taia)); } /* allocate hash structure used to calculate bitmap indices */ hashes = xmalloc(nfuncs * sizeof(uint32_t)); /* turn of line buffering */ tcgetattr(STDIN_FILENO, &tio); tio=tio; tio.c_lflag &=(~ICANON); tcsetattr(STDIN_FILENO,TCSANOW, &tio); /* prepare poll */ fd = STDIN_FILENO; pfd.fd = fd; pfd.events = POLLIN; data = buffer_new(); /* event loop */ while (1) { /* timeout every second */ ret = poll(&pfd, 1, 1000); if (ret < 0) pfatal("poll"); if (pfd.revents == POLLIN) { buffer_fd_append(data, fd, fd_ravail(fd)); ret = buffer_findchar(data, '\n', &off); nextline: if (ret < 0) { if (buffer_avail(data)>=MAX_LINELEN) { fatal("line too long"); } continue; } else if (off >= MAX_LINELEN-1) { fatal("line too long"); } buffer_consume(data, line, off+1); buffer_reset(data); line[off] = 0; /* strip whitespace between id and data and * rejoin the datasuch that it's only * separated by a space */ p = line; while (*p) { if (*p == ' ' || *p == '\t') { *p = 0; p++; break; } p++; } while (*p == ' ' || *p == '\t') p++; if (!strlen(line) || p == line+off) fatal("invalid line"); /* reset the data so that the id and the data are separated by just only one space */ memmove(line+strlen(line)+1, p, strlen(p)); *(line+strlen(line)) = 0; *(line+strlen(line)+1+strlen(p))=0; /* calculate the hashes */ hash_func(line, strlen(line), hashes, nfuncs, counts_per_func); /* loop over the bitmaps and see if for any of the * maps the maximum limits were reached */ for (j=0;j<NR_BITMAPS;j++) { min = UINT32_MAX; for (i=0;i<nfuncs;i++) { off = i * counts_per_func; index = hashes[i] + off; bitmaps[j][index] += 1; if (bitmaps[j][index] < min) { min = bitmaps[j][index]; } } if (min > bitmap_max[j]) { debug("treshold reached for %s\n", line); exec_cmd(cmd, line); } } ret = buffer_findchar(data, '\n', &off); if (ret >= 0) goto nextline; } /* reset the bitmaps if they've passed the time treshold */ taia_now(&now); for (i=0;i<NR_BITMAPS;i++) { taia_diff(×tamps[i], &now, &diff); if (diff.sec.x >= bitmap_diffs[i]) { memcpy(&(timestamps[i]), &now, sizeof(struct taia)); memset(bitmaps[i], 0, size); } } } }
void std2_process_request() { fork_state* fs = get_fork(current_fork_id); if (read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, 20)) { fprintf(stderr, "std2: child got disconnection\n"); exit(1); } int marker = buffer_read_32(&fs->in_buffer); int req_id = buffer_read_32(&fs->in_buffer); if (marker == 'c') { int m = buffer_read_32(&fs->in_buffer); int f = buffer_read_32(&fs->in_buffer); int params_size = buffer_read_32(&fs->in_buffer); read_buffer_append(fs->to_client_fd[0], &fs->in_buffer, params_size); fprintf(stderr, "call id=%d, %d, %d, %d\n", req_id, m, f, params_size); // Construct parameters. void* start_ptr = buffer_cursor(&fs->in_buffer); void* end_ptr = (char*)buffer_cursor(&fs->in_buffer) + params_size; void* p = start_ptr; void* args[16]; int param_count = std2_get_param_count(m, f); int i; for (i = 0; i < param_count; i++) { struct std2_param t = std2_get_param_type(m, f, i); switch (t.type) { case STD2_INT32: args[i] = p; p = (char*)p + 4; break; case STD2_C_STRING: { int size = *(int*)p; p = (char*)p + 4; args[i] = p; p = (char*)p + size; } break; case STD2_INSTANCE: args[i] = *(void**)p; p = (char*)p + sizeof(void*); break; default: fprintf(stderr, "std2: (c) unknown type %d\n", t.type); abort(); } assert(p <= end_ptr); } fs->in_buffer.pos += (char*)p - (char*)start_ptr; // Do the call. struct std2_param ret_type = std2_get_return_type(m, f); buffer_append_32(&fs->out_buffer, req_id); // size will be filled afterwards int size_pos = fs->out_buffer.size; buffer_append_32(&fs->out_buffer, 0); // size will be filled afterwards int ret; switch (ret_type.type) { case STD2_VOID: ret = std2_call(0, m, f, 0, args); break; case STD2_INT32: { std2_int32 v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_32(&fs->out_buffer, v); } break; case STD2_C_STRING: { const char* v; ret = std2_call(0, m, f, &v, args); if (!ret) { int l = strlen(v) + 1; int n = (l + 3) & ~3; buffer_append_32(&fs->out_buffer, n); buffer_append_data(&fs->out_buffer, v, l); buffer_append_alignment(&fs->out_buffer, 4); } } break; case STD2_INSTANCE: { void* v; ret = std2_call(0, m, f, &v, args); if (!ret) buffer_append_data(&fs->out_buffer, &v, sizeof(void*)); } break; default: fprintf(stderr, "std2: (a) unknown type %d\n", ret_type.type); abort(); } if (ret) { fprintf(stderr, "delayed return\n"); fs->out_buffer.size -= 8; // req_id and size return; } *(int*)((char*)fs->out_buffer.data + size_pos) = fs->out_buffer.size - size_pos - 4; while (buffer_avail(&fs->out_buffer)) write_buffer(fs->to_host_fd[1], &fs->out_buffer); fprintf(stderr, "response written\n"); buffer_compact(&fs->in_buffer); buffer_compact(&fs->out_buffer); } else if (marker == 'u') { assert(!"todo unrefer"); } else { fprintf(stderr, "std2: protocol error, bad marker %d\n", marker); abort(); } }