
 #include "java_common.h"

// #include "bpf_tracing.h"
// #include "bpf_helpers.h"
// #include <asm/ptrace.h>
// #include "bpf_base.h"
// #define ROCK_MAX_BUFFER_SIZE 65536

#define ROCK_MAX_LEN 1022

//struct sock_t {
//	int size;
//	int header_offset_idx;
//	char payload[ROCK_MAX_LEN];
//};
//
//struct {
//	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
//	__type(key, int);
//	__type(value, struct sock_t);
//	__uint(max_entries, 1);
//} socket_heap SEC(".maps");

//struct {
//	__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
//	__type(key, int);
//	__type(value, struct apm_span_context);
//	__uint(max_entries, 1);
//} apm_span_context_heap SEC(".maps");

 struct {
	 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
	 __uint(key_size, 4);
	 __uint(value_size, 4);
	 __uint(max_entries, 2);
 } jmp_table1 SEC(".maps");

//struct {
//	__uint(type, BPF_MAP_TYPE_ARRAY);
//	__type(key, int); // 键类型为int
//	__uint(value_size, 124); // 数组的值的大小
//	__uint(max_entries, 1);
//} large_array_map SEC(".maps");

#define CHECK_BYTE(data, idx, c) if (data[idx] != c) return 0;
static __inline int check_partial_header(const char *data, u32 i) {
	 CHECK_BYTE(data, i + 2, 'c');
	 CHECK_BYTE(data, i + 3, 'w');
	 CHECK_BYTE(data, i + 4, 't');
	 CHECK_BYTE(data, i + 5, 'r');
	 CHECK_BYTE(data, i + 6, 'a');
	 CHECK_BYTE(data, i + 7, 'c');
	 CHECK_BYTE(data, i + 8, 'e');
//	 CHECK_BYTE(data, i + 9, ':');
//	 CHECK_BYTE(data, i + 10, ' ');
	 return 1;
 }

static __inline u32 get_http_header_offset(const char *data, u32 offset, u32 len) {
#pragma clang loop unroll(full)
	for (u32 i = offset; i < len; i++) {
		if (data[i] == '\r' && data[i + 1] == '\n' && check_partial_header(data, i)) {
			return i + 11;
		}

//		if (data[i] == '\r' &&
//		   data[i + 1] == '\n' &&
//		   data[i + 2] == 'c' &&
//		   data[i + 3] == 'w' &&
//		   data[i + 4] == 't' &&
//		   data[i + 5] == 'r' &&
//		   data[i + 6] == 'a' &&
//		   data[i + 7] == 'c' &&
//		   data[i + 8] == 'e'
////		   data[i + 9] == ':' &&
////		   data[i + 10] == ' '
//		   ) {
//			return i + 11;
//		}
	 }
	 return 0;
 }

static __inline u32 has_cw_header(const char *data)
{
	// cw header 查询
	long cw_header_native_lo = 0x6361727477630a0dLL; // 小端序下的 "\r\ncwtrac" {0x0d,0x0a,0x63,0x77,0x74,0x72,0x61,0x63}
	long cw_header_native_up = 0x6361727477430a0dLL; // 小端序下的 "\r\nCwtrac" {0x0d,0x0a,0x43,0x77,0x74,0x72,0x61,0x63}
#pragma clang loop unroll(full)
	for (u32 i = 0; i < 500 - 8; i++) {
		long tmp_data = *(long long *) (data + i);
		if (tmp_data == cw_header_native_lo || tmp_data == cw_header_native_up) {
			return i+11;
		}
	}
	return 0;

//	u32 ii;
//#pragma unroll
//	for (int i = 0; i < 11; ++i) {
//		ii = get_http_header_offset(data, i * 25, (i + 1) * 25);
//		if (ii > 0) {
//			break;
//		}
//	}
//	return ii;
//	if (ii > 0) {
//		u32 key = 0;
//		struct sock_t *map_data = bpf_map_lookup_elem(&socket_heap, &key);
//		if (!map_data) {
//			return 0;
//		}
//		map_data->header_offset_idx = ii;
//	}


//	u32 i = get_http_header_offset(data, 0, 275);

//	u32 i = get_http_header_offset(data, 0, 25);
//	if (i == 0) {
//		i = get_http_header_offset(data, 25, 50);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 50, 75);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 75, 100);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 100, 125);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 125, 150);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 150, 175);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 175, 200);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 200, 225);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 225, 250);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 250, 275);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 275, 300);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 300, 325);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 325, 350);
//	}
//	if (i == 0) {
//		i = get_http_header_offset(data, 350, 500);
//	}
//	return i;
}

SEC("uprobe/Java_sun_nio_ch_FileDispatcherImpl_read0")
int uprobe_ret_Java_sun_nio_ch_FileDispatcherImpl_read0(struct pt_regs *ctx) {
	//计算 rbp-0x30
//	cw_bpf_debug("enter the ret uprobe_Java_sun_nio_ch_FileDispatcherImpl_read0\n");
	unsigned long jhttpdata_ptr;
	// jhttpdata_ptr = (ctx)->rsi;
	PT_HTTP_RESP_REGS(ctx, jhttpdata_ptr);
//	cw_bpf_debug("enter rsi is %llx.\n", jhttpdata_ptr);
	
	//x/s addr
	u32 key = 0;
//	struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&apm_span_context_heap, &key);
//	if (cw_parent_span_context == NULL) {
//		return -1;
//	}

//	int offset = 0;
	struct sock_t *map_data = bpf_map_lookup_elem(&socket_heap, &key);
	if (!map_data) {
		return 0;
	}

	long err = bpf_probe_read_user(map_data->payload, sizeof(map_data->payload), (void *) (jhttpdata_ptr));
	if (err < 0) {
//		cw_bpf_debug("bpf_probe_read_user failed with return code: %d\n", err);
		return 0;
	}
	if (map_data->payload[0] != 'G' &&
	    map_data->payload[0] != 'P' &&
	    map_data->payload[0] != 'D' &&
	    !(map_data->payload[0] == 'H' && map_data->payload[1] == 'E') &&
	    map_data->payload[0] != 'O') {
		return -1;
	}

	cw_bpf_debug("read data is : %s\n", map_data->payload);

	u32 offset = has_cw_header(map_data->payload);
	map_data->header_offset_idx = offset;
	cw_bpf_debug("[Jvm service] Header offset: [%d]\n", offset);
//	bpf_tail_call(ctx, &jmp_table1, 0);
	bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_DATA_SAVE_UP_IDX);
	return 0;
}

// bpf_prog_up__save_sc
 PROGUP(java_save_sc)(struct pt_regs *ctx) {
	 u32 key = 0;

	 struct sock_t *map_data = bpf_map_lookup_elem(&socket_heap, &key);
	 if (!map_data) {
		 return 0;
	 }

	 struct apm_span_context *cw_parent_span_context = bpf_map_lookup_elem(&apm_span_context_heap, &key);
	 if (cw_parent_span_context == NULL) {
		 return -1;
	 }
	 __builtin_memset(cw_parent_span_context, 0, sizeof(struct apm_span_context));

	 if (map_data->header_offset_idx >0) {
		 cw_string_to_span_context(&map_data->payload[map_data->header_offset_idx], cw_parent_span_context);
	 } else {
		 generate_random_bytes(cw_parent_span_context->trace_id, TRACE_ID_SIZE);
	 }

	 // 保存 trace_id 到psc
	 cw_save_parent_tracking_span(cw_parent_span_context);
	 return 0;
 }