The Power of Signed vs Unsigned

Developer Blogs & Updates

The Power of Signed vs Unsigned

Postby Schmunzel on January 15th, 2010, 6:49 am

It was for some time now, that we had trouble with some of our qa - Staff not being able to relog to the loginserver after having been disconnected. ONLY the Loginserver. As long as they stayed logged in they could hop from zone to zone at their leisure - the connectionserver handed them nicely from server to server.
The puzzling thing however, was that it only happened on the tc, that it only happened to some of the QA - and only sometimes - and that no one of us could reproduce the issue on our own developement machines.

The initial thought was that it was a threading issue which surfaced as we just ported our entire core from 3rd party libraries like zThread to Boost

Intensive debugging efforts yielded the rather surprising result, that the hash that was constructed out of adress and port was sporting a different value when the session was looked up for destruction than when it was used to look a session up in the session map when a packet arrived.

now.

Adress|(uint64)(port<<32) with adress and port being constant do not have a lot of room for different values. - None to be precise.
OF course, - when someone suspects threading issues, those issues can be used to blame almost anything on them!
So while investigating this issue I came up with a master plan, so that I could ensure that the Adressmap was only accessed from one single thread. Always. ever. - To no avail.
I played with this for 4 Weeks - without any success in resolving the issue.

Until. I found. That the session object. Stored the adress as unsigned integer.

...

For everyone not using Sockets - the Adress as returned by the Socket is a signed integer.
Schmunzel
MasterDoc HORDE
Dantooine Infinity
SWG:ANH Resident Wookiee :evil:
Schmunzel
SWGANH Developer
 
Posts: 109
Joined: December 24th, 2008, 8:18 pm

Re: The Power of Signed vs Unsigned

Postby Eruptor on March 24th, 2010, 4:49 pm

May I suggest the alternate title to this blog “How to spend 4+ weeks not having a clue” :)

First, Socket does NOT store the Adress as signed, as you claim.
Here is the definition from Windows SDK

typedef struct sockaddr_in {
#if(_WIN32_WINNT < 0x0600)
short sin_family;
#else //(_WIN32_WINNT < 0x0600)
ADDRESS_FAMILY sin_family;
#endif //(_WIN32_WINNT < 0x0600)

USHORT sin_port;
IN_ADDR sin_addr;
CHAR sin_zero[8];
} SOCKADDR_IN, *PSOCKADDR_IN;

typedef struct in_addr {
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;


If you store the data otherwise, don’t blame Sockets for that.


Second, the Adress uses unsigned integer, CORRECTLY. Expanding any unsigned to unsigned 64 bits will NOT alter the value. So that’s has nothing to do with you problem, either. You could have had an issue with the Adress, if you had used it as signed, but you claimed that was not the case :
“Until. I found. That the session object. Stored the adress as unsigned integer.”



The resulting hash value is stored in an unsigned 64 bits variable (not shown by your example), so the unsigned Adress part will occupy the lowest 32 bits unaltered.

According to your example, “Adress|(uint64)(port<<32)” ,
if port is 16 or 32 bits, and shifted 32 bits to the left; the result will ALWAYS be zero.
It does not matter then that the result after the shift is expanded to 64 bits. Zero expands to zero.

You end up with a hash consisting of the Adress only. That’s why you got issues when attempting to relog, even if the client uses a different Port.
You should also have seen this issue if you had done any testing with two clients simultaneously from same host (same address). Come on, you said you were hunting threading issues during 4 weeks, what did you do?


Try something like this instead, expand the Port value to 64 bits BEFORE shifting it. Also make sure that Port is unsigned before casting to uint64.

struct sockaddr_in from;
uint32 address;
uint16 port;

address = from.sin_addr.s_addr;
port = from.sin_port;
uint64 hash = address | (((uint64)port) << 32);

The funny thing is, the code example above is picked from the official ANH code base, file SocketReadThread.cpp date 2009-09-22.

Friendly advice:
When putting up code on a blog, you have to at least describe the data types used; without them the example may be completely useless for everybody not having your source files.
and
Don’t fix what’s not broken.


Cheers Eru
Eruptor
 
Posts: 20
Joined: January 24th, 2009, 3:07 pm

Re: The Power of Signed vs Unsigned

Postby Schmunzel on March 25th, 2010, 5:51 am

Hey Eruptor :)
Its nice to hear from you again :)
Sadly you do not understand the point I was making.
It is of no concern to me if the sessions adress is stored as signed or unsigned - infact I couldnt care less.
The issue is that if it is stored as either way it shouldnt be converted to something different.
A Hash that was created with a signed integer that has a negative value is quite different from a hash that is created by the same integer after it has been converted to an unsigned integer.

So we just need to decide whether we store it the one way or the other. Then our hashs will stay the same and the session will always be found :)

