| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 | /* 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"/* This callback function will be called during the encoding. * It will write out any number of FileInfo entries, without consuming unnecessary memory. * This is accomplished by fetching the filenames one at a time and encoding them * immediately. */bool ListFilesResponse_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field){    PB_UNUSED(istream);    if (ostream != NULL && field->tag == ListFilesResponse_file_tag)    {        DIR *dir = *(DIR**)field->pData;        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';            /* This encodes the header for the field, based on the constant info            * from pb_field_t. */            if (!pb_encode_tag_for_field(ostream, field))                return false;            /* This encodes the data for the field, based on our FileInfo structure. */            if (!pb_encode_submessage(ostream, FileInfo_fields, &fileinfo))                return false;        }        /* Because the main program uses pb_encode_delimited(), this callback will be        * called twice. Rewind the directory for the next call. */        rewinddir(dir);    }    return true;}/* Handle one arriving client connection. * Clients are expected to send a ListFilesRequest, terminated by a '0'. * Server will respond with a ListFilesResponse message. */void handle_connection(int connfd){    DIR *directory = NULL;        /* Decode the message from the client and open the requested directory. */    {        ListFilesRequest request = {};        pb_istream_t input = pb_istream_from_socket(connfd);                if (!pb_decode_delimited(&input, ListFilesRequest_fields, &request))        {            printf("Decode failed: %s\n", PB_GET_ERROR(&input));            return;        }                directory = opendir(request.path);        printf("Listing directory: %s\n", request.path);    }        /* List the files in the directory and transmit the response to client */    {        ListFilesResponse response = {};        pb_ostream_t output = pb_ostream_from_socket(connfd);                if (directory == NULL)        {            perror("opendir");                        /* Directory was not found, transmit error status */            response.has_path_error = true;            response.path_error = true;        }        else        {            /* Directory was found, transmit filenames */            response.has_path_error = false;            response.file = directory;        }                if (!pb_encode_delimited(&output, ListFilesResponse_fields, &response))        {            printf("Encoding failed: %s\n", PB_GET_ERROR(&output));        }    }        if (directory != NULL)        closedir(directory);}int main(int argc, char **argv){    int listenfd, connfd;    struct sockaddr_in servaddr;    int reuse = 1;        /* Listen on localhost:1234 for TCP connections */    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(;;)    {        /* Wait for a client */        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);    }        return 0;}
 |