/* Copyright (C) 2014 Carlos Aguilar Melchor, Joris Barrier, Marc-Olivier Killijian * This file is part of XPIR. * * XPIR is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * XPIR is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with XPIR. If not, see . */ #include "main.hpp" // Client constants static const std::string DEFAULT_IP("127.0.0.1"); static const int DEFAULT_PORT = 1234; static const bool DEFAULT_AUTOCHOICE = false; // Optimizer constants static const int DEFAULT_SECURITY = 80; static const unsigned long DEFAULT_N = 1000; static const unsigned int DEFAULT_L = 24000000; static const unsigned int DEFAULT_TUPC = 100000000; static const unsigned int DEFAULT_TDOC = 100000000; static const unsigned int DEFAULT_K = 80; static const unsigned int DEFAULT_ALPHAMAX = 0; // 0 means no limit static const unsigned int DEFAULT_DMAX = 4; static const unsigned int DEFAULT_DMIN = 1; static const FitnessType DEFAULT_FITNESSMETHOD = MAX; static const std::string DEFAULT_CRYPTO_PARAMS("LWE:80:1024:60:22"); //Global vars string fileToOptimizeFrom; bool no_pipeline = false; void sighandler(int sig_num) { FixedVars fixedVars; cerr.flush(); if(sig_num == SIGPIPE) cerr << "Broken pipe detected"; cerr << endl << "Exiting client..." << endl << endl; exit(EXIT_SUCCESS); } void defineClientOptions(ClientParams* paramsPtr, po::options_description* odptr){ odptr->add_options() ("help,h", "help message") ("serverip,ip", po::value(¶msPtr->server_ip)->default_value(DEFAULT_IP), "PIR server IP" ) ("port,p", po::value(¶msPtr->port)->default_value(DEFAULT_PORT), "PIR server port") ("autochoice,c", "Auto-choose the first file") ("dry-run", "Enable dry-run mode") ("verbose-optim", "Ask the optimizer to be more verbose") ("dont-write", "Don't write result to a file") ("file,f", po::value(&fileToOptimizeFrom), "Use a config file to test different optimizations in dry-run mode (see sample.conf)"); } void defineOptimizerOptions(FixedVars* varsPtr, po::options_description* odptr){ odptr->add_options() ("file-nbr,n", po::value(), "Used in dry-run mode only: Number of database elements" ) ("file-size,l", po::value(), "Used in dry-run mode only: Database element size in bits") ("upload,up", po::value(), "Force client upload speed in bits/s (bandwith test will be skipped)") ("download,down", po::value(), "Force client download speed in bits/s (bandwidth test will be skipped)") ("crypto-params,r", po::value(&varsPtr->manual_crypto_params), "Set cryptographic parameteres manually") ("security,k", po::value(&varsPtr->k)->default_value(DEFAULT_SECURITY), "Security bits wanted") ("dmin", po::value(&varsPtr->dMin)->default_value(DEFAULT_DMIN), "Min dimension value to test") ("dmax", po::value(&varsPtr->dMax)->default_value(DEFAULT_DMAX), "Max dimension value to test") ("alphaMax,a", po::value(&varsPtr->alphaMax)->default_value(DEFAULT_ALPHAMAX), "Max aggregation value to test (1 = no aggregation, 0 = no limit)") ("fitness,x", po::value((int*)&varsPtr->fitness)->default_value((int)DEFAULT_FITNESSMETHOD), "Set fitness method to: \n0=SUM Sum of the times on each task\n1=MAX Max of server times + Max of client times\n2=CLOUD Dollars in a cloud model (see sourcecode)"); } void defineHiddenOptions(FixedVars* varsPtr, po::options_description* odptr){ odptr->add_options() ("no-pipeline", "No pipeline mode\n") ("reclvl", po::value(), "Number of dimension used for database representation"); } void processOptions(FixedVars* varsPtr, ClientParams* paramsPtr, po::variables_map vm){ // Client options if(vm.count("serverip")) { std::cout << "CLI: Server ip set to " << paramsPtr->server_ip << std::endl; } if(vm.count("port")) { std::cout << "CLI: Upload port set to " << paramsPtr->port << std::endl; } if(vm.count("autochoice")) { std::cout << "CLI: Auto-choice activated" << std::endl; paramsPtr->autochoice = true; } if(vm.count("dry-run")) { std::cout << "CLI: Dry-run mode activated" << std::endl; paramsPtr->dryrunmode = true; varsPtr->n = DEFAULT_N; varsPtr->l = DEFAULT_L; varsPtr->Tupc = DEFAULT_TUPC; varsPtr->Tdos = DEFAULT_TUPC; varsPtr->Tdoc = DEFAULT_TDOC; varsPtr->Tups = DEFAULT_TDOC; std::cout << "CLI: Setting default values for dry-run mode (a thousand mp3 files, 100MBit/s connection)" <verboseoptim = true; } if(vm.count("dont-write")) { std::cout << "CLI: Will ask PIRReplyWriter not to write to a file" << std::endl; paramsPtr->dontwrite = true; } else paramsPtr->dontwrite = false; // Optimizer options if(vm.count("file-nbr")) { if(vm.count("dry-run")) { varsPtr->n = vm["file-nbr"].as(); std::cout << "CLI: Changing number of database elements to "\ << varsPtr->n << std::endl; } else { std::cout << "CLI: Option -n,--file-nbr ignored as we are not in dry-run mode"\ << std::endl; } } if(vm.count("file-size")) { if(vm.count("dry-run")) { varsPtr->l = vm["file-size"].as(); std::cout << "CLI: Changing database element size to " << varsPtr->l <Tupc = vm["upload"].as(); varsPtr->Tdos = varsPtr->Tupc; cout << "CLI: Upload speed forced to "<< varsPtr->Tupc << endl; } if (vm.count("download")) { varsPtr->Tdoc = vm["download"].as(); varsPtr->Tups = varsPtr->Tdoc; cout << "CLI: Download speed forced to "<< varsPtr->Tdoc << endl; } if(vm.count("crypto-params")) { std::cout << "CLI: Crypto parameters set to " << varsPtr->manual_crypto_params << std::endl; std::vector fields; boost::algorithm::split(fields, varsPtr->manual_crypto_params, boost::algorithm::is_any_of(":")); if (fields.size()>1 && atoi(fields[1].c_str()) > 0) { varsPtr->k = atoi(fields[1].c_str()); } if (fields.size()>4) { std::cout << "CLI: WARNING Absorption size will be overriden by the optimizer" << varsPtr->manual_crypto_params << std::endl; varsPtr->k = 0; } } if(vm.count("security")) { std::cout << "CLI: Security set to " << varsPtr->k << std::endl; } if (vm.count("dmin")) { cout << "CLI: Minimum recursion level set to "<< varsPtr->dMin << endl; } if (vm.count("dmax")) { cout << "CLI: Maximum recursion level set to "<< varsPtr->dMax << endl; } if(vm.count("alphaMax")) { varsPtr->alphaMax = vm["alphaMax"].as(); cout << "CLI: Max aggregation set to "<< varsPtr->alphaMax << endl; } if(vm.count("fitness")) { cout << "CLI: Fitness method set to "<< varsPtr->fitness << endl; } // Hidden options if (vm.count("reclvl")) { varsPtr->dMax = vm["reclvl"].as(); varsPtr->dMin = vm["reclvl"].as(); cout << "CLI: Recursion level forced to "<< varsPtr->dMax << endl; } if (vm.count("no-pipeline")) { std::cout << "CLI: WARNING no pipeline mode activated" << std::endl; no_pipeline = true; } } int main(int argc, char** argv) { boost::asio::io_service ios; // Vars for the optimizer (and pot. client) FixedVars fixedVars = {}; // Inits to default value all fields // Vars for the client only ClientParams clientParams = {}; // Same here // Add and define options po::options_description od("Client options"); po::options_description optimizeropts("Optimizer options"); po::options_description hidden("Hidden options"); defineOptimizerOptions(&fixedVars, &optimizeropts); defineClientOptions(&clientParams, &od); defineHiddenOptions(&fixedVars, &hidden); // Set which options are visible and which not po::options_description visible; visible.add(od).add(optimizeropts); po::options_description all; all.add(visible).add(hidden); po::variables_map vm; // Parse options from command line try { po::store(po::parse_command_line(argc, argv, all), vm); } catch (const std::exception& ex) { std::cout << "CLI: Error checking program options: " << ex.what() << std::endl; std::cout << visible << std::endl; return 1; } po::notify(vm); // Show usage help if requested if(vm.count("help")) { std::cout << visible << endl; return 0; } // Set variables according to options processOptions(&fixedVars, &clientParams, vm); // If we are on dry-run mode run only the optimizer not the client if(vm.count("dry-run")) { std::cout << "CLI: Dry-run mode activated" << std::endl; // The optimizer connects to the same PIR server but on a higher port for // optimization related exchanges PIROptimizer optimizer(clientParams.server_ip, clientParams.port, fixedVars.fitness); if (vm.count("file")) { int experience_nbr = OptimService::getNumberOfExperiences(fileToOptimizeFrom); if(experience_nbr == -1) { cout << "CLI: Unable to open : " << fileToOptimizeFrom << " aborting" << endl; cout << "CLI: Try exp/sample.conf to test a predefined set of configurations" << endl; return 1; } for (int exp_i = 0 ; exp_i <= experience_nbr ; exp_i++) { OptimService::readTestValues(exp_i, fixedVars, fileToOptimizeFrom); OptimService::writeHeadFile(exp_i, fixedVars); optimizer.optimize(fixedVars, exp_i); } } else { cout << "CLI: Default example : A thousand mp3 files, ADSL, no aggregation, k=80" << endl; cout << "CLI: n : " << fixedVars.n << " l : " << fixedVars.l; cout << "CLI: Tupc : " << fixedVars.Tupc << " Tdoc : " << fixedVars.Tdoc << endl; OptimService::writeHeadFile(0, fixedVars); optimizer.optimize(fixedVars, 0); } return 0; } // If we are not in dry-run mode create client and controller PIRClientSimple client(ios, clientParams, fixedVars); PIRController controller(client); // Set no_pipeline if needed if(no_pipeline) client.no_pipeline(true); // Start by connecting to the PIR server client.connect(); // Downloads the file catalog client.downloadCatalog(); // Get from the server whether we are in client-driven mode or not client.rcvPIRParamsExchangeMethod(); // Use the optimizer to choose best parameters // (returns immediately in server-driven mode) client.optimize(); // Send PIR and cryptographic parameters to the server in client-driven mode // and receive and process them in server-driven mode client.processCryptoParams(); client.processPIRParams(); /*User chooses the file here.*/ client.chooseFile(); double start = omp_get_wtime(); /* Asynchronously generate and send the request separately in two threads*/ client.startProcessQuery(); /* Receive asynchronously the response from the server and asynchronously writes it */ client.startProcessResult(); client.joinAllThreads(); double end = omp_get_wtime(); cout << "CLI: Query RTT was " << end-start << " seconds" << endl; cout << "CLI: Exiting..." << endl; return EXIT_SUCCESS; }