Welcome! Log In Create A New Profile Wiibrew Wiki HackMii Blog

Advanced

Networking trouble: random, permanent failures in net_recv()

Posted by zman 
Networking trouble: random, permanent failures in net_recv()
August 03, 2008 10:46AM
Hi, I've got several problems with networking on the Wii. Check out this simple test program (compilable by putting it as template.c into the template project):

#include 
#include 
#include 
#include 
#include 

#include 
#include 

static void *xfb = NULL;
static GXRModeObj *rmode = NULL;

//---------------------------------------------------------------------------------
int main(int argc, char **argv) {
//---------------------------------------------------------------------------------

	// Initialise the video system
	VIDEO_Init();
	
	// This function initialises the attached controllers
	WPAD_Init();
	
	// Obtain the preferred video mode from the system
	// This will correspond to the settings in the Wii menu
	rmode = VIDEO_GetPreferredMode(NULL);

	// Allocate memory for the display in the uncached region
	xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
	
	// Initialise the console, required for printf
	console_init(xfb,20,20,rmode->fbWidth,rmode->xfbHeight,rmode->fbWidth*VI_DISPLAY_PIX_SZ);
	
	// Set up the video registers with the chosen mode
	VIDEO_Configure(rmode);
	
	// Tell the video hardware where our display memory is
	VIDEO_SetNextFramebuffer(xfb);
	
	// Make the display visible
	VIDEO_SetBlack(FALSE);

	// Flush the video register changes to the hardware
	VIDEO_Flush();

	// Wait for Video setup to complete
	VIDEO_WaitVSync();
	if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();


	printf("\n\n\n    Initializing network...\n");

    s32 result = net_init();
    while ( result == -EAGAIN )
    {
        result = net_init();
    }
    if ( result < 0 )
    {
        printf("    Failed. Bye!\n" );
        exit(0);
    }

    char name[100];
    if_config( name, 0, 0, 1 );
	// printf("    name: %d.%d.%d.%d\n", name[0], name[1], name[2], name[3] );
	printf("    Success. My IP: %s\n", name );

    int type = SOCK_DGRAM;

    // source address
    struct sockaddr_in source;
    memset(&source, 0, sizeof(struct sockaddr_in)); /* clear our address */
    source.sin_family= AF_INET;              /* this is our host address */
    source.sin_port= htons(5100);                /* this is our port number */
    unsigned char * addr = (unsigned char *)(&source.sin_addr);

    // read Wii's IP: and store it
    int a, b, c, d;
    result = sscanf( name, "%d.%d.%d.%d", &a, &b, &c, &d );
    if ( result < 4 )
    {
        printf("    Oops, sscanf failed. Bye!\n" );
        exit(0);
    }
    addr[0] = a;
    addr[1] = b;
    addr[2] = c;
    addr[3] = d;
    source.sin_len = 8;

    // destination address
    struct sockaddr_in dest;
    memset(&dest, 0, sizeof(struct sockaddr_in)); /* clear our address */
    dest.sin_family= AF_INET;              /* this is our host address */
    dest.sin_port= htons(5101);                /* this is our port number */
    dest.sin_addr = source.sin_addr;           /* copy over source address */
    dest.sin_len = 8;

    // open sending socket
    int socket1 = net_socket(AF_INET, type, 0 );
	printf("    socket1: %d\n", socket1 );

    // open receiving socket
    int socket2 = net_socket(AF_INET, type, 0 );
	printf("    socket2: %d\n", socket2 );

    // unblock receiving socket (appears not to work)
    int _true = true;
    result = net_ioctl (socket2, FIONBIO, (char *)(&_true));
    printf("    ioctl: %d\n", result );

    // bind the sockets to their addresses
    result = net_bind(socket1,(struct sockaddr *)&source,8);
    printf("    bind1: %d\n", result );

    result = net_bind(socket2,(struct sockaddr *)&dest,8);
    printf("    bind2: %d\n", result );

    // data to be sent
    #define DLEN 100
    char data[DLEN];
    data[0]='A';
    data[1]='b';
    data[2]='C';
    data[3]='d';
    data[4]=0;
    result = net_sendto( socket1, data, DLEN, 0, (struct sockaddr *)&dest, 8 );
    printf("    send1: %d\n", result );

    // receive data
    data[0]=110;
    result = net_recv( socket2, data, DLEN, 0 );
    printf("    receive: %d, %d\n", result, (int)data[0] );
    
    int i = 2;
	while(1) {
        if ( result >= 0 )
        {
            // destination address
            memset(&dest, 0, sizeof(struct sockaddr_in)); /* clear our address */
            dest.sin_family= AF_INET;              /* this is our host address */
            dest.sin_port= htons(5101);                /* this is our port number */
            dest.sin_addr = source.sin_addr;           /* copy over source address */
            dest.sin_len = 8;

            ++i;
            data[0]='A';
            result = net_sendto( socket1, data, DLEN, 0, (struct sockaddr *)&dest, 8 );
            printf("    send %d: %d\n", i, result );

            if ( result >= 0 )
            {
                data[0]=110;
                result = net_recv( socket2, data, DLEN, 0 );
                printf("    receive %d: %d, %d\n", i, result, (int)data[0] );
            }
        }

        if ( result < 0 )
        {
            printf("    Error! Reopening sockets.\n" );
            result = net_init();
            printf("    net_init: %d\n", result );

            net_close( socket1 );
            net_close( socket2 );

            // open sending socket
            socket1 = net_socket(AF_INET, type, 0 );
            printf("    socket1: %d\n", socket1 );

            // open receiving socket
            socket2 = net_socket(AF_INET, type, 0 );
            printf("    socket2: %d\n", socket2 );

            // bind the sockets to their addresses
            result = net_bind(socket1,(struct sockaddr *)&source,8);
            printf("    bind1: %d\n", result );

            result = net_bind(socket2,(struct sockaddr *)&dest,8);
            printf("    bind2: %d\n", result );

            // pause
            int j;
            for( j = 120; j > 0; --j )
            {
                VIDEO_WaitVSync();
            }
        }

		// Call WPAD_ScanPads each loop, this reads the latest controller states
		WPAD_ScanPads();

		// WPAD_ButtonsDown tells us which buttons were pressed in this loop
		// this is a "one shot" state which will not fire again until the button has been released
		u32 pressed = WPAD_ButtonsDown(0);

		// We return to the launcher application via exit
		if ( pressed & WPAD_BUTTON_HOME ) exit(0);

		// Wait for the next frame
		VIDEO_WaitVSync();
	}

	return 0;
}
All it does is:
1. initialize the network
2. open two UDP sockets
3. continuously send data from one socket to the other

The main problem is that after a couple hundred of successful runs, the recv() call in the loop fails at one point with return -22, ( == -EINVAL ). All reviving attempts fail: closing the sockets, opening them and binding them don't give errors, but the next call to send() then also returns -22. Am I missing something here or is it a bug in the networking subsystem? The data passed to recv() is definitely not invalid, it's just the socket, data and maximal data length.

The two secondary problems are that the network initialization fails randomly (I've observed the Homebrew channel and ftpii have the same problem, so it's either my home network or a general problem), and that unblocking the receiving socket definitely does not work: after unblocking, a call to recv() without pending incoming should return 0, but in fact blocks. Passing MSG_DONTWAIT as the flags argument also does not change this. I remember reading about someone else with the same problem, but I'm afraid it may have been on the old forums as I can't find it any more.

Any help/pointers are appreciated. The recv() failure is the most important problem, I can accept/work around the other two.
Sorry, only registered users may post in this forum.

Click here to login