// Copyright The CW Authors


#include "netcore_common.h"
static __inline int updataSocket3(struct sock_t *map_data_res, char * payload,int len,void * jbytechar_ptr,void * len_from_rbp_ptr) {

	long res = bpf_probe_write_user((void *) jbytechar_ptr,  &map_data_res->payload, sizeof(map_data_res->payload));
	bpf_printk("sizeof(map_data_res->payload) %d\n", sizeof(map_data_res->payload));
	bpf_printk("sizeof(payload) %d\n", sizeof(payload));
	bpf_printk("&payload 0x%lx\n", &payload);

	if (res == 0) {
		bpf_printk("Successfully wrote value to user address: 0x%lx\n", jbytechar_ptr);
	} else {
		bpf_printk("Failed to write value to user address: %p, error: %ld\n", jbytechar_ptr, res);
	}

	unsigned long new_val;
	new_val = len;
	res = bpf_probe_write_user((void *) len_from_rbp_ptr, &new_val, sizeof(new_val));
	if (res == 0) {
		bpf_printk("Successfully wrote value to user address: 0x%lx\n", len_from_rbp_ptr);
	} else {
		bpf_printk("Failed to write value to user address: %p, error: %ld\n", len_from_rbp_ptr, res);
	}

	bpf_printk("len %d\n", len);

//	bpf_printk("payload %s\n", payload);
//	for (int i = 270; i < len; ++i) {
//		bpf_printk("data[%d]=%c", i,payload[i]);
//		if(payload[i]=='\0'){
//			break;
//		}
//	}
	return 0;
}

static __inline int updataSocket4(struct sock_t *map_data_res,void * jbytechar_ptr,void * len_from_rbp_ptr) {

	long res = bpf_probe_write_user((void *) jbytechar_ptr, &map_data_res->payload, sizeof(map_data_res->payload));
	if (res == 0) {
		bpf_printk("Successfully wrote value to user address: 0x%lx\n", jbytechar_ptr);
	} else {
		bpf_printk("Failed to write value to user address: %p, error: %ld\n", jbytechar_ptr, res);
	}

	unsigned long new_val;
	new_val = map_data_res->size;
	res = bpf_probe_write_user((void *) len_from_rbp_ptr, &new_val, sizeof(new_val));
	if (res == 0) {
		bpf_printk("Successfully wrote value to user address: 0x%lx\n", len_from_rbp_ptr);
	} else {
		bpf_printk("Failed to write value to user address: %p, error: %ld\n", len_from_rbp_ptr, res);
	}

	bpf_printk("Successfully %d\n", map_data_res->size);

	bpf_printk("Successfully %s\n", map_data_res->payload);
//	for (int i = 270; i < 290; ++i) {
//		bpf_printk("data[%d]=%c", i,map_data_res->payload[i]);
//		if(map_data_res->payload[i]=='\0'){
//			break;
//		}
//	}
	return 0;
}

