1/* This is a simple TCP server that listens on port 1234 and provides lists
2 * of files to clients, using a protocol defined in file_server.proto.
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 listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
27{
28    DIR *dir = (DIR*) *arg;
29    struct dirent *file;
30    FileInfo fileinfo;
31
32    while ((file = readdir(dir)) != NULL)
33    {
34        fileinfo.inode = file->d_ino;
35        strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
36        fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
37
38        if (!pb_encode_tag_for_field(stream, field))
39            return false;
40
41        if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo))
42            return false;
43    }
44
45    return true;
46}
47
48void handle_connection(int connfd)
49{
50    ListFilesRequest request;
51    ListFilesResponse response;
52    pb_istream_t input = pb_istream_from_socket(connfd);
53    pb_ostream_t output = pb_ostream_from_socket(connfd);
54    DIR *directory;
55
56    if (!pb_decode(&input, ListFilesRequest_fields, &request))
57    {
58        printf("Decode failed: %s\n", PB_GET_ERROR(&input));
59        return;
60    }
61
62    directory = opendir(request.path);
63
64    printf("Listing directory: %s\n", request.path);
65
66    if (directory == NULL)
67    {
68        perror("opendir");
69
70        response.has_path_error = true;
71        response.path_error = true;
72        response.file.funcs.encode = NULL;
73    }
74    else
75    {
76        response.has_path_error = false;
77        response.file.funcs.encode = &listdir_callback;
78        response.file.arg = directory;
79    }
80
81    if (!pb_encode(&output, ListFilesResponse_fields, &response))
82    {
83        printf("Encoding failed.\n");
84    }
85}
86
87int main(int argc, char **argv)
88{
89    int listenfd, connfd;
90    struct sockaddr_in servaddr;
91    int reuse = 1;
92
93    listenfd = socket(AF_INET, SOCK_STREAM, 0);
94
95    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
96
97    memset(&servaddr, 0, sizeof(servaddr));
98    servaddr.sin_family = AF_INET;
99    servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
100    servaddr.sin_port = htons(1234);
101    if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
102    {
103        perror("bind");
104        return 1;
105    }
106
107    if (listen(listenfd, 5) != 0)
108    {
109        perror("listen");
110        return 1;
111    }
112
113    for(;;)
114    {
115        connfd = accept(listenfd, NULL, NULL);
116
117        if (connfd < 0)
118        {
119            perror("accept");
120            return 1;
121        }
122
123        printf("Got connection.\n");
124
125        handle_connection(connfd);
126
127        printf("Closing connection.\n");
128
129        close(connfd);
130    }
131}
132