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.
4 * It directly deserializes and serializes messages from network, minimizing
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.
12 #include <sys/socket.h>
13 #include <sys/types.h>
14 #include <netinet/in.h>
20 #include <pb_encode.h>
21 #include <pb_decode.h>
23 #include "fileproto.pb.h"
26 /* This callback function will be called once during the encoding.
27 * It will write out any number of FileInfo entries, without consuming unnecessary memory.
28 * This is accomplished by fetching the filenames one at a time and encoding them
31 bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg)
33 DIR *dir = (DIR*) *arg;
35 FileInfo fileinfo = {};
37 while ((file = readdir(dir)) != NULL)
39 fileinfo.inode = file->d_ino;
40 strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name));
41 fileinfo.name[sizeof(fileinfo.name) - 1] = '\0';
43 /* This encodes the header for the field, based on the constant info
45 if (!pb_encode_tag_for_field(stream, field))
48 /* This encodes the data for the field, based on our FileInfo structure. */
49 if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo))
56 /* Handle one arriving client connection.
57 * Clients are expected to send a ListFilesRequest, terminated by a '0'.
58 * Server will respond with a ListFilesResponse message.
60 void handle_connection(int connfd)
62 DIR *directory = NULL;
64 /* Decode the message from the client and open the requested directory. */
66 ListFilesRequest request = {};
67 pb_istream_t input = pb_istream_from_socket(connfd);
69 if (!pb_decode(&input, ListFilesRequest_fields, &request))
71 printf("Decode failed: %s\n", PB_GET_ERROR(&input));
75 directory = opendir(request.path);
76 printf("Listing directory: %s\n", request.path);
79 /* List the files in the directory and transmit the response to client */
81 ListFilesResponse response = {};
82 pb_ostream_t output = pb_ostream_from_socket(connfd);
84 if (directory == NULL)
88 /* Directory was not found, transmit error status */
89 response.has_path_error = true;
90 response.path_error = true;
91 response.file.funcs.encode = NULL;
95 /* Directory was found, transmit filenames */
96 response.has_path_error = false;
97 response.file.funcs.encode = &listdir_callback;
98 response.file.arg = directory;
101 if (!pb_encode(&output, ListFilesResponse_fields, &response))
103 printf("Encoding failed: %s\n", PB_GET_ERROR(&output));
107 if (directory != NULL)
111 int main(int argc, char **argv)
113 int listenfd, connfd;
114 struct sockaddr_in servaddr;
117 /* Listen on localhost:1234 for TCP connections */
118 listenfd = socket(AF_INET, SOCK_STREAM, 0);
119 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
121 memset(&servaddr, 0, sizeof(servaddr));
122 servaddr.sin_family = AF_INET;
123 servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
124 servaddr.sin_port = htons(1234);
125 if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0)
131 if (listen(listenfd, 5) != 0)
139 /* Wait for a client */
140 connfd = accept(listenfd, NULL, NULL);
148 printf("Got connection.\n");
150 handle_connection(connfd);
152 printf("Closing connection.\n");