Infrastructure PSP->PSP communication

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Infrastructure PSP->PSP communication

Post by AnonymousTipster »

I've been trying to modify PSPet's Simple Wifi sample to allow basic communication between two PSPs via a stream socket, but upon connection, sceNetApctlGetInfo(8, szMyIPAddr) gives me 192.168.1.100, and upon testing with another persons PSP on a different router, it gave him a local IP too.

How can I get two PSPs connecting and communicating via wifi infrastructure?
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

I assume you are running two different programs (or the same program in two different modes). One must be the 'server' (bind/listen/accept) and the other must be the 'client' (connect).
The client must know the IP address of the server to initiatiate the connection.

NOTE: the technique is the same whether using WiFi 'adhoc' (2 PSPs only) or WiFi 'infrastructure' mode (PSPs with access point). PSP 'adhoc' mode is something else.

-----
> and upon testing with another persons PSP on a different router
The two PSPs must be able to see eachother on the network (ie. be on the same WiFi ESSID access point and in the same address range 192.168.1.XXX). That's the easy case.

If going through multiple routers/access points you must be sure that any address mapping is working for the IP ranges you picked (both sides may have to do "NAT"). Also make sure there is no firewall blocking the ports you are using. Ie. you should be able to 'ping' either PSP from the other.

I recommend starting with the easy case (one access point, 2 PSPs in the same room one at 192.168.1.100 the other at 192.168.1.101) to get the PSP problems fixed first. Then worry about the network configuration routing issues [not specific to the PSP]
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Thanks for the response, Psppet.

What I did was modify the simple wifi sample to add a client mode, so either you choose server, which runs the telnetD code, or client, which allows input of an IP, which it then connects to and sends a message.
The problem is that if the client tries to connect to 192.168.1.100, it fails, because my PSP is across the internet on another router, not the same router as the client.

As both PSPs are connecting via a router, their addresses are translated, so how can I find the IP address which will connect the client to the server if they are both translated across two seperate routers?

I'm going to start looking at the LUA Player source, as netlib for LUA seems like the sort of thing I want to achieve, but in C.
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

> because my PSP is across the internet on another router, not the same router as the client.
That's the problem. Nothing to do with PSP or WiFi - but a general Internet issue.
Ie. you can't simply ping your home computer from work by typing in the IP address of your home machine.

I assume your router(s) don't have fixed IP addresses from your ISP. So the two routers will get dynamic IP addresses. Each router does NAT. There is no way the two sides will see eachother unless you open up the router (if supported) or coordinate with a known server on the web (with fixed domain and/or IP address)

There are some alternatives to work around this. Look for dynamic DNS services (use with PSP may be a pain)
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Found this in LUAPlayer:

Code: Select all

