diff options
Diffstat (limited to 'examples/network_server')
-rw-r--r-- | examples/network_server/client.c | 98 | ||||
-rw-r--r-- | examples/network_server/server.c | 85 |
2 files changed, 118 insertions, 65 deletions
diff --git a/examples/network_server/client.c b/examples/network_server/client.c index e6e9a2e0..00f6dab8 100644 --- a/examples/network_server/client.c +++ b/examples/network_server/client.c @@ -23,9 +23,13 @@ #include "fileproto.pb.h" #include "common.h" +/* This callback function will be called once for each filename received + * from the server. The filenames will be printed out immediately, so that + * no memory has to be allocated for them. + */ bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) { - FileInfo fileinfo; + FileInfo fileinfo = {}; if (!pb_decode(stream, FileInfo_fields, &fileinfo)) return false; @@ -35,51 +39,70 @@ bool printfile_callback(pb_istream_t *stream, const pb_field_t *field, void **ar return true; } +/* This function sends a request to socket 'fd' to list the files in + * directory given in 'path'. The results received from server will + * be printed to stdout. + */ bool listdir(int fd, char *path) { - ListFilesRequest request; - ListFilesResponse response; - pb_istream_t input = pb_istream_from_socket(fd); - pb_ostream_t output = pb_ostream_from_socket(fd); - uint8_t zero = 0; - - if (path == NULL) - { - request.has_path = false; - } - else + /* Construct and send the request to server */ { - request.has_path = true; - if (strlen(path) + 1 > sizeof(request.path)) + ListFilesRequest request = {}; + pb_ostream_t output = pb_ostream_from_socket(fd); + uint8_t zero = 0; + + /* In our protocol, path is optional. If it is not given, + * the server will list the root directory. */ + if (path == NULL) + { + request.has_path = false; + } + else { - fprintf(stderr, "Too long path.\n"); + request.has_path = true; + if (strlen(path) + 1 > sizeof(request.path)) + { + fprintf(stderr, "Too long path.\n"); + return false; + } + + strcpy(request.path, path); + } + + /* Encode the request. It is written to the socket immediately + * through our custom stream. */ + if (!pb_encode(&output, ListFilesRequest_fields, &request)) + { + fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&output)); return false; } - strcpy(request.path, path); + /* We signal the end of request with a 0 tag. */ + pb_write(&output, &zero, 1); } - if (!pb_encode(&output, ListFilesRequest_fields, &request)) + /* Read back the response from server */ { - fprintf(stderr, "Encoding failed.\n"); - return false; - } - - /* We signal the end of request with a 0 tag. */ - pb_write(&output, &zero, 1); - - response.file.funcs.decode = &printfile_callback; - - if (!pb_decode(&input, ListFilesResponse_fields, &response)) - { - fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input)); - return false; - } - - if (response.path_error) - { - fprintf(stderr, "Server reported error.\n"); - return false; + ListFilesResponse response = {}; + pb_istream_t input = pb_istream_from_socket(fd); + + /* Give a pointer to our callback function, which will handle the + * filenames as they arrive. */ + response.file.funcs.decode = &printfile_callback; + + if (!pb_decode(&input, ListFilesResponse_fields, &response)) + { + fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&input)); + return false; + } + + /* If the message from server decodes properly, but directory was + * not found on server side, we get path_error == true. */ + if (response.path_error) + { + fprintf(stderr, "Server reported error.\n"); + return false; + } } return true; @@ -96,6 +119,7 @@ int main(int argc, char **argv) sockfd = socket(AF_INET, SOCK_STREAM, 0); + /* Connect to server running on localhost:1234 */ memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -107,9 +131,11 @@ int main(int argc, char **argv) return 1; } + /* Send the directory listing request */ if (!listdir(sockfd, path)) return 2; + /* Close connection */ close(sockfd); return 0; diff --git a/examples/network_server/server.c b/examples/network_server/server.c index 9a9c2644..46a5f38d 100644 --- a/examples/network_server/server.c +++ b/examples/network_server/server.c @@ -23,11 +23,16 @@ #include "fileproto.pb.h" #include "common.h" +/* This callback function will be called once 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 listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) { DIR *dir = (DIR*) *arg; struct dirent *file; - FileInfo fileinfo; + FileInfo fileinfo = {}; while ((file = readdir(dir)) != NULL) { @@ -35,9 +40,12 @@ bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * cons 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(stream, field)) return false; + /* This encodes the data for the field, based on our FileInfo structure. */ if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo)) return false; } @@ -45,43 +53,59 @@ bool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * cons 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) { - ListFilesRequest request; - ListFilesResponse response; - pb_istream_t input = pb_istream_from_socket(connfd); - pb_ostream_t output = pb_ostream_from_socket(connfd); - DIR *directory; + DIR *directory = NULL; - if (!pb_decode(&input, ListFilesRequest_fields, &request)) + /* Decode the message from the client and open the requested directory. */ { - printf("Decode failed: %s\n", PB_GET_ERROR(&input)); - return; + ListFilesRequest request = {}; + pb_istream_t input = pb_istream_from_socket(connfd); + + if (!pb_decode(&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); } - directory = opendir(request.path); - - printf("Listing directory: %s\n", request.path); - - if (directory == NULL) + /* List the files in the directory and transmit the response to client */ { - perror("opendir"); + ListFilesResponse response = {}; + pb_ostream_t output = pb_ostream_from_socket(connfd); - 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 (directory == NULL) + { + perror("opendir"); + + /* Directory was not found, transmit error status */ + response.has_path_error = true; + response.path_error = true; + response.file.funcs.encode = NULL; + } + else + { + /* Directory was found, transmit filenames */ + 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: %s\n", PB_GET_ERROR(&output)); + } } - if (!pb_encode(&output, ListFilesResponse_fields, &response)) - { - printf("Encoding failed.\n"); - } + if (directory != NULL) + closedir(directory); } int main(int argc, char **argv) @@ -90,8 +114,8 @@ int main(int argc, char **argv) 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)); @@ -112,6 +136,7 @@ int main(int argc, char **argv) for(;;) { + /* Wait for a client */ connfd = accept(listenfd, NULL, NULL); if (connfd < 0) @@ -128,4 +153,6 @@ int main(int argc, char **argv) close(connfd); } + + return 0; } |