http支持

This commit is contained in:
2026-04-25 12:33:18 +08:00
parent f22930acae
commit 8c350bbc10
9 changed files with 714 additions and 30 deletions

View File

@@ -128,7 +128,7 @@ list(SORT DOOMGENERIC_DEP_SOURCES_ABS)
set(USER_SHELL_COMMAND_APPS
help args ls cat grep head tail wc cut uniq sort pwd cd exec pid spawn wait sleep yield
ping ifconfig nslookup
ping ifconfig nslookup httpget
bg fg jobs kill ps top
procstat sysstat
diskinfo mkfsfat32 mount partctl

View File

@@ -33,9 +33,10 @@ static int ush_cmd_help(void) {
ush_writeln(" mkfsfat32 [label]");
ush_writeln(" mount [path] (default suggested: /temp/disk)");
ush_writeln(" partctl <subcommand> (mbr partition control: list/init-mbr/create/delete/set-boot)");
ush_writeln(" ping <a.b.c.d> [count]");
ush_writeln(" ifconfig");
ush_writeln(" nslookup <domain>");
ush_writeln(" ping <a.b.c.d> [count]");
ush_writeln(" ifconfig");
ush_writeln(" nslookup <domain>");
ush_writeln(" httpget <http://host[:port]/path>");
ush_writeln(" pid");
ush_writeln(" spawn <path|name> [args...] / bg <path|name> [args...]");
ush_writeln(" wait <pid> / fg [pid]");

View File

@@ -0,0 +1,609 @@
#include "cmd_runtime.h"
#include <stdio.h>
#define USH_HTTPGET_HOST_MAX 128U
#define USH_HTTPGET_PATH_MAX 256U
#define USH_HTTPGET_DNS_PACKET_MAX 512U
#define USH_HTTPGET_RECV_CHUNK 2048U
#define USH_HTTPGET_TCP_POLL_BUDGET 200000000ULL
#define USH_HTTPGET_TCP_RECV_IDLE_LOOPS 120ULL
typedef unsigned char u8;
typedef unsigned short u16;
typedef struct ush_httpget_url {
char host[USH_HTTPGET_HOST_MAX];
char path[USH_HTTPGET_PATH_MAX];
u16 port;
} ush_httpget_url;
static u16 ush_httpget_read_be16(const u8 *ptr) {
return (u16)(((u16)ptr[0] << 8U) | (u16)ptr[1]);
}
static void ush_httpget_write_be16(u8 *ptr, u16 value) {
ptr[0] = (u8)((value >> 8U) & 0xFFU);
ptr[1] = (u8)(value & 0xFFU);
}
static int ush_httpget_parse_ipv4_be(const char *text, u64 *out_ipv4_be) {
u64 acc = 0ULL;
u64 value = 0ULL;
u64 parts = 0ULL;
u64 has_digit = 0ULL;
u64 i = 0ULL;
if (text == (const char *)0 || out_ipv4_be == (u64 *)0) {
return 0;
}
while (text[i] != '\0') {
char ch = text[i];
if (ch >= '0' && ch <= '9') {
value = (value * 10ULL) + (u64)(ch - '0');
if (value > 255ULL) {
return 0;
}
has_digit = 1ULL;
} else if (ch == '.') {
if (has_digit == 0ULL || parts >= 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
parts++;
value = 0ULL;
has_digit = 0ULL;
} else {
return 0;
}
i++;
}
if (has_digit == 0ULL || parts != 3ULL) {
return 0;
}
acc = (acc << 8ULL) | value;
*out_ipv4_be = acc & 0xFFFFFFFFULL;
return 1;
}
static void ush_httpget_print_ipv4(u64 ipv4_be) {
unsigned int a = (unsigned int)((ipv4_be >> 24ULL) & 0xFFULL);
unsigned int b = (unsigned int)((ipv4_be >> 16ULL) & 0xFFULL);
unsigned int c = (unsigned int)((ipv4_be >> 8ULL) & 0xFFULL);
unsigned int d = (unsigned int)(ipv4_be & 0xFFULL);
(void)printf("%u.%u.%u.%u", a, b, c, d);
}
static int ush_httpget_parse_url(const char *url, ush_httpget_url *out_url) {
const char *p;
const char *host_begin;
const char *host_end;
const char *path_begin;
u64 host_len;
u64 path_len;
u64 i;
if (url == (const char *)0 || out_url == (ush_httpget_url *)0) {
return 0;
}
ush_zero(out_url, (u64)sizeof(*out_url));
if (url[0] == '\0') {
return 0;
}
if (!(url[0] == 'h' && url[1] == 't' && url[2] == 't' && url[3] == 'p' && url[4] == ':' && url[5] == '/' &&
url[6] == '/')) {
return 0;
}
p = url + 7;
host_begin = p;
while (*p != '\0' && *p != '/') {
p++;
}
host_end = p;
host_len = (u64)(host_end - host_begin);
if (host_len == 0ULL || host_len >= (u64)sizeof(out_url->host)) {
return 0;
}
for (i = 0ULL; i < host_len; i++) {
out_url->host[i] = host_begin[i];
}
out_url->host[host_len] = '\0';
out_url->port = 80U;
for (i = 0ULL; i < host_len; i++) {
if (out_url->host[i] == ':') {
u64 parsed_port = 0ULL;
if (i == 0ULL || i + 1ULL >= host_len) {
return 0;
}
out_url->host[i] = '\0';
if (ush_parse_u64_dec(out_url->host + i + 1ULL, &parsed_port) == 0 || parsed_port == 0ULL ||
parsed_port > 65535ULL) {
return 0;
}
out_url->port = (u16)parsed_port;
break;
}
}
if (out_url->host[0] == '\0') {
return 0;
}
path_begin = (*p == '/') ? p : "/";
path_len = ush_strlen(path_begin);
if (path_len == 0ULL || path_len >= (u64)sizeof(out_url->path)) {
return 0;
}
for (i = 0ULL; i < path_len; i++) {
out_url->path[i] = path_begin[i];
}
out_url->path[path_len] = '\0';
return 1;
}
static int ush_httpget_dns_encode_qname(const char *host, u8 *out, u64 out_cap, u64 *out_len) {
const char *p;
u64 at = 0ULL;
if (host == (const char *)0 || out == (u8 *)0 || out_len == (u64 *)0 || out_cap < 2ULL || host[0] == '\0') {
return 0;
}
p = host;
while (*p != '\0') {
const char *dot = p;
u64 label_len;
u64 i;
while (*dot != '\0' && *dot != '.') {
dot++;
}
label_len = (u64)(dot - p);
if (label_len == 0ULL || label_len > 63ULL) {
return 0;
}
if (at + 1ULL + label_len + 1ULL > out_cap) {
return 0;
}
out[at++] = (u8)label_len;
for (i = 0ULL; i < label_len; i++) {
out[at++] = (u8)p[i];
}
if (*dot == '.') {
p = dot + 1;
} else {
p = dot;
}
}
out[at++] = 0U;
*out_len = at;
return 1;
}
static int ush_httpget_dns_skip_name(const u8 *msg, u64 msg_len, u64 *io_off) {
u64 pos;
u64 depth = 0ULL;
int jumped = 0;
if (msg == (const u8 *)0 || io_off == (u64 *)0 || *io_off >= msg_len) {
return 0;
}
pos = *io_off;
while (depth < 32ULL) {
u8 len;
if (pos >= msg_len) {
return 0;
}
len = msg[pos];
if (len == 0U) {
if (jumped == 0) {
*io_off = pos + 1ULL;
}
return 1;
}
if ((len & 0xC0U) == 0xC0U) {
u16 ptr;
if (pos + 1ULL >= msg_len) {
return 0;
}
ptr = (u16)(((u16)(len & 0x3FU) << 8U) | (u16)msg[pos + 1ULL]);
if ((u64)ptr >= msg_len) {
return 0;
}
if (jumped == 0) {
*io_off = pos + 2ULL;
jumped = 1;
}
pos = (u64)ptr;
depth++;
continue;
}
if ((len & 0xC0U) != 0U) {
return 0;
}
if (pos + 1ULL + (u64)len > msg_len) {
return 0;
}
pos += 1ULL + (u64)len;
if (jumped == 0) {
*io_off = pos;
}
depth++;
}
return 0;
}
static int ush_httpget_dns_parse_first_a(const u8 *resp, u64 resp_len, u16 expected_id, u64 *out_ipv4_be) {
u16 id;
u16 flags;
u16 qdcount;
u16 ancount;
u16 i;
u64 off = 12ULL;
if (resp == (const u8 *)0 || out_ipv4_be == (u64 *)0 || resp_len < 12ULL) {
return 0;
}
id = ush_httpget_read_be16(&resp[0]);
if (id != expected_id) {
return 0;
}
flags = ush_httpget_read_be16(&resp[2]);
qdcount = ush_httpget_read_be16(&resp[4]);
ancount = ush_httpget_read_be16(&resp[6]);
if ((flags & 0x8000U) == 0U) {
return 0;
}
if ((flags & 0x000FU) != 0U) {
return 0;
}
for (i = 0U; i < qdcount; i++) {
if (ush_httpget_dns_skip_name(resp, resp_len, &off) == 0) {
return 0;
}
if (off + 4ULL > resp_len) {
return 0;
}
off += 4ULL;
}
for (i = 0U; i < ancount; i++) {
u16 type;
u16 klass;
u16 rdlen;
if (ush_httpget_dns_skip_name(resp, resp_len, &off) == 0) {
return 0;
}
if (off + 10ULL > resp_len) {
return 0;
}
type = ush_httpget_read_be16(&resp[off + 0ULL]);
klass = ush_httpget_read_be16(&resp[off + 2ULL]);
rdlen = ush_httpget_read_be16(&resp[off + 8ULL]);
off += 10ULL;
if (off + (u64)rdlen > resp_len) {
return 0;
}
if (type == 1U && klass == 1U && rdlen == 4U) {
*out_ipv4_be = ((u64)resp[off] << 24ULL) | ((u64)resp[off + 1ULL] << 16ULL) |
((u64)resp[off + 2ULL] << 8ULL) | (u64)resp[off + 3ULL];
return 1;
}
off += (u64)rdlen;
}
return 0;
}
static int ush_httpget_dns_resolve_ipv4(const char *host, u64 *out_ipv4_be) {
u64 dns_server;
u8 query[USH_HTTPGET_DNS_PACKET_MAX];
u8 answer[USH_HTTPGET_DNS_PACKET_MAX];
u64 qname_len = 0ULL;
u64 query_len;
u16 txid;
u16 src_port;
cleonos_net_udp_send_req send_req;
u64 loops;
if (host == (const char *)0 || out_ipv4_be == (u64 *)0 || host[0] == '\0') {
return 0;
}
dns_server = cleonos_sys_net_dns_server();
if (dns_server == 0ULL) {
return 0;
}
txid = (u16)((cleonos_sys_timer_ticks() ^ 0x48A1ULL) & 0xFFFFULL);
src_port = (u16)(42000U + (txid % 20000U));
(void)memset(query, 0, sizeof(query));
if (ush_httpget_dns_encode_qname(host, query + 12ULL, (u64)sizeof(query) - 12ULL, &qname_len) == 0) {
return 0;
}
ush_httpget_write_be16(&query[0], txid);
ush_httpget_write_be16(&query[2], 0x0100U);
ush_httpget_write_be16(&query[4], 1U);
ush_httpget_write_be16(&query[6], 0U);
ush_httpget_write_be16(&query[8], 0U);
ush_httpget_write_be16(&query[10], 0U);
query_len = 12ULL + qname_len;
if (query_len + 4ULL > (u64)sizeof(query)) {
return 0;
}
ush_httpget_write_be16(&query[query_len], 1U);
ush_httpget_write_be16(&query[query_len + 2ULL], 1U);
query_len += 4ULL;
send_req.dst_ipv4_be = dns_server;
send_req.dst_port = 53ULL;
send_req.src_port = (u64)src_port;
send_req.payload_ptr = (u64)(usize)query;
send_req.payload_len = query_len;
if (cleonos_sys_net_udp_send(&send_req) != query_len) {
return 0;
}
for (loops = 0ULL; loops < 700ULL; loops++) {
cleonos_net_udp_recv_req recv_req;
u64 got;
u64 src_ip = 0ULL;
u64 src_p = 0ULL;
u64 dst_p = 0ULL;
recv_req.out_payload_ptr = (u64)(usize)answer;
recv_req.payload_capacity = (u64)sizeof(answer);
recv_req.out_src_ipv4_ptr = (u64)(usize)&src_ip;
recv_req.out_src_port_ptr = (u64)(usize)&src_p;
recv_req.out_dst_port_ptr = (u64)(usize)&dst_p;
got = cleonos_sys_net_udp_recv(&recv_req);
if (got == 0ULL) {
(void)cleonos_sys_sleep_ticks(2ULL);
continue;
}
if (src_p != 53ULL || src_ip != dns_server) {
continue;
}
if (ush_httpget_dns_parse_first_a(answer, got, txid, out_ipv4_be) != 0) {
return 1;
}
}
return 0;
}
static int ush_httpget_stdout_write(const void *buffer, u64 size) {
const u8 *bytes = (const u8 *)buffer;
u64 written_total = 0ULL;
if (size == 0ULL) {
return 1;
}
if (buffer == (const void *)0) {
return 0;
}
while (written_total < size) {
u64 written = cleonos_sys_fd_write(1ULL, bytes + written_total, size - written_total);
if (written == (u64)-1 || written == 0ULL) {
return 0;
}
written_total += written;
}
return 1;
}
static int ush_cmd_httpget(const char *arg) {
ush_httpget_url url;
u64 dst_ipv4_be = 0ULL;
cleonos_net_tcp_connect_req conn_req;
cleonos_net_tcp_send_req send_req;
char request[1024];
int request_len;
u64 sent;
u64 idle_loops = 0ULL;
if (arg == (const char *)0 || arg[0] == '\0') {
(void)puts("httpget: usage httpget <http://host[:port]/path>");
return 0;
}
if (ush_streq(arg, "--help") != 0 || ush_streq(arg, "-h") != 0) {
(void)puts("usage: httpget <http://host[:port]/path>");
(void)puts("note: https:// is not supported yet");
return 1;
}
if (cleonos_sys_net_available() == 0ULL) {
(void)puts("httpget: network unavailable");
return 0;
}
if (ush_httpget_parse_url(arg, &url) == 0) {
(void)puts("httpget: invalid URL, expected http://host[:port]/path");
return 0;
}
if (ush_httpget_parse_ipv4_be(url.host, &dst_ipv4_be) == 0) {
if (ush_httpget_dns_resolve_ipv4(url.host, &dst_ipv4_be) == 0) {
(void)fputs("httpget: DNS resolve failed for ", 1);
(void)puts(url.host);
return 0;
}
}
(void)fputs("httpget: connect ", 1);
ush_httpget_print_ipv4(dst_ipv4_be);
(void)printf(":%u\n", (unsigned int)url.port);
ush_zero(&conn_req, (u64)sizeof(conn_req));
conn_req.dst_ipv4_be = dst_ipv4_be;
conn_req.dst_port = (u64)url.port;
conn_req.src_port = 0ULL;
conn_req.poll_budget = USH_HTTPGET_TCP_POLL_BUDGET;
if (cleonos_sys_net_tcp_connect(&conn_req) == 0ULL) {
(void)puts("httpget: tcp connect failed");
return 0;
}
if (url.port != 80U) {
request_len = snprintf(request, sizeof(request),
"GET %s HTTP/1.1\r\nHost: %s:%u\r\nUser-Agent: cleonos-httpget/1.0\r\nAccept: */*\r\n"
"Connection: close\r\n\r\n",
url.path, url.host, (unsigned int)url.port);
} else {
request_len = snprintf(request, sizeof(request),
"GET %s HTTP/1.1\r\nHost: %s\r\nUser-Agent: cleonos-httpget/1.0\r\nAccept: */*\r\n"
"Connection: close\r\n\r\n",
url.path, url.host);
}
if (request_len <= 0 || (u64)request_len >= (u64)sizeof(request)) {
(void)cleonos_sys_net_tcp_close(USH_HTTPGET_TCP_POLL_BUDGET);
(void)puts("httpget: request build failed");
return 0;
}
send_req.payload_ptr = (u64)(usize)request;
send_req.payload_len = (u64)request_len;
send_req.poll_budget = USH_HTTPGET_TCP_POLL_BUDGET;
sent = cleonos_sys_net_tcp_send(&send_req);
if (sent != (u64)request_len) {
(void)cleonos_sys_net_tcp_close(USH_HTTPGET_TCP_POLL_BUDGET);
(void)puts("httpget: tcp send failed");
return 0;
}
for (;;) {
cleonos_net_tcp_recv_req recv_req;
u8 chunk[USH_HTTPGET_RECV_CHUNK];
u64 got;
recv_req.out_payload_ptr = (u64)(usize)chunk;
recv_req.payload_capacity = (u64)sizeof(chunk);
recv_req.poll_budget = 60000ULL;
got = cleonos_sys_net_tcp_recv(&recv_req);
if (got == 0ULL) {
idle_loops++;
if (idle_loops >= USH_HTTPGET_TCP_RECV_IDLE_LOOPS) {
break;
}
(void)cleonos_sys_sleep_ticks(1ULL);
continue;
}
idle_loops = 0ULL;
if (ush_httpget_stdout_write(chunk, got) == 0) {
(void)cleonos_sys_net_tcp_close(USH_HTTPGET_TCP_POLL_BUDGET);
(void)puts("\nhttpget: write failed");
return 0;
}
}
(void)cleonos_sys_net_tcp_close(USH_HTTPGET_TCP_POLL_BUDGET);
return 1;
}
int cleonos_app_main(void) {
ush_cmd_ctx ctx;
ush_cmd_ret ret;
ush_state sh;
char initial_cwd[USH_PATH_MAX];
int has_context = 0;
int success = 0;
const char *arg = "";
ush_zero(&ctx, (u64)sizeof(ctx));
ush_zero(&ret, (u64)sizeof(ret));
ush_init_state(&sh);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
if (ush_command_ctx_read(&ctx) != 0) {
if (ctx.cmd[0] != '\0' && ush_streq(ctx.cmd, "httpget") != 0) {
has_context = 1;
arg = ctx.arg;
if (ctx.cwd[0] == '/') {
ush_copy(sh.cwd, (u64)sizeof(sh.cwd), ctx.cwd);
ush_copy(initial_cwd, (u64)sizeof(initial_cwd), sh.cwd);
}
}
}
success = ush_cmd_httpget(arg);
if (has_context != 0) {
if (ush_streq(sh.cwd, initial_cwd) == 0) {
ret.flags |= USH_CMD_RET_FLAG_CWD;
ush_copy(ret.cwd, (u64)sizeof(ret.cwd), sh.cwd);
}
if (sh.exit_requested != 0) {
ret.flags |= USH_CMD_RET_FLAG_EXIT;
ret.exit_code = sh.exit_code;
}
(void)ush_command_ret_write(&ret);
}
return (success != 0) ? 0 : 1;
}

View File

@@ -1,6 +1,8 @@
#include "cmd_runtime.h"
#include <stdio.h>
#define USH_PING_POLL_BUDGET 200000000ULL
static int ush_ping_parse_ipv4_be(const char *text, u64 *out_ipv4_be) {
u64 acc = 0ULL;
u64 value = 0ULL;
@@ -111,7 +113,7 @@ static int ush_cmd_ping(const char *arg) {
(void)putchar('\n');
for (i = 0ULL; i < count; i++) {
u64 ok = cleonos_sys_net_ping(target_ipv4_be, 300000ULL);
u64 ok = cleonos_sys_net_ping(target_ipv4_be, USH_PING_POLL_BUDGET);
if (ok != 0ULL) {
(void)fputs("reply from ", 1);

View File

@@ -68,13 +68,32 @@ typedef struct cleonos_net_udp_send_req {
u64 payload_len;
} cleonos_net_udp_send_req;
typedef struct cleonos_net_udp_recv_req {
u64 out_payload_ptr;
u64 payload_capacity;
u64 out_src_ipv4_ptr;
u64 out_src_port_ptr;
u64 out_dst_port_ptr;
} cleonos_net_udp_recv_req;
typedef struct cleonos_net_udp_recv_req {
u64 out_payload_ptr;
u64 payload_capacity;
u64 out_src_ipv4_ptr;
u64 out_src_port_ptr;
u64 out_dst_port_ptr;
} cleonos_net_udp_recv_req;
typedef struct cleonos_net_tcp_connect_req {
u64 dst_ipv4_be;
u64 dst_port;
u64 src_port;
u64 poll_budget;
} cleonos_net_tcp_connect_req;
typedef struct cleonos_net_tcp_send_req {
u64 payload_ptr;
u64 payload_len;
u64 poll_budget;
} cleonos_net_tcp_send_req;
typedef struct cleonos_net_tcp_recv_req {
u64 out_payload_ptr;
u64 payload_capacity;
u64 poll_budget;
} cleonos_net_tcp_recv_req;
#define CLEONOS_SYSCALL_LOG_WRITE 0ULL
#define CLEONOS_SYSCALL_TIMER_TICKS 1ULL
@@ -175,10 +194,14 @@ typedef struct cleonos_net_udp_recv_req {
#define CLEONOS_SYSCALL_NET_IPV4_ADDR 96ULL
#define CLEONOS_SYSCALL_NET_PING 97ULL
#define CLEONOS_SYSCALL_NET_UDP_SEND 98ULL
#define CLEONOS_SYSCALL_NET_UDP_RECV 99ULL
#define CLEONOS_SYSCALL_NET_NETMASK 100ULL
#define CLEONOS_SYSCALL_NET_GATEWAY 101ULL
#define CLEONOS_SYSCALL_NET_DNS_SERVER 102ULL
#define CLEONOS_SYSCALL_NET_UDP_RECV 99ULL
#define CLEONOS_SYSCALL_NET_NETMASK 100ULL
#define CLEONOS_SYSCALL_NET_GATEWAY 101ULL
#define CLEONOS_SYSCALL_NET_DNS_SERVER 102ULL
#define CLEONOS_SYSCALL_NET_TCP_CONNECT 103ULL
#define CLEONOS_SYSCALL_NET_TCP_SEND 104ULL
#define CLEONOS_SYSCALL_NET_TCP_RECV 105ULL
#define CLEONOS_SYSCALL_NET_TCP_CLOSE 106ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length);
@@ -280,9 +303,13 @@ u64 cleonos_sys_net_available(void);
u64 cleonos_sys_net_ipv4_addr(void);
u64 cleonos_sys_net_netmask(void);
u64 cleonos_sys_net_gateway(void);
u64 cleonos_sys_net_dns_server(void);
u64 cleonos_sys_net_ping(u64 dst_ipv4_be, u64 poll_budget);
u64 cleonos_sys_net_udp_send(const cleonos_net_udp_send_req *req);
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req);
#endif
u64 cleonos_sys_net_dns_server(void);
u64 cleonos_sys_net_ping(u64 dst_ipv4_be, u64 poll_budget);
u64 cleonos_sys_net_udp_send(const cleonos_net_udp_send_req *req);
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req);
u64 cleonos_sys_net_tcp_connect(const cleonos_net_tcp_connect_req *req);
u64 cleonos_sys_net_tcp_send(const cleonos_net_tcp_send_req *req);
u64 cleonos_sys_net_tcp_recv(cleonos_net_tcp_recv_req *req);
u64 cleonos_sys_net_tcp_close(u64 poll_budget);
#endif

View File

@@ -440,6 +440,22 @@ u64 cleonos_sys_net_udp_send(const cleonos_net_udp_send_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_UDP_SEND, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_UDP_RECV, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_udp_recv(cleonos_net_udp_recv_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_UDP_RECV, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_tcp_connect(const cleonos_net_tcp_connect_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_TCP_CONNECT, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_tcp_send(const cleonos_net_tcp_send_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_TCP_SEND, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_tcp_recv(cleonos_net_tcp_recv_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_TCP_RECV, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_net_tcp_close(u64 poll_budget) {
return cleonos_syscall(CLEONOS_SYSCALL_NET_TCP_CLOSE, poll_budget, 0ULL, 0ULL);
}

2
clks

Submodule clks updated: 4664494e04...dbc0db3aff

View File

@@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `/proc/<pid>`:指定 PID 快照文本
- `/proc` 为只读;写入类 syscall 不支持。
## 4. Syscall 列表0~102
## 4. Syscall 列表0~106
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -780,6 +780,34 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- 参数:无
- 返回:当前 DNS 服务器 IPv4`u32`,网络字节序,位于返回值低 32 位)。
- 说明:优先使用 DHCP 下发值;若 DHCP 未提供则按回退策略填充。
### 103 `CLEONOS_SYSCALL_NET_TCP_CONNECT`
- 参数:
- `arg0`: `const struct { u64 dst_ipv4_be; u64 dst_port; u64 src_port; u64 poll_budget; } *req`
- 返回:连接成功返回 `1`,失败返回 `0`
- 说明:最小 TCP 客户端连接能力SYN/SYN-ACK/ACK`src_port=0` 时内核自动分配临时端口。
### 104 `CLEONOS_SYSCALL_NET_TCP_SEND`
- 参数:
- `arg0`: `const struct { u64 payload_ptr; u64 payload_len; u64 poll_budget; } *req`
- 返回:实际发送并确认的字节数;失败返回 `0`
- 说明:当前实现为单连接发送路径,内部按分片发送并等待 ACK。
### 105 `CLEONOS_SYSCALL_NET_TCP_RECV`
- 参数:
- `arg0`: `struct { u64 out_payload_ptr; u64 payload_capacity; u64 poll_budget; } *req`
- 返回:实际拷贝到用户缓冲区的字节数;无数据/超时/失败返回 `0`
- 说明:接收缓冲区上限受内核实现限制(当前 64 KiB
### 106 `CLEONOS_SYSCALL_NET_TCP_CLOSE`
- 参数:
- `arg0`: `u64 poll_budget`
- 返回:关闭成功返回 `1`,失败返回 `0`
- 说明:最小关闭流程支持 FIN/ACK 轮询等待,超时会强制回收连接状态。
## 5. 用户态封装函数
@@ -815,6 +843,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `cleonos_sys_disk_read_sector()` / `cleonos_sys_disk_write_sector()`
- `cleonos_sys_net_available()` / `cleonos_sys_net_ipv4_addr()` / `cleonos_sys_net_netmask()` / `cleonos_sys_net_gateway()` / `cleonos_sys_net_dns_server()` / `cleonos_sys_net_ping()`
- `cleonos_sys_net_udp_send()` / `cleonos_sys_net_udp_recv()`
- `cleonos_sys_net_tcp_connect()` / `cleonos_sys_net_tcp_send()` / `cleonos_sys_net_tcp_recv()` / `cleonos_sys_net_tcp_close()`
## 6. 开发注意事项
@@ -825,7 +854,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
## 7. Wine 兼容说明
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..102`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*``NET_*`)。
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..106`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*``NET_*`)。
- `DL_*``77..79`)在 Wine 中为“可运行兼容”实现:
- `DL_OPEN`:加载 guest ELF 到当前 Unicorn 地址空间,返回稳定 `handle`,并做引用计数。
- `DL_SYM`:解析 ELF `SYMTAB/DYNSYM` 并返回 guest 可调用地址。
@@ -842,7 +871,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `DISK_FORMAT_FAT32` 会初始化/重置 Wine rootfs 下的虚拟磁盘目录。
- `DISK_MOUNT`/`DISK_MOUNT_PATH` 支持挂载点管理,并与 `FS_MKDIR/WRITE/APPEND/REMOVE` 的路径规则联动。
- `DISK_READ_SECTOR`/`DISK_WRITE_SECTOR``93..94`)在 Wine 中已实现为 512B 原始扇区读写host 文件后端)。
- 网络 syscall`95..102`)在 Wine 当前为兼容占位实现(统一返回 `0`);即 Wine 运行模式下不会提供真实网络收发。
- 网络 syscall`95..106`)在 Wine 当前为兼容占位实现(统一返回 `0`);即 Wine 运行模式下不会提供真实网络收发。
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0``AUDIO_PLAY_TONE=0``AUDIO_STOP=1`
- Wine 版本号策略固定为 `85.0.0-wine`(历史兼容号;不会随 syscall 扩展继续增长)。

2
wine

Submodule wine updated: cfe386b21d...abf4a53e78