// resolve host
	const char *host = luaL_checkstring(L, 1);
	int port = luaL_checkint(L, 2);
	socket->addrTo.sin_family = AF_INET;
	socket->addrTo.sin_port = htons(port);
	int err = sceNetInetInetAton(host, &socket->addrTo.sin_addr);
	if (err == 0) {
		err = sceNetResolverStartNtoA(resolverId, host, &socket->addrTo.sin_addr, 2, 3);
		if &#40;err < 0&#41; return luaL_error&#40;L, "Socket&#58;connect&#58; DNS resolving failed."&#41;;
	&#125;
Might just be helpful.
ufoz
Posts: 86
Joined: Thu Nov 10, 2005 2:36 am
Location: Tokyo
Contact:

Post by ufoz »

sg57
Posts: 144
Joined: Fri Oct 14, 2005 2:26 pm

Post by sg57 »

I, too, would like to know this, as I want to connect to an online server, allowing users of the app/game (AKA client) to connect to the server, then to another client, making a connection to thus send small packets/bytes of data, and have a global 'checklist' to match up that byte with a list of commands...

(Is there a better way?)

So please do, keep posting on this and how its bypassed, PSPet. Thanks alot!
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

That's pretty much what I want to do SG57, except I plan to have some scripts on the server keep track of IP addresses of the 'server psps'. The client grabs this from the server, and picks the server it wants to connect to, and does so. The remainder of the communication is PSP->PSP. After looking through the netlib source, the PSP-PSP communication doesn't seem to be possible.

The central server needs to allow the PSPs to coordinate with each other, as Psppet said.

The other complication is that there are two protocols: TCP and UDP. TCP is reliable, will always arrive in the right order and error-free, but are slower than UDP. TCP would be best for chat-apps which don't need to be fast, but do need to be in the right order. UDP packets are essentially chunks of data which have a header on them, telling them where to go, and where they came from. Trouble is that they may never arrive, and may arrive in the wrong order. To ensure the data has arrived, the sender has to keep sending the data until the reciever sends it an acknowlegement that it arrived.

To me, it sounds like TCP is simpler to get up and running, but UDP is more efficient.

After looking through the netlib 1.3 source, it appears to ping a server, and then send data:

Code: Select all

function netsend&#40;id, data, abtribute&#41;
if id == "" then error&#40;"invalid id"&#41; end
if not &#40;abtribute == "a" or abtribute == "w"&#41; then
error&#40;"bad abtribute, must be 'a' or 'w'"&#41;
end
data = replace&#40;data," ","%20"&#41;
data = replace&#40;data,"&#58;","%3A"&#41;
socket = Socket.connect&#40;"208.97.136.133", 80&#41;
while not socket&#58;isConnected&#40;&#41; do System.sleep&#40;100&#41; end
bytesSent = socket&#58;send&#40;"GET /youresam/net/write"..abtribute..".php?id="..id.."&data="..data.." HTTP/1.0\r\n"&#41;
bytesSent = socket&#58;send&#40;"host&#58; www.psp-programming.com\r\n\r\n"&#41;
socket&#58;close&#40;&#41;
end
Then another PSP grabs this data by it's ID via:

Code: Select all

function netget&#40;id&#41;
if id == "" then error&#40;"invalid id"&#41; end
socket = Socket.connect&#40;"208.97.136.133", 80&#41;
while not socket&#58;isConnected&#40;&#41; do 
if Controls.read&#40;&#41;&#58;start&#40;&#41; then return end
System.sleep&#40;100&#41; 
end
bytesSent = socket&#58;send&#40;"GET /youresam/net/id/"..id..".txt HTTP/1.0\r\n"&#41;
bytesSent = socket&#58;send&#40;"host&#58; www.psp-programming.com\r\n\r\n"&#41;
total = ""
request = 0
while true do
	buffer = socket&#58;recv&#40;&#41;
		if string.len&#40;buffer&#41; > 0 then 
			total = total..buffer
			request = 1
		else
			if request == 1 then request = 2 end
		end
	
	if request == 2 then 
		socket&#58;close&#40;&#41;
		break
	end
screen.waitVblankStart&#40;6&#41;
if Controls.read&#40;&#41;&#58;start&#40;&#41; then break end
end
--sort out data
start = string.find&#40;total,"text/plain"&#41; or 1
begin = start+14
total = string.sub&#40;total,begin&#41;
return total
end
So, if I'm understanding this correctly, whenever a piece of data needs to be sent from one PSP to another, the data is written to the server with an ID, and the other PSP grabs this data. Wouldn't this be rather slow?

The good thing about the game I want to use this code for is that it doesn't need to sync the players, so there could be tonnes of lag, and it doesn't affect gameplay. I'm hoping TCP will be enough for my purposes, as it seems simpler than UDP.

If anything i've written in this post is wrong, please tell me and i'll correct it.
sg57
Posts: 144
Joined: Fri Oct 14, 2005 2:26 pm

Post by sg57 »

Something as simple as an online highscore list would easily be TCP, as you dont want corrupt scores, and since it doesnt matter about LAG, then the shoe fits :)

And ya, I kind of am getting at what your saying... I had a question you just answered, it was since I want to send/recieve data from a server, there'd be alot of traffic, and recieving bytes/data by just grasping randomly would be impossible, let alone the one i needed, so that 'haeder id' should basically give w/e im in need of a temp name, that i can 'ask' the server to send to w/e client and vice versa, in puesdo code of course lol (i wish it were real code ;) ).

