Thread: UDP Sockets (linux)

  1. #16
    Registered User
    Join Date
    Nov 2008
    Posts
    127
    buf1 is an array but you are passing &buf1. This will copy the inbound data to some undesirable point in memory. This could be why printing out result is causing a crash. recvfrom takes a void *. Arrays are pretty much identical to pointers in terms of use, so just cast buf1 to a void * when you pass it into recvfrom.

  2. #17
    Registered User
    Join Date
    Nov 2011
    Posts
    20
    Right, no more segfaults. However it still isnt saving the buffer into the appropriate places in the struct. i assumed it would do that automatically with:

    Code:
    ReplyPacket *temp; temp = (ReplyPacket *) buf1; cout << "Struct" << temp->hostname << "\n";
    But the above example doesnt print the hostname out as it should. which is buf1[5] .. buf1[n] == NULL btw. Perhaps i should go back to basics here, I thought it would
    save the buffer into the struct automagically, but i guess im wrong about that. Ill go back to basics with parsing the buffer by NULL and using string sizes to figure out
    what data is meant to go where.

  3. #18
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    We would need to see what your sendto() looks like, to start making any guesses as to whether your receive code is doing anything useful.

    Assuming for the moment that it is a string of printable characters, then it is broken.
    Code:
                        char buf1[1024];
                        result = recvfrom(sockfd, buf1, 1024, 0, (struct sockaddr *) &udp_fromaddr, &length);
                        cout << "Bytes Received: " << result << "\n";
         
                        string newbuf;
                        newbuf = buf1;
    a) there is no evidence of a \0
    b) recvfrom() won't add one for you, unless you explicitly send a \0
    c) there isn't room in the buffer to add a \0, if recvfrom() writes 1024 bytes of data.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #19
    Registered User
    Join Date
    Nov 2011
    Posts
    20
    My coding is based on communicating with a Valve source server, in the example code i listed it communicates with a Left 4 Dead 2 server. The sendto is fully functional, it sends the appropriate challenge to the server, and the server does respond with the correct information based on the A2S_INFO reply listed on https://developer.valvesoftware.com/...urce_servers_2

    That reply is what im trying to decode and parse and enter into a struct in my program. As i say, the send packet is fully functional as the program receives the correct response and the correct information from the server (that i can tell doing char by char output), its just the receiving packet I have a problem/issue with parsing. As i dont have access to the server, i cant see how its being sent, but i do have the example reply from the above web page.

    Based on the above information listed on the website, the packet consists of the following:

    Type byte Should be equal to 'I' (0x49)
    Version byte Network version. 0x07 is the current Steam version. Goldsource games will return 48 (0x30), also refered to as protocol version.
    Server Name string The Source server's name, eg: "Recoil NZ CS Server #1"
    Map string The current map being played, eg: "de_dust"
    Game Directory string The name of the folder containing the game files, eg: "cstrike"
    Game Description string A friendly string name for the game type, eg: "Counter Strike: Source"
    AppID short Steam Application ID
    Number of players byte The number of players currently on the server
    Maximum players byte Maximum allowed players for the server
    Number of bots byte Number of bot players currently on the server
    Dedicated byte 'l' for listen, 'd' for dedicated, 'p' for SourceTV
    OS byte Host operating system. 'l' for Linux, 'w' for Windows
    Password byte If set to 0x01, a password is required to join this server
    Secure byte if set to 0x01, this server is VAC secured
    Game Version string The version of the game, eg: "1.0.0.22"
    Extra Data Flag (EDF) byte if present this specifies which additional data fields will be included
    if ( EDF & 0x80 ) short The server's game port # is included
    if ( EDF & 0x10 ) long long The server's SteamID is included
    if ( EDF & 0x40 ) short string The spectator port # and then the spectator server name are included
    if ( EDF & 0x20 ) string The game tag data string for the server is included [future use]
    if ( EDF & 0x01 ) long long The server's 64-bit GameID is included

    Strings are terminated by "\0" within the packet. The problem i have is finding out how long the string is within the packet so then i can find the location of the next string. So, id need to find "\0" within the packet to find the end point of "hostname", then +1, and find the next end point to retrieve the map name.

    The problem i currently have, is that when the data is within the "char buf1", and if i copy it to a string variable as i stated, i cant use for example:

    Code:
    string test;
    test = buf1;
    int i;
    for (i = 6; i < (bytesreceived - 6); i++)
    {
         if (test.substr(i, 1) == NULL) {
              // NULL located. get text from start location and copy to 
              // appropriate struct member
         }
    }
    As for some reason, the substr(i,1) is invalid, i believe due to the the way its store in the buf1 variable, and its use of bytes.

    using cout << buf1 << "\n" would output the buffer by 4 characters, until it hit the 5. Now whilst, buf1[6] and upwards is still accessible, for some reason, it believes that the data ends at [4].

    Now, either im going insane, having a really bad week and overlooking something, or i need a slap. It could be all 3 tbh. I did code another program which communicated with servers, but alas it was a php script, and that coding was lost in the ether some time ago.

  5. #20
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I'd use a less improptu method for checking the server response, like writing out verbatim to a file and using hexdump. You could also try the code I posted here:

    need some help with writing and reading to/from a file

    (in post #29, I think this gets screwed up by the post-load syntax highlighting)

    Which looks best on linux if you use a terminal with a dark background. This will just allow you to confirm the response is structured the way you think it is.

    After that, the best way to deal with protocols like this, IMO, is to parse byte by byte. That's kind of what you are doing, but awkwardly. Put all the data into a temporary single buffer and extract from that. C++ strings are not so good for this as they are intended for text data and the header is not text, even if it contains some. You could use a vector<char> or a plain char array and work your way thru. Putting the string type members into a string is fine, but finding them in a haystack typed string is not.

    So, eg, if the first member is an int, read exactly four bytes from the beginning into an int. If the next member is a string, keep a placeholder (index or pointer) to the beginning. Then you keep going until you find the '\0'. Now you know how long the data is and where it starts in the buffer, place that into a string. Don't just throw it all into a string, search that for zero, truncate, and put the data back or whatever it is you were thinking.

    Also, for your statically sized numerical types, don't just use int, use int32_t or whatever is precisely appropriate.
    Last edited by MK27; 01-11-2012 at 02:21 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #21
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    So where in the spec does it say that the strings are a given length?
    Code:
        char ServerName[256];
        char Map[32];
        char GameDirectory[32];
        char GameDescription[256];
    Because you can't guarantee the padding and alignment in your code, you should really do it the long way. Well you can mostly fix P&A with say #pragma pack, if your compiler supports it, but there's no way to fix Endianness if your machine differs from the sender.

    Typically, you receive the data into an unsigned char buffer, then you laboriously go through with things like
    Code:
    struct A2SReplyPacket info;
    info.Type = buffer[0];
    info.Version = buffer[1];
    strncpy(info.ServerName,&buffer[2],sizeof(info.ServerName));
    info.ServerName[sizeof(info.ServerName)-1] = '\0';
    // and so on
    Also, get wireshark so you can see what is actually being sent on the wire.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #22
    Registered User
    Join Date
    Dec 2011
    Posts
    795
    Oddly, I've written a Source engine info retriever as well, you can take a look at my code if that helps:

    [C] tf2 info ret. - Pastebin.com

    Edit: yes, I'm aware of the memory leakage, but that wasn't really my first priority writing it. I'll fix it if I get around to it.

  8. #23
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > Oddly, I've written a Source engine info retriever as well,
    Can you say how all your string copies from the received data to your data structure
    a) do not overflow
    b) how they become \0 terminated

    And why they're different sizes to the structure the OP posted.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #24
    Registered User
    Join Date
    Nov 2011
    Posts
    20
    Quote Originally Posted by memcpy View Post
    Oddly, I've written a Source engine info retriever as well, you can take a look at my code if that helps:

    [C] tf2 info ret. - Pastebin.com

    Edit: yes, I'm aware of the memory leakage, but that wasn't really my first priority writing it. I'll fix it if I get around to it.

    Thanks for this, ill take a look at it later on this afternoon.

  10. #25
    Registered User
    Join Date
    Nov 2011
    Posts
    20
    Managed to do this eventually. I just went through the buffer looking for the NULL character, and copied the strings from last null+1 to current null-1 to obtain the server information. Thanks for the help with this though.

    However, next question. If i wanted to run this on both linux and windows, should i write my socket class/library to each, ie Berkley and Winsock, or should i insist people compile with Cygwin for example? Any benefits/cons to only using Cygwin or Berkley/Winsock?

  11. #26
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Just how fancy is your socket code?

    Intro
    Apart from needing WSAStartup(), and select not working on non-socket descriptors, there isn't a lot in it.

    You could make your own "thin" class, where the ctor calls WSAStartup() in Windows, and does nothing in Linux, and then say your class.recv() maps directly to the recv() API of each respective OS.

    You end up with mySockClass_windows.cpp and mySockClass_Linux.cpp where all the detail is hidden, and the rest of your code just has #include "mySockClass.h".
    The only extra bit of magic is when you build, you make sure of your choice of implementation.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #27
    Registered User
    Join Date
    Nov 2011
    Posts
    20
    Quote Originally Posted by Salem View Post
    Just how fancy is your socket code?
    Ha, not very fancy at all tbh, it works but currently has basic error checking, it only supports Linux natively, with support for windows sockets when compiled with Cygwin on Windows (test app i wrote to use it doesnt throw any errors at me and works as intended). Id like to implement native Windows socket support so then i dont have to rely on Cygwin as a compiler if I decided to allow others to use it from source. Altho I guess i could just supply binaries of the dll for Windows.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. UDP Sockets in C under Linux
    By goodsamaritan in forum C Programming
    Replies: 6
    Last Post: 03-23-2011, 06:02 AM
  2. Linux Sockets in C
    By Scythed in forum C Programming
    Replies: 8
    Last Post: 11-07-2010, 10:23 AM
  3. sockets in linux question
    By matrixon in forum Networking/Device Communication
    Replies: 6
    Last Post: 08-27-2006, 01:48 PM
  4. Segfault with C sockets on Linux
    By arti_valekar in forum C Programming
    Replies: 3
    Last Post: 02-16-2005, 02:25 AM
  5. Need help with Linux sockets
    By junbin in forum Linux Programming
    Replies: 1
    Last Post: 07-21-2002, 12:42 PM