Esempio n. 1
0
/*
 * Performs HTTP handshake. *fd* is the file descriptor of the
 * connection to the client. This function returns 0 if it succeeds,
 * or returns -1.
 */
int http_handshake(int fd) {
	char header[16384], *accept_key, *keyhdstart, *keyhdend, res_header[256];
	size_t header_length = 0, res_header_sent = 0, res_header_length;
	ssize_t r;
	while(1) {
		while((r = read(fd, header+header_length,
							      sizeof(header)-header_length)) == -1 && errno == EINTR);
		if(r == -1) {
			perror("read");
			return -1;
		} else if(r == 0) {
			fprintf(stderr, "HTTP Handshake: Got EOF\n");
			return -1;
		} else {
			header_length += r;
			if(header_length >= 4 &&
				 memcmp(header+header_length-4, "\r\n\r\n", 4) == 0) {
				break;
			} else if(header_length == sizeof(header)) {
				fprintf(stderr, "HTTP Handshake: Too large HTTP headers\n");
				return -1;
			}
		}
	}

	if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
		 http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
		 (keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key", NULL)) == NULL) {
		fprintf(stderr, "HTTP Handshake: Missing required header fields\n");
		return -1;
	}
	for(; *keyhdstart == ' '; ++keyhdstart);
	keyhdend = keyhdstart;
	for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);
	if(keyhdend-keyhdstart != 24) {
		printf("%s\n", keyhdstart);
		fprintf(stderr, "HTTP Handshake: Invalid value in Sec-WebSocket-Key\n");
		return -1;
	}
	accept_key = create_accept_key(keyhdstart);
	snprintf(res_header, sizeof(res_header),
					 "HTTP/1.1 101 Switching Protocols\r\n"
					 "Upgrade: websocket\r\n"
					 "Connection: Upgrade\r\n"
					 "Sec-WebSocket-Accept: %s\r\n"
					 "\r\n", accept_key);
	free(accept_key);
	res_header_length = strlen(res_header);
	while(res_header_sent < res_header_length) {
		while((r = write(fd, res_header+res_header_sent, res_header_length-res_header_sent)) == -1 && errno == EINTR);
		if(r == -1) {
			perror("write");
			return -1;
		} else {
			res_header_sent += r;
		}
	}
	return 0;
}
Esempio n. 2
0
/*
 * Performs HTTP handshake. *fd* is the file descriptor of the
 * connection to the client. This function returns 0 if it succeeds,
 * or returns -1.
 */
int http_handshake(int fd)
{
  /*
   * Note: The implementation of HTTP handshake in this function is
   * written for just a example of how to use of wslay library and is
   * not meant to be used in production code.  In practice, you need
   * to do more strict verification of the client's handshake.
   */
  char header[16384], accept_key[29], *keyhdstart, *keyhdend, res_header[256];
  size_t header_length = 0, res_header_sent = 0, res_header_length;
  ssize_t r;
  while(1) {
    while((r = read(fd, header+header_length,
                    sizeof(header)-header_length)) == -1 && errno == EINTR);
    if(r == -1) {
      perror("read");
      return -1;
    } else if(r == 0) {
      fprintf(stderr, "HTTP Handshake: Got EOF");
      return -1;
    } else {
      header_length += r;
      if(header_length >= 4 &&
         memcmp(header+header_length-4, "\r\n\r\n", 4) == 0) {
        break;
      } else if(header_length == sizeof(header)) {
        fprintf(stderr, "HTTP Handshake: Too large HTTP headers");
        return -1;
      }
    }
  }

  if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL ||
     http_header_find_field_value(header, "Connection", "Upgrade") == NULL ||
     (keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key", NULL)) == NULL) {
    fprintf(stderr, "HTTP Handshake: Missing required header fields");
    return -1;
  }
  for(; *keyhdstart == ' '; ++keyhdstart);
  keyhdend = keyhdstart;
  for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);
  if(keyhdend-keyhdstart != 24) {
    printf("%s\n", keyhdstart);
    fprintf(stderr, "HTTP Handshake: Invalid value in Sec-WebSocket-Key");
    return -1;
  }
  create_accept_key(accept_key, keyhdstart);
  snprintf(res_header, sizeof(res_header),
           "HTTP/1.1 101 Switching Protocols\r\n"
           "Upgrade: websocket\r\n"
           "Connection: Upgrade\r\n"
           "Sec-WebSocket-Accept: %s\r\n"
           "\r\n", accept_key);
  res_header_length = strlen(res_header);
  while(res_header_sent < res_header_length) {
    while((r = write(fd, res_header+res_header_sent,
                     res_header_length-res_header_sent)) == -1 &&
          errno == EINTR);
    if(r == -1) {
      perror("write");
      return -1;
    } else {
      res_header_sent += r;
    }
  }
  return 0;
}
Esempio n. 3
0
/*
 * \brief Performs simple HTTP handshake. *fd* is the file descriptor of the
 * connection to the client. This function returns 0 if it succeeds,
 * or returns -1.
 */
