/* This is a simple TCP server that listens on port 1234 and provides lists * of files to clients, using a protocol defined in file_server.proto. * * It directly deserializes and serializes messages from network, minimizing * memory use. * * For flexibility, this example is implemented using posix api. * In a real embedded system you would typically use some other kind of * a communication and filesystem layer. */ #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <unistd.h> #include <dirent.h> #include <stdio.h> #include <string.h> #include <pb_encode.h> #include <pb_decode.h> #include "fileproto.pb.h" #include "common.h" bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, const void *arg) { DIR *dir = (DIR*) arg; struct dirent *file; FileInfo fileinfo; while ((file = readdir(dir)) != NULL) { fileinfo.inode = file->d_ino; strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name)); fileinfo.name[sizeof(fileinfo.name) - 1] = '\0'; if (!pb_encode_tag_for_field(stream, field)) return false; if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo)) return false; } return true; } void handle_connection(int connfd) { ListFilesRequest request; ListFilesResponse response; pb_istream_t input = pb_istream_from_socket(connfd); pb_ostream_t output = pb_ostream_from_socket(connfd); DIR *directory; if (!pb_decode(&input, ListFilesRequest_fields, &request)) { printf("Decoding failed.\n"); return; } directory = opendir(request.path); printf("Listing directory: %s\n", request.path); if (directory == NULL) { perror("opendir"); response.has_path_error = true; response.path_error = true; response.file.funcs.encode = NULL; } else { response.has_path_error = false; response.file.funcs.encode = &listdir_callback; response.file.arg = directory; } if (!pb_encode(&output, ListFilesResponse_fields, &response)) { printf("Encoding failed.\n"); } } int main(int argc, char **argv) { int listenfd, connfd; struct sockaddr_in servaddr; int reuse = 1; listenfd = socket(AF_INET, SOCK_STREAM, 0); setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); servaddr.sin_port = htons(1234); if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0) { perror("bind"); return 1; } if (listen(listenfd, 5) != 0) { perror("listen"); return 1; } for(;;) { connfd = accept(listenfd, NULL, NULL); if (connfd < 0) { perror("accept"); return 1; } printf("Got connection.\n"); handle_connection(connfd); printf("Closing connection.\n"); close(connfd); } }