1/* This is a simple TCP client that connects to port 1234 and prints a list
2 * of files in a given directory.
3 *
4 * It directly deserializes and serializes messages from network, minimizing
5 * memory use.
6 *
7 * For flexibility, this example is implemented using posix api.
8 * In a real embedded system you would typically use some other kind of
9 * a communication and filesystem layer.
10 */
11
12#include <sys/socket.h>
13#include <sys/types.h>
14#include <netinet/in.h>
15#include <unistd.h>
16#include <dirent.h>
17#include <stdio.h>
18#include <string.h>
19
20#include <pb_encode.h>
21#include <pb_decode.h>
22
23#include "fileproto.pb.h"
24#include "common.h"
25
26bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
27{
28    FileInfo fileinfo;
29
30    if (!pb_decode(stream, FileInfo_fields, &fileinfo))
31        return false;
32
33    printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
34
35    return true;
36}
37
38bool listdir(int fd, char *path)
39{
40    ListFilesRequest request;
41    ListFilesResponse response;
42    pb_istream_t input = pb_istream_from_socket(fd);
43    pb_ostream_t output = pb_ostream_from_socket(fd);
44    uint8_t zero = 0;
45
46    if (path == NULL)
47    {
48        request.has_path = false;
49    }
50    else
51    {
52        request.has_path = true;
53        if (strlen(path) + 1 > sizeof(request.path))
54        {
55            fprintf(stderr, "Too long path.\n");
56            return false;
57        }
58
59        strcpy(request.path, path);
60    }
61
62    if (!pb_encode(&output, ListFilesRequest_fields, &request))
63    {
64        fprintf(stderr, "Encoding failed.\n");
65        return false;
66    }
67
68    /* We signal the end of request with a 0 tag. */
69    pb_write(&output, &zero, 1);
70
71    response.file.funcs.decode = &printfile_callback;
72
73    if (!pb_decode(&input, ListFilesResponse_fields, &response))
74    {
75        fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
76        return false;
77    }
78
79    if (response.path_error)
80    {
81        fprintf(stderr, "Server reported error.\n");
82        return false;
83    }
84
85    return true;
86}
87
88int main(int argc, char **argv)
89{
90    int sockfd;
91    struct sockaddr_in servaddr;
92    char *path = NULL;
93
94    if (argc > 1)
95        path = argv[1];
96
97    sockfd = socket(AF_INET, SOCK_STREAM, 0);
98
99    memset(&servaddr, 0, sizeof(servaddr));
100    servaddr.sin_family = AF_INET;
101    servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
102    servaddr.sin_port = htons(1234);
103
104    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
105    {
106        perror("connect");
107        return 1;
108    }
109
110    if (!listdir(sockfd, path))
111        return 2;
112
113    close(sockfd);
114
115    return 0;
116}
117