Im really starting to think about porting netlib to C, as Lua Player is open source, and since netlib just uses alot of functions inside the open source LUa, why not just copy and paste the functions netlib uses, into a source file, and give them the names netlib has given them...

I dunno... But having a netlib in C would definitely increase online games / activity, as infracture is a must with the PSP... Ad-Hoc just cant compate...
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Well it would at least be worth replicating the more useful communication features of netlib, as C developers are definitely going to want to add online multiplayer to their games sometime, and I think it's better if this gets started sooner than later.

As far as I can tell, netlib 1.3 (TCP) communicates with a HTTP server, but I can't tell, as 208.97.136.133 returns a page, but it isn't available at the moment. Netlib 2.0 uses UDP and requires a PC to run an executable on it to act as the server. If 1.3 is indeed communicating to a regular HTTP server, it would be more reliable than a user's PC (as was demonstrated by SonicBattleArena continually suffering outages and server switches).

I just need someone to confirm that what i'm thinking is right, so I know i'm heading down the right path.
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

> I, too, would like to know this, as I want to connect to an online server, allowing users of the app/game (AKA client) to connect to the server...
> (Is there a better way?)
IMHO that's the best way.
Best if you have a serious webserver (ie. real domain and fixed IP address) and can run custom CGI/ASP scripts. Possible to run on your home PC with dynamic DNS.

That's what most serious online game servers use (eg: gamespy). BTW: Even AC:WW on the Nintendo DS (Animal Crossing Wild World) uses that approach. Once connected two DSs communicate directly over UDP. They only use the main server for initial connection and heart-beat like infrequent status checks

----
re: central server starting the communication
As mentioned, for smaller or non-time critical data (eg: scores), sending everything to the server is best. For real-time play you want PSP-to-PSP.

> keep track of IP addresses of the 'server psps'... remainder of the communication is PSP->PSP.
> whenever a piece of data needs to be sent from one PSP to another, the data is written to the server with an ID, and the other PSP grabs this data. Wouldn't this be rather slow?
Yes. Not recommended. See trick below:
----

The Trick:
To get direct PSP->PSP through the two routers and NAT transformation PSP#1 needs to find the find the EXTERNALLY VISIBLE IP address and port created by the NAT for PSP#2 (and vice-versa)
Have both sides connect to the server on a special port. The server records the REPLY IPAddress/port of the connection. It can then send that IP/port to the other PSP. Assuming a relatively standard topology - PSP#1 can now directly access PSP#2 (and vice-versa) by using that NAT translated IPAddress/port

This hides any details of the NAT translation and is fairly portable (and only assumes the NAT translation port doesn't change during the life of the connection)
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Right, so (if I understand correctly) I need to code a script in ASP (would PHP work?) that will get the reply IP+port of a PSP when it queries the script. This IP/port would be stored by the server and could be retrieved by another PSP wishing to connect to the first PSP.

A question: PSPA queries server, server saves reply IP[A]. PSPB queries server, server saves reply IP. PSPB gets IP[A] and connects to it. PSPA hears this incoming connection and accepts. Any data PSPB now sends will get to PSPA via this connection (as long as PSPA calls recv()).
PSP#1 can now directly access PSP#2 (and vice-versa)

Now the question is this: with said connection between PSPA and PSPB (which PSPB connect()ed), is the connection still valid for PSPA to send data back to PSPB, or has the address been translated so that this doesn't work? If invalid, does this mean that PSPA has to query the server for IP and then connect to that, therefore meaning two connections, both one-way? (Just want to clarify my interpretation of the quote).

Also, if using stream TCP sockets, is there a risk of connection drop-out? I had heard that it wasn't reliable for continuous communication, and the UDP is better. I would prefer to stick with TCP if it should work.

Thanks for explaining this PspPet, the information is most useful.
sg57
Posts: 144
Joined: Fri Oct 14, 2005 2:26 pm

Post by sg57 »

Im not much of a network person, but this sure is helping alot for me ;)

