mirror of
https://github.com/google/pebble.git
synced 2025-06-03 00:33:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
17
third_party/nanopb/examples/network_server/Makefile
vendored
Normal file
17
third_party/nanopb/examples/network_server/Makefile
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
# Include the nanopb provided Makefile rules
|
||||
include ../../extra/nanopb.mk
|
||||
|
||||
# Compiler flags to enable all warnings & debug info
|
||||
CFLAGS = -ansi -Wall -Werror -g -O0
|
||||
CFLAGS += -I$(NANOPB_DIR)
|
||||
|
||||
all: server client
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
clean:
|
||||
rm -f server client fileproto.pb.c fileproto.pb.h
|
||||
|
||||
%: %.c common.c fileproto.pb.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ $(NANOPB_CORE)
|
||||
|
60
third_party/nanopb/examples/network_server/README.txt
vendored
Normal file
60
third_party/nanopb/examples/network_server/README.txt
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
Nanopb example "network_server"
|
||||
===============================
|
||||
|
||||
This example demonstrates the use of nanopb to communicate over network
|
||||
connections. It consists of a server that sends file listings, and of
|
||||
a client that requests the file list from the server.
|
||||
|
||||
Example usage
|
||||
-------------
|
||||
|
||||
user@host:~/nanopb/examples/network_server$ make # Build the example
|
||||
protoc -ofileproto.pb fileproto.proto
|
||||
python ../../generator/nanopb_generator.py fileproto.pb
|
||||
Writing to fileproto.pb.h and fileproto.pb.c
|
||||
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o server server.c
|
||||
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
|
||||
cc -ansi -Wall -Werror -I .. -g -O0 -I../.. -o client client.c
|
||||
../../pb_decode.c ../../pb_encode.c fileproto.pb.c common.c
|
||||
|
||||
user@host:~/nanopb/examples/network_server$ ./server & # Start the server on background
|
||||
[1] 24462
|
||||
|
||||
petteri@oddish:~/nanopb/examples/network_server$ ./client /bin # Request the server to list /bin
|
||||
Got connection.
|
||||
Listing directory: /bin
|
||||
1327119 bzdiff
|
||||
1327126 bzless
|
||||
1327147 ps
|
||||
1327178 ntfsmove
|
||||
1327271 mv
|
||||
1327187 mount
|
||||
1327259 false
|
||||
1327266 tempfile
|
||||
1327285 zfgrep
|
||||
1327165 gzexe
|
||||
1327204 nc.openbsd
|
||||
1327260 uname
|
||||
|
||||
|
||||
Details of implementation
|
||||
-------------------------
|
||||
fileproto.proto contains the portable Google Protocol Buffers protocol definition.
|
||||
It could be used as-is to implement a server or a client in any other language, for
|
||||
example Python or Java.
|
||||
|
||||
fileproto.options contains the nanopb-specific options for the protocol file. This
|
||||
sets the amount of space allocated for file names when decoding messages.
|
||||
|
||||
common.c/h contains functions that allow nanopb to read and write directly from
|
||||
network socket. This way there is no need to allocate a separate buffer to store
|
||||
the message.
|
||||
|
||||
server.c contains the code to open a listening socket, to respond to clients and
|
||||
to list directory contents.
|
||||
|
||||
client.c contains the code to connect to a server, to send a request and to print
|
||||
the response message.
|
||||
|
||||
The code is implemented using the POSIX socket api, but it should be easy enough
|
||||
to port into any other socket api, such as lwip.
|
138
third_party/nanopb/examples/network_server/client.c
vendored
Normal file
138
third_party/nanopb/examples/network_server/client.c
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* This is a simple TCP client that connects to port 1234 and prints a list
|
||||
* of files in a given directory.
|
||||
*
|
||||
* It directly deserializes and serializes messages from network, minimizing
|
||||
* memory use.
|
||||
*
|
||||
* For flexibility, this example is implemented using posix api.
|
||||
* In a real embedded system you would typically use some other kind of
|
||||
* a communication and filesystem layer.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "fileproto.pb.h"
|
||||
#include "common.h"
|
||||
|
||||
/* This callback function will be called once for each filename received
|
||||
* from the server. The filenames will be printed out immediately, so that
|
||||
* no memory has to be allocated for them.
|
||||
*/
|
||||
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
PB_UNUSED(ostream);
|
||||
if (istream != NULL && field->tag == ListFilesResponse_file_tag)
|
||||
{
|
||||
FileInfo fileinfo = {};
|
||||
|
||||
if (!pb_decode(istream, FileInfo_fields, &fileinfo))
|
||||
return false;
|
||||
|
||||
printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This function sends a request to socket 'fd' to list the files in
|
||||
* directory given in 'path'. The results received from server will
|
||||
* be printed to stdout.
|
||||
*/
|
||||
bool listdir(int fd, char *path)
|
||||
{
|
||||
/* Construct and send the request to server */
|
||||
{
|
||||
ListFilesRequest request = {};
|
||||
pb_ostream_t output = pb_ostream_from_socket(fd);
|
||||
|
||||
/* In our protocol, path is optional. If it is not given,
|
||||
* the server will list the root directory. */
|
||||
if (path == NULL)
|
||||
{
|
||||
request.has_path = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
request.has_path = true;
|
||||
if (strlen(path) + 1 > sizeof(request.path))
|
||||
{
|
||||
fprintf(stderr, "Too long path.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(request.path, path);
|
||||
}
|
||||
|
||||
/* Encode the request. It is written to the socket immediately
|
||||
* through our custom stream. */
|
||||
if (!pb_encode_delimited(&output, ListFilesRequest_fields, &request))
|
||||
{
|
||||
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read back the response from server */
|
||||
{
|
||||
ListFilesResponse response = {};
|
||||
pb_istream_t input = pb_istream_from_socket(fd);
|
||||
|
||||
if (!pb_decode_delimited(&input, ListFilesResponse_fields, &response))
|
||||
{
|
||||
fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the message from server decodes properly, but directory was
|
||||
* not found on server side, we get path_error == true. */
|
||||
if (response.path_error)
|
||||
{
|
||||
fprintf(stderr, "Server reported error.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sockfd;
|
||||
struct sockaddr_in servaddr;
|
||||
char *path = NULL;
|
||||
|
||||
if (argc > 1)
|
||||
path = argv[1];
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
/* Connect to server running on localhost:1234 */
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port = htons(1234);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
perror("connect");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Send the directory listing request */
|
||||
if (!listdir(sockfd, path))
|
||||
return 2;
|
||||
|
||||
/* Close connection */
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
43
third_party/nanopb/examples/network_server/common.c
vendored
Normal file
43
third_party/nanopb/examples/network_server/common.c
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* Simple binding of nanopb streams to TCP sockets.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
static bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count)
|
||||
{
|
||||
int fd = (intptr_t)stream->state;
|
||||
return send(fd, buf, count, 0) == count;
|
||||
}
|
||||
|
||||
static bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count)
|
||||
{
|
||||
int fd = (intptr_t)stream->state;
|
||||
int result;
|
||||
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
result = recv(fd, buf, count, MSG_WAITALL);
|
||||
|
||||
if (result == 0)
|
||||
stream->bytes_left = 0; /* EOF */
|
||||
|
||||
return result == count;
|
||||
}
|
||||
|
||||
pb_ostream_t pb_ostream_from_socket(int fd)
|
||||
{
|
||||
pb_ostream_t stream = {&write_callback, (void*)(intptr_t)fd, SIZE_MAX, 0};
|
||||
return stream;
|
||||
}
|
||||
|
||||
pb_istream_t pb_istream_from_socket(int fd)
|
||||
{
|
||||
pb_istream_t stream = {&read_callback, (void*)(intptr_t)fd, SIZE_MAX};
|
||||
return stream;
|
||||
}
|
9
third_party/nanopb/examples/network_server/common.h
vendored
Normal file
9
third_party/nanopb/examples/network_server/common.h
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef _PB_EXAMPLE_COMMON_H_
|
||||
#define _PB_EXAMPLE_COMMON_H_
|
||||
|
||||
#include <pb.h>
|
||||
|
||||
pb_ostream_t pb_ostream_from_socket(int fd);
|
||||
pb_istream_t pb_istream_from_socket(int fd);
|
||||
|
||||
#endif
|
16
third_party/nanopb/examples/network_server/fileproto.options
vendored
Normal file
16
third_party/nanopb/examples/network_server/fileproto.options
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
# This file defines the nanopb-specific options for the messages defined
|
||||
# in fileproto.proto.
|
||||
#
|
||||
# If you come from high-level programming background, the hardcoded
|
||||
# maximum lengths may disgust you. However, if your microcontroller only
|
||||
# has a few kB of ram to begin with, setting reasonable limits for
|
||||
# filenames is ok.
|
||||
#
|
||||
# On the other hand, using the callback interface, it is not necessary
|
||||
# to set a limit on the number of files in the response.
|
||||
|
||||
* include:"sys/types.h"
|
||||
* include:"dirent.h"
|
||||
ListFilesResponse.file type:FT_CALLBACK, callback_datatype:"DIR*"
|
||||
ListFilesRequest.path max_size:128
|
||||
FileInfo.name max_size:128
|
20
third_party/nanopb/examples/network_server/fileproto.proto
vendored
Normal file
20
third_party/nanopb/examples/network_server/fileproto.proto
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
// This defines protocol for a simple server that lists files.
|
||||
//
|
||||
// See also the nanopb-specific options in fileproto.options.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message ListFilesRequest {
|
||||
optional string path = 1 [default = "/"];
|
||||
}
|
||||
|
||||
message FileInfo {
|
||||
required uint64 inode = 1;
|
||||
required string name = 2;
|
||||
}
|
||||
|
||||
message ListFilesResponse {
|
||||
optional bool path_error = 1 [default = false];
|
||||
repeated FileInfo file = 2;
|
||||
}
|
||||
|
164
third_party/nanopb/examples/network_server/server.c
vendored
Normal file
164
third_party/nanopb/examples/network_server/server.c
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
/* This is a simple TCP server that listens on port 1234 and provides lists
|
||||
* of files to clients, using a protocol defined in file_server.proto.
|
||||
*
|
||||
* It directly deserializes and serializes messages from network, minimizing
|
||||
* memory use.
|
||||
*
|
||||
* For flexibility, this example is implemented using posix api.
|
||||
* In a real embedded system you would typically use some other kind of
|
||||
* a communication and filesystem layer.
|
||||
*/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
|
||||
#include "fileproto.pb.h"
|
||||
#include "common.h"
|
||||
|
||||
/* This callback function will be called during the encoding.
|
||||
* It will write out any number of FileInfo entries, without consuming unnecessary memory.
|
||||
* This is accomplished by fetching the filenames one at a time and encoding them
|
||||
* immediately.
|
||||
*/
|
||||
bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field)
|
||||
{
|
||||
PB_UNUSED(istream);
|
||||
if (ostream != NULL && field->tag == ListFilesResponse_file_tag)
|
||||
{
|
||||
DIR *dir = *(DIR**)field->pData;
|
||||
struct dirent *file;
|
||||
FileInfo fileinfo = {};
|
||||
|
||||
while ((file = readdir(dir)) != NULL)
|
||||
{
|
||||
fileinfo.inode = file->d_ino;
|
||||
strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
|
||||
fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
|
||||
|
||||
/* This encodes the header for the field, based on the constant info
|
||||
* from pb_field_t. */
|
||||
if (!pb_encode_tag_for_field(ostream, field))
|
||||
return false;
|
||||
|
||||
/* This encodes the data for the field, based on our FileInfo structure. */
|
||||
if (!pb_encode_submessage(ostream, FileInfo_fields, &fileinfo))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Because the main program uses pb_encode_delimited(), this callback will be
|
||||
* called twice. Rewind the directory for the next call. */
|
||||
rewinddir(dir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Handle one arriving client connection.
|
||||
* Clients are expected to send a ListFilesRequest, terminated by a '0'.
|
||||
* Server will respond with a ListFilesResponse message.
|
||||
*/
|
||||
void handle_connection(int connfd)
|
||||
{
|
||||
DIR *directory = NULL;
|
||||
|
||||
/* Decode the message from the client and open the requested directory. */
|
||||
{
|
||||
ListFilesRequest request = {};
|
||||
pb_istream_t input = pb_istream_from_socket(connfd);
|
||||
|
||||
if (!pb_decode_delimited(&input, ListFilesRequest_fields, &request))
|
||||
{
|
||||
printf("Decode failed: %s\n", PB_GET_ERROR(&input));
|
||||
return;
|
||||
}
|
||||
|
||||
directory = opendir(request.path);
|
||||
printf("Listing directory: %s\n", request.path);
|
||||
}
|
||||
|
||||
/* List the files in the directory and transmit the response to client */
|
||||
{
|
||||
ListFilesResponse response = {};
|
||||
pb_ostream_t output = pb_ostream_from_socket(connfd);
|
||||
|
||||
if (directory == NULL)
|
||||
{
|
||||
perror("opendir");
|
||||
|
||||
/* Directory was not found, transmit error status */
|
||||
response.has_path_error = true;
|
||||
response.path_error = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Directory was found, transmit filenames */
|
||||
response.has_path_error = false;
|
||||
response.file = directory;
|
||||
}
|
||||
|
||||
if (!pb_encode_delimited(&output, ListFilesResponse_fields, &response))
|
||||
{
|
||||
printf("Encoding failed: %s\n", PB_GET_ERROR(&output));
|
||||
}
|
||||
}
|
||||
|
||||
if (directory != NULL)
|
||||
closedir(directory);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int listenfd, connfd;
|
||||
struct sockaddr_in servaddr;
|
||||
int reuse = 1;
|
||||
|
||||
/* Listen on localhost:1234 for TCP connections */
|
||||
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
|
||||
|
||||
memset(&servaddr, 0, sizeof(servaddr));
|
||||
servaddr.sin_family = AF_INET;
|
||||
servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
servaddr.sin_port = htons(1234);
|
||||
if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
|
||||
{
|
||||
perror("bind");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (listen(listenfd, 5) != 0)
|
||||
{
|
||||
perror("listen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
/* Wait for a client */
|
||||
connfd = accept(listenfd, NULL, NULL);
|
||||
|
||||
if (connfd < 0)
|
||||
{
|
||||
perror("accept");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Got connection.\n");
|
||||
|
||||
handle_connection(connfd);
|
||||
|
||||
printf("Closing connection.\n");
|
||||
|
||||
close(connfd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue