17ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen/* This is a simple TCP server that listens on port 1234 and provides lists 27ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * of files to clients, using a protocol defined in file_server.proto. 37ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * 47ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * It directly deserializes and serializes messages from network, minimizing 57ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * memory use. 67ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * 77ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * For flexibility, this example is implemented using posix api. 87ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * In a real embedded system you would typically use some other kind of 97ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen * a communication and filesystem layer. 107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen */ 117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <sys/socket.h> 137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <sys/types.h> 147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <netinet/in.h> 157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <unistd.h> 167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <dirent.h> 177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <stdio.h> 187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <string.h> 197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <pb_encode.h> 217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include <pb_decode.h> 227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "fileproto.pb.h" 247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen#include "common.h" 257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenbool listdir_callback(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) 277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen DIR *dir = (DIR*) *arg; 297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen struct dirent *file; 307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen FileInfo fileinfo; 317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 327ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen while ((file = readdir(dir)) != NULL) 337ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 347ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fileinfo.inode = file->d_ino; 357ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen strncpy(fileinfo.name, file->d_name, sizeof(fileinfo.name)); 367ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen fileinfo.name[sizeof(fileinfo.name) - 1] = '\0'; 377ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 387ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_encode_tag_for_field(stream, field)) 397ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 407ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 417ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_encode_submessage(stream, FileInfo_fields, &fileinfo)) 427ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return false; 437ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 447ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 457ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return true; 467ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 477ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 487ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenvoid handle_connection(int connfd) 497ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 507ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ListFilesRequest request; 517ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen ListFilesResponse response; 527ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_istream_t input = pb_istream_from_socket(connfd); 537ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen pb_ostream_t output = pb_ostream_from_socket(connfd); 547ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen DIR *directory; 557ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 567ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_decode(&input, ListFilesRequest_fields, &request)) 577ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 587ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen printf("Decode failed: %s\n", PB_GET_ERROR(&input)); 597ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return; 607ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 617ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 627ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen directory = opendir(request.path); 637ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 647ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen printf("Listing directory: %s\n", request.path); 657ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 667ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (directory == NULL) 677ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 687ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen perror("opendir"); 697ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 707ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.has_path_error = true; 717ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.path_error = true; 727ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.file.funcs.encode = NULL; 737ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 747ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen else 757ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 767ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.has_path_error = false; 777ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.file.funcs.encode = &listdir_callback; 787ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen response.file.arg = directory; 797ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 807ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 817ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (!pb_encode(&output, ListFilesResponse_fields, &response)) 827ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 837ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen printf("Encoding failed.\n"); 847ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 857ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 867ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 877ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohenint main(int argc, char **argv) 887ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen{ 897ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen int listenfd, connfd; 907ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen struct sockaddr_in servaddr; 917ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen int reuse = 1; 927ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 937ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen listenfd = socket(AF_INET, SOCK_STREAM, 0); 947ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 957ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); 967ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 977ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen memset(&servaddr, 0, sizeof(servaddr)); 987ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen servaddr.sin_family = AF_INET; 997ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen servaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 1007ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen servaddr.sin_port = htons(1234); 1017ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0) 1027ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1037ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen perror("bind"); 1047ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 1; 1057ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1067ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1077ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (listen(listenfd, 5) != 0) 1087ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1097ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen perror("listen"); 1107ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 1; 1117ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1127ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1137ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen for(;;) 1147ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1157ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen connfd = accept(listenfd, NULL, NULL); 1167ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1177ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen if (connfd < 0) 1187ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen { 1197ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen perror("accept"); 1207ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen return 1; 1217ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1227ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1237ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen printf("Got connection.\n"); 1247ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1257ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen handle_connection(connfd); 1267ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1277ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen printf("Closing connection.\n"); 1287ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen 1297ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen close(connfd); 1307ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen } 1317ef855e462b9a18b7d330e4b40f350164a6ad9daEtan Cohen} 132