So a basic netlib port should pretty much do it, along with some added features (chose UDP/TCP depending on what to send to/from... server/psp)...
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Ok, I tried to find out my 'real' IP address by calling this script: www.anonymoustipster.com/myip.php then getting the client to connect to that IP. The client appeared to pass the connect(), so it should send a little hello message, but my server didn't receive it.
After connecting to the hotspot, and getting the net IP from my script, the server calls:

Code: Select all

static void TestMiniTelnetD&#40;const char* szMyIPAddr&#41;
&#123;
    u32 err;

    // instructions
    //pspDebugScreenClear&#40;&#41;;
    printf&#40;"Connected!\n"&#41;;
    printf&#40;"  telnet to %s port 66476\n", szMyIPAddr&#41;;
    printf&#40;"\n"&#41;;

    // mini telnetd-lite server
    &#123;
        SOCKET sockListen;
        struct sockaddr_in addrListen;
        struct sockaddr_in addrAccept;
        int cbAddrAccept;
        SOCKET sockClient;

        sockListen = sceNetInetSocket&#40;AF_INET, SOCK_STREAM, 0&#41;;
        if &#40;sockListen <= 0&#41;
        &#123;
            printf&#40;"socket returned $%x\n", sockListen&#41;;
            goto done;
        &#125;

        addrListen.sin_family = AF_INET;
        addrListen.sin_port = htons&#40;66476&#41;;//23
        addrListen.sin_addr&#91;0&#93; = 0;
        addrListen.sin_addr&#91;1&#93; = 0;
        addrListen.sin_addr&#91;2&#93; = 0;
        addrListen.sin_addr&#91;3&#93; = 0;
		
            // any

        err = sceNetInetBind&#40;sockListen, &addrListen, sizeof&#40;addrListen&#41;&#41;;
        if &#40;err != 0&#41;
        &#123;
            printf&#40;"bind returned $%x\n", err&#41;;
            printf&#40;"  errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
            goto done;
        &#125;

        err = sceNetInetListen&#40;sockListen, 1&#41;;
        if &#40;err != 0&#41;
        &#123;
            printf&#40;"listen returned $%x\n", err&#41;;
            printf&#40;"  errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
            goto done;
        &#125;

        // blocking accept &#40;wait for one connection&#41;
        cbAddrAccept = sizeof&#40;addrAccept&#41;;
        sockClient = sceNetInetAccept&#40;sockListen, &addrAccept, &cbAddrAccept&#41;;
        if &#40;sockClient <= 0&#41;
        &#123;
            printf&#40;"accept returned $%x\n", err&#41;;
            printf&#40;"  errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
            goto done;
        &#125;

        sceNetInetSend&#40;sockClient, "Hello from PSP\n\r", 14+2, 0&#41;;
        sceNetInetSend&#40;sockClient, "type all you want\n\r", 17+2, 0&#41;;
            // send returns number of bytes sent

        // This example uses socket timeouts "RCVTIMEO"
        // See the fancy version of WiFi MultiTest for similar telnet-d
        //  without the timeout

        // warning - not all values will work &#40;please confirm experimentally&#41;
        u32 timeout = 1000000; // in microseconds == 1 sec
        err = sceNetInetSetsockopt&#40;sockClient, SOL_SOCKET, SO_RCVTIMEO, &#40;char*&#41;&timeout, sizeof&#40;timeout&#41;&#41;;
        if &#40;err != 0&#41;
            printf&#40;"set SO_RCVTIMEO failed\n"&#41;;

#if 0
        // check the current setting
        &#123;
        u32 data;
        int len;
        err = sceNetInetGetsockopt&#40;sockClient, SOL_SOCKET, SO_RCVTIMEO,
            &#40;char*&#41;&data, &len&#41;;
        if &#40;err == 0 && len == 4&#41;
            printf&#40;"Get SO_RCVTIMEO = %d &#40;$%x&#41;\n", data, data&#41;;
        &#125;
        // NOTE&#58; returns "100"
