select()

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

Moderators: cheriff, TyRaNiD

Post Reply
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

select()

Post by DaVajj »

The network select() command implemented through the PSPSDK, does it support everything the normal network select() does?

Cause i've had problems with passing a timer crashing my PSP, and passing a set of sockets to check for write makes it return immediatly (the sockets are usually writable, so i know why it does that) but then the set of read sockets i pass in doesn't get set like they should.

Isn't the PSPSDK select() fully done yet, or am i just doing something awfully wrong here?

At one point i do a select on all the sockets my program handles, and i don't pass a timer structure to select() since i want the program to block, since if i don't have any readable/writable sockets my program just might as well do nothing, and therefore save CPU. But as soon as a socket is either readable or writable, i want the select() to return. And well, yeah, this is my problem. When passing a write set to select, my read set doesn't get set like i expect it to be set.

Any help would be appreciated. Could post code if someone needs it.
TyRaNiD
Posts: 907
Joined: Sun Jan 18, 2004 12:23 am

Post by TyRaNiD »

Hmm are sockets not always writable unless the buffer fills up, therefore specifying a write set will only make it return immediately?

And the select should be fully working, it uses Sony's library to do it so if theirs doesn't work neither will ours (and I have used select quite happily). The only thing to bear in mind is when using the bsd like names for the socket api (such as socket(), recv(), send() etc.) then socket returns the socket number + a constant so that the underlying c library can use them for things like write/read/close which would otherwise not work. The upshot of this is if you are doing something like taking the last socket number as the higest socket value it might do strange things cause the number will be in the millions.

All in all unless you are porting existing code which you really dont want to change to much you are best off using the Sony names, e.g. sceNetInetSocket(), sceNetInetSelect to do your stuff.
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

Post by DaVajj »

That constant had me thinking a while. I saw it in a sample, and just as they do i pass FD_SETSIZE to select().

"Hmm are sockets not always writable unless the buffer fills up, therefore specifying a write set will only make it return immediately? "
Yeah. But if there's an incoming connection, and i've got the listener socket added to my read set, wouldn't the set contain my listener? Even though i pass other sockets (and the listener too) in as the write set?

