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:
parent
d3c7152528
commit
4a771bad37
18
samples/net/sockets/http_get/Makefile
Normal file
18
samples/net/sockets/http_get/Makefile
Normal 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
|
4
samples/net/sockets/http_get/Makefile.posix
Normal file
4
samples/net/sockets/http_get/Makefile.posix
Normal file
|
@ -0,0 +1,4 @@
|
|||
# This makefile builds the sample for a POSIX system, like Linux
|
||||
|
||||
http_get: src/http_get.c
|
||||
$(CC) $^ -o $@
|
68
samples/net/sockets/http_get/README.rst
Normal file
68
samples/net/sockets/http_get/README.rst
Normal 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.
|
33
samples/net/sockets/http_get/prj.conf
Normal file
33
samples/net/sockets/http_get/prj.conf
Normal 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
|
8
samples/net/sockets/http_get/sample.yaml
Normal file
8
samples/net/sockets/http_get/sample.yaml
Normal 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
|
3
samples/net/sockets/http_get/src/Makefile
Normal file
3
samples/net/sockets/http_get/src/Makefile
Normal file
|
@ -0,0 +1,3 @@
|
|||
include $(ZEPHYR_BASE)/samples/net/common/Makefile.common
|
||||
|
||||
obj-y += http_get.o
|
90
samples/net/sockets/http_get/src/http_get.c
Normal file
90
samples/net/sockets/http_get/src/http_get.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue