#include "context.h" #include "packet.h" #include #include #include #include #include #include #include void debug_context_init(struct debug_context *ctx) { memset(ctx, 0x0, sizeof *ctx); ctx->ctx_sock = -1; pthread_mutex_init(&ctx->ctx_packet_lock, NULL); pthread_cond_init(&ctx->ctx_packet_cond, NULL); } void debug_context_cleanup(struct debug_context *ctx) { ctx->ctx_quit = true; if (ctx->ctx_sock != -1) { close(ctx->ctx_sock); } pthread_join(ctx->ctx_packet_thread, NULL); } static void *packet_thread(void *arg) { struct debug_context *ctx = arg; while (!ctx->ctx_quit) { struct mxdbg_packet hdr; int err = 0; size_t r; err = debug_context_recv(ctx, &hdr, sizeof hdr, &r); if (err != 0) { printf("packet recv failed\n"); continue; } if (r != sizeof hdr) { printf("packet size is wrong\n"); continue; } if (!mxdbg_packet_validate(&hdr)) { printf("packet is malformed\n"); continue; } struct packet *packet = packet_create(hdr.pkt_length); if (!packet) { printf("packet alloc failed\n"); continue; } memcpy(&packet->p_packet, &hdr, sizeof hdr); err = debug_context_recv_packet_data( ctx, &packet->p_packet, &r); if (err != 0) { printf("packet data read failed\n"); free(packet); continue; } pthread_mutex_lock(&ctx->ctx_packet_lock); fx_queue_push_back(&ctx->ctx_packets, &packet->p_entry); pthread_cond_broadcast(&ctx->ctx_packet_cond); pthread_mutex_unlock(&ctx->ctx_packet_lock); } return NULL; } static void *event_thread(void *arg) { struct debug_context *ctx = arg; while (!ctx->ctx_quit) { struct packet *packet = debug_context_await_packet(ctx, MXDBG_PACKET_EVENT); ctx->ctx_on_event(ctx, packet); packet_destroy(packet); } return NULL; } void debug_context_start_threads(struct debug_context *ctx) { pthread_create(&ctx->ctx_packet_thread, NULL, packet_thread, ctx); pthread_create(&ctx->ctx_event_thread, NULL, event_thread, ctx); } int debug_context_connect_net( struct debug_context *ctx, const char *address, int port) { ctx->ctx_sock = socket(AF_INET, SOCK_STREAM, 0); if (ctx->ctx_sock < 0) { return -1; } struct sockaddr_in dest = {0}; dest.sin_family = AF_INET; dest.sin_port = htons(port); inet_pton(AF_INET, address, &dest.sin_addr); return connect(ctx->ctx_sock, (struct sockaddr *)&dest, sizeof dest); } int debug_context_recv( struct debug_context *ctx, void *p, size_t len, size_t *nr_read) { size_t total_read = 0; unsigned char *buf = p; while (total_read < len) { long r = read(ctx->ctx_sock, p + total_read, len - total_read); if (r < 0) { return -1; } total_read += r; } *nr_read = total_read; return 0; } int debug_context_send_packet( struct debug_context *ctx, const struct mxdbg_packet *packet) { pthread_mutex_lock(&ctx->ctx_sock_lock); int err = 0; size_t len = packet->pkt_length; size_t total_written = 0; const unsigned char *buf = (const unsigned char *)packet; while (total_written < len) { long w = write(ctx->ctx_sock, buf + total_written, len - total_written); if (w < 0) { err = -1; break; } total_written += w; } pthread_mutex_unlock(&ctx->ctx_sock_lock); return err; } int debug_context_recv_packet_data( struct debug_context *ctx, struct mxdbg_packet *packet, size_t *nr_read) { if (packet->pkt_magic != MXDBG_PACKET_MAGIC) { return -1; } if (!packet->pkt_length) { *nr_read = 0; return 0; } void *dest = packet + 1; return debug_context_recv( ctx, dest, packet->pkt_length - sizeof *packet, nr_read); } static struct packet *dequeue_packet( struct debug_context *ctx, enum mxdbg_packet_type packet_type) { fx_queue_entry *cur = fx_queue_first(&ctx->ctx_packets); while (cur) { struct packet *packet = fx_unbox(struct packet, cur, p_entry); if (packet->p_packet.pkt_type == packet_type) { fx_queue_delete(&ctx->ctx_packets, cur); return packet; } cur = fx_queue_next(cur); } return NULL; } struct packet *debug_context_await_packet( struct debug_context *ctx, enum mxdbg_packet_type packet_type) { pthread_mutex_lock(&ctx->ctx_packet_lock); struct packet *result = NULL; while (1) { result = dequeue_packet(ctx, packet_type); if (result) { break; } pthread_cond_wait(&ctx->ctx_packet_cond, &ctx->ctx_packet_lock); } pthread_mutex_unlock(&ctx->ctx_packet_lock); return result; }