It seems select() favors the write set and doesn't process the read set.
If this is normal select() behaviour then i guess i need to do this some other way ~_~.
(Maybe the problem is i've got the listener in the write set, cause normally you don't write to listening sockets... Hmm, i'll try some stuff out later. )
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

Post by DaVajj »

So.

Code: Select all

mySocket = create_socket() //just pseudo function giving me a socket
fd_set mySet;
FD_SET( mySocket, &mySet );
FD_ISSET( mySocket, &mySet ); //This would return false
I come to this conclusion through observing the net/simple example from the PSPSDK. Is this correct? I recon it must be since:

Code: Select all

	FD_ZERO(&set);
	FD_SET(sock, &set);
	setsave = set;

	while(1)
	{
		int i;
		set = setsave;
		if&#40;select&#40;FD_SETSIZE, &set, NULL, NULL, NULL&#41; < 0&#41;
		&#123;
			printf&#40;"select error\n"&#41;;
			return;
		&#125;

		for&#40;i = 0; i < FD_SETSIZE; i++&#41;
		&#123;
			if&#40;FD_ISSET&#40;i, &set&#41;&#41;
			&#123;
				int val;

				/* Unfortunate cludge to make things work &#58;&#40; */
				val = i | SOCKET_FD_PAT;
				if&#40;val == sock&#41;
				&#123;
					new = accept&#40;sock, &#40;struct sockaddr *&#41; &client, &size&#41;;
Here they have a set, add their socket, run it through select, and check through all socket ids and find one that is set, and then they need to do the
val = i | SOCKET_FD_PAT to see if the value in the set, would represent our socket id.

And i notice they use write() in the example, why do they use that, and not regular send() ?
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Post by raf »

DaVajj wrote:So.

Code: Select all

mySocket = create_socket&#40;&#41; //just pseudo function giving me a socket
fd_set mySet;
FD_SET&#40; mySocket, &mySet &#41;;
FD_ISSET&#40; mySocket, &mySet &#41;; //This would return false
You need to call FD_ZERO(&mySet); before you can call FD_SET, as your mySet is in an uninitialized state until you do.
Then, after doing FD_SET for mySocket, FD_ISSET SHOULD RETURN TRUE.

Here they have a set, add their socket, run it through select, and check through all socket ids and find one that is set, and then they need to do the
val = i | SOCKET_FD_PAT to see if the value in the set, would represent our socket id.
You don't need (or can for that matter) use the SOCKET_FD_PAT anymore (if you update to the latest newlib), as I removed it.
And i notice they use write() in the example, why do they use that, and not regular send() ?
write will internally call send, if the passed file descriptor is a socket.

Raf.
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

Post by DaVajj »

Now why is this code not working as it is supposed to?
itsSocketID is a listening socket.
And when i run this, the socket is set all the time, even when there's not an incoming connection available. And then my programs just gets stuck on the accept() call.

By the way, i figured it isn't a good thing calling select on just a set with one socket. Cause this is what i do in each of the CSocket classes. Which could take down speed with alot of people connected. Or, isn't it that bad? Comments?

Code: Select all

bool CListenSocket&#58;&#58;update&#40;&#41;
&#123;
	if&#40; !listening&#40;&#41; &#41; return false;

	//Timer variables
	timeval timer;
	timer.tv_usec = 0;
	timer.tv_sec = 0;
	
	//Socket sets	
	fd_set read_fds;
	FD_ZERO&#40;&read_fds&#41;;
	FD_SET&#40;itsSocketID, &read_fds&#41;;

	printf&#40;"Before select."&#41;;
	if&#40;select&#40;itsSocketID + 1, &read_fds, NULL, NULL, &timer&#41; < 0&#41;
	&#123;
		printf&#40;"Error in select! &#58;O\n"&#41;;
		closeListener&#40;&#41;;
		return false;
	&#125;
	printf&#40;"After select."&#41;;

	if&#40; FD_ISSET&#40; itsSocketID, &read_fds&#41; &#41;
	&#123;
		printf&#40;"listener set!\n"&#41;;
		//Reset
		//*statusVariable = 0;

		//Variables
		size_t size;
		struct sockaddr_in clientInfo;
		int newSocket = accept&#40;itsSocketID, &#40;struct sockaddr *&#41; &clientInfo, &size&#41;;
		if&#40; newSocket < 0 &#41;
		&#123;
			closeListener&#40;&#41;;
			return false;
		&#125;

		socketList.push_back&#40; new CSocket&#40;newSocket&#41; &#41;;
	&#125;

	printf&#40;"end of update&#40;&#41;\n"&#41;;
	//Success
	return true;
&#125;
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Post by raf »

DaVajj wrote:Now why is this code not working as it is supposed to?
itsSocketID is a listening socket.
And when i run this, the socket is set all the time, even when there's not an incoming connection available. And then my programs just gets stuck on the accept() call.

By the way, i figured it isn't a good thing calling select on just a set with one socket. Cause this is what i do in each of the CSocket classes. Which could take down speed with alot of people connected. Or, isn't it that bad? Comments?

Code: Select all

bool CListenSocket&#58;&#58;update&#40;&#41;
&#123;
	if&#40; !listening&#40;&#41; &#41; return false;

	//Timer variables
	timeval timer;
	timer.tv_usec = 0;
	timer.tv_sec = 0;
	
	//Socket sets	
	fd_set read_fds;
	FD_ZERO&#40;&read_fds&#41;;
	FD_SET&#40;itsSocketID, &read_fds&#41;;

	printf&#40;"Before select."&#41;;
	if&#40;select&#40;itsSocketID + 1, &read_fds, NULL, NULL, &timer&#41; < 0&#41;
	&#123;
		printf&#40;"Error in select! &#58;O\n"&#41;;
		closeListener&#40;&#41;;
		return false;
	&#125;
	printf&#40;"After select."&#41;;

	if&#40; FD_ISSET&#40; itsSocketID, &read_fds&#41; &#41;
	&#123;
		printf&#40;"listener set!\n"&#41;;
		//Reset
		//*statusVariable = 0;

		//Variables
		size_t size;
		struct sockaddr_in clientInfo;
		int newSocket = accept&#40;itsSocketID, &#40;struct sockaddr *&#41; &clientInfo, &size&#41;;
		if&#40; newSocket < 0 &#41;
		&#123;
			closeListener&#40;&#41;;
			return false;
		&#125;

		socketList.push_back&#40; new CSocket&#40;newSocket&#41; &#41;;
	&#125;

	printf&#40;"end of update&#40;&#41;\n"&#41;;
	//Success
	return true;
&#125;
At first glance, that looks like it should work. A question though, why are you passing a zeroed timer to select? that will cause it to return immediately. Pass a NULL if you want it to block until something is ready.
Are you using the latest newlib? I commited a patch late last week with my own implementation of select(). It will internally call the sceNet select for sockets, though; so I'd think it would behave the same way for something like this. But just in case. (If you're using the old newlib, then passing socket+1 may not work right, btw. try passing FD_SETSIZE)

Raf.
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

Post by DaVajj »

Thanks for the quick response, i'm really eager to get this thing working.
Well, i pass a zeroed timer just because i don't want wait-time at all, i just want to poll the socket. All my connections are of class CSocket, and on each main loop i call update() on them causing the socket to read in all network data and place it in a buffer, and send as much data as possible. Doing all this in a main loop means i can't have anything blocking, then i'll end up with a slow program. I'm trying to do a multiplexed ftp server, i.e i'm just using one thread for everything. Passing zeroes like this has always worked for me before. And the correct behaviour for select() is to not have any sockets set in the read_fds if the timer runs out and nothing has happened, or so i read here: http://www.scit.wlv.ac.uk/cgi-bin/mansec?3C+FD_ISSET.

Quoting site:
"If the time limit expires before any event
occurs that would cause one of the masks to be set to a
non-zero value, select() completes successfully and returns
0."

I've also tried with FD_SETSIZE. I downloaded the 20060120 toolchain script and ran it, so i guess i should have the latest newlib. (i hope).

Anyway, calling select like this in each of my CSockets just to poll one socket at a time maybe isn't that good of an idea, so i was thinking of centralizing it somehow. But that would mean that my main loop would block, until i can do something network-wise. But since i'm trying to do a simple FTP that also won't work since i'm gonna read/write files, and at each loop i need to read in some new data to send. Well, it just get's difficult. But i thought this way would work for now...
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Post by raf »

DaVajj wrote:Thanks for the quick response, i'm really eager to get this thing working.
Well, i pass a zeroed timer just because i don't want wait-time at all, i just want to poll the socket. All my connections are of class CSocket, and on each main loop i call update() on them causing the socket to read in all network data and place it in a buffer, and send as much data as possible. Doing all this in a main loop means i can't have anything blocking, then i'll end up with a slow program. I'm trying to do a multiplexed ftp server, i.e i'm just using one thread for everything. Passing zeroes like this has always worked for me before. And the correct behaviour for select() is to not have any sockets set in the read_fds if the timer runs out and nothing has happened, or so i read here: http://www.scit.wlv.ac.uk/cgi-bin/mansec?3C+FD_ISSET.

Quoting site:
"If the time limit expires before any event
occurs that would cause one of the masks to be set to a
non-zero value, select() completes successfully and returns
0."
That is correct, it will return 0, make sure you look at the return value of select() and only act on the fd_set if it's greater than 0.
It's OK that you poll like that, if that's your intention. Just make sure you're not in a busy loop continuosly, that's not good practice.
(But it shouldn't have the descriptor bit set after select, unless it's ready, or select returns error, that's true).
I've also tried with FD_SETSIZE. I downloaded the 20060120 toolchain script and ran it, so i guess i should have the latest newlib. (i hope).
That's not the latest, like I said, I patched it last week, the toolchain you are using is from Jan 20th. To get the latest you will need subversion.

Raf.
DaVajj
Posts: 9
Joined: Wed Apr 19, 2006 12:39 am

Post by DaVajj »

Doesn't the psptoolchain script grab the newest stuff from the SVN and install it all?

Edit: Else, how do i go about getting and installing the latest newlib? (Running a native linux envoirment, also got svn)
raf
Posts: 57
Joined: Thu Oct 13, 2005 7:38 am

Post by raf »

DaVajj wrote:Doesn't the psptoolchain script grab the newest stuff from the SVN and install it all?

Edit: Else, how do i go about getting and installing the latest newlib? (Running a native linux envoirment, also got svn)
Maybe it does, I'm not sure.. I use svn exclusively.. If it does, then you still would need to rebuild. Question for the people in the know.

Raf.
cory1492
Posts: 216
Joined: Fri Dec 10, 2004 1:49 pm

Post by cory1492 »

DaVajj wrote:Doesn't the psptoolchain script grab the newest stuff from the SVN and install it all?

Edit: Else, how do i go about getting and installing the latest newlib? (Running a native linux envoirment, also got svn)
Get psptoolchain directly from svn repository or run "svn update" where you have psptoolchain extracted to. I just did an update of my psptoolchain that way and the newlib patch was updated to a May 03/2006 v1893. Some of your other stuff will probably need updating too.
Post Reply