#endif

        // lame processing loop
        int idleCount = 0; // number of seconds of idle
        while &#40;1&#41;
        &#123;
            char buffer&#91;128&#93;;
            int cch;
            cch = sceNetInetRecv&#40;sockClient, &#40;u8*&#41;buffer, sizeof&#40;buffer&#41;-1, 0&#41;;
            if &#40;cch == 0&#41;
                break;      // connection closed

            if &#40;cch < 0&#41;
            &#123;
                int errno = sceNetInetGetErrno&#40;&#41;;
                if &#40;errno == 11&#41;
                &#123;
                    // recv timeout
                    if &#40;++idleCount >= 15&#41;
                    &#123;
                        // nag
                        sceNetInetSend&#40;sockClient, " &#91;I'm waiting &#93; ", 16+2, 0&#41;;
                        idleCount = 0;
                    &#125;
                    continue; // call recv again
                &#125;
                // other problem
                printf&#40;"recv failed errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
                break;
            &#125;
            buffer&#91;cch&#93; = '\0';
            printf&#40;"%s", buffer&#41;;
            idleCount = 0;
        &#125;
        printf&#40;"\n"&#41;;

        err = sceNetInetClose&#40;sockClient&#41;;
        if &#40;err != 0&#41;
            printf&#40;"closesocket&#40;client&#41; returned $%x\n", err&#41;;
        printf&#40;"Connection closed\n"&#41;;

done&#58;
        // done for now
        err = sceNetInetClose&#40;sockListen&#41;;
        if &#40;err != 0&#41;
            printf&#40;"closesocket returned $%x\n", err&#41;;
    &#125;
&#125;
And the client calls this:

Code: Select all

