17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* This is a simple TCP server that listens on port 1234 and provides lists
27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * of files to clients, using a protocol defined in file_server.proto.
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 listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    DIR *dir = (DIR*) *arg;
297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    struct dirent *file;
307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    FileInfo fileinfo;
317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    while ((file = readdir(dir)) != NULL)
337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        fileinfo.inode = file->d_ino;
357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!pb_encode_tag_for_field(stream, field))
397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo))
427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return false;
437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    return true;
467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenvoid handle_connection(int connfd)
497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    ListFilesRequest request;
517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    ListFilesResponse response;
527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_istream_t input = pb_istream_from_socket(connfd);
537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    pb_ostream_t output = pb_ostream_from_socket(connfd);
547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    DIR *directory;
557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_decode(&input, ListFilesRequest_fields, &request))
577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        printf("Decode failed: %s\n", PB_GET_ERROR(&input));
597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return;
607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    directory = opendir(request.path);
637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    printf("Listing directory: %s\n", request.path);
657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (directory == NULL)
677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        perror("opendir");
697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.has_path_error = true;
717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.path_error = true;
727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.file.funcs.encode = NULL;
737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    else
757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.has_path_error = false;
777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.file.funcs.encode = &listdir_callback;
787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        response.file.arg = directory;
797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (!pb_encode(&output, ListFilesResponse_fields, &response))
827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        printf("Encoding failed.\n");
847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenint main(int argc, char **argv)
887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{
897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int listenfd, connfd;
907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    struct sockaddr_in servaddr;
917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    int reuse = 1;
927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    listenfd = socket(AF_INET, SOCK_STREAM, 0);
947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    memset(&servaddr, 0, sizeof(servaddr));
987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_family = AF_INET;
997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    servaddr.sin_port = htons(1234);
1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        perror("bind");
1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return 1;
1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    if (listen(listenfd, 5) != 0)
1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        perror("listen");
1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        return 1;
1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    for(;;)
1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    {
1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        connfd = accept(listenfd, NULL, NULL);
1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        if (connfd < 0)
1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        {
1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            perror("accept");
1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen            return 1;
1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        }
1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        printf("Got connection.\n");
1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        handle_connection(connfd);
1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        printf("Closing connection.\n");
1287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen
1297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen        close(connfd);
1307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen    }
1317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen}
132