17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* This is a simple TCP client that connects to port 1234 and prints a list
27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * of files in a given directory.
37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *
47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * It directly deserializes and serializes messages from network, minimizing
57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * memory use.
67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen *
77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * For flexibility, this example is implemented using posix api.
87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * In a real embedded system you would typically use some other kind of
97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * a communication and filesystem layer.
107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */
117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <sys/socket.h>
137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <sys/types.h>
147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <netinet/in.h>
157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <unistd.h>
167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <dirent.h>
177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <stdio.h>
187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <string.h>
197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <pb_encode.h>
217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <pb_decode.h>
227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "fileproto.pb.h"
247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "common.h"
257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    FileInfo fileinfo;
297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_decode(stream, FileInfo_fields, &fileinfo))
317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool listdir(int fd, char *path)
397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    ListFilesRequest request;
417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    ListFilesResponse response;
427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_istream_t input = pb_istream_from_socket(fd);
437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_ostream_t output = pb_ostream_from_socket(fd);
447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    uint8_t zero = 0;
457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (path == NULL)
477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        request.has_path = false;
497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        request.has_path = true;
537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (strlen(path) + 1 > sizeof(request.path))
547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            fprintf(stderr, "Too long path.\n");
567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        strcpy(request.path, path);
607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode(&output, ListFilesRequest_fields, &request))
637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        fprintf(stderr, "Encoding failed.\n");
657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    /* We signal the end of request with a 0 tag. */
697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_write(&output, &zero, 1);
707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    response.file.funcs.decode = &printfile_callback;
727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_decode(&input, ListFilesResponse_fields, &response))
747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (response.path_error)
807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        fprintf(stderr, "Server reported error.\n");
827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return false;
837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenint main(int argc, char **argv)
897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int sockfd;
917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    struct sockaddr_in servaddr;
927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    char *path = NULL;
937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (argc > 1)
957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        path = argv[1];
967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    sockfd = socket(AF_INET, SOCK_STREAM, 0);
987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    memset(&servaddr, 0, sizeof(servaddr));
1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_family = AF_INET;
1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_port = htons(1234);
1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        perror("connect");
1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return 1;
1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!listdir(sockfd, path))
1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return 2;
1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    close(sockfd);
1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return 0;
1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
117