static void TestClient&#40;const char* szMyIPAddr&#41;
&#123;
	pspDebugScreenClear&#40;&#41;;
    u32 err;

    // instructions
    //pspDebugScreenClear&#40;&#41;;
    printf&#40;"Connected!\n"&#41;;
    //printf&#40;"  telnet to %s port 23\n", szMyIPAddr&#41;;
    printf&#40;"\n"&#41;;

    // mini telnetd-lite server
    &#123;
        SOCKET sockListen;
        struct sockaddr_in addrListen;
        struct sockaddr_in addrAccept;
        int cbAddrAccept;
        SOCKET sockClient;

        sockListen = sceNetInetSocket&#40;AF_INET, SOCK_STREAM, 0&#41;;
        if &#40;sockListen <= 0&#41;
        &#123;
            printf&#40;"socket returned $%x\n", sockListen&#41;;
            goto done;
        &#125;

        addrListen.sin_family = AF_INET;
        addrListen.sin_port = htons&#40;66476&#41;;//23
        addrListen.sin_addr&#91;0&#93; = 0;
        addrListen.sin_addr&#91;1&#93; = 0;
        addrListen.sin_addr&#91;2&#93; = 0;
        addrListen.sin_addr&#91;3&#93; = 0;
            // any

		/*
        err = sceNetInetBind&#40;sockListen, &addrListen, sizeof&#40;addrListen&#41;&#41;;
        if &#40;err != 0&#41;
        &#123;
            printf&#40;"bind returned $%x\n", err&#41;;
            printf&#40;"  errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
            goto done;
        &#125;*/
		char *connectIpAddr;connectIpAddr = memalign&#40;16,32&#41;;
		int IPDigitSelected = 0;
		int buttonCount=0;
		sprintf&#40;connectIpAddr,"000.000.000.000\0"&#41;;
		while&#40;1&#41;&#123;
		pspDebugScreenSetXY&#40;0,15&#41;;
		printf&#40;"\nPleaseEnterConnectIP&#58;"&#41;;
		int k=0;
		for&#40;k=0;k<32;k++&#41;&#123;
			if&#40;&#40;connectIpAddr&#91;k&#93; >= 48 && connectIpAddr&#91;k&#93; <= 57&#41; || connectIpAddr&#91;k&#93; == 46&#41;&#123;//is a number or .
				if&#40;k == IPDigitSelected&#41;&#123;pspDebugScreenSetTextColor&#40;0xffff0000&#41;;&#125;else&#123;
					pspDebugScreenSetTextColor&#40;0xffffffff&#41;;&#125;
				printf&#40;"%c",connectIpAddr&#91;k&#93;&#41;;
			&#125;
		&#125;
		pspDebugScreenSetTextColor&#40;0xffffffff&#41;;
		printf&#40;"\n"&#41;;
		addrListen.sin_addr&#91;0&#93; = &#40;int&#41;&#40;&#40;&#40;int&#41;&#40;connectIpAddr&#91;0&#93;-48&#41;*100&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;1&#93;-48&#41;*10&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;2&#93;-48&#41;&#41;&#41;;
        addrListen.sin_addr&#91;1&#93; = &#40;int&#41;&#40;&#40;&#40;int&#41;&#40;connectIpAddr&#91;4&#93;-48&#41;*100&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;5&#93;-48&#41;*10&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;6&#93;-48&#41;&#41;&#41;;
        addrListen.sin_addr&#91;2&#93; = &#40;int&#41;&#40;&#40;&#40;int&#41;&#40;connectIpAddr&#91;8&#93;-48&#41;*100&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;9&#93;-48&#41;*10&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;10&#93;-48&#41;&#41;&#41;;
        addrListen.sin_addr&#91;3&#93; = &#40;int&#41;&#40;&#40;&#40;int&#41;&#40;connectIpAddr&#91;12&#93;-48&#41;*100&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;13&#93;-48&#41;*10&#41;+&#40;&#40;int&#41;&#40;connectIpAddr&#91;14&#93;-48&#41;&#41;&#41;;
		printf&#40;"sin_addr&#58;%i,%i,%i,%i\n",&#40;int&#41;addrListen.sin_addr&#91;0&#93;,&#40;int&#41;addrListen.sin_addr&#91;1&#93;,&#40;int&#41;addrListen.sin_addr&#91;2&#93;,&#40;int&#41;addrListen.sin_addr&#91;3&#93;&#41;;
		
		//do controls
		SceCtrlData pad;sceCtrlSetSamplingCycle&#40;0&#41;;sceCtrlSetSamplingMode&#40;PSP_CTRL_MODE_ANALOG&#41;;sceCtrlReadBufferPositive&#40;&pad, 1&#41;;

		buttonCount++;
		if&#40;buttonCount > 4&#41;&#123;
			if&#40;pad.Buttons & PSP_CTRL_CROSS&#41;&#123;
			break;
			&#125;

			if&#40;pad.Buttons & PSP_CTRL_LEFT&#41;&#123;IPDigitSelected--;buttonCount=0;&#125;
			if&#40;pad.Buttons & PSP_CTRL_RIGHT&#41;&#123;IPDigitSelected++;buttonCount=0;&#125;
			if&#40;IPDigitSelected < 0&#41;&#123;IPDigitSelected = 0;&#125;
			if&#40;IPDigitSelected > 14&#41;&#123;IPDigitSelected = 14;&#125;
			if&#40;connectIpAddr&#91;IPDigitSelected&#93; != 46&#41;&#123;
			if&#40;pad.Buttons & PSP_CTRL_DOWN&#41;&#123;connectIpAddr&#91;IPDigitSelected&#93;--;buttonCount=0;&#125;
			if&#40;pad.Buttons & PSP_CTRL_UP&#41;&#123;connectIpAddr&#91;IPDigitSelected&#93;++;buttonCount=0;&#125;
			if&#40;connectIpAddr&#91;IPDigitSelected&#93; < 48&#41;&#123;connectIpAddr&#91;IPDigitSelected&#93; = 48;&#125;
			if&#40;connectIpAddr&#91;IPDigitSelected&#93; > 57&#41;&#123;connectIpAddr&#91;IPDigitSelected&#93; = 57;&#125;
			&#125;
		&#125;

		&#125;
		printf&#40;"Connecting to %i,%i,%i,%i\n", addrListen.sin_addr&#91;0&#93;,addrListen.sin_addr&#91;1&#93;,addrListen.sin_addr&#91;2&#93;,addrListen.sin_addr&#91;3&#93;&#41;;

		err = sceNetInetConnect&#40;sockListen,&addrListen,sizeof&#40;struct sockaddr_in&#41;&#41;;
		if &#40;err < 0&#41;
        &#123;
            printf&#40;"Connect&#40;&#41; errored out\n"&#41;;
            goto done;
        &#125;

		printf&#40;"Connect complete\n"&#41;;

		/*
        err = sceNetInetListen&#40;sockListen, 1&#41;;
        if &#40;err != 0&#41;
        &#123;
            printf&#40;"listen returned $%x\n", err&#41;;
            printf&#40;"  errno=$%x\n", sceNetInetGetErrno&#40;&#41;&#41;;
            goto done;
        &#125;*/
		sceNetInetSend&#40;sockListen, "Hello from Client\n\r", 14+2, 0&#41;;



		printf&#40;"wait a sec...."&#41;;
		sceKernelDelayThread&#40;4*1000*1000&#41;;
   //quit
