devkitPro / wut

Let's try to make a Wii U Toolchain / SDK for creating rpx/rpl.
zlib License
244 stars 52 forks source link

Network socket changes: socket_lib_finish() shouldn't be a stub function #169

Closed V10lator closed 3 years ago

V10lator commented 3 years ago

If one calls somemopt the homebrew will never be able to exit as somemopt blocks untill socket_lib_finish is called which can't be done if said function is replaced by a stub.

Now you might ask "why call somemopt in the first place?" - the answer is simple: Performance reasons. You'll get much faster up-/downloads by using I/O buffers in userspace and the way to set these buffers is somemopt (socket memory option).

Example code to show the issue:

#define DLBGT_STACK_SIZE    0x2000
#define SOCKET_BUFSIZE      (128 * 1024)
#define SOCKLIB_BUFSIZE     (SOCKET_BUFSIZE * 4) // For send & receive + double buffering

static OSThread dlbgThread;
static uint8_t *dlbgThreadStack;

int dlbgThreadMain(int argc, const char **argv)
{
    void *buf = MEMAllocFromDefaultHeapEx(SOCKLIB_BUFSIZE, 64);
    if(buf == NULL)
        return 1;

    if(somemopt(0x01, buf, SOCKLIB_BUFSIZE, 0) == -1 && socketlasterr() != 50) // This will block untill socket_lib_finish() is called
        return 1;

    MEMFreeToDefaultHeap(buf);
    return 0;
}

bool initDownloader()
{
    dlbgThreadStack = MEMAllocFromDefaultHeapEx(DLBGT_STACK_SIZE, 8);

    if(dlbgThreadStack == NULL || !OSCreateThread(&dlbgThread, dlbgThreadMain, 0, NULL, dlbgThreadStack + DLBGT_STACK_SIZE, DLBGT_STACK_SIZE, 0, OS_THREAD_ATTRIB_AFFINITY_ANY))
        return false;

    OSSetThreadName(&dlbgThread, "DL background thread");
    OSResumeThread(&dlbgThread);
    return true;
}

void deinitDownloader()
{
    socket_lib_finish();
    int ret;
    OSJoinThread(&dlbgThread, &ret);
    MEMFreeToDefaultHeap(dlbgThreadStack);
    socket_lib_init();
}

static curl_off_t initSocket(void *ptr, curl_socket_t socket, curlsocktype type)
{
    int o = 1;
    // Activate userspace buffer (fom somemopt)
    if(setsockopt(socket, SOL_SOCKET, 0x10000, &o, sizeof(o)) != 0)
        return 1;

    o = SOCKET_BUFSIZE;
    // Set send buffersize
    if(setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &o, sizeof(o)) != 0)
        return 1;

    // Set receive buffersize
    if(setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &o, sizeof(o)) != 0)
        return 1;

    return 0;
}

int main()
{
    initDownloader();
    CURL *curl = curl_easy_init();
    curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, (curl_sockopt_callback)initSocket);

    // Do something, like a download...

    curl_easy_cleanup(curl);
    deinitDownloader();
}
fincs commented 3 years ago

I've created a branch: https://github.com/devkitPro/wut/tree/socket-init

This branch makes it possible to call socket_lib_init/finalize again, which now performs refcounting and handles devoptab registration/etc. However, the main addition is the ability to override the socket initialization/deinitialization logic, so that it can be customized to do things such as setting up somemopt. E.g.

void __init_wut_socket()
{
    socket_lib_init();
    // somemopt thread creation goes here
    // wait for somemopt to be initialized? dunno how that's done
    // AC initialization/connection goes here
}

void __fini_wut_socket()
{
    // AC deinitialization goes here
    socket_lib_finish();
    // somemopt thread teardown goes here
}

Please test this branch, and see if the changes suit your use case.

fincs commented 3 years ago

See https://github.com/devkitPro/wut/commit/eb0306184d46a63d929aede352f54109701b7112

socket_lib_init/finish are no longer stubs.