WebAssembly / wasi-sdk

WASI-enabled WebAssembly C/C++ toolchain
Apache License 2.0
1.22k stars 176 forks source link

Raise errors when compiling c socket to wasm #447

Closed hungryzzz closed 1 month ago

hungryzzz commented 1 month ago

Hi, I write a C program which will send an HTTP request to a server and it can run successfully when compiling it to machine code.

When I try to use wasi-sdk to compile it, I encounter the following errors. It seems that wasi-sdk cannot find the socket library API. What should I do to compile it successfully? Thank you very much!

ubuntu:~/c-app$ /home/ubuntu/wasi-sdk-23.0/bin/clang --sysroot=/home/ubuntu/wasi-sdk-23.0/share/wasi-sysroot app.c -o app.wasm
app.c:24:9: error: call to undeclared function 'socket'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   24 |         sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
      |                ^
app.c:25:2: error: call to undeclared function 'setsockopt'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   25 |         setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));
      |         ^
app.c:25:2: note: did you mean 'getsockopt'?
/home/ubuntu/wasi-sdk-23.0/share/wasi-sysroot/include/wasm32-wasi/sys/socket.h:436:5: note: 'getsockopt' declared here
  436 | int getsockopt (int, int, int, void *__restrict, socklen_t *__restrict);
      |     ^
app.c:32:5: error: call to undeclared function 'connect'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
   32 |         if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
      |            ^
3 errors generated.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#include <netinet/tcp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int socket_connect(char *host, in_port_t port){struct sockaddr_in addr;
    int on = 1, sock;     

    addr.sin_port = htons(port);
    addr.sin_family = AF_INET;
        if (inet_pton(AF_INET, host, &addr.sin_addr) <= 0) {
          perror("inet_pton");
          exit(1);
        }

    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&on, sizeof(int));

    if(sock == -1){
        perror("setsockopt");
        exit(1);
    }

    if(connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) == -1){
        perror("connect");
        exit(1);

    }
    return sock;
}

#define BUFFER_SIZE 1024

int main(){
    int fd;
    char buffer[BUFFER_SIZE];
        char header[] = "GET / HTTP/1.1\r\n\r\n";
        char hostname[] = "127.0.0.1";
        char port[] = "6000";

        fd = socket_connect(hostname, atoi(port));
    write(fd, header, strlen(header));
    bzero(buffer, BUFFER_SIZE);

    while(read(fd, buffer, BUFFER_SIZE - 1) != 0){
        fprintf(stderr, "%s", buffer);
        bzero(buffer, BUFFER_SIZE);
    }

    shutdown(fd, SHUT_RDWR); 
    close(fd); 

    return 0;
}
abrown commented 1 month ago

I suspect that what is happening here is that you are hitting a target that has not yet enabled support for wasi-sockets. This is actually more of a wasi-libc issue, since that is where the C definitions of those functions would get plumbed to the appropriate wasi-sockets calls. In fact, there's already an issue open on this where @dicej talks about a plan for a wasi-libc target that would support this: https://github.com/WebAssembly/wasi-libc/issues/447.

I suggest we close this issue and ask for a status update there? If something is still broken, I can move this issue to that repository.

hungryzzz commented 1 month ago

Sure. But I am curious that before the wasi-sockets or wasi-http APIs are implemented, is there any other way to run a C program which sends HTTP requests to other services on Wasm?

abrown commented 1 month ago

I mean, you could always import a function from the host to do that, but I think the standard way is going to be via one of those WASI proposals.