1

I have just started an assignment in which I must create a simple server that processes http requests.

To get me started, I decided to make a basic server that waits for a connection and then continuously prints out whatever it receives from read().

Using this code to print, I expected to see a plain text http request with \r and \n replaced by <\r> and <\n> respectively (when I visit http://ip:port in my web browser):

    char buffer[buffer_size];
    size_t bytes;

    while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
      buffer[bytes] = '\0';
      int i = 0;
      while(buffer[i] != '\0') {
        if (buffer[i] == '\n') {
          printf("%s","<\\n>\n");
        } else if (buffer[i] == '\r') {
          printf("%s","<\\r>");
        } else {
          printf("%c",buffer[i]);
        }
        i++;
      }
    }

However, instead I just get my console spammed with alternating <\r> and some weird square with what looks like 001B written inside (Here is a link to a picture of my terminal http://gyazo.com/13288989dc0c1f4782052a1914eb7f84). Is this a problem with my code? Does Mozilla keep spamming these intentionally?

EDIT:All of my code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define buffer_size 1024


int main(int argc, char **argv) {
  int port;
  int client;
  struct sockaddr_in6 my_add;
  struct sockaddr_in6 their_add;
  socklen_t their_add_size = sizeof(their_add);

  if (argc != 2) {
    printf("%s\n","Usage: ./server <port>");
    return -1;
  }

  port = atoi(argv[1]);

  my_add.sin6_family = AF_INET6;
  my_add.sin6_addr = in6addr_any;
  my_add.sin6_port = htons(port);

  int s = socket(PF_INET6, SOCK_STREAM, 0);

  if (s < 0) {
    printf("%s","error on socket()");
    return -1;
  }

  if (bind (s, (struct sockaddr *) &my_add, sizeof(my_add)) != 0) {
    printf("%s","error on bind()");
    return -1;
  }

  if (listen (s, 5) != 0) {
    printf("%s","error on listen()");
    return -1;
  }

  client = accept(s, (struct sockaddr *) &their_add, &their_add_size);
  printf("%s","connected");

  char buffer[buffer_size];
  size_t bytes;

  while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
    buffer[bytes] = '\0';
    int i = 0;
    while(buffer[i] != '\0') {
      if (buffer[i] == '\n') {
    printf("%s","<\\n>\n");
      } else if (buffer[i] == '\r') {
    printf("%s","<\\r>");
      } else {
    printf("%c",buffer[i]);
      }
      i++;
    }
  }

  if (bytes != 0) {
    printf("%s","something went wrong. bytes != 0.");
    return -1;
  }

  printf("%s", "connection closed");
  close(s);
  return 0;
}
halfer
  • 19,824
  • 17
  • 99
  • 186
toastedDeli
  • 570
  • 5
  • 28
  • 1
    what does the debugger show is in buffer? – pm100 Oct 19 '17 at 16:10
  • @pm100 sorry I'm not sure what you mean? I'm just using emacs basically as a text editor and compiling in terminal – toastedDeli Oct 19 '17 at 16:14
  • 2
    you should learn how to run your program under a debugger. ON linux that will be gdb, you can pause the program inspect data, etc. google 'getting started with gdb' – pm100 Oct 19 '17 at 16:29

1 Answers1

4

You are using the wrong data type for the bytes variable:

The function prototype of read() is:

ssize_t read(int, void *, size_t)

But you are using size_t which is unsigned (ssize_t is signed)

So if read() ever returns a negative number it gets converted to a huge number effectively causing an infinite loop.

Also you can simplify your code:

char buffer[buffer_size];
ssize_t bytes;

while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {
    // Just loop over the number of bytes we've just read
    for (ssize_t i = 0; i < bytes; ++i) {
        const char ch = buffer[i];

        // Handle `ch`
        if (ch == '\n') {
            printf("<\\n>\n");
        } else if (ch == '\r') {
            printf("<\\r>");
        } else {
            printf("%c", ch);
        }
    }
}

Regarding updated OP question:

if (bytes != 0) {
    printf("%s","something went wrong. bytes != 0.");
    return -1;
}

Should be:

if (0 > bytes) {
    printf("bytes is negative. ERRNO = %d", errno);

    return -1;
}

(Include #include <errno.h> for it to exist.)

Running your code on my machine gives me 57 which is Socket not connected so you have another error in your logic.

A quick search on google reveals the problem:

You're sending to the listening socket, when you should be sending to the accepted/connected one.

Source

So instead of:

while ((bytes = read(s, buffer, buffer_size - 1)) > 0) {

You should be using:

while ((bytes = read(client, buffer, buffer_size - 1)) > 0) {

Because you want to read from the connected client client, not your listening socket s.

This fixes the problem on my machine:

./a.out 1337
connectedGET / HTTP/1.1<\r><\n>
Host: localhost:1337<\r><\n>
Connection: keep-alive<\r><\n>
Cache-Control: max-age=0<\r><\n>
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36<\r><\n>
Upgrade-Insecure-Requests: 1<\r><\n>
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8<\r><\n>
Accept-Encoding: gzip, deflate, br<\r><\n>
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<\r><\n>
Cookie: TripmanagerHighlightedParameter_index=flow_l_h<\r><\n>
<\r><\n>
Marco
  • 7,007
  • 2
  • 19
  • 49
  • I just changed my code and now when I try, I instead exit the while loop without printing anything and my next check fails (bytes != 0) – toastedDeli Oct 19 '17 at 16:26
  • 1
    Wow looks like I got the client variable ready and then forgot to use it. I'm extremely grateful for the time you put in to help me solve this. All is working well now. – toastedDeli Oct 19 '17 at 16:45
  • @toastedDeli You're welcome :) I'm glad I could help. – Marco Oct 19 '17 at 16:45