Thread: simple dict client problem

  1. #16
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    My client runs ok now, althrough now i also need to write a server. So I do, but in one of the lines i am receiving segmentation error, which i understand is an event that occurs when i try to acces memory that doesnt exist(?)

    And this happens at this line:
    Code:
    *(pos + 1) = '\0';
    without it i can connect to my server and receive answer properly, but receiving answer from dict.org server is faulty.
    I have to honest with you, im not sure what is the need for this line.
    Would you mind explaining it?
    The if-statement checks whether the reply from the server contains the terminating sequence. If it's true it searches for the next newline character which should terminate the status line (the line starting with "250"). But your server doesn't send a correct status message, thus "pos" will be NULL and you are trying to dereference an invalid address.

    Code:
            if ((pos = strstr(pos, "\r\n.\r\n250")))
            {
                pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
    I've used pos + 6 on purpose in the second call of strstr(). After the first call, "pos" will point to the first '\r' of the sequence "\r\n.\r\n250". Thus pos + 6 will point to '5' and you are able to look for the next '\n' which will terminate the status message ("250 <possible some text>\r\n").
    I admit this was a hack and in hindsight I shouldn't have used it. It would be better to split the reply from the server into lines (terminated by '\n'). Then you should simply wait for a line which contains only ".\r\n" which is the sign that the text message is over. Finally you would parse the following status line (parsing a status line is a good candidate for a function).

    Code:
        message = "151 Definicja Pingwina yo\nDefinicja Pingwina yo\nDefinicja Pingwina yo\n\r\n.\r\n250";
    That's the line which is wrong in the server code. The end of the message should read "250\r\n" to send a valid status message.

    I've also noticed some other things:
    Code:
    int socket_desc , new_socket , c , *new_sock;
    ...
    new_sock = malloc(1);
    *new_sock = new_socket;
    "new_sock" is a pointer to an int but you allocate only 1 byte for it. And int is usually at least 4 bytes nowadays.
    What do you want to achieve here?

    Code:
    char prefix[3];
    ...
    memcpy(prefix, server_reply, sizeof(char) * 3);
        
    if (0 == strcmp("150", prefix))
    "prefix" has only room for 3 characters, thus you are missing the terminating '\0'. But strcmp() expects a '\0'-terminated string.

    Bye, Andreas

  2. #17
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Thank you for the answer.
    About the malloc- Tbh I was following a tcp tutorial, and havent noticed this, it had to be an old one :P. You are right that its 4.
    In prefix I am holding the server reply. I didnt know strcmp needs '\0' i just wanted to compare the reply (3 first chars) with 150 didnt know i needed the '\0', coz the function worked. At home ill try to fix the application as u adviced.
    Thank you again.

  3. #18
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Hi there again, could you please specify how shuld the 151 message look exacly to fit what client expects? adding \r\n after the 250 used to work, but now when i opened up client and server on the same machine and im trying to use forbiden memory again...

  4. #19
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    could you please specify how shuld the 151 message look exacly to fit what client expects?
    Well, that's all explained in the RFC. Have you still not read it?

    Bye, Andreas

  5. #20
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    I did, it shuld work at it is but im still consfused with the line *(pos + 1) = '\0'; As I said it used to work after i changed the ending to 250\r\n (but client was on raspberry pi and client on my pc if it makes any difference). Then i tried to run both on my pc and i got segfault out of the sudden like before.

  6. #21
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Have you also changed this line:
    Code:
    pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
    BTW: Your 151 message from the server code in post #15 isn't correct according to the RFC. I suggest you reread the part about the define command (section 3.2).

    Bye, Andreas

  7. #22
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    yes my new 151 message looks like this:
    Code:
    message = "151 Definicja Pingwina yo\nDefinicja Pingwina yo\nDefinicja Pingwina yo\n\r\n.\r\n250\r\n";
    Have you also changed this line:
    Code:
    pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
    I havent changed it, do i need to change it to:
    Code:
    pos = strstr(pos + strlen(WORLD_2_SEND), "\r\n");
    ?

  8. #23
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    I havent changed it, do i need to change it to:
    Code:
    pos = strstr(pos + strlen(WORLD_2_SEND), "\r\n");
    ?
    You obviously don't understand that part of my example code. It's never a good idea to just copy'n'paste some code snippets you've found somewhere and put them into your code.
    The idea was to search for the terminating sequence in the buffer you've got from the recv() call and if you found it search for the newline character which terminates the line of the 250 status message.
    With that information and the description of strstr() you should be able to find out what's wrong with the above line.

    But I wouldn't use that approach in a real program. Consider for example what will happen when you get the terminating sequence split up into two parts (which is possible considering how recv() works.). Thus, I suggest you find another way to parse the answer from the server.

    Quote Originally Posted by bremenpl View Post
    yes my new 151 message looks like this:
    Code:
    message = "151 Definicja Pingwina yo\nDefinicja Pingwina yo\nDefinicja Pingwina yo\n\r\n.\r\n250\r\n";
    As I've already told you that's not a valid 151 message.
    Can you quote the part of the RFC which you don't understand?

    Bye, Andreas

  9. #24
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    But you said before that "250\r\n" ending is valid.
    In the future, extensions to the protocol may be provided
    which allow a client to request binary encodings, but the default
    SHOULD always be that the client can look for a "CRLF . CRLF"
    sequence to locate the end of the current text response.

    heres the part saying how to end a text response.
    And heres an example of define command:


    C: HELP


    S: 113 Help text follows
    S: DEFINE database word look up word in database
    S: MATCH database strategy word match word in database using strategy
    S: [ more server-dependent help text ]
    S: .
    S: 250 Command complete

    for what i see is, that the command doesnt look like you described but it works and i dont understand why, but works only with dict.org not my server.


    Shuld the command end with \r.\n250 some text \n?

  10. #25
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    But you said before that "250\r\n" ending is valid.
    I'm not talking about the 250 message but about the 151 message. These are two different status messages from the server.

    Here's the relevant part from the RFC ("3.2 The DEFINE command"):
    If the word was found, then status code 150 is sent, indicating that one or more definitions follow.

    For each definition, status code 151 is sent, followed by the textual body of the definition. The first three space-delimited parameters following status code 151 give the word retrieved, the name of the database (which is the same as the first column of the SHOW DB command), and a short description for the database (which is the same as the second column of the SHOW DB command).
    ...
    3.2.2. Responses
    550 Invalid database, use "SHOW DB" for list of databases
    552 No match
    150 n definitions retrieved - definitions follow
    151 word database name - text follows
    250 ok (optional timing information here)

    Response codes 150 and 151 require special parameters as part of their text.
    Granted that's not the reason why your client crashes but if you want to write a DICT server (even a simple one with a limited set of commands) you need to adhere to the protocol.

    Quote Originally Posted by bremenpl View Post
    for what i see is, that the command doesnt look like you described but it works and i dont understand why, but works only with dict.org not my server.
    Your client works with the server at dict.org because you are lucky.

    Code:
    if ((pos = strstr(pos, "\r\n.\r\n250")))
    {
        pos = strstr(pos + strlen(WORLD_2_SEND), "\n");
        *(pos + 1) = '\0';
        break;
    }
    else
        pos = answer + len;
    Here's an explanation for the part above:
    The first line checks if the buffer contains the sequence "\r\n.\r\n250". If it does, "pos" will point to the first character of the sequence ('\r').
    The second call to strstr() will add 18 characters to that position (strlen(WORLD_2_SEND)) and start a new search from there.
    The server at dict.org adds some text to the 250 message, thus you are still inside the buffer and strstr() will succeed finding the terminating '\n'.
    But your server just sends the status code followed by CRLF. So from "pos" to the end of the string in the buffer there are only 9 characters and adding 18 to "pos" will put you beyond the end of the reply from the server. This could be the first point where your client crashes.
    If the client didn't crash, it's very likely that strstr() doesn't find a newline character and will return NULL. Hence, the client will surely crash on the following line (*(pos + 1) = '\0';)

    I guess one objective of your assignment is to understand how many protocols at the application layer like DICT, HTTP, FTP, SMTP, ... work. All this protocols use a combination of commands and status codes/messages to communicate.
    Your server should be able to parse a command from the client and construct a reply adhering to the protocol.
    Your client should be able to parse this reply and act accordingly.

    Bye, Andreas
    Last edited by AndiPersti; 05-08-2013 at 04:22 AM.

  11. #26
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    So if i understand it correctly now, i need to have at least 18 characters behind the 250 code, ie:
    Code:
    message = "151 Definicja Pingwina yo\nDefinicja Pingwina yo\nDefinicja Pingwina yo\n\r\n.\r\n250 text that i could send after the 250 code message\n";
    I guess one objective of your assignment is to understand how many protocols at the application layer like DICT, HTTP, FTP, SMTP, ... work. All this protocols use a combination of commands and status codes/messages to communicate.
    Your server should be able to parse a command from the client and construct a reply adhering to the protocol.
    Your client should be able to parse this reply and act accordingly.
    I admit that i have very weak expirience with sockets and protocols, but ill get to that though.

  12. #27
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by bremenpl View Post
    So if i understand it correctly now, i need to have at least 18 characters behind the 250 code, ie:
    No, not at all. You would need to change the line back to how I wrote it
    Code:
    pos = strstr(pos + 6, "\n");
    with the minor correction that I've obviously miscounted the characters when I've written it because adding 5 is enough.
    Again, "pos" is pointing to the first '\r' in the sequence:
    Code:
    \r\n.\r\n250...<optional text>...\r\n
    ^
    pos
    Would you call strstr() from this position to find the next '\n' (actually using strchr() would be more appropriate because you just want to search for a character--I shouldn't write code late at night after a long working day), it would return pos+1 because that's the next '\n' in the string. That's why you need to add 5 to "pos". Then it will point to '2':
    Code:
    \r\n.\r\n250...<optional text>...\r\n
             ^
             pos
    and the next '\n' which will be found would be the one which terminates the 250 message.

    But as I've already said: This approach won't work in the real world (i.e. when you get the reply over the internet instead of just from another process on your computer) because there is no guarantee that you will always get the complete terminating sequence in one recv()-call.
    See also FAQ > Reading data from a socket - Cprogramming.com

    Bye, Andreas

  13. #28
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Thank you for the explanation, ill try to update my code this night if i get to my pc.
    I know all this is just a "fix" but this application is as well. If i would mean to write a real server or client i would go for librarys too.
    I rly aprichiate you sacreficing your time for me man, i would rly like to meet more people like you over the internet (and irl too :P).

  14. #29
    Registered User bremenpl's Avatar
    Join Date
    Apr 2013
    Posts
    57
    Yes, you explanation helped and replacing with 5 works. Thank you for your time to explain me everything.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple FTP client
    By Ravi25187 in forum C Programming
    Replies: 2
    Last Post: 05-06-2011, 04:09 PM
  2. Cost of dict
    By scott_ill in forum C# Programming
    Replies: 4
    Last Post: 07-09-2009, 08:06 AM
  3. Problem with simple socket client/server program
    By spencer88 in forum C Programming
    Replies: 6
    Last Post: 05-05-2009, 11:05 PM
  4. Simple NTP Client?
    By Kritical in forum Networking/Device Communication
    Replies: 11
    Last Post: 04-04-2006, 03:36 AM
  5. Simple? winsock client - server problem
    By knutso in forum Windows Programming
    Replies: 2
    Last Post: 03-26-2003, 04:51 AM

Tags for this Thread