As the bug that prevented us to delete the session was solved after changing that it certainly indicates that my Analysis of the situation was proper. When the Sessions adress needs to be stored as an unsigned integer we happily can do so. We just need to do so from the start.

My last comment saying that it is a signed integer seems indeed to be false, as our current code converts the ULONG to a signed integer.
Thus, storing it then as signed integer seems to be an internal thing we are doing!

still doing uint64 hash = address | (((uint64)port) << 32);

with 5 instead of -5 for adress, will give us a different hash.

It would be nice however if you complained to the person implementing the hash, as I am just the one who has to live with the current Netlayer somehow :)
Schmunzel
MasterDoc HORDE
Dantooine Infinity
SWG:ANH Resident Wookiee :evil:
Schmunzel
SWGANH Developer
 
Posts: 109
Joined: December 24th, 2008, 8:18 pm

Re: The Power of Signed vs Unsigned

Postby Eruptor on March 26th, 2010, 6:32 pm

Hi Schmünzel!

The title hinted to reveal something about the mystery about signed and unsigned data.
I honestly have to say the article itself did not explain much of that.

And my suggestion for a new title was a joke, thus the smiley.

Your second post confirmed what I thought was the issue, and thanks for the clarification.
I just thought the blog was confusing, especially when trying to interpretate the examples.
If you don’t mind, let me post my view of signed and unsigned.


To be “on topic” about the mystery of signed versus unsigned data, let’s focuses on the topic hinted by the title of this blog.

16 bits data can hold a value between 0 and 65535, that’s 0x0000 – 0xFFFF in hexadecimal.
That is, if the representation is unsigned (positive values only).

When 16 bits data is used as signed, they can represent value between -32768 to 32767.

As an example of signed data, the value of -5 is represented by the hexadecimal 0xFFFB.
0 = 0x0000
-1 = 0xFFFF
-2 = 0xFFFE
-3 = 0xFFFD
-4 = 0xFFFC
-5 = 0xFFFB
….

If the same value 0xFFFB would be treated as a positive, unsigned, the decimal value would be 65531.
0 = 0x0000
1 = 0x0001
….
….
0xFFFB = 65531

Let’s assume we have a value of 0xFFFB in a 16 bits variable and we would like to expand that value into a 32 bit variable.

If we treat 0xFFFB as an unsigned value (65531), the new 32 bits value would be 0x0000FFFB (still 65531).

If 0xFFFB is treated as signed (-5), the new 32 bits value would be 0xFFFFFFFB (still -5).

Conclusion: The expansion of a 16 bits value (0xFFFB ) to a 32 bits value depends on how the value is treated, signed or unsigned. (a somewhat simplified explanation).


Let’s go back to the issue in the OP, using the 32 bits IP address as a base for 64 bits value and then adding (by or’ing) the Port value at the upper 32 bits.

An IP address of 192.168.10.5 would be represented as 0xCOA80A05.
192 = CO
168 = A8
10 = 0A
05 = 05

If treated as unsigned, the expanded 64 bits value would be 0x00000000COA80A05, and any Port address or’ed into the upper 32 bits would be significant for the value of the new 64 bits data. This would be working as intended.

If treated as signed, the sign expansion will convert the data 0xCOA80A05 to 0xFFFFFFFFCOA80A05. Any Port address or’ed to the upper 32 bits would not change the value of the new 64 bits data, since all bits already set to 1. This could be the reason for the hash issues.


Since the msb of 192 (most sigificant bit, 0xCO) was set to 1, it’s possible to get different results if data is treated as signed or unsigned. If the IP address had started with 64 (0x40), like in 64.7.136.227, the msb would have been 0, and the signed expansion would not have been an issue, since the data would have been treated as positive. So the IP address itself may be a clue to why some servers do have the issue and some servers don’t.

Your system may store the IP address reversed, then the 227 in the example above may be a clue (msb is set), but I have not bothered to check, the above is just an example of what may happened if you don’t handle unsigned and signed data correctly, not a “how to” of handling IP’s or how Socket store data. That’s beyond my point.

Cheers Eru
Eruptor
 
Posts: 20
Joined: January 24th, 2009, 3:07 pm

Re: The Power of Signed vs Unsigned

Postby Schmunzel on March 27th, 2010, 4:05 am

Ok - now you get me to learn to become a full fledged IT Specialist.
I agree that the bit representation of an int32 5 to an uint32 5 is the same.
With the borderline case that if we convert a high enough positive uint32 to an int32 we will get screwed.

I will look up the code tomorrow and reserve my answer until then to not blame myself further ... :)
Schmunzel
MasterDoc HORDE
Dantooine Infinity
SWG:ANH Resident Wookiee :evil:
Schmunzel
SWGANH Developer
 
Posts: 109
Joined: December 24th, 2008, 8:18 pm


Return to Development

Who is online

Users browsing this forum: No registered users and 1 guest