diff --git a/examples/wsperf/case.hpp b/examples/wsperf/case.hpp index f4d863c4a8..cf1fe0520e 100644 --- a/examples/wsperf/case.hpp +++ b/examples/wsperf/case.hpp @@ -28,20 +28,36 @@ #ifndef WSPERF_CASE_HPP #define WSPERF_CASE_HPP +#include "wscmd.hpp" + #include "../../src/roles/client.hpp" #include "../../src/websocketpp.hpp" #include +#include + using websocketpp::client; namespace wsperf { +class case_exception : public std::exception { +public: + case_exception(const std::string& msg) : m_msg(msg) {} + ~case_exception() throw() {} + + virtual const char* what() const throw() { + return m_msg.c_str(); + } + + std::string m_msg; +}; + class case_handler : public client::handler { public: typedef case_handler type; - void start(connection_ptr con, int timeout) { + void start(connection_ptr con, uint64_t timeout) { m_timer.reset(new boost::asio::deadline_timer( con->get_io_service(), boost::posix_time::seconds(0)) @@ -110,12 +126,10 @@ public: double kbps = (double(m_bytes)/1000.0)/seconds; - std::stringstream o; std::stringstream s; switch (m_pass) { case FAIL: - o << m_name << " fails in " << seconds << "s"; s << "{\"name\":\"" << m_name << "\",\"result\":\"fail\",\"min\":" << m_times[0] << ",\"max\":" << m_times[m_times.size()-1] << ",\"median\":" << m_times[(m_times.size()-1)/2] << ",\"avg\":" << avg << ",\"stddev\":" << stddev << ",\"sqsum\":" << squaresum << ",\"total\":" << total << ",\"KBps\":" << kbps << ",\"quantiles\":["; for (int i = 0; i < 10; i++) { @@ -124,9 +138,7 @@ public: s << "]}"; break; - case PASS: - o << m_name << " passes in " << seconds << "s"; - + case PASS: s << "{\"name\":\"" << m_name << "\",\"result\":\"pass\",\"min\":" << m_times[0] << ",\"max\":" << m_times[m_times.size()-1] << ",\"median\":" << m_times[(m_times.size()-1)/2] << ",\"avg\":" << avg << ",\"stddev\":" << stddev << ",\"sqsum\":" << squaresum << ",\"total\":" << total << ",\"KBps\":" << kbps << ",\"quantiles\":["; for (int i = 0; i < 10; i++) { @@ -136,7 +148,6 @@ public: s << "]}"; break; case TIME_OUT: - o << m_name << " times out in " << seconds << "s"; s << "{\"name\":\"" << m_name << "\",\"result\":\"time_out\",\"min\":" << m_times[0] << ",\"max\":" << m_times[m_times.size()-1] << ",\"median\":" << m_times[(m_times.size()-1)/2] << ",\"avg\":" << avg << ",\"stddev\":" << stddev << ",\"sqsum\":" << squaresum << ",\"total\":" << total << ",\"KBps\":" << kbps << ",\"quantiles\":["; for (int i = 0; i < 10; i++) { @@ -145,9 +156,11 @@ public: s << "]}"; break; + case RUNNING: + throw case_exception("end() called from RUNNING state"); + break; } - m_result = o.str(); m_data = s.str(); con->close(websocketpp::close::status::NORMAL,""); @@ -185,6 +198,38 @@ public: } } + std::string extract_string(wscmd::cmd command,std::string key) { + if (command.args[key] != "") { + return command.args[key]; + } else { + throw case_exception("Invalid " + key + " parameter."); + } + } + + template + T extract_number(wscmd::cmd command,std::string key) { + if (command.args[key] != "") { + std::istringstream buf(command.args[key]); + T val; + + buf >> val; + + if (buf) {return val;} + } + throw case_exception("Invalid " + key + " parameter."); + } + + bool extract_bool(wscmd::cmd command,std::string key) { + if (command.args[key] != "") { + if (command.args[key] == "true") { + return true; + } else if (command.args[key] == "false") { + return false; + } + } + throw case_exception("Invalid " + key + " parameter."); + } + void on_timer(connection_ptr con,const boost::system::error_code& error) { if (error == boost::system::errc::operation_canceled) { return; // timer was canceled because test finished @@ -196,19 +241,17 @@ public: this->end(con); } - void on_close(connection_ptr con) { - //std::cout << " fails in " << len.length() << std::endl; - } + void on_close(connection_ptr con) {} void on_fail(connection_ptr con) { m_data = "{\"result\":\"connection_failed\"}"; } - const std::string& get_result() const { - return m_result; - } const std::string& get_data() const { return m_data; } + const std::string& get_token() const { + return m_token; + } protected: enum status { FAIL = 0, @@ -218,7 +261,8 @@ protected: }; std::string m_name; - std::string m_result; + std::string m_uri; + std::string m_token; std::string m_data; status m_pass; diff --git a/examples/wsperf/generic.hpp b/examples/wsperf/generic.hpp index 3033adf904..313be131fd 100644 --- a/examples/wsperf/generic.hpp +++ b/examples/wsperf/generic.hpp @@ -29,6 +29,7 @@ #define WSPERF_CASE_GENERIC_HPP #include "case.hpp" +#include "wscmd.hpp" namespace wsperf { @@ -55,6 +56,35 @@ public: m_acks(0) {} + explicit message_test(wscmd::cmd& cmd) { + // message_test:uri=[string]; ws://localhost:9000 + // size=[interger]; 4096 + // count=[integer]; 1000 + // timeout=[integer]; 10000 + // binary=[bool]; true/false + // sync=[bool]; true/false + // correctness=[string]; exact/length + // token=[string]; foo + + m_uri = extract_string(cmd,"uri"); + m_token = extract_string(cmd,"token"); + + m_message_count = extract_number(cmd,"size"); + m_message_size = extract_number(cmd,"count"); + m_timeout = extract_number(cmd,"timeout"); + + m_binary = extract_bool(cmd,"binary"); + m_sync = extract_bool(cmd,"sync"); + + if (cmd.args["correctness"] == "exact") { + m_mode = EXACT; + } else if (cmd.args["correctness"] == "length") { + m_mode = LENGTH; + } else { + throw case_exception("Invalid correctness parameter."); + } + } + void on_open(connection_ptr con) { m_msg = con->get_data_message(); @@ -105,16 +135,18 @@ public: } } private: - uint64_t m_message_size; - uint64_t m_message_count; - int m_timeout; - bool m_binary; - bool m_sync; - correctness_mode m_mode; + // Simulation Parameters + uint64_t m_message_size; + uint64_t m_message_count; + uint64_t m_timeout; + bool m_binary; + bool m_sync; + correctness_mode m_mode; - std::string m_data; - message_ptr m_msg; - uint64_t m_acks; + // Simulation temporaries + std::string m_data; + message_ptr m_msg; + uint64_t m_acks; }; } // namespace wsperf diff --git a/examples/wsperf/request.cpp b/examples/wsperf/request.cpp new file mode 100644 index 0000000000..1156347606 --- /dev/null +++ b/examples/wsperf/request.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ \ No newline at end of file diff --git a/examples/wsperf/request.hpp b/examples/wsperf/request.hpp new file mode 100644 index 0000000000..3968e7527a --- /dev/null +++ b/examples/wsperf/request.hpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2011, Peter Thorson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the WebSocket++ Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WSPERF_REQUEST_HPP +#define WSPERF_REQUEST_HPP + +#include "case.hpp" +#include "generic.hpp" +#include "wscmd.hpp" + +#include "../../src/roles/client.hpp" +#include "../../src/websocketpp.hpp" + +using websocketpp::client; + +namespace wsperf { + +class writer { +public: + virtual void write(std::string& msg) = 0; +}; + +typedef boost::shared_ptr writer_ptr; + +template +class ws_writer : writer { +public: + ws_writer(typename T::handler::connection_ptr con) : m_con(con) {} + + void write(std::string& msg) { + m_con->write; + } +private: + typename T::handler::connection_ptr m_con; +}; + +// A request encapsulates all of the information necesssary to perform a request +// the coordinator will fill in this information from the websocket connection +// and add it to the processing queue. Sleeping in this example is a placeholder +// for any long serial task. +struct request { + writer_ptr writer; + + std::string req; // The raw request + std::string token; // Parsed test token. Return in all results + + /// Run a test and return JSON result + void process() { + case_handler_ptr test; + std::string uri; + + wscmd::cmd command = wscmd::parse(req); + + try { + if (command.command == "message_test") { + test = case_handler_ptr(new message_test(command)); + token = test.get_token(); + } else { + writer.write(prepare_response("error","Invalid Command")); + return; + } + } catch (case_exception& e) { + writer.write(prepare_response("error",e.what())); + return; + } + + writer.write(prepare_response("test_start","")); + + client e(test); + + e.alog().unset_level(websocketpp::log::alevel::ALL); + e.elog().unset_level(websocketpp::log::elevel::ALL); + + e.elog().set_level(websocketpp::log::elevel::ERROR); + e.elog().set_level(websocketpp::log::elevel::FATAL); + + e.connect(); + e.run(); + + writer.write(prepare_response("test_start",tests[i]->get_data())); + + writer.write(prepare_response("test_complete","")); + } + + std::string prepare_response(std::string type,std::string data) { + return "{\"type\":\"" + type + "\",\"token\":\"" + m_token + "\",\"data\":\"" + data + "\"}"; + } +}; + +// The coordinator is a simple wrapper around an STL queue. add_request inserts +// a new request. get_request returns the next available request and blocks +// (using condition variables) in the case that the queue is empty. +class request_coordinator { +public: + void add_request(const request& r) { + boost::unique_lock lock(m_lock); + m_requests.push(r); + lock.unlock(); + m_cond.notify_one(); + } + + void get_request(request& value) { + boost::unique_lock lock(m_lock); + + while (m_requests.empty()) { + m_cond.wait(lock); + } + + value = m_requests.front(); + m_requests.pop(); + } +private: + std::queue m_requests; + boost::mutex m_lock; + boost::condition_variable m_cond; +}; + +// The WebSocket++ handler in this case reads numbers from connections and packs +// connection pointer + number into a request struct and passes it off to the +// coordinator. +class concurrent_server_handler : public server::handler { +public: + concurrent_server_handler(request_coordinator& c) : m_coordinator(c) {} + + void on_message(connection_ptr con,message_ptr msg) { + request r; + r.writer = writer_ptr(new ws_writer(con)); + r.req = msg->get_payload(); + m_coordinator.add_request(r); + } +private: + request_coordinator& m_coordinator; +}; + +// process_requests is the body function for a processing thread. It loops +// forever reading requests, processing them serially, then reading another +// request. +void process_requests(request_coordinator* coordinator); + +void process_requests(request_coordinator* coordinator) { + request r; + + while (1) { + coordinator->get_request(r); + + r.process(); + } +} + +} // namespace wsperf + + + + + + + + +#endif // WSPERF_REQUEST_HPP \ No newline at end of file diff --git a/examples/wsperf/wsperf.cpp b/examples/wsperf/wsperf.cpp index 277b50909f..c81622aa78 100644 --- a/examples/wsperf/wsperf.cpp +++ b/examples/wsperf/wsperf.cpp @@ -25,12 +25,8 @@ * */ -#include "wscmd.hpp" -#include "case.hpp" -#include "autobahn.hpp" -#include "generic.hpp" +#include "request.hpp" -#include "../../src/roles/client.hpp" #include "../../src/websocketpp.hpp" #include @@ -41,215 +37,6 @@ #include using websocketpp::server; -using websocketpp::client; - -// A request encapsulates all of the information necesssary to perform a request -// the coordinator will fill in this information from the websocket connection -// and add it to the processing queue. Sleeping in this example is a placeholder -// for any long serial task. -struct request { - server::handler::connection_ptr con; - std::string req; - std::string token; - - // message_test:uri=ws://localhost:9000;size=4096;count=1000;timeout=10000;binary=true;sync=true;correctness=exact;token=foo; - - void process() { - std::vector tests; - std::string uri; - - wscmd::cmd command = wscmd::parse(req); - - if (command.command == "message_test") { - uint64_t message_size; - uint64_t message_count; - uint64_t timeout; - - bool binary; - bool sync; - - wsperf::correctness_mode mode; - - if (!extract_string(command,"uri",uri)) {return;} - if (!extract_string(command,"token",token)) {return;} - - if (!extract_number(command,"size",message_size)) {return;} - if (!extract_number(command,"count",message_count)) {return;} - if (!extract_number(command,"timeout",timeout)) {return;} - - if (!extract_bool(command,"binary",binary)) {return;} - if (!extract_bool(command,"sync",sync)) {return;} - - if (command.args["correctness"] == "exact") { - mode = wsperf::EXACT; - } else if (command.args["correctness"] == "length") { - mode = wsperf::LENGTH; - } else { - send_error("Invalid correctness parameter"); - return; - } - - tests.push_back(wsperf::case_handler_ptr(new wsperf::message_test(message_size,message_count,timeout,binary,sync,mode))); - } else { - send_error("Invalid Command"); - return; - } - - con->send("{\"type\":\"test_start\",\"token\":\"" + token + "\"}"); - - // 9.1.x and 9.2.x tests - /*for (int i = 1; i <= 2; i++) { - for (int j = 1; j <= 6; j++) { - tests.push_back(wsperf::case_handler_ptr(new wsperf::test_9_1_X(i,j))); - } - }*/ - - // 9.7.x and 9.8.x tests - /*for (int i = 7; i <= 8; i++) { - for (int j = 1; j <= 6; j++) { - tests.push_back(wsperf::case_handler_ptr(new wsperf::test_9_7_X(i,j))); - } - }*/ - - - - client e(tests[0]); - - e.alog().unset_level(websocketpp::log::alevel::ALL); - e.elog().unset_level(websocketpp::log::elevel::ALL); - - e.elog().set_level(websocketpp::log::elevel::ERROR); - e.elog().set_level(websocketpp::log::elevel::FATAL); - - for (size_t i = 0; i < tests.size(); i++) { - if (i > 0) { - e.reset(); - e.set_handler(tests[i]); - } - - e.connect(uri); - e.run(); - - std::stringstream json; - - json << "{\"type\":\"test_data\",\"uri\":\"" << uri << "\",\"token\":\"" << token << "\",\"data\":" << tests[i]->get_data() << "}"; - - con->send(json.str()); - } - - con->send("{\"type\":\"test_complete\",\"token\":\"" + token + "\"}"); - } - - bool extract_string(wscmd::cmd command,std::string key,std::string &val) { - if (command.args[key] != "") { - val = command.args[key]; - return true; - } else { - //std::stringstream response; - //response << "{\"type\":\"message\",\"data\":\"" << key << " parameter is required.\"}"; - //con->send(response.str()); - con->send("{\"type\":\"error\",\"data\":\"Invalid " + key + " parameter.\"}"); - return false; - } - } - - bool extract_number(wscmd::cmd command,std::string key,uint64_t &val) { - if (command.args[key] != "") { - std::istringstream buf(command.args[key]); - - buf >> val; - - if (buf) {return true;} - } - //std::stringstream response; - //response << "{\"type\":\"message\",\"data\":\"" << key << " parameter is required.\"}"; - //con->send(response.str()); - con->send("{\"type\":\"error\",\"data\":\"Invalid " + key + " parameter.\"}"); - return false; - } - - bool extract_bool(wscmd::cmd command,std::string key,bool &val) { - if (command.args[key] != "") { - if (command.args[key] == "true") { - val = true; - return true; - } else if (command.args[key] == "false") { - val = false; - return true; - } - } - //std::stringstream response; - //response << ; - con->send("{\"type\":\"error\",\"data\":\"Invalid " + key + " parameter.\"}"); - return false; - } - - void send_error(std::string msg) { - std::stringstream response; - response << "{\"type\":\"error\",\"data\":\"" << msg << "\"}"; - con->send(response.str()); - } -}; - -// The coordinator is a simple wrapper around an STL queue. add_request inserts -// a new request. get_request returns the next available request and blocks -// (using condition variables) in the case that the queue is empty. -class request_coordinator { -public: - void add_request(const request& r) { - boost::unique_lock lock(m_lock); - m_requests.push(r); - lock.unlock(); - m_cond.notify_one(); - } - - void get_request(request& value) { - boost::unique_lock lock(m_lock); - - while (m_requests.empty()) { - m_cond.wait(lock); - } - - value = m_requests.front(); - m_requests.pop(); - } -private: - std::queue m_requests; - boost::mutex m_lock; - boost::condition_variable m_cond; -}; - -// The WebSocket++ handler in this case reads numbers from connections and packs -// connection pointer + number into a request struct and passes it off to the -// coordinator. -class concurrent_server_handler : public server::handler { -public: - concurrent_server_handler(request_coordinator& c) : m_coordinator(c) {} - - void on_message(connection_ptr con,message_ptr msg) { - request r; - r.con = con; - r.req = msg->get_payload(); - m_coordinator.add_request(r); - } -private: - request_coordinator& m_coordinator; -}; - -// process_requests is the body function for a processing thread. It loops -// forever reading requests, processing them serially, then reading another -// request. -void process_requests(request_coordinator* coordinator); - -void process_requests(request_coordinator* coordinator) { - request r; - - while (1) { - coordinator->get_request(r); - - r.process(); - } -} // concurrent server takes two arguments. A port to bind to and a number of // worker threads to create. The thread count must be an integer greater than @@ -267,13 +54,12 @@ void process_requests(request_coordinator* coordinator) { // based on hardware concurrency available and expected load and // job length. int main(int argc, char* argv[]) { - unsigned short port = 9002; + unsigned short port = 9003; unsigned short num_threads = 2; - std::list > threads; - std::list >::iterator thit; - try { + std::list< boost::shared_ptr > threads; + if (argc == 2) { std::stringstream buffer(argv[1]); buffer >> port; @@ -284,14 +70,14 @@ int main(int argc, char* argv[]) { buffer >> num_threads; } - request_coordinator rc; + wsperf::request_coordinator rc; server::handler::ptr h; if (num_threads == 0) { std::cout << "bad thread number" << std::endl; return 1; } else { - h = server::handler::ptr(new concurrent_server_handler(rc)); + h = server::handler::ptr(new wsperf::concurrent_server_handler(rc)); } server echo_endpoint(h); diff --git a/websocketpp.xcodeproj/project.pbxproj b/websocketpp.xcodeproj/project.pbxproj index cd973adc81..9f9bcff609 100644 --- a/websocketpp.xcodeproj/project.pbxproj +++ b/websocketpp.xcodeproj/project.pbxproj @@ -98,6 +98,7 @@ B6DF1CDC1435EDCE0029A1B1 /* echo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6DF1CCB1435ED760029A1B1 /* echo.cpp */; }; B6DF1CDE1435EDF00029A1B1 /* libwebsocketpp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B6DF1C721434A8280029A1B1 /* libwebsocketpp.dylib */; }; B6DF1CE21435F1860029A1B1 /* libboost_system.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B6DF1CE11435F1860029A1B1 /* libboost_system.dylib */; }; + B6E56D80150644A3007E1707 /* request.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E56D7E150644A3007E1707 /* request.cpp */; }; B6E7E77E1505536500394909 /* wsperf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E56D6814FEFC54007E1707 /* wsperf.cpp */; }; B6E7E77F1505536500394909 /* autobahn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E56D6B14FF0183007E1707 /* autobahn.cpp */; }; B6E7E7801505536500394909 /* case.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B6E56D6914FEFE95007E1707 /* case.cpp */; }; @@ -369,6 +370,8 @@ B6E56D6D1503DF2C007E1707 /* generic.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = generic.cpp; path = examples/wsperf/generic.cpp; sourceTree = ""; }; B6E56D6E1503DF2C007E1707 /* generic.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = generic.hpp; path = examples/wsperf/generic.hpp; sourceTree = ""; }; B6E56D6F150457B8007E1707 /* wscmd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = wscmd.hpp; path = examples/wsperf/wscmd.hpp; sourceTree = ""; }; + B6E56D7E150644A3007E1707 /* request.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = request.cpp; path = examples/wsperf/request.cpp; sourceTree = ""; }; + B6E56D7F150644A3007E1707 /* request.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = request.hpp; path = examples/wsperf/request.hpp; sourceTree = ""; }; B6E7E7731505532E00394909 /* wsperf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wsperf; sourceTree = BUILT_PRODUCTS_DIR; }; B6E7E78A150553D000394909 /* libboost_chrono.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libboost_chrono.dylib; path = usr/local/lib/libboost_chrono.dylib; sourceTree = SDKROOT; }; B6FE8CE2144DE17F00B32547 /* readme.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = readme.txt; sourceTree = ""; }; @@ -899,6 +902,8 @@ B6E56D6614FEFC54007E1707 /* Makefile */, B6E56D6714FEFC54007E1707 /* wsperf_commander.html */, B6E56D6814FEFC54007E1707 /* wsperf.cpp */, + B6E56D7E150644A3007E1707 /* request.cpp */, + B6E56D7F150644A3007E1707 /* request.hpp */, B6E56D6B14FF0183007E1707 /* autobahn.cpp */, B6E56D6C14FF0184007E1707 /* autobahn.hpp */, B6E56D6914FEFE95007E1707 /* case.cpp */, @@ -1350,6 +1355,7 @@ B6E7E77F1505536500394909 /* autobahn.cpp in Sources */, B6E7E7801505536500394909 /* case.cpp in Sources */, B6E7E7811505536500394909 /* generic.cpp in Sources */, + B6E56D80150644A3007E1707 /* request.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2023,6 +2029,7 @@ B6E7E77B1505532E00394909 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; B6FE8D5614730AEA00B32547 /* Build configuration list for PBXNativeTarget "policy_test" */ = { isa = XCConfigurationList;