diff options
-rw-r--r-- | example/Makefile | 4 | ||||
-rw-r--r-- | example/client.c | 116 | ||||
-rw-r--r-- | example/common.c | 49 | ||||
-rw-r--r-- | example/common.h | 9 | ||||
-rw-r--r-- | example/server.c | 30 |
5 files changed, 182 insertions, 26 deletions
diff --git a/example/Makefile b/example/Makefile index 0f08f2d7..efc4a8de 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,10 +1,10 @@ CFLAGS=-ansi -Wall -Werror -I .. -g -O0 DEPS=../pb_decode.c ../pb_decode.h ../pb_encode.c ../pb_encode.h ../pb.h -all: server +all: server client %: %.c $(DEPS) fileproto.h - $(CC) $(CFLAGS) -o $@ $< ../pb_decode.c ../pb_encode.c fileproto.c + $(CC) $(CFLAGS) -o $@ $< ../pb_decode.c ../pb_encode.c fileproto.c common.c fileproto.h: fileproto.proto ../generator/nanopb_generator.py protoc -I. -I../generator -I/usr/include -ofileproto.pb $< diff --git a/example/client.c b/example/client.c new file mode 100644 index 00000000..f0520574 --- /dev/null +++ b/example/client.c @@ -0,0 +1,116 @@ +/* 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.h" +#include "common.h" + +bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void *arg) +{ + FileInfo fileinfo; + + if (!pb_decode(stream, FileInfo_fields, &fileinfo)) + return false; + + printf("%-10lld %s\n", fileinfo.inode, fileinfo.name); + + return true; +} + +bool listdir(int fd, char *path) +{ + ListFilesRequest request; + ListFilesResponse response; + pb_istream_t input = pb_istream_from_socket(fd); + pb_ostream_t output = pb_ostream_from_socket(fd); + uint8_t zero = 0; + + 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); + } + + if (!pb_encode(&output, ListFilesRequest_fields, &request)) + { + fprintf(stderr, "Encoding failed.\n"); + return false; + } + + /* We signal the end of request with a 0 tag. */ + pb_write(&output, &zero, 1); + + response.file.funcs.decode = &printfile_callback; + + if (!pb_decode(&input, ListFilesResponse_fields, &response)) + { + fprintf(stderr, "Decoding failed.\n"); + return false; + } + + 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); + + 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; + } + + if (!listdir(sockfd, path)) + return 2; + + close(sockfd); + + return 0; +} diff --git a/example/common.c b/example/common.c new file mode 100644 index 00000000..9d93219b --- /dev/null +++ b/example/common.c @@ -0,0 +1,49 @@ +/* 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 = (int)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 = (int)stream->state; + int result; + + if (buf == NULL) + { + /* Well, this is a really inefficient way to skip input. */ + /* It is only used when there are unknown fields. */ + char dummy; + while (count-- && recv(fd, &dummy, 1, 0) == 1); + return count == 0; + } + + 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*)fd, SIZE_MAX, 0}; + return stream; +} + +pb_istream_t pb_istream_from_socket(int fd) +{ + pb_istream_t stream = {&read_callback, (void*)fd, SIZE_MAX}; + return stream; +} diff --git a/example/common.h b/example/common.h new file mode 100644 index 00000000..8dab3b7c --- /dev/null +++ b/example/common.h @@ -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
\ No newline at end of file diff --git a/example/server.c b/example/server.c index a671f4cb..04f88f0f 100644 --- a/example/server.c +++ b/example/server.c @@ -21,28 +21,7 @@ #include <pb_decode.h> #include "fileproto.h" - -bool write_callback(pb_ostream_t *stream, const uint8_t *buf, size_t count) -{ - int fd = *(int*)stream->state; - return send(fd, buf, count, 0) == count; -} - -bool read_callback(pb_istream_t *stream, uint8_t *buf, size_t count) -{ - int fd = *(int*)stream->state; - - if (buf == NULL) - { - /* Well, this is a really inefficient way to skip input. */ - /* It is only used when there are unknown fields. */ - char dummy; - while (count-- && recv(fd, &dummy, 1, 0) == 1); - return count == 0; - } - - return recv(fd, buf, count, MSG_WAITALL) == count; -} +#include "common.h" bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, const void *arg) { @@ -70,8 +49,8 @@ void handle_connection(int connfd) { ListFilesRequest request; ListFilesResponse response; - pb_istream_t input = {&read_callback, &connfd, SIZE_MAX}; - pb_ostream_t output = {&write_callback, &connfd, SIZE_MAX, 0}; + pb_istream_t input = pb_istream_from_socket(connfd); + pb_ostream_t output = pb_ostream_from_socket(connfd); DIR *directory; if (!pb_decode(&input, ListFilesRequest_fields, &request)) @@ -109,9 +88,12 @@ int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; + int reuse = 1; 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); |