@@ -3462,34 +3462,110 @@ static int32_t WaitForSocketEventsInner(int32_t port, SocketEvent* buffer, int32
34623462
34633463#if defined(TARGET_WASI )
34643464// from https://github.com/WebAssembly/wasi-libc/blob/161b3195fc25/libc-bottom-half/headers/private/wasi/descriptor_table.h
3465+ // The descriptor table entry is a "fat pointer":
3466+ // typedef struct { void* data; descriptor_vtable_t* vtable; } descriptor_table_entry_t;
3467+ // where `data` points to the descriptor-specific state (a tcp_socket_t* or udp_socket_t*).
34653468void * descriptor_table_get_ref (int fd );
34663469
34673470// this method is invading private implementation details of wasi-libc
34683471// we could get rid of it when https://github.com/WebAssembly/wasi-libc/issues/542 is resolved
34693472// or after WASIp3 promises are implemented, whatever comes first
3470- int32_t SystemNative_GetWasiSocketDescriptor (intptr_t socket , void * * entry )
3473+ //
3474+ // Returns the descriptor-specific `data` pointer in *entry and the kind of socket in
3475+ // *socketType (1 = TCP/stream, 2 = UDP/datagram, 0 = unknown). The vtable that identifies
3476+ // the socket kind is a private static symbol in wasi-libc, so we discriminate via SO_TYPE.
3477+ int32_t SystemNative_GetWasiSocketDescriptor (intptr_t socket , void * * entry , int32_t * socketType )
34713478{
3472- if (entry == NULL )
3479+ if (entry == NULL || socketType == NULL )
34733480 {
34743481 return Error_EFAULT ;
34753482 }
34763483
34773484 int fd = ToFileDescriptor (socket );
3478- void * ref = descriptor_table_get_ref (fd );
3485+ // The returned pointer is a descriptor_table_entry_t*; its first word is the `data` pointer.
3486+ void * * ref = (void * * )descriptor_table_get_ref (fd );
34793487 if (ref == NULL )
34803488 {
34813489 return Error_EFAULT ;
34823490 }
3483- * entry = ref ;
3491+ * entry = ref [0 ];
3492+
3493+ int type = 0 ;
3494+ socklen_t length = sizeof (type );
3495+ if (getsockopt (fd , SOL_SOCKET , SO_TYPE , & type , & length ) != 0 )
3496+ {
3497+ return Error_EFAULT ;
3498+ }
3499+
3500+ if (type == SOCK_STREAM )
3501+ {
3502+ * socketType = 1 ;
3503+ }
3504+ else if (type == SOCK_DGRAM )
3505+ {
3506+ * socketType = 2 ;
3507+ }
3508+ else
3509+ {
3510+ * socketType = 0 ;
3511+ }
3512+
34843513 return Error_SUCCESS ;
34853514}
3515+
3516+ // In the new wasi-libc descriptor-table design, the pollables embedded in the socket state
3517+ // (socket_pollable / input_pollable / output_pollable / incoming_pollable / outgoing_pollable)
3518+ // are created lazily: their handle is 0 until the corresponding `subscribe` import is called.
3519+ // The managed event loop needs the actual pollable handle to merge it into wasi:io/poll.poll,
3520+ // so it asks us to lazily subscribe when it observes a 0 handle.
3521+ //
3522+ // All of the wasi component-model handle types are ABI-identical: a struct wrapping a single
3523+ // int32_t handle, passed and returned directly. We mirror that with WasiPollHandle_t so we can
3524+ // call the (private) wasi-libc subscribe imports without pulling in the generated headers.
3525+ typedef struct { int32_t __handle ; } WasiPollHandle_t ;
3526+ extern WasiPollHandle_t streams_method_input_stream_subscribe (WasiPollHandle_t self );
3527+ extern WasiPollHandle_t streams_method_output_stream_subscribe (WasiPollHandle_t self );
3528+ extern WasiPollHandle_t tcp_method_tcp_socket_subscribe (WasiPollHandle_t self );
3529+ extern WasiPollHandle_t udp_method_udp_socket_subscribe (WasiPollHandle_t self );
3530+ extern WasiPollHandle_t udp_method_incoming_datagram_stream_subscribe (WasiPollHandle_t self );
3531+ extern WasiPollHandle_t udp_method_outgoing_datagram_stream_subscribe (WasiPollHandle_t self );
3532+
3533+ // kind: 0 = input-stream, 1 = output-stream, 2 = tcp-socket, 3 = udp-socket,
3534+ // 4 = incoming-datagram-stream, 5 = outgoing-datagram-stream
3535+ // `handle` is the borrowed stream/socket handle read from the socket state. Returns the newly
3536+ // created pollable handle (the caller stores it back into the socket state so wasi-libc owns
3537+ // and eventually drops it), or 0 for an unknown kind.
3538+ int32_t SystemNative_WasiSubscribeSocketPollable (int32_t kind , int32_t handle )
3539+ {
3540+ WasiPollHandle_t self = { handle };
3541+ WasiPollHandle_t pollable ;
3542+ switch (kind )
3543+ {
3544+ case 0 : pollable = streams_method_input_stream_subscribe (self ); break ;
3545+ case 1 : pollable = streams_method_output_stream_subscribe (self ); break ;
3546+ case 2 : pollable = tcp_method_tcp_socket_subscribe (self ); break ;
3547+ case 3 : pollable = udp_method_udp_socket_subscribe (self ); break ;
3548+ case 4 : pollable = udp_method_incoming_datagram_stream_subscribe (self ); break ;
3549+ case 5 : pollable = udp_method_outgoing_datagram_stream_subscribe (self ); break ;
3550+ default : return 0 ;
3551+ }
3552+ return pollable .__handle ;
3553+ }
34863554#else
3487- int32_t SystemNative_GetWasiSocketDescriptor (intptr_t socket , void * * entry )
3555+ int32_t SystemNative_GetWasiSocketDescriptor (intptr_t socket , void * * entry , int32_t * socketType )
34883556{
34893557 (void )socket ;
34903558 (void )entry ;
3559+ (void )socketType ;
34913560 return Error_ENOSYS ;
34923561}
3562+
3563+ int32_t SystemNative_WasiSubscribeSocketPollable (int32_t kind , int32_t handle )
3564+ {
3565+ (void )kind ;
3566+ (void )handle ;
3567+ return 0 ;
3568+ }
34933569#endif // TARGET_WASI
34943570
34953571int32_t SystemNative_CreateSocketEventPort (intptr_t * port )
0 commit comments