static int http_handshake(int sockfd)
{
	char header[16384], accept_key[29], res_header[256];
	char *keyhdstart, *keyhdend;
	size_t header_length = 0, res_header_sent = 0, res_header_length;
	ssize_t ret;
	fd_set set;
	struct timeval timeout_tv, start_tv, current_tv;

	/* Get current time */
	gettimeofday(&start_tv, NULL);

	/* Set default timeout */
	timeout_tv.tv_sec = VRS_TIMEOUT;
	timeout_tv.tv_usec = 0;

	/* Try to read whole header without blocking read, use select and
	 * timeout */
	while(1) {

		FD_ZERO(&set);
		FD_SET(sockfd, &set);

		if( (ret = select(sockfd + 1, &set, NULL, NULL, &timeout_tv)) == -1 ) {
			v_print_log(VRS_PRINT_ERROR, "%s:%s():%d select(): %s\n",
					__FILE__, __FUNCTION__,  __LINE__, strerror(errno));
			return -1;
		/* Was event on the listen socket */
		} else if(ret > 0) {
			if(FD_ISSET(sockfd, &set)) {
				ret = read(sockfd,
						header + header_length,
						sizeof(header) - header_length);

				if(ret == -1) {
					v_print_log(VRS_PRINT_ERROR, "read(): %s\n", strerror(errno));
					return -1;
				} else if(ret == 0) {
					v_print_log(VRS_PRINT_ERROR,
							"HTTP Handshake: Got EOF");
					return -1;
				} else {
					header_length += ret;
					/* Was end of HTTP header reached? */
					if(header_length >= 4 &&
							memcmp(header + header_length - 4, "\r\n\r\n", 4) == 0)
					{
						break;
					} else if(header_length == sizeof(header)) {
						v_print_log(VRS_PRINT_ERROR,
								"HTTP Handshake: Too large HTTP headers\n");
						return -1;
					}
				}
			}
		}

		gettimeofday(&current_tv, NULL);

		/* Update timeout */
		timeout_tv.tv_sec = VRS_TIMEOUT - (current_tv.tv_sec - start_tv.tv_sec);
		timeout_tv.tv_usec = 0;

		/* Where there is no elapsing time, then exit handshake */
		if(timeout_tv.tv_sec <= 0) {
			v_print_log(VRS_PRINT_DEBUG_MSG,
					"HTTP Handshake: Timed out\n");
			return -1;
		}
	}

	header[header_length] = '\0';

	v_print_log(VRS_PRINT_DEBUG_MSG,
			"HTTP Handshake: received request: %s\n",
			header);

	/* Check if required HTTP headers were received in the request */

	/* Header has to contain field "Upgrade: websocket" */
	if(http_header_find_field_value(header, "Upgrade", "websocket") == NULL) {
		v_print_log(VRS_PRINT_ERROR,
				"HTTP Handshake: Missing required header field 'Upgrade: websocket'\n");
		return -1;
	}
	/* Header has to contain field "Connection: Upgrade" */
	if(http_header_find_field_value(header, "Connection", "Upgrade") == NULL) {
		v_print_log(VRS_PRINT_ERROR,
				"HTTP Handshake: Missing required header field 'Connection: Upgrade'\n");
		return -1;
	}
	/* Client has to send field Sec-WebSocket-Key in HTTP header */
	if( (keyhdstart = http_header_find_field_value(header, "Sec-WebSocket-Key",
			NULL)) == NULL)
	{
		v_print_log(VRS_PRINT_ERROR,
				"HTTP Handshake: Missing required header field 'Sec-WebSocket-Key: SOME_SECRET_KEY'\n");
		return -1;
	}
	/* Requested protocol name has to be equal to "v1.verse.tul.cz" */
	if( http_header_find_field_value(header, "Sec-WebSocket-Protocol",
			WEB_SOCKET_PROTO_NAME) == NULL)
	{
		v_print_log(VRS_PRINT_ERROR,
				"HTTP Handshake: Missing required header field 'Sec-WebSocket-Protocol: %s'\n",
				WEB_SOCKET_PROTO_NAME);
		return -1;
	}

	/* Check the length of WebSocket key */
	for(; *keyhdstart == ' '; ++keyhdstart);
	keyhdend = keyhdstart;
	for(; *keyhdend != '\r' && *keyhdend != ' '; ++keyhdend);
	if(keyhdend - keyhdstart != WS_CLIENT_KEY_LEN) {
		v_print_log(VRS_PRINT_ERROR,
				"HTTP Handshake: Invalid value in Sec-WebSocket-Key\n");
		return -1;
	}

	/* Create accepted key */
	create_accept_key(accept_key, keyhdstart);

	/* Create response for client */
	snprintf(res_header, sizeof(res_header),
			"HTTP/1.1 101 Switching Protocols\r\n"
			"Upgrade: websocket\r\n"
			"Connection: Upgrade\r\n"
			"Sec-WebSocket-Accept: %s\r\n"
			"Sec-WebSocket-Protocol: %s\r\n"
			"\r\n",
			accept_key,
			WEB_SOCKET_PROTO_NAME);

	/* Send response to the client */
	res_header_length = strlen(res_header);
	while(res_header_sent < res_header_length) {
		while((ret = write(sockfd, res_header + res_header_sent,
				res_header_length - res_header_sent)) == -1 &&
				errno == EINTR);
		if(ret == -1) {
			v_print_log(VRS_PRINT_ERROR, "write(): %s\n", strerror(errno));
			return -1;
		} else {
			res_header_sent += ret;
		}
	}

	v_print_log(VRS_PRINT_DEBUG_MSG, "HTTP Handshake: sent response\n");

	return 0;
}