static __inline struct sock_t* buildHeader2(struct sock_t *map_data) {

	int key = 0;
	struct sock_t *map_data_res = bpf_map_lookup_elem(&socket_res, &key);

	if (!map_data_res) {
		bpf_printk("Failed to lookup socket_heap");
		return NULL;
	}

//	__builtin_memset(map_data_res, 0, sizeof(struct sock_t));
//	char header[5] = "cwt\r\n";

//	char header[CW_STREAM_HEADER_LEN] = "cwtrace: 00:00:1015481350055581:5450531005555981:5610250100539899:304775019cd3218a304775019cd3218a:1001025098564810:140acc88cde8773f\r\n";
	struct apm_span_context *cw_span_context = bpf_map_lookup_elem(&apm_span_context_heap, &key);

	if (cw_span_context == NULL){
		return NULL;
	}

	struct apm_span_context *cw_psc = cw_get_parent_tracking_span();
	if(cw_psc){
		copy_byte_arrays(cw_psc->trace_id, cw_span_context->trace_id, APM_TRACE_ID_SIZE);
		// new spanid
		generate_random_bytes(cw_span_context->span_id, APM_SPAN_ID_SIZE);
	}

	// set host_id/appid
	u32 k0 = 0;
	struct trace_conf_t *trace_conf = trace_conf_map__lookup(&k0);
	if (trace_conf) {
		for (int i = 0; i < 8; ++i) {
//			cw_bpf_debug("[Client] host_id:%02x", trace_conf->host_id[i]);
		}
		copy_byte_arrays(trace_conf->host_id, cw_span_context->host_id, APM_HOST_ID_SIZE);
		copy_byte_arrays(trace_conf->app_id, cw_span_context->app_id, APM_APP_ID_SIZE);
	}

	__u64 pid_tgid = bpf_get_current_pid_tgid();
	__u32 tgid = pid_tgid >> 32;
	struct ebpf_proc_info *proc_info =
			bpf_map_lookup_elem(&proc_info_map, &tgid);
	if (proc_info) {
		for (int i = 0; i < 8; ++i) {
//			cw_bpf_debug("[Client] instance_id:%02x", proc_info->instance_id[i]);
		}
		copy_byte_arrays(proc_info->instance_id, cw_span_context->instance_id, APM_APP_ID_SIZE);
	}

	// set assumed_app_id
	set_assumed_app_id_arrays("111", cw_span_context->assumed_app_id, APM_ASSUMED_APP_ID_STRING_SIZE);
	cw_save_current_tracking_span(cw_span_context);

	char header[CW_STREAM_HEADER_LEN];
	span_context_to_cw_string_stream(cw_span_context, header, '1');
	bpf_printk("Successfully HEADER  %s\n", header);

// bpf_probe_read(map_data_res->payload, map_data->header_offset_idx, map_data->payload);
//	bpf_printk("Successfully %s\n", data);
//	return 1;
#pragma unroll
	for (int i = 0; i < MAX_LEN; i++) {
		if (i < map_data->header_offset_idx) {
			map_data_res->payload[i] = map_data->payload[i];
		} else {
			if (i == map_data->header_offset_idx) {
#pragma unroll
				for (int k = 0; k < CW_STREAM_HEADER_LEN; k++) {
					int tmp_len = i + k;
					if (tmp_len < MAX_LEN) {
						map_data_res->payload[tmp_len] = header[k];
					}
				}
			}
			int tmp_len = i + CW_STREAM_HEADER_LEN;
			if (tmp_len < MAX_LEN) {
				map_data_res->payload[tmp_len] = map_data->payload[i];
				if (map_data->payload[i] == '\0')
					break;
//				bpf_printk("map_data->payload: %c->i=%d, offindex %d", map_data_res->payload[i], i, map_data->header_offset_idx);
			}
		}
	}
	map_data_res->size = map_data->size + CW_STREAM_HEADER_LEN;

	return map_data_res;
}

static __inline int insertHeader2(struct sock_t *map_data,void * jbytechar_ptr,void * len_from_rbp_ptr) {

	struct sock_t *map_data_res= buildHeader2(map_data);
	if (map_data_res == NULL) {
		bpf_printk("Failed to lookup socket_heap");
		return -1;
	}

	/*修改部分*/
	// bpf_printk("map_data->payload: %s, len %d\n", map_data_res->payload, map_data_res->size);
	return updataSocket3(map_data_res, map_data_res->payload, map_data_res->size, jbytechar_ptr, len_from_rbp_ptr);
}