&#125;
In the middle of the client, there is an input loop to insert teh IP into connectIpAddr. The IP of my server is usually 86.137.1xx.xxx.

Any ideas where i'm going wrong?
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

Possibly you don't have appropriate port forwarding in your NAT router.

Normally (these days) NAT is fairly intelligent about mapping and routing replies to connections initiated from behind the firewall to servers in the outside world.

But if you're trying to connect from an client outside the firewall, to a server inside the firewall, then you'll need to configure the firewall to route connections on the appropriate port through to the appropriate internal IP address.

I didn't look at the code yet - judging by previous questions, this sort of NAT issue seems most likely, compared to a coding error.
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

The way I have the network set up is as follows:
The modem is connected to a switch, and the PCs are connected to this switch. The wifi router/AP is then connected to this switch. When my PSP connects to my wifi AP, it goes through the AP, through the switch and through the modem. I know that the switch is definitely doing NAPT, but don't think my wifi AP is.
My switch deals IPs starting at 10.0.0.3 and my AP deals IPs starting at 192.168.1.100. In my AP settings, I have incoming packets on port 55555 forwarded to IP 192.168.1.100 (which is the address my PSP tells my is it's local IP).
Should this now work, or do I need to change the settings on my switch to forward incoming packets to 192.169.1.1 (the AP IP)?

Only thing that gets me is that netlib (or at least SonicBattleArena) appears to work perfectly with no messing around of settings. Maybe this has something to do with me using TCP, and netlib 2.0 using UDP. Is UDP more reliable to get around NAT or my configuration?
Samstag
Posts: 5
Joined: Thu Nov 24, 2005 10:41 am

Post by Samstag »

What Fanjita said.

Configure your router to forward port 66476 to the internal IP address of your PSP (192.168.X.X) and you should be in business.

One of the problems with your method of connecting PSPs is that every end-user who wants to act as a server will have to learn the same thing. This also means that unless your users have admin rights to the router they use nobody (including your connection server) can find them. That ties many players to their home routers.

EDIT: Additional info since I was late in hitting send:

First, you say you forwarded 55555, but your code is opening 66476? Second, your switch will need to be configured for forwarding. Third, if your router is handing out addresses then you've got one more layer to deal with. As it is, you may need to forward from the switch to 192.168.1.1, then forward from the router to 192.168.1.100. Or turn off the router DHCP server and you should get a 10.0.0.X addres at the PSP which you can forward directly from the switch.

Netlib works because both PSPs connect to the server. There is no new connection back to any PSP.
jimparis
Posts: 1145
Joined: Fri Jun 10, 2005 4:21 am
Location: Boston

Post by jimparis »

66476 is not a valid TCP/IP port
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Ok, good news is that I've managed to get the above code fragment to work with port 55555 (I realised it was invalid, so changed it).
Your collective responses were correct, my Wifi setup wasn't working correctly as a server. I used LordSturm's PSP as the server which connected to me perfectly and he recieved my message.
I still can't host the server, so I need to look into my router settings.
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

This probably is getting off-topic for the PS2DEV/PSP forums.
These are general issues for NAT and game servers.

For building any similar game infrastructure I strongly recommend getting it working from PC to PC
That way you can get a reliable infrastructure first, get the server scripts working, and put in more diagnostics
After it is working, worry about the PSP port (and PSP specific details)
----
Selective comments
> (would PHP work?)
It should. You simply need to find the sending ipaddr and port when someone connects to your server.

> PSP#1 can now directly access PSP#2 (and vice-versa)
> Now the question is this: with said connection between PSPA and PSPB (which PSPB connect()ed), is the connection still valid for PSPA to send data back to PSPB

Yes, that's the main reason for the trick I recommended. You don't need to open up any ports on your router or do other router specific tricks.
Assuming the central server can get back to PSPB/PSP#2 then in general PSPA/PSP#1 should be able to get to it as well.
------
If creating a general system (not just for your personal use), then I recommend staying away from router specific tricks
BTW: I am basing this on the way the Nintendo DS WiFi games work (technology from gamespy) - and they do work for a large number of hardware configurations for relatively newbie users.
However it isn't 100%, but it is pretty good (ie. no port forwarding, or other tricks - firewalls can be a problem)

-------
> and the UDP is better...
IMHO: if you are going through the bother of PSP to PSP realtime, you should be using UDP. Define your protocol to be fault tolerant (ie. include a sequence number). Don't hang if you miss a few UDP packets.

> I tried to find out my 'real' IP address by calling this script: ...
That's half of the problem.
What NAT does it translate you local IP and local port into an EXTERNALLY VISIBLE IP address *AND* port. The port number is changed - that's the cool part about NAT - one IP address and many different ports (which act as alternative IP addresses)

> I didn't look at the code yet...
Me neither - my head already exploded ;->
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Ok. I've fixed up my router settings (I think), and my PSP can now act as the server and recieve data from the client. For some reason, when connecting to another PSP, the code:

Code: Select all

u32 timeout = 1000000; // in microseconds == 1 sec
        err = sceNetInetSetsockopt&#40;sockClient, SOL_SOCKET, SO_RCVTIMEO, &#40;char*&#41;&timeout, sizeof&#40;timeout&#41;&#41;;
        if &#40;err != 0&#41;
            printf&#40;"set SO_RCVTIMEO failed\n"&#41;;
fails, but when I use my PSP as a server and connect locally via telnet, it works fine.

I'm trying to make the socket non blocking to avoid this, but there doesn't seem to be a define for it in my_socket.h
Should there be a define for it, or is non-blocking setup a different way?

EDIT: nvm, think i've got it
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

Ok, I've got all my communication calls (like recv) to be non-blocking by calling

Code: Select all

int setSockNoBlock&#40;SOCKET s, u32 val&#41;
&#123; 
    return sceNetInetSetsockopt&#40;s, SOL_SOCKET, 0x1009, &#40;const char*&#41;&val, sizeof&#40;u32&#41;&#41;;
&#125;
EDIT: Got sceNetInetPoll working in what appears to be a correct manner.
AnonymousTipster
Posts: 197
Joined: Fri Jul 01, 2005 2:50 am

Post by AnonymousTipster »

I've decided to drop TCP in favour of UDP, which should suit my needs better.
Problem is that sceNetInetRecvfrom() always returns -1 with an errno of 11, which is supposed to be Resource Temporarily Unavailable.
EDIT: I've found elsewhere that errno 11 is EAGAIN, saying that it would block if it wasn't set to non-blocking. Unfortunately, it still doesn't recieve the data even if it's being sent constantly from another PSP.
My code is:

Code: Select all

       sockaddr addrDS;
		socklen_t addr_len;addr_len = sizeof&#40;addrDS&#41;;
			char* buffer;buffer = &#40;char*&#41;memalign&#40;16,MAX_INCOMING&#41;;memset&#40;buffer,'\0',MAX_INCOMING&#41;;
		int byt;
byt =sceNetInetRecvfrom&#40;&#40;int&#41;sockUDPServer,&#40;void*&#41;buffer,&#40;size_t&#41;MAX_INCOMING-1,0,&#40;sockaddr*&#41;&#40;&addrDS&#41;, &#40;socklen_t*&#41;&addr_len&#41;;
		
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

Don't know about nonblocking
UDP blocking receive *does* work (see the photo frame feature of the original WiFi03 sample)
I suggest spawning another thread to do the UDP reading/waiting. That has other advantages instead of constantly polling
Post Reply