Home | History | Annotate | Download | only in network_server
      1 /* This is a simple TCP client that connects to port 1234 and prints a list
      2  * of files in a given directory.
      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 
     26 /* This callback function will be called once for each filename received
     27  * from the server. The filenames will be printed out immediately, so that
     28  * no memory has to be allocated for them.
     29  */
     30 bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg)
     31 {
     32     FileInfo fileinfo = {};
     33 
     34     if (!pb_decode(stream, FileInfo_fields, &fileinfo))
     35         return false;
     36 
     37     printf("%-10lld %s\n", (long long)fileinfo.inode, fileinfo.name);
     38 
     39     return true;
     40 }
     41 
     42 /* This function sends a request to socket 'fd' to list the files in
     43  * directory given in 'path'. The results received from server will
     44  * be printed to stdout.
     45  */
     46 bool listdir(int fd, char *path)
     47 {
     48     /* Construct and send the request to server */
     49     {
     50         ListFilesRequest request = {};
     51         pb_ostream_t output = pb_ostream_from_socket(fd);
     52         uint8_t zero = 0;
     53 
     54         /* In our protocol, path is optional. If it is not given,
     55          * the server will list the root directory. */
     56         if (path == NULL)
     57         {
     58             request.has_path = false;
     59         }
     60         else
     61         {
     62             request.has_path = true;
     63             if (strlen(path) + 1 > sizeof(request.path))
     64             {
     65                 fprintf(stderr, "Too long path.\n");
     66                 return false;
     67             }
     68 
     69             strcpy(request.path, path);
     70         }
     71 
     72         /* Encode the request. It is written to the socket immediately
     73          * through our custom stream. */
     74         if (!pb_encode(&output, ListFilesRequest_fields, &request))
     75         {
     76             fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output));
     77             return false;
     78         }
     79 
     80         /* We signal the end of request with a 0 tag. */
     81         pb_write(&output, &zero, 1);
     82     }
     83 
     84     /* Read back the response from server */
     85     {
     86         ListFilesResponse response = {};
     87         pb_istream_t input = pb_istream_from_socket(fd);
     88 
     89         /* Give a pointer to our callback function, which will handle the
     90          * filenames as they arrive. */
     91         response.file.funcs.decode = &printfile_callback;
     92 
     93         if (!pb_decode(&input, ListFilesResponse_fields, &response))
     94         {
     95             fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input));
     96             return false;
     97         }
     98 
     99         /* If the message from server decodes properly, but directory was
    100          * not found on server side, we get path_error == true. */
    101         if (response.path_error)
    102         {
    103             fprintf(stderr, "Server reported error.\n");
    104             return false;
    105         }
    106     }
    107 
    108     return true;
    109 }
    110 
    111 int main(int argc, char **argv)
    112 {
    113     int sockfd;
    114     struct sockaddr_in servaddr;
    115     char *path = NULL;
    116 
    117     if (argc > 1)
    118         path = argv[1];
    119 
    120     sockfd = socket(AF_INET, SOCK_STREAM, 0);
    121 
    122     /* Connect to server running on localhost:1234 */
    123     memset(&servaddr, 0, sizeof(servaddr));
    124     servaddr.sin_family = AF_INET;
    125     servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    126     servaddr.sin_port = htons(1234);
    127 
    128     if (connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
    129     {
    130         perror("connect");
    131         return 1;
    132     }
    133 
    134     /* Send the directory listing request */
    135     if (!listdir(sockfd, path))
    136         return 2;
    137 
    138     /* Close connection */
    139     close(sockfd);
    140 
    141     return 0;
    142 }
    143