void cache_wait(AbstractCache * cache) { #else void cache_wait_dbg(const char * file, int line, AbstractCache * cache) { #endif assert(is_dispatch_thread()); assert(current_client.client != NULL); if (current_client.client != NULL) { current_cache = cache; cache_miss_cnt++; #ifndef NDEBUG current_client.file = file; current_client.line = line; current_client.time_stamp = time(NULL); if (!cache_timer_posted) { post_event_with_delay(cache_timer, NULL, 5000000); cache_timer_posted = 1; } #endif } #ifndef NDEBUG else { trace(LOG_ALWAYS, "Illegal cache access at %s:%d", file, line); } #endif exception(ERR_CACHE_MISS); }
static int tcp_is_closed(Channel * channel) { ChannelTCP * c = channel2tcp(channel); assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->lock_cnt > 0); return c->socket < 0; }
void cache_wait(AbstractCache * cache) { #else void cache_wait_dbg(const char * file, int line, AbstractCache * cache) { #endif assert(is_dispatch_thread()); assert(client_exited == 0); if (current_client.client != NULL && cache_miss_cnt == 0) { if (cache->wait_list_cnt >= cache->wait_list_max) { cache->wait_list_max += 8; cache->wait_list_buf = (WaitingCacheClient *)loc_realloc(cache->wait_list_buf, cache->wait_list_max * sizeof(WaitingCacheClient)); } if (current_client.args != NULL && !current_client.args_copy) { void * mem = loc_alloc(current_client.args_size); memcpy(mem, current_client.args, current_client.args_size); current_client.args = mem; current_client.args_copy = 1; } #ifndef NDEBUG current_client.file = file; current_client.line = line; #endif if (cache->wait_list_cnt == 0) list_add_last(&cache->link, &cache_list); cache->wait_list_buf[cache->wait_list_cnt++] = current_client; channel_lock(current_client.channel); } #ifndef NDEBUG else if (current_client.client == NULL) { trace(LOG_ALWAYS, "cache_wait(): illegal cache access at %s:%d", file, line); } #endif cache_miss_cnt++; exception(ERR_CACHE_MISS); }
static void realloc_msg_buf(void) { assert(is_dispatch_thread()); if (msg_buf_max <= msg_buf_len + 128 || msg_buf_max > msg_buf_len + 2048) { msg_buf_max = msg_buf_len + 256; msg_buf = (char *)loc_realloc(msg_buf, msg_buf_max); } }
static int send_packet(PortConnection * conn, char * buffer, size_t size) { JsonWriteBinaryState state; assert (is_dispatch_thread()); assert (conn->pending_write_request < MAX_STREAM_WRITE); protocol_send_command(conn->server->channel, "Streams", "write", write_stream_done, conn); json_write_string(&conn->server->channel->out, conn->out_stream_id); write_stream(&conn->server->channel->out, 0); json_write_long(&conn->server->channel->out, size); write_stream(&conn->server->channel->out, MARKER_EOA); json_write_binary_start(&state, &conn->server->channel->out, size); json_write_binary_data(&state, buffer, size); json_write_binary_end(&state); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); conn->pending_write_request ++; if (conn->pending_write_request == MAX_STREAM_WRITE) { return 0; } else { send_packet_callback(conn, 0); } return 0; }
void cache_exit(void) { assert(is_dispatch_thread()); assert(current_client.client != NULL); assert(!client_exited); if (cache_miss_cnt > 0) exception(ERR_CACHE_MISS); client_exited = 1; }
static char * system_strerror(DWORD error_code, HMODULE module) { WCHAR * buf = NULL; assert(is_dispatch_thread()); msg_buf_len = 0; if (FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK | (module ? FORMAT_MESSAGE_FROM_HMODULE : 0), module, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ (LPWSTR)&buf, 0, NULL)) { msg_buf_len = WideCharToMultiByte(CP_UTF8, 0, buf, -1, NULL, 0, NULL, NULL); if (msg_buf_len > 0) { realloc_msg_buf(); msg_buf_len = WideCharToMultiByte(CP_UTF8, 0, buf, -1, msg_buf, (int)msg_buf_max, NULL, NULL); } } if (msg_buf_len == 0) { realloc_msg_buf(); msg_buf_len = snprintf(msg_buf, msg_buf_max, "System error code 0x%08x", (unsigned)error_code); } if (buf != NULL) LocalFree(buf); while (msg_buf_len > 0 && msg_buf[msg_buf_len - 1] <= ' ') msg_buf_len--; if (msg_buf_len > 0 && msg_buf[msg_buf_len - 1] == '.') msg_buf_len--; msg_buf[msg_buf_len] = 0; return msg_buf; }
static void clear_stale_peers(void * x) { PeerServer ** sp = &peers; PeerServer * s; time_t timenow = time(NULL); int keep_timer = 0; assert(is_dispatch_thread()); while ((s = *sp) != NULL) { if (s->expiration_time <= timenow) { /* Delete stale entry */ *sp = s->next; notify_listeners(s, PS_EVENT_REMOVED); s->listed = 0; peer_server_free(s); } else { keep_timer = 1; sp = &s->next; } } if (keep_timer) { post_event_with_delay(clear_stale_peers, NULL, PEER_DATA_REFRESH_PERIOD * 1000000); } else { stale_timer_active = 0; } }
void * tmp_alloc(size_t size) { void * p; LINK * l; assert(is_dispatch_thread()); if (!tmp_gc_posted) { post_event(gc_event, NULL); tmp_gc_posted = 1; } #if ENABLE_FastMemAlloc if (tmp_pool_pos + size + ALIGNMENT + sizeof(size_t *) > tmp_pool_max) { if (tmp_pool != NULL) { l = (LINK *)tmp_pool; list_add_last(l, &tmp_alloc_list); tmp_alloc_size += tmp_pool_pos; } tmp_pool_max = POOL_SIZE / 0x10 + size; tmp_pool = (char *)loc_alloc(tmp_pool_max); tmp_pool_pos = sizeof(LINK); } tmp_pool_pos += sizeof(size_t *); tmp_pool_pos = (tmp_pool_pos + ALIGNMENT - 1) & ~(ALIGNMENT - 1); p = tmp_pool + tmp_pool_pos; *((size_t *)p - 1) = size; tmp_pool_pos += size; return p; #else l = (LINK *)loc_alloc(sizeof(LINK) + size); list_add_last(l, &tmp_alloc_list); tmp_alloc_size += size + ALIGNMENT + sizeof(size_t *); p = l + 1; return p; #endif }
void cache_dispose(AbstractCache * cache) { assert(is_dispatch_thread()); assert(cache->wait_list_cnt == 0); assert(list_is_empty(&cache->link)); loc_free(cache->wait_list_buf); memset(cache, 0, sizeof(*cache)); }
static void np_channel_read_done(void * x) { AsyncReqInfo * req = (AsyncReqInfo *)x; ChannelNP * c = (ChannelNP *)req->client_data; ssize_t len = 0; assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->read_pending != 0); assert(c->lock_cnt > 0); loc_free(req->u.user.data); c->read_pending = 0; /* some data is available retrieve it */ { len = c->rd_req.u.user.rval; if (req->error) { if (c->chan.state != ChannelStateDisconnected) { trace(LOG_ALWAYS, "Can't read from socket: %s", errno_to_str(req->error)); } len = 0; /* Treat error as EOF */ } } if (c->chan.state != ChannelStateDisconnected) { ibuf_read_done(&c->ibuf, len); } else if (len > 0) { np_post_read(&c->ibuf, c->ibuf.buf, c->ibuf.buf_size); } else { np_unlock(&c->chan); } }
int set_trap_a(Trap * trap) { assert(is_dispatch_thread()); memset(trap, 0, sizeof(Trap)); trap->next = chain; chain = trap; return 0; }
static int np_is_closed(Channel * channel) { ChannelNP * c = channel2np(channel); assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->lock_cnt > 0); return c->chan.state == ChannelStateDisconnected; }
static int pipe_is_closed(Channel * channel) { ChannelPIPE * c = channel2pipe(channel); assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->lock_cnt > 0); return c->chan->state == ChannelStateDisconnected; }
static void handle_channel_msg(void * x) { Trap trap; ChannelNP * c = (ChannelNP *)x; int has_msg; assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->ibuf.handling_msg == HandleMsgTriggered); assert(c->ibuf.message_count); has_msg = ibuf_start_message(&c->ibuf); if (has_msg <= 0) { if (has_msg < 0 && c->chan.state != ChannelStateDisconnected) { trace(LOG_PROTOCOL, "Socket is shutdown by remote peer, channel %#lx %s", c, c->chan.peer_name); channel_close(&c->chan); } } else if (set_trap(&trap)) { if (c->chan.receive) { c->chan.receive(&c->chan); } else { handle_protocol_message(&c->chan); assert(c->out_bin_block == NULL); } clear_trap(&trap); } else { trace(LOG_ALWAYS, "Exception in message handler: %s", errno_to_str(trap.error)); send_eof_and_close(&c->chan, trap.error); } }
int context_read_mem(Context * ctx, ContextAddress address, void * buf, size_t size) { ContextAddress word_addr; unsigned word_size = context_word_size(ctx); assert(is_dispatch_thread()); assert(!ctx->exited); trace(LOG_CONTEXT, "context: read memory ctx %#lx, id %s, address %#lx, size %zu", ctx, ctx->id, address, size); assert(word_size <= sizeof(unsigned long)); for (word_addr = address & ~((ContextAddress)word_size - 1); word_addr < address + size; word_addr += word_size) { unsigned long word = 0; errno = 0; word = ptrace(PTRACE_PEEKDATA, EXT(ctx)->pid, (char *)word_addr, 0); if (errno != 0) { int err = errno; trace(LOG_CONTEXT, "error: ptrace(PTRACE_PEEKDATA, ...) failed: ctx %#lx, id %s, addr %#lx, error %d %s", ctx, ctx->id, word_addr, err, errno_to_str(err)); errno = err; return -1; } if (word_addr < address || word_addr + word_size > address + size) { size_t i; for (i = 0; i < word_size; i++) { if (word_addr + i >= address && word_addr + i < address + size) { ((char *)buf)[word_addr + i - address] = ((char *)&word)[i]; } } } else { memcpy((char *)buf + (word_addr - address), &word, word_size); } } return check_breakpoints_on_memory_read(ctx, address, buf, size); }
static void tcp_flush_with_flags(ChannelTCP * c, int flags) { unsigned char * p = c->obuf; assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->chan.out.end == p + sizeof(c->obuf)); assert(c->out_bin_block == NULL); assert(c->chan.out.cur >= p); assert(c->chan.out.cur <= p + sizeof(c->obuf)); if (c->chan.out.cur == p) return; if (c->chan.state != ChannelStateDisconnected && c->out_errno == 0) { #if ENABLE_OutputQueue c->out_queue.post_io_request = post_write_request; output_queue_add(&c->out_queue, p, c->chan.out.cur - p); #else assert(c->ssl == NULL); while (p < c->chan.out.cur) { size_t sz = c->chan.out.cur - p; ssize_t wr = send(c->socket, p, sz, flags); if (wr < 0) { int err = errno; trace(LOG_PROTOCOL, "Can't send() on channel %#lx: %s", c, errno_to_str(err)); c->out_errno = err; c->chan.out.cur = c->obuf; return; } p += wr; } assert(p == c->chan.out.cur); #endif } c->chan.out.cur = c->obuf; }
void * tmp_realloc(void * ptr, size_t size) { if (ptr == NULL) return tmp_alloc(size); assert(is_dispatch_thread()); assert(tmp_gc_posted); #if ENABLE_FastMemAlloc { void * p; size_t m = *((size_t *)ptr - 1); if (m >= size) return ptr; if ((char *)ptr >= tmp_pool && (char *)ptr <= tmp_pool + tmp_pool_max) { size_t pos = tmp_pool_pos - m; if (ptr == tmp_pool + pos && pos + size <= tmp_pool_max) { tmp_pool_pos = pos + size; *((size_t *)ptr - 1) = size; return ptr; } } p = tmp_alloc(size); if (m > size) m = size; return memcpy(p, ptr, m); } #else { LINK * l = (LINK *)ptr - 1; list_remove(l); l = (LINK *)loc_realloc(l, sizeof(LINK) + size); list_add_last(l, &tmp_alloc_list); return l + 1; } #endif }
static void connect_port_callback(PortConnection * conn, int error) { assert(is_dispatch_thread()); port_unlock(conn); if (conn->shutdown_in_progress) return; if (error != 0) { port_connection_close(conn); return; } else { int idx; if (conn->server->connect_callback) conn->server->connect_callback(conn->server, conn->server->callback_data); conn->connected = 1; if (conn->fd != -1) { port_lock(conn); conn->recv_req.u.sio.sock = conn->fd; conn->recv_req.u.sio.addr = &conn->server->client_addr; conn->recv_req.u.sio.addrlen = sizeof(conn->server->client_addr); async_req_post(&conn->recv_req); } /* Send multiple TCF streams read requests in parallel; this is * to limit the performance impact on network with high latency. */ for (idx = 0; idx < MAX_STREAM_READ; idx++) read_packet(conn, idx); } }
int set_win32_errno(DWORD win32_error_code) { if (win32_error_code == 0) return errno = 0; if (win32_error_code >= ERR_WINDOWS_CNT) { if (!is_dispatch_thread()) return errno = ERR_OTHER; return set_errno(ERR_OTHER, system_strerror(win32_error_code, NULL)); } return errno = ERR_WINDOWS_MIN + win32_error_code; }
static void tcp_flush_with_flags(OutputStream * out, int flags) { int cnt = 0; ChannelTCP * c = channel2tcp(out2channel(out)); assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->obuf_inp <= BUF_SIZE); if (c->obuf_inp == 0) return; if (c->socket < 0 || c->out_errno) { c->obuf_inp = 0; return; } while (cnt < c->obuf_inp) { int wr = 0; if (c->ssl) { #if ENABLE_SSL wr = SSL_write(c->ssl, c->obuf + cnt, c->obuf_inp - cnt); if (wr <= 0) { int err = SSL_get_error(c->ssl, wr); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { struct timeval tv; fd_set readfds; fd_set writefds; fd_set errorfds; FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&errorfds); if (err == SSL_ERROR_WANT_READ) FD_SET(c->socket, &readfds); if (err == SSL_ERROR_WANT_WRITE) FD_SET(c->socket, &writefds); FD_SET(c->socket, &errorfds); tv.tv_sec = 10L; tv.tv_usec = 0; if (select(c->socket + 1, &readfds, &writefds, &errorfds, &tv) >= 0) continue; } trace(LOG_PROTOCOL, "Can't SSL_write() on channel %#lx: %s", c, ERR_error_string(ERR_get_error(), NULL)); c->out_errno = EIO; c->obuf_inp = 0; return; } #else assert(0); #endif } else { wr = send(c->socket, c->obuf + cnt, c->obuf_inp - cnt, flags); if (wr < 0) { int err = errno; trace(LOG_PROTOCOL, "Can't send() on channel %#lx: %d %s", c, err, errno_to_str(err)); c->out_errno = err; c->obuf_inp = 0; return; } } cnt += wr; } assert(cnt == c->obuf_inp); c->obuf_inp = 0; }
static void channel_check_pending(Channel * channel) { ChannelNP * c = channel2np(channel); assert(is_dispatch_thread()); if (c->ibuf.handling_msg == HandleMsgIdle && c->ibuf.message_count) { post_event(handle_channel_msg, c); c->ibuf.handling_msg = HandleMsgTriggered; } }
/* Find peer server based on ID */ PeerServer * peer_server_find(const char * id) { PeerServer * s; assert(is_dispatch_thread()); for (s = peers; s != NULL; s = s->next) { if (strcmp(s->id, id) == 0) return s; } return NULL; }
void release_error_report(ErrorReport * r) { if (r != NULL) { ReportBuffer * report = (ReportBuffer *)((char *)r - offsetof(ReportBuffer, pub)); assert(is_dispatch_thread()); assert(report->gets > 0); report->gets--; release_report(report); } }
int context_continue(Context * ctx) { int signal = 0; assert(is_dispatch_thread()); assert(ctx->stopped); assert(!ctx->pending_intercept); assert(!EXT(ctx)->pending_step); assert(!ctx->exited); if (skip_breakpoint(ctx, 0)) return 0; if (!EXT(ctx)->ptrace_event) { while (ctx->pending_signals != 0) { while ((ctx->pending_signals & (1 << signal)) == 0) signal++; if (ctx->sig_dont_pass & (1 << signal)) { ctx->pending_signals &= ~(1 << signal); signal = 0; } else { break; } } assert(signal != SIGSTOP); assert(signal != SIGTRAP); } trace(LOG_CONTEXT, "context: resuming ctx %#lx, id %s, with signal %d", ctx, ctx->id, signal); if (EXT(ctx)->regs_dirty) { if (ptrace(PTRACE_SETREGS, EXT(ctx)->pid, 0, (int)EXT(ctx)->regs) < 0) { int err = errno; if (err == ESRCH) { EXT(ctx)->regs_dirty = 0; send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_SETREGS) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } EXT(ctx)->regs_dirty = 0; } if (ptrace(PTRACE_CONT, EXT(ctx)->pid, 0, signal) < 0) { int err = errno; if (err == ESRCH) { send_context_started_event(ctx); return 0; } trace(LOG_ALWAYS, "error: ptrace(PTRACE_CONT, ...) failed: ctx %#lx, id %s, error %d %s", ctx, ctx->id, err, errno_to_str(err)); errno = err; return -1; } ctx->pending_signals &= ~(1 << signal); send_context_started_event(ctx); return 0; }
static void signal_handler(int sig) { if (is_dispatch_thread()) { discovery_stop(); signal(sig, SIG_DFL); raise(sig); } else { post_event(shutdown_event, NULL); } }
static void tcp_unlock(Channel * channel) { ChannelTCP * c = channel2tcp(channel); assert(is_dispatch_thread()); assert(c->magic == CHANNEL_MAGIC); assert(c->lock_cnt > 0); c->lock_cnt--; if (c->lock_cnt == 0 && !c->read_pending) { delete_channel(c); } }
static void np_trigger_message(InputBuf * ibuf) { ChannelNP * c = ibuf2np(ibuf); assert(is_dispatch_thread()); assert(c->ibuf.message_count > 0); if (c->ibuf.handling_msg == HandleMsgIdle) { post_event(handle_channel_msg, c); c->ibuf.handling_msg = HandleMsgTriggered; } }
static void disconnect_port(PortConnection * conn) { assert (is_dispatch_thread()); conn->shutdown_in_progress = 1; port_lock(conn); protocol_send_command(conn->server->channel, "PortForward", "delete", delete_config_done, conn); json_write_string(&conn->server->channel->out, conn->id); write_stream(&conn->server->channel->out, MARKER_EOA); write_stream(&conn->server->channel->out, MARKER_EOM); }
void cache_exit(void) { unsigned i; assert(is_dispatch_thread()); assert(current_client.client != NULL); if (cache_miss_cnt > 0) exception(ERR_CACHE_MISS); for (i = 0; i < listeners_cnt; i++) listeners[i](CTLE_COMMIT); memset(¤t_client, 0, sizeof(current_client)); current_cache = NULL; cache_miss_cnt = 0; def_channel = NULL; }