samples: net: sockets: Add HTTP GET example

This example shows usage of client connection and getaddrinfo().

Signed-off-by: Paul Sokolovsky <paul.sokolovsky@linaro.org>
This commit is contained in:
Paul Sokolovsky 2017-09-14 20:53:31 +03:00 committed by Jukka Rissanen
parent d3c7152528
commit 4a771bad37
7 changed files with 224 additions and 0 deletions

View file

@ -0,0 +1,18 @@
# Makefile - simple socket-based HTTP GET example
#
# Copyright (c) 2017 Linaro Limited
#
# SPDX-License-Identifier: Apache-2.0
#
BOARD ?= qemu_x86
CONF_FILE ?= prj.conf
include $(ZEPHYR_BASE)/Makefile.inc
ifeq ($(CONFIG_NET_L2_BT), y)
QEMU_EXTRA_FLAGS = -serial unix:/tmp/bt-server-bredr
else
include $(ZEPHYR_BASE)/samples/net/common/Makefile.ipstack
endif

View file

@ -0,0 +1,4 @@
# This makefile builds the sample for a POSIX system, like Linux
http_get: src/http_get.c
$(CC) $^ -o $@

View file

@ -0,0 +1,68 @@
.. _sockets-http-get:
Socket HTTP GET Example
#######################
Overview
********
The sockets/http_get sample application for Zephyr implements a simple
HTTP GET client using a BSD Sockets compatible API. The purpose of this
sample is to show how it's possible to develop a sockets application
portable to both POSIX and Zephyr. As such, it is kept minimal and
supports only IPv4.
The source code for this sample application can be found at:
:file:`samples/net/sockets/http_get`.
Requirements
************
- :ref:`networking_with_qemu`
- or, a board with hardware networking
- NAT/routing should be set up to allow connections to the Internet
- DNS server should be available on the host to resolve domain names
Building and Running
********************
Build the Zephyr version of the application like this:
.. code-block:: console
$ cd $ZEPHYR_BASE/samples/net/sockets/http_get
$ make pristine
$ make BOARD=<board_to_use>
``board_to_use`` defaults to ``qemu_x86``. In this case, you can run the
application in QEMU using ``make run``. If you used another BOARD, you
will need to consult its documentation for application deployment
instructions. You can read about Zephyr support for specific boards in
the documentation at :ref:`boards`.
After the sample starts, it issues HTTP GET request to "google.com:80"
and dumps the response. You can edit the source code to issue a request
to any other site on the Internet (or on the local network, in which
case no NAT/routing setup is needed).
Running application on POSIX Host
=================================
The same application source code can be built for a POSIX system, e.g.
Linux. (Note: if you look at the source, you will see that the code is
the same except the header files are different for Zephyr vs POSIX.)
To build for a host POSIX OS:
.. code-block:: console
$ make -f Makefile.posix
To run:
.. code-block:: console
$ ./http_get
As can be seen, the behavior of the application is the same as the Zephyr
version.

View file

@ -0,0 +1,33 @@
# General config
CONFIG_NEWLIB_LIBC=y
# Networking config
CONFIG_NETWORKING=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_POSIX_NAMES=y
CONFIG_DNS_RESOLVER=y
CONFIG_DNS_SERVER_IP_ADDRESSES=y
CONFIG_DNS_SERVER1="192.0.2.2"
# Network driver config
CONFIG_TEST_RANDOM_GENERATOR=y
# Without CONFIG_NET_BUF_LOG printf() doesn't work
CONFIG_NET_BUF_LOG=y
# Network address config
CONFIG_NET_APP_SETTINGS=y
CONFIG_NET_APP_NEED_IPV4=y
CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1"
CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2"
CONFIG_NET_APP_MY_IPV4_GW="192.0.2.2"
# Network debug config
CONFIG_NET_LOG=y
CONFIG_NET_LOG_GLOBAL=y
CONFIG_SYS_LOG_NET_LEVEL=2
#CONFIG_NET_DEBUG_SOCKETS=y

View file

@ -0,0 +1,8 @@
sample:
description: BSD Sockets API HTTP GET example
name: socket_http_get
tests:
- test:
min_ram: 32
build_only: true
tags: net

View file

@ -0,0 +1,3 @@
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common
obj-y += http_get.o

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#ifndef __ZEPHYR__
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#else
#include <net/socket.h>
#include <kernel.h>
#include <net/net_app.h>
#endif
#define SSTRLEN(s) (sizeof(s) - 1)
#define CHECK(r) { if (r == -1) { printf("Error: " #r "\n"); } }
#define REQUEST "GET / HTTP/1.0\r\n\r\n"
static char response[1024];
void dump_addrinfo(const struct addrinfo *ai)
{
printf("addrinfo @%p: fam=%d, socktype=%d, proto=%d, "
"addr_fam=%d, addr_port=%x\n",
ai, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
ai->ai_addr->sa_family,
((struct sockaddr_in *)ai->ai_addr)->sin_port);
}
int main(void)
{
static struct addrinfo hints;
struct addrinfo *res;
int st, sock;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
st = getaddrinfo("google.com", "80", &hints, &res);
printf("getaddrinfo status: %d\n", st);
if (st != 0) {
printf("Unable to resolve address, quitting\n");
return 1;
}
#if 0
for (; res; res = res->ai_next) {
dump_addrinfo(res);
}
#endif
dump_addrinfo(res);
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
CHECK(sock);
printf("sock = %d\n", sock);
CHECK(connect(sock, res->ai_addr, res->ai_addrlen));
send(sock, REQUEST, SSTRLEN(REQUEST), 0);
printf("Response:\n");
while (1) {
int len = recv(sock, response, sizeof(response) - 1, 0);
if (len < 0) {
printf("Error reading response\n");
return 1;
}
if (len == 0) {
break;
}
response[len] = 0;
printf("%s", response);
}
return 0;
}