SEC("uprobe/netcore_asmnop")
int netcore_asmnop(struct pt_regs *ctx) {
	bpf_printk("enter the ret netcore_asmnop\n");
	unsigned long jhttpdata_ptr;
#if defined(__x86_64__)
	jhttpdata_ptr = (ctx)->rsi;
	unsigned long len_from_rbp_ptr = (ctx)->rsp-0x8;
#elif defined(__aarch64__)
	jhttpdata_ptr = (ctx)->regs[1];
	unsigned long len_from_rbp_ptr = (ctx)->regs[16]-0x8;
#endif
	bpf_printk("[len_from_rbp_ptr] <0x%lx>", len_from_rbp_ptr);

	// 捕获第六个参数 data_count
	int data_count = PT_REGS_PARM3(ctx);
	if (data_count < MIN_LEN) {
		return 0;
	}

	cw_bpf_debug("[netcore client] data_count:%d\n", data_count);

	void *len_ptr = 0;
	cw_bpf_debug("[netcore client] address: len_from_rbp_ptr<0x%lx>\n", len_from_rbp_ptr);

	bpf_probe_read(&len_ptr, sizeof(len_ptr), (void *) len_from_rbp_ptr);
	cw_bpf_debug("[netcore client] [len_ptr] before addr<0x%lx>, %d \n", len_from_rbp_ptr, len_ptr);

	if ((long) len_ptr != data_count) {
		cw_bpf_debug("[netcore client] [len_ptr] check error.");
		return 0;
	}

	int key = 0;
	struct sock_t *map_data = bpf_map_lookup_elem(&socket_heap, &key);
	if (!map_data) {
		cw_bpf_debug("[netcore client] Failed to lookup socket_heap\n");
		return 1;
	}

	// 获取jbytearray
	__u32 tgid = (__u32) (bpf_get_current_pid_tgid() >> 32);
	map_data->proc_info = bpf_map_lookup_elem(&proc_info_map, &tgid);
	if (!map_data->proc_info) {
		return 0;
	}

	// 读取用户空间数据到 map_data->payload
	void *jbytechar_ptr = (void *) jhttpdata_ptr;
	// cw_bpf_debug("[java client] [jbytechar_ptr] <0x%lx>", jbytechar_ptr);
	long err = bpf_probe_read_user_str(map_data->payload, sizeof(map_data->payload), jbytechar_ptr);

	if (err < 0) {
		cw_bpf_debug("[netcore client] bpf_probe_read_user failed with return code: %d\n", err);
		return 0;
	}
	map_data->size = data_count;
	map_data->payload_char_p = (void *) jbytechar_ptr;
	map_data->payload_len_p = (void *) len_from_rbp_ptr;

	// http协议过滤
	if (!is_http_request2(map_data->payload, map_data->size)) {
		return -1;
	}

	// 查找 Header 开始位置
	long header_start_native = 0x0a0d312e312f5054LL; // 小端序下的 "TP/1.1\r\n" (0x54 0x50 0x2f 0x31 0x2e 0x31 0x0d 0x0a)
#pragma clang loop unroll(full)
	for (u32 i = 0; i < 200 - 8; i++) {
		long data = *(long long *) (map_data->payload + i);
		if (data == header_start_native) {
			map_data->header_offset_idx = i + 8;
			break;
		}
	}

	if (map_data->header_offset_idx == 0) {
		cw_bpf_debug("[netcore client] header_offset_idx error:\n");
		return 1;
	}

	map_data->end_str_len = data_count - map_data->header_offset_idx + 1;
	u32 copy_size = L7_IOVEC_BUF_SIZE;
	if (map_data->end_str_len > copy_size) {
		u32 chunk = (u32) map_data->end_str_len / copy_size;
		if (chunk > MAX_CHUNK) {
			cw_bpf_debug("[netcore client] Exceeding the max_chunk:%d need_chunk:%d\n", MAX_CHUNK, chunk);
			return 1;
		}
	}
	cw_bpf_debug("[netcore client] header_offset_idx:%d\n", map_data->header_offset_idx);

	// tail payload保存
	u32 tail_key = 1;
	char *tail_payload = bpf_map_lookup_elem(&large_array_map, &tail_key);
	if (!tail_payload) {
		// cw_bpf_debug("[java client ]header ->end %s\n", tail_payload);
		return 1;
	}
	__builtin_memset(tail_payload, 0, sizeof(char *));

	bpf_probe_read_user_str(tail_payload, JAVA_MAX_BUFFER_SIZE,
	                        (void *) (jbytechar_ptr + map_data->header_offset_idx));
	// host查询
	bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_DATA_JAVA_FIND_HOST_UP_IDX);
	return 0;

	bpf_tail_call(ctx, &NAME(progs_jmp_up_map), PROG_DATA_JAVA_UPDATE_HEADER_UP_IDX);

	return 0;
}
