<commit_before>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

#include <regex>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Response {
            friend class ServerBase<socket_type>;
        private:
            boost::asio::yield_context& yield;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            Response(boost::asio::io_service& io_service, std::shared_ptr<socket_type> socket, boost::asio::yield_context& yield):
                    yield(yield), socket(socket), stream(&streambuf) {}

            void flush() {
                boost::system::error_code ec;
                boost::asio::async_write(*socket, streambuf, yield[ec]);

                if(ec)
                    throw std::runtime_error(ec.message());
            }

        public:
            std::ostream stream;

            template <class T>
            Response& operator<<(const T& t) {
                stream << t;
                return *this;
            }

            Response& operator<<(std::ostream& (*manip)(std::ostream&)) {
                stream << manip;
                return *this;
            }

            Response& operator<<(Response& (*manip)(Response&)) {
                return manip(*this);
            }
        };

        static Response& flush(Response& r) {
            r.flush();
            return r;
        }

        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_multimap<std::string, std::string> header;

            std::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(&streambuf) {}

            boost::asio::streambuf streambuf;

            void read_remote_endpoint_data(socket_type& socket) {
                try {
                    remote_endpoint_address=socket.lowest_layer().remote_endpoint().address().to_string();
                    remote_endpoint_port=socket.lowest_layer().remote_endpoint().port();
                }
                catch(const std::exception& e) {}
            }
        };

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<std::regex,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(std::regex(res.first), res_method.second);
                }
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            io_service.stop();
        }

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        boost::asio::strand strand;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(io_service, endpoint), strand(io_service),
                num_threads(num_threads), timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket_strand_wrapped(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait(strand.wrap([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            }));
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            request->read_remote_endpoint_data(*socket);

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    const auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        unsigned long long content_length;
                        try {
                            content_length=stoull(it->second);
                        }
                        catch(const std::exception &e) {
                            return;
                        }
                        boost::asio::async_read(*socket, request->streambuf,
                                boost::asio::transfer_exactly(content_length-num_additional_bytes),
                                [this, socket, request, timer]
                                (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                            if(timeout_content>0)
                                timer->cancel();
                            if(!ec)
                                find_resource(socket, request);
                        });
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end=line.find(' ');
            size_t path_end=line.find(' ', method_end+1);
            if(method_end!=std::string::npos && path_end!=std::string::npos) {
                request->method=line.substr(0, method_end);
                request->path=line.substr(method_end+1, path_end-method_end-1);
                request->http_version=line.substr(path_end+6, line.size()-path_end-7);

                getline(stream, line);
                size_t param_end=line.find(':');
                while(param_end!=std::string::npos) {
                    size_t value_start=param_end+1;
                    if(line[value_start]==' ')
                        value_start++;

                    std::string key=line.substr(0, param_end);
                    request->header.insert(std::make_pair(key, line.substr(value_start, line.size()-value_start-1)));

                    getline(stream, line);
                    param_end=line.find(':');
                }
            }
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        std::smatch sm_res;
                        if(std::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket_strand_wrapped(socket, timeout_content);

            boost::asio::spawn(strand, [this, &resource_function, socket, request, timer](boost::asio::yield_context yield) {
                Response response(io_service, socket, yield);

                try {
                    resource_function(response, request);
                }
                catch(const std::exception& e) {
                    return;
                }

                try {
                    response.flush();
                }
                catch(const std::exception &e) {
                    return;
                }
                if(timeout_content>0)
                    timer->cancel();
                if(stof(request->http_version)>1.05)
                    read_request_and_content(socket);
            });
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<commit_msg>Added size_t Response::size().<commit_after>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

#include <regex>
#include <unordered_map>
#include <thread>
#include <functional>
#include <iostream>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Response {
            friend class ServerBase<socket_type>;
        private:
            boost::asio::yield_context& yield;

            boost::asio::streambuf streambuf;

            std::shared_ptr<socket_type> socket;

            Response(boost::asio::io_service& io_service, std::shared_ptr<socket_type> socket, boost::asio::yield_context& yield):
                    yield(yield), socket(socket), stream(&streambuf) {}

            void flush() {
                boost::system::error_code ec;
                boost::asio::async_write(*socket, streambuf, yield[ec]);

                if(ec)
                    throw std::runtime_error(ec.message());
            }

        public:
            std::ostream stream;

            size_t size() {
                return streambuf.size();
            }

            template <class T>
            Response& operator<<(const T& t) {
                stream << t;
                return *this;
            }

            Response& operator<<(std::ostream& (*manip)(std::ostream&)) {
                stream << manip;
                return *this;
            }

            Response& operator<<(Response& (*manip)(Response&)) {
                return manip(*this);
            }
        };

        static Response& flush(Response& r) {
            r.flush();
            return r;
        }

        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_multimap<std::string, std::string> header;

            std::smatch path_match;

            std::string remote_endpoint_address;
            unsigned short remote_endpoint_port;

        private:
            Request(): content(&streambuf) {}

            boost::asio::streambuf streambuf;

            void read_remote_endpoint_data(socket_type& socket) {
                try {
                    remote_endpoint_address=socket.lowest_layer().remote_endpoint().address().to_string();
                    remote_endpoint_port=socket.lowest_layer().remote_endpoint().port();
                }
                catch(const std::exception& e) {}
            }
        };

        std::unordered_map<std::string, std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > >  resource;

        std::unordered_map<std::string,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > default_resource;

    private:
        std::vector<std::pair<std::string, std::vector<std::pair<std::regex,
            std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)> > > > > opt_resource;

    public:
        void start() {
            //Copy the resources to opt_resource for more efficient request processing
            opt_resource.clear();
            for(auto& res: resource) {
                for(auto& res_method: res.second) {
                    auto it=opt_resource.end();
                    for(auto opt_it=opt_resource.begin();opt_it!=opt_resource.end();opt_it++) {
                        if(res_method.first==opt_it->first) {
                            it=opt_it;
                            break;
                        }
                    }
                    if(it==opt_resource.end()) {
                        opt_resource.emplace_back();
                        it=opt_resource.begin()+(opt_resource.size()-1);
                        it->first=res_method.first;
                    }
                    it->second.emplace_back(std::regex(res.first), res_method.second);
                }
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            threads.clear();
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    io_service.run();
                });
            }

            //Main thread
            io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            io_service.stop();
        }

    protected:
        boost::asio::io_service io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        boost::asio::strand strand;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(io_service, endpoint), strand(io_service),
                num_threads(num_threads), timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            });
            return timer;
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket_strand_wrapped(std::shared_ptr<socket_type> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait(strand.wrap([socket](const boost::system::error_code& ec){
                if(!ec) {
                    boost::system::error_code ec;
                    socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                    socket->lowest_layer().close();
                }
            }));
            return timer;
        }

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());
            request->read_remote_endpoint_data(*socket);

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->streambuf.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    const auto it=request->header.find("Content-Length");
                    if(it!=request->header.end()) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);
                        unsigned long long content_length;
                        try {
                            content_length=stoull(it->second);
                        }
                        catch(const std::exception &e) {
                            return;
                        }
                        boost::asio::async_read(*socket, request->streambuf,
                                boost::asio::transfer_exactly(content_length-num_additional_bytes),
                                [this, socket, request, timer]
                                (const boost::system::error_code& ec, size_t /*bytes_transferred*/) {
                            if(timeout_content>0)
                                timer->cancel();
                            if(!ec)
                                find_resource(socket, request);
                        });
                    }
                    else {
                        find_resource(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::string line;
            getline(stream, line);
            size_t method_end=line.find(' ');
            size_t path_end=line.find(' ', method_end+1);
            if(method_end!=std::string::npos && path_end!=std::string::npos) {
                request->method=line.substr(0, method_end);
                request->path=line.substr(method_end+1, path_end-method_end-1);
                request->http_version=line.substr(path_end+6, line.size()-path_end-7);

                getline(stream, line);
                size_t param_end=line.find(':');
                while(param_end!=std::string::npos) {
                    size_t value_start=param_end+1;
                    if(line[value_start]==' ')
                        value_start++;

                    std::string key=line.substr(0, param_end);
                    request->header.insert(std::make_pair(key, line.substr(value_start, line.size()-value_start-1)));

                    getline(stream, line);
                    param_end=line.find(':');
                }
            }
        }

        void find_resource(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and call write_response
            for(auto& res: opt_resource) {
                if(request->method==res.first) {
                    for(auto& res_path: res.second) {
                        std::smatch sm_res;
                        if(std::regex_match(request->path, sm_res, res_path.first)) {
                            request->path_match=std::move(sm_res);
                            write_response(socket, request, res_path.second);
                            return;
                        }
                    }
                }
            }
            auto it_method=default_resource.find(request->method);
            if(it_method!=default_resource.end()) {
                write_response(socket, request, it_method->second);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request,
                std::function<void(typename ServerBase<socket_type>::Response&, std::shared_ptr<typename ServerBase<socket_type>::Request>)>& resource_function) {
            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_content>0)
                timer=set_timeout_on_socket_strand_wrapped(socket, timeout_content);

            boost::asio::spawn(strand, [this, &resource_function, socket, request, timer](boost::asio::yield_context yield) {
                Response response(io_service, socket, yield);

                try {
                    resource_function(response, request);
                }
                catch(const std::exception& e) {
                    return;
                }

                try {
                    response.flush();
                }
                catch(const std::exception &e) {
                    return;
                }
                if(timeout_content>0)
                    timer->cancel();
                if(stof(request->http_version)>1.05)
                    read_request_and_content(socket);
            });
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {}

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec){
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    boost::asio::ip::tcp::no_delay option(true);
                    socket->set_option(option);

                    read_request_and_content(socket);
                }
            });
        }
    };
}
#endif	/* SERVER_HTTP_HPP */
<|endoftext|>


<commit_before>#include "server_functions.h"
#include <create_server.cpp>

#include <string.h>
#include <rpc.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>

#include <netdb.h>
#include <stdlib.h>

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

char * get_msg(int sock, vector<int>& myToRemove) {
  int status;
  char * errorMsg = "ERROR";

  // receive the buffer length
  int msg_len = 0;
  status = recv(sock, &msg_len, sizeof msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: receive failed" << endl;
    return errorMsg;
  }
  if (status == 0) {
    // client has closed the connection
    myToRemove.push_back(sock);
    return errorMsg;
  }

  // receive the string
  char* msg = new char[msg_len];
  status = recv(sock, msg, msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: receive failed" << endl;
    return errorMsg;
  }
  return msg;
}

void send_result(int sock, vector<int>& myToRemove, string result) {
  int status;

  // send the buffer length
  const char* to_send = result.c_str();
  msg_len = strlen(to_send) + 1;
  status = send(sock, &msg_len, sizeof msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: send failed" << endl;
    return;
  }

  // send the result string
  status = send(sock, to_send, msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: send failed" << endl;
    return;
  }

  delete[] msg;
}

int main(){

	//TODO:
	//MANAGE CLIENT CONNECTION
	//MANAGE SERVER CONNECTION
	//DATABASE
	//ROUND ROBIN

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  char hostname[256];
  gethostname(hostname, 256);

  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);

  getsockname(sock, (struct sockaddr *)&sin, &len);

  stringstream ss;
  ss << ntohs(sin.sin_port);
  string ps = ss.str();
  const char* portString = ps.c_str();

  cout << "SERVER_ADDRESS " << hostname << endl;
  cout << "SERVER_PORT " << ntohs(sin.sin_port) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR

    FD_ZERO(&readfds); //This macro initializes the file descriptor set &readfds to be the empty set.
    FD_SET(sock, &readfds); //This macro adds sock to the file descriptor set &readfds.

    n = sock; //set variable n to be the file descriptor

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
      //This macro adds connection to the file descriptor set &readfds.
      if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;

          if (FD_ISSET(tempConnection, &readfds)) {

            char * msg = get_msg(tempConnection, myToRemove);

              // We need to do stuff here,
			  // msg is the input
			  // string str(msg);
  		 	  // string result = title_case(str);

			send_result(tempConnection, myToRemove, result);

          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin();
          it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<commit_msg>binder networking works<commit_after>#include "server_functions.h"
#include <create_server.cpp>

#include <string.h>
#include <rpc.h>

#include <iostream>
#include <sstream>

#include <netinet/in.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <vector>
#include <algorithm>

#include <netdb.h>
#include <stdlib.h>

using namespace std;

//TODO:
//MANAGE CLIENT CONNECTION
//MANAGE SERVER CONNECTION
//DATABASE
//ROUND ROBIN

string do_stuff(){

}

char * get_msg(int sock, vector<int>& myToRemove) {
  int status;
  char * errorMsg = "ERROR";
  int msg_len = 0;

  status = recv(sock, &msg_len, sizeof msg_len, 0);

  if (status < 0) {
    cerr << "ERROR: receive failed" << endl;
    return errorMsg;
  }

  if (status == 0) {
    myToRemove.push_back(sock);
    return errorMsg;
  }

  char* msg = new char[msg_len];
  status = recv(sock, msg, msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: receive failed" << endl;
    return errorMsg;
  }
  return msg;
}

void send_result(int sock, string result) {
  int status;
  int msg_len;

  const char* to_send = result.c_str();
  msg_len = strlen(to_send) + 1;
  status = send(sock, &msg_len, sizeof msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: send failed" << endl;
    return;
  }

  status = send(sock, to_send, msg_len, 0);
  if (status < 0) {
    cerr << "ERROR: send failed" << endl;
    return;
  }
}

int main(){

  vector<int> myConnections;
  vector<int> myToRemove;

  int status;
  struct addrinfo hints;
  struct addrinfo* servinfo;
  struct addrinfo* p;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;

  status = getaddrinfo(NULL, "0", &hints, &servinfo);

  if (status != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    return 0;
  }

  p = servinfo;
  int sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);

  status = bind(sock, servinfo->ai_addr, servinfo->ai_addrlen);
  status = listen(sock, 5);

  char hostname[256];
  gethostname(hostname, 256);

  struct sockaddr_in sin;
  socklen_t len = sizeof(sin);

  getsockname(sock, (struct sockaddr *)&sin, &len);

  stringstream ss;
  ss << ntohs(sin.sin_port);
  string ps = ss.str();

  cout << "SERVER_ADDRESS " << hostname << endl;
  cout << "SERVER_PORT " << ntohs(sin.sin_port) << endl;

  fd_set readfds;
  int n;
  struct sockaddr_storage their_addr;

  while(true){
    //CONNECTIONS VECTOR
    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);

    n = sock;

    for (vector<int>::iterator it = myConnections.begin();it != myConnections.end(); ++it) {
      int connection = *it;
      FD_SET(connection, &readfds);
      if (connection > n){
        n = connection;
      }
    }

    n = n+1;

    status = select(n, &readfds, NULL, NULL, NULL);

    if (status == -1) {
      cerr << "ERROR: select failed." << endl;
    } else {

      if (FD_ISSET(sock, &readfds)) {
        socklen_t addr_size = sizeof their_addr;
        int new_sock = accept(sock, (struct sockaddr*)&their_addr, &addr_size);

        if (new_sock < 0) {
          cerr << "ERROR: while accepting connection" << endl;
          close(new_sock);
          continue;
        }

        myConnections.push_back(new_sock);

      } else {

        for (vector<int>::iterator it = myConnections.begin(); it != myConnections.end(); ++it) {
          int tempConnection = *it;

          if (FD_ISSET(tempConnection, &readfds)) {
            char * msg = get_msg(tempConnection, myToRemove);
            //string str(msg);
            //string result = title_case(str);
            string result = do_stuff();
            send_result(tempConnection, result);
            delete[] msg;

          }
        }
      }

      for (vector<int>::iterator it = myToRemove.begin(); it != myToRemove.end(); ++it) {
        myConnections.erase(remove(myConnections.begin(), myConnections.end(), *it), myConnections.end());
        close(*it);
      }
      myToRemove.clear();
    }
  }

  freeaddrinfo(servinfo);
}
<|endoftext|>


<commit_before>/** bidding_agent_ex.cc                                 -*- C++ -*-
    Rémi Attab, 22 Feb 2013
    Copyright (c) 2013 Datacratic.  All rights reserved.

    Example of a simple fixed-price bidding agent.

*/

#include "rtbkit/common/bids.h"
#include "rtbkit/core/banker/slave_banker.h"
#include "rtbkit/core/agent_configuration/agent_config.h"
#include "rtbkit/plugins/bidding_agent/bidding_agent.h"
#include "soa/service/service_utils.h"

#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include <iostream>
#include <thread>
#include <chrono>
#include <string>     // std::string, std::to_string

using namespace std;
using namespace ML;

namespace RTBKIT {

/******************************************************************************/
/* FIXED PRICE BIDDING AGENT                                                  */
/******************************************************************************/

/** Simple bidding agent whose sole purpose in life is to bid 0.1$ CPM on every
    bid requests it sees. It also has a very simple pacer which ensures that we
    always have at most 1$ to spend every 10 seconds.

 */
struct FixedPriceBiddingAgent :
        public BiddingAgent
{
    FixedPriceBiddingAgent(
            std::shared_ptr<Datacratic::ServiceProxies> services,
            const string& serviceName) :
        BiddingAgent(services, serviceName),
        accountSetup(false)
    {}

    void init(const std::shared_ptr<ApplicationLayer> appLayer)
    {
        // We only want to specify a subset of the callbacks so turn the
        // annoying safety belt off.
        strictMode(false);

        onBidRequest = bind(
                &FixedPriceBiddingAgent::bid, this, _1, _2, _3, _4, _5, _6);

        // This component is used to speak with the master banker and pace the
        // rate at which we spend our budget.
        budgetController.setApplicationLayer(appLayer);
        budgetController.start();

        // Update our pacer every 10 seconds. Note that since this interacts
        // with the budgetController which is only synced up with the router
        // every few seconds, the wait period shouldn't be set too low.
        addPeriodic("FixedPriceBiddingAgent::pace", 10.0,
                [&] (uint64_t) { this->pace(); });

        BiddingAgent::init();

    }

    void start()
    {
        BiddingAgent::start();

        // Build our configuration and tell the world about it.
        setConfig();

    }

    void shutdown()
    {
        BiddingAgent::shutdown();

        budgetController.shutdown();
    }

    /** Sets up an agent configuration for our example. */
    void setConfig()
    {
        config = AgentConfig();

        // Accounts are used to control the allocation of spending budgets for
        // an agent. The whole mechanism is fully generic and can be setup in
        // whatever you feel it bests suits you.
        config.account = {"hello", "world"};

        // Specify the properties of the creatives we are trying to show.
        config.creatives.push_back(Creative::sampleLB);
        config.creatives.push_back(Creative::sampleWS);
        config.creatives.push_back(Creative::sampleBB);
        config.creatives.push_back(Creative::sampleAA);
        config.creatives.push_back(Creative::sampleCC);
        config.creatives.push_back(Creative::sampleDD);
        config.creatives.push_back(Creative::sampleRR);

    //    config.providerConfig["appodeal"]["seat"] = 12;
        config.providerConfig["appodeal"]["iurl"] = "http://www.gnu.org";

                for(auto & c: config.creatives){
                    c.providerConfig["appodeal"]["adm"] = "http://52.208.150.10:17340";
                    c.providerConfig["appodeal"]["nurl"] = "http://adserver.com/123456?winprice=${AUCTION_PRICE}&auction_id=%{bidrequest.id}&adspot_id=%{creative.id}";
                  }

        // Indicate to the router that we want our bid requests to be augmented
        // with our frequency cap augmentor example.
        {
            AugmentationConfig augConfig;

            // Name of the requested augmentor.
            augConfig.name = "frequency-cap-ex";

            // If the augmentor was unable to augment our bid request then it
            // should be filtered before it makes it to our agent.
            augConfig.required = true;

            // Config parameter sent used by the augmentor to determine which
            // tag to set.
            augConfig.config = Json::Value(112);

            // Instruct to router to filter out all bid requests who have not
            // been tagged by our frequency cap augmentor.
            augConfig.filters.include.push_back("pass-frequency-cap-ex");

            config.addAugmentation(augConfig);
        }

        // Configures the agent to only receive 10% of the bid request traffic
        // that matches its filters.
        config.bidProbability = 0.7;

        // Tell the world about our config. We can change the configuration of
        // an agent at any time by calling this function.
        doConfig(config);

    }

    /** Simple fixed price bidding strategy. Note that the router is in charge
        of making sure we stay within budget and don't go bankrupt.
    */
    void bid(
            double timestamp,
            const Id & id,
            std::shared_ptr<RTBKIT::BidRequest> br,
            Bids bids,
            double timeLeftMs,
            const Json::Value & augmentations)
    {

        for (Bid& bid : bids) {

            // In our example, all our creatives are of the different sizes so
            // there should only ever be one biddable creative. Note that that
            // the router won't ask for bids on imp that don't have any
            // biddable creatives.
            ExcAssertEqual(bid.availableCreatives.size(), 1);

            int availableCreative = bid.availableCreatives.front();

            // We don't really need it here but this is how you can get the
            // AdSpot and Creative object from the indexes.
            (void) br->imp[bid.spotIndex];

            (void) config.creatives[availableCreative];

            // Create a 0.0001$ CPM bid with our available creative.
            // Note that by default, the bid price is set to 0 which indicates
            // that we don't wish to bid on the given spot.
            bid.bid(availableCreative, MicroUSD(100));

        }

        // A value that will be passed back to us when we receive the result of
        // our bid.
        Json::Value metadata = 42;

        // Send our bid back to the agent.
        doBid(id, bids, metadata);

    }

    /** Simple pacing scheme which allocates 1$ to spend every period. */
    void pace()
    {
        // We need to register our account once with the banker service.
        if (!accountSetup) {
            accountSetup = true;
            budgetController.addAccountSync(config.account);
        }

        // Make sure we have 1$ to spend for the next period.
        budgetController.topupTransferSync(config.account, USD(1));
    }

    AgentConfig config;

    bool accountSetup;
    SlaveBudgetController budgetController;
};

} // namepsace RTBKIT

/******************************************************************************/
/* MAIN                                                                       */
/******************************************************************************/

int main(int argc, char** argv)
{
    using namespace boost::program_options;

    Datacratic::ServiceProxyArguments args;
    RTBKIT::SlaveBankerArguments bankerArgs;

    options_description options = args.makeProgramOptions();
    options.add_options()
        ("help,h", "Print this message");
    options.add(bankerArgs.makeProgramOptions());

    variables_map vm;
    store(command_line_parser(argc, argv).options(options).run(), vm);
    notify(vm);

    if (vm.count("help")) {
        cerr << options << endl;
        return 1;
    }

    auto serviceProxies = args.makeServiceProxies();
    RTBKIT::FixedPriceBiddingAgent agent(serviceProxies, "fixed-price-agent-ex");
    agent.init(bankerArgs.makeApplicationLayer(serviceProxies));
    agent.start();

    while (true) this_thread::sleep_for(chrono::seconds(10));

    // Won't ever reach this point but this is how you shutdown an agent.
    agent.shutdown();

    return 0;
}

<commit_msg>test3<commit_after>/** bidding_agent_ex.cc                                 -*- C++ -*-
    Rémi Attab, 22 Feb 2013
    Copyright (c) 2013 Datacratic.  All rights reserved.

    Example of a simple fixed-price bidding agent.

*/

#include "rtbkit/common/bids.h"
#include "rtbkit/core/banker/slave_banker.h"
#include "rtbkit/core/agent_configuration/agent_config.h"
#include "rtbkit/plugins/bidding_agent/bidding_agent.h"
#include "soa/service/service_utils.h"

#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include <iostream>
#include <thread>
#include <chrono>
#include <string>     // std::string, std::to_string

using namespace std;
using namespace ML;

namespace RTBKIT {

/******************************************************************************/
/* FIXED PRICE BIDDING AGENT                                                  */
/******************************************************************************/

/** Simple bidding agent whose sole purpose in life is to bid 0.1$ CPM on every
    bid requests it sees. It also has a very simple pacer which ensures that we
    always have at most 1$ to spend every 10 seconds.

 */
struct FixedPriceBiddingAgent :
        public BiddingAgent
{
    FixedPriceBiddingAgent(
            std::shared_ptr<Datacratic::ServiceProxies> services,
            const string& serviceName) :
        BiddingAgent(services, serviceName),
        accountSetup(false)
    {}

    void init(const std::shared_ptr<ApplicationLayer> appLayer)
    {
        // We only want to specify a subset of the callbacks so turn the
        // annoying safety belt off.
        strictMode(false);

        onBidRequest = bind(
                &FixedPriceBiddingAgent::bid, this, _1, _2, _3, _4, _5, _6);

        // This component is used to speak with the master banker and pace the
        // rate at which we spend our budget.
        budgetController.setApplicationLayer(appLayer);
        budgetController.start();

        // Update our pacer every 10 seconds. Note that since this interacts
        // with the budgetController which is only synced up with the router
        // every few seconds, the wait period shouldn't be set too low.
        addPeriodic("FixedPriceBiddingAgent::pace", 10.0,
                [&] (uint64_t) { this->pace(); });

        BiddingAgent::init();

    }

    void start()
    {
        BiddingAgent::start();

        // Build our configuration and tell the world about it.
        setConfig();

    }

    void shutdown()
    {
        BiddingAgent::shutdown();

        budgetController.shutdown();
    }

    /** Sets up an agent configuration for our example. */
    void setConfig()
    {
        config = AgentConfig();

        // Accounts are used to control the allocation of spending budgets for
        // an agent. The whole mechanism is fully generic and can be setup in
        // whatever you feel it bests suits you.
        config.account = {"hello", "world"};

        // Specify the properties of the creatives we are trying to show.
        config.creatives.push_back(Creative::sampleLB);
        config.creatives.push_back(Creative::sampleWS);
        config.creatives.push_back(Creative::sampleBB);
        config.creatives.push_back(Creative::sampleAA);
        config.creatives.push_back(Creative::sampleCC);
        config.creatives.push_back(Creative::sampleDD);
        config.creatives.push_back(Creative::sampleRR);

    //    config.providerConfig["appodeal"]["seat"] = 12;
        config.providerConfig["appodeal"]["iurl"] = "http://www.gnu.org";

                for(auto & c: config.creatives){
                    c.providerConfig["appodeal"]["adm"] = "some";
                    c.providerConfig["appodeal"]["nurl"] = "http://adserver.com/123456?winprice=${AUCTION_PRICE}&auction_id=%{bidrequest.id}&adspot_id=%{creative.id}";
                  }

        // Indicate to the router that we want our bid requests to be augmented
        // with our frequency cap augmentor example.
        {
            AugmentationConfig augConfig;

            // Name of the requested augmentor.
            augConfig.name = "frequency-cap-ex";

            // If the augmentor was unable to augment our bid request then it
            // should be filtered before it makes it to our agent.
            augConfig.required = true;

            // Config parameter sent used by the augmentor to determine which
            // tag to set.
            augConfig.config = Json::Value(112);

            // Instruct to router to filter out all bid requests who have not
            // been tagged by our frequency cap augmentor.
            augConfig.filters.include.push_back("pass-frequency-cap-ex");

            config.addAugmentation(augConfig);
        }

        // Configures the agent to only receive 10% of the bid request traffic
        // that matches its filters.
        config.bidProbability = 0.7;

        // Tell the world about our config. We can change the configuration of
        // an agent at any time by calling this function.
        doConfig(config);

    }

    /** Simple fixed price bidding strategy. Note that the router is in charge
        of making sure we stay within budget and don't go bankrupt.
    */
    void bid(
            double timestamp,
            const Id & id,
            std::shared_ptr<RTBKIT::BidRequest> br,
            Bids bids,
            double timeLeftMs,
            const Json::Value & augmentations)
    {

        for (Bid& bid : bids) {

            // In our example, all our creatives are of the different sizes so
            // there should only ever be one biddable creative. Note that that
            // the router won't ask for bids on imp that don't have any
            // biddable creatives.
            ExcAssertEqual(bid.availableCreatives.size(), 1);

            int availableCreative = bid.availableCreatives.front();

            // We don't really need it here but this is how you can get the
            // AdSpot and Creative object from the indexes.
            (void) br->imp[bid.spotIndex];

            (void) config.creatives[availableCreative];

            // Create a 0.0001$ CPM bid with our available creative.
            // Note that by default, the bid price is set to 0 which indicates
            // that we don't wish to bid on the given spot.
            bid.bid(availableCreative, MicroUSD(100));

        }

        // A value that will be passed back to us when we receive the result of
        // our bid.
        Json::Value metadata = 42;

        // Send our bid back to the agent.
        doBid(id, bids, metadata);

    }

    /** Simple pacing scheme which allocates 1$ to spend every period. */
    void pace()
    {
        // We need to register our account once with the banker service.
        if (!accountSetup) {
            accountSetup = true;
            budgetController.addAccountSync(config.account);
        }

        // Make sure we have 1$ to spend for the next period.
        budgetController.topupTransferSync(config.account, USD(1));
    }

    AgentConfig config;

    bool accountSetup;
    SlaveBudgetController budgetController;
};

} // namepsace RTBKIT

/******************************************************************************/
/* MAIN                                                                       */
/******************************************************************************/

int main(int argc, char** argv)
{
    using namespace boost::program_options;

    Datacratic::ServiceProxyArguments args;
    RTBKIT::SlaveBankerArguments bankerArgs;

    options_description options = args.makeProgramOptions();
    options.add_options()
        ("help,h", "Print this message");
    options.add(bankerArgs.makeProgramOptions());

    variables_map vm;
    store(command_line_parser(argc, argv).options(options).run(), vm);
    notify(vm);

    if (vm.count("help")) {
        cerr << options << endl;
        return 1;
    }

    auto serviceProxies = args.makeServiceProxies();
    RTBKIT::FixedPriceBiddingAgent agent(serviceProxies, "fixed-price-agent-ex");
    agent.init(bankerArgs.makeApplicationLayer(serviceProxies));
    agent.start();

    while (true) this_thread::sleep_for(chrono::seconds(10));

    // Won't ever reach this point but this is how you shutdown an agent.
    agent.shutdown();

    return 0;
}

<|endoftext|>


<commit_before>#include "Geometry.h"

#include "VertexAttrib.h"

Geometry::Geometry()
{
  glGenVertexArrays(1, &glVertexArray);
  glBindVertexArray(glVertexArray);

  glGenBuffers(1, &glIndiceBuffer);
  glGenBuffers(1, &glPositionBuffer);

  glBindVertexArray(0);
}

Geometry::Ptr createGeometryFromFile(std::string fileName)
{
  Geometry::Ptr geometry = std::make_shared<Geometry>();
  std::ifstream file(fileName, std::ifstream::binary);

  char *intBuffer = new char[sizeof(int)];
  char floatBuffer[sizeof(float)];

  file.read(intBuffer, sizeof(int));
  int numIndicies = *(int *)intBuffer;

  geometry->indices.reserve(numIndicies);
  for (int i=0; i < numIndicies; ++i) {
    file.read(intBuffer, sizeof(int));
    int ind = *(int *)intBuffer;
    geometry->indices.push_back(ind);
  }

  file.read(intBuffer, sizeof(int));
  int numVerts = *(int *)intBuffer;

  geometry->positions.reserve(numVerts * 3);
  geometry->normals.reserve(numVerts * 3);
  for (int i=0; i < numVerts; ++i) {
    file.read(floatBuffer, sizeof(float));
    float posX = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float posY = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float posZ = *(float *)floatBuffer;

    geometry->positions.push_back(posX);
    geometry->positions.push_back(posY);
    geometry->positions.push_back(posZ);
  }

  for (int i=0; i < numVerts; ++i) {
    file.read(floatBuffer, sizeof(float));
    float normX = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float normY = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float normZ = *(float *)floatBuffer;

    geometry->normals.push_back(normX);
    geometry->normals.push_back(normY);
    geometry->normals.push_back(normZ);
  }
  return geometry;
}

void bindFloatBuffer(int index, GLuint glBuffer, const std::vector<float> data)
{
  glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
  glBufferData(GL_ARRAY_BUFFER, sizeof(float) * data.size(), data.data(), GL_STATIC_DRAW);

  glEnableVertexAttribArray(VertexAttrib::iPosition);
  GLenum vertexSize = 3;
  bool isNormalized = GL_FALSE;
  GLsizei stride = 0;
  GLvoid * pointer = 0;
  glVertexAttribPointer(index, vertexSize, GL_FLOAT, isNormalized, stride, pointer);
}

void Geometry::bindGlBuffers()
{
  glBindVertexArray(glVertexArray);

  glBindBuffer(GL_ARRAY_BUFFER, glIndiceBuffer);
  size_t indicesSize = sizeof(indices[0]) * indices.size();
  glBufferData(GL_ARRAY_BUFFER, indicesSize, indices.data(), GL_STATIC_DRAW);

  bindFloatBuffer(VertexAttrib::iPosition, glPositionBuffer, positions);
  bindFloatBuffer(VertexAttrib::iNormal, glNormalBuffer, normals);

  glBindVertexArray(0);
}

void drawGeometry(Geometry::Ptr geometry)
{
  glBindVertexArray(geometry->glVertexArray);
  glDrawElements(GL_TRIANGLES, geometry->indices.size(), GL_UNSIGNED_INT, geometry->indices.data());
  glBindVertexArray(0);
}
<commit_msg>removed unneeded code<commit_after>#include "Geometry.h"

#include "VertexAttrib.h"

Geometry::Geometry()
{
  glGenVertexArrays(1, &glVertexArray);
  glBindVertexArray(glVertexArray);

  glGenBuffers(1, &glIndiceBuffer);
  glGenBuffers(1, &glPositionBuffer);

  glBindVertexArray(0);
}

Geometry::Ptr createGeometryFromFile(std::string fileName)
{
  Geometry::Ptr geometry = std::make_shared<Geometry>();
  std::ifstream file(fileName, std::ifstream::binary);

  char *intBuffer = new char[sizeof(int)];
  char floatBuffer[sizeof(float)];

  file.read(intBuffer, sizeof(int));
  int numIndicies = *(int *)intBuffer;

  geometry->indices.reserve(numIndicies);
  for (int i=0; i < numIndicies; ++i) {
    file.read(intBuffer, sizeof(int));
    int ind = *(int *)intBuffer;
    geometry->indices.push_back(ind);
  }

  file.read(intBuffer, sizeof(int));
  int numVerts = *(int *)intBuffer;

  geometry->positions.reserve(numVerts * 3);
  geometry->normals.reserve(numVerts * 3);
  for (int i=0; i < numVerts; ++i) {
    file.read(floatBuffer, sizeof(float));
    float posX = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float posY = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float posZ = *(float *)floatBuffer;

    geometry->positions.push_back(posX);
    geometry->positions.push_back(posY);
    geometry->positions.push_back(posZ);
  }

  for (int i=0; i < numVerts; ++i) {
    file.read(floatBuffer, sizeof(float));
    float normX = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float normY = *(float *)floatBuffer;
    file.read(floatBuffer, sizeof(float));
    float normZ = *(float *)floatBuffer;

    geometry->normals.push_back(normX);
    geometry->normals.push_back(normY);
    geometry->normals.push_back(normZ);
  }
  return geometry;
}

void bindFloatBuffer(int index, GLuint glBuffer, const std::vector<float> data)
{
  glBindBuffer(GL_ARRAY_BUFFER, glBuffer);
  glBufferData(GL_ARRAY_BUFFER, sizeof(float) * data.size(), data.data(), GL_STATIC_DRAW);

  glEnableVertexAttribArray(VertexAttrib::iPosition);
  GLenum vertexSize = 3;
  bool isNormalized = GL_FALSE;
  GLsizei stride = 0;
  GLvoid * pointer = 0;
  glVertexAttribPointer(index, vertexSize, GL_FLOAT, isNormalized, stride, pointer);
}

void Geometry::bindGlBuffers()
{
  glBindVertexArray(glVertexArray);

  bindFloatBuffer(VertexAttrib::iPosition, glPositionBuffer, positions);
  bindFloatBuffer(VertexAttrib::iNormal, glNormalBuffer, normals);

  glBindVertexArray(0);
}

void drawGeometry(Geometry::Ptr geometry)
{
  glBindVertexArray(geometry->glVertexArray);
  glDrawElements(GL_TRIANGLES, geometry->indices.size(), GL_UNSIGNED_INT, geometry->indices.data());
  glBindVertexArray(0);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef WITHOUT_HSA_BACKEND

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#include "os/os.hpp"
#include "rocdevice.hpp"
#include "rocprogram.hpp"
#if defined(WITH_LIGHTNING_COMPILER)
#include "opencl1.2-c.amdgcn.inc"
#include "opencl2.0-c.amdgcn.inc"
#else // !defined(WITH_LIGHTNING_COMPILER)
#include "roccompilerlib.hpp"
#endif // !defined(WITH_LIGHTNING_COMPILER)
#include "utils/options.hpp"
#include <cstdio>

#if defined(ATI_OS_LINUX)
#include <dlfcn.h>
#include <libgen.h>
#endif // defined(ATI_OS_LINUX)

#if defined(WITH_LIGHTNING_COMPILER)
static std::string llvmBin_(amd::Os::getEnvironment("LLVM_BIN"));
#endif // defined(WITH_LIGHTNING_COMPILER)

//CLC_IN_PROCESS_CHANGE
extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typeInfo = NULL);

namespace roc {

/* Temporary log function for the compiler library */
static void
logFunction(const char* msg, size_t size)
{
    std::cout<< "Compiler Log: " << msg << std::endl;
}

static int programsCount = 0;

#if defined(WITH_LIGHTNING_COMPILER)
bool
HSAILProgram::compileImpl_LC(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
    using namespace amd::opencl_driver;
    std::auto_ptr<Compiler> C(newCompilerInstance());
    std::vector<Data*> inputs;

    Data* input = C->NewBufferReference(DT_CL,
        sourceCode.c_str(), sourceCode.length());
    if (input == NULL) {
        buildLog_ += "Error while creating data from source code";
        return false;
    }

    inputs.push_back(input);

    Buffer* output = C->NewBuffer(DT_LLVM_BC);
    if (output == NULL) {
        buildLog_ += "Error while creating buffer for the LLVM bitcode";
        return false;
    }

    //Set the options for the compiler
    std::ostringstream ostrstr;
    std::copy(options->clangOptions.begin(), options->clangOptions.end(),
        std::ostream_iterator<std::string>(ostrstr, " "));

    ostrstr << " -m" << sizeof(void*) * 8;
    std::string driverOptions(ostrstr.str());

    const char* xLang = options->oVariables->XLang;
    if (xLang != NULL && strcmp(xLang, "cl")) {
        buildLog_ += "Unsupported OpenCL language.\n";
    }

    //FIXME_Nikolay: the program manager should be setting the language
    //driverOptions.append(" -x cl");

    driverOptions.append(" -cl-std=").append(options->oVariables->CLStd);

    // Set the -O#
    std::ostringstream optLevel;
    optLevel << " -O" << options->oVariables->OptLevel;
    driverOptions.append(optLevel.str());

    // Set the machine target
    driverOptions.append(" -mcpu=");
    driverOptions.append(dev().deviceInfo().machineTarget_);

    driverOptions.append(options->llvmOptions);

    driverOptions.append(preprocessorOptions(options));

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();

        Data* inc = C->NewFileReference(DT_CL_HEADER, headerFileNames[i]);
        if (inc == NULL) {
            buildLog_ += "Error while creating data from headers";
            return false;
        }
        inputs.push_back(inc);
    }

    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        driverOptions.append(" -I");
        driverOptions.append(tempFolder);
    }

    if (options->isDumpFlagSet(amd::option::DUMP_CL)) {
        std::ofstream f(options->getDumpFileName(".cl").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f << "/* Compiler options:\n" \
                   "-c -emit-llvm -target amdgcn-amd-amdhsa-opencl -x cl "
                   << driverOptions << " -include opencl-c.h "
                << "\n*/\n\n" << sourceCode;
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the OpenCL source failed.\n";
        }
    }

    //FIXME_lmoriche: has the CL option been validated?
    uint clcStd = (options->oVariables->CLStd[2] - '0') * 100
        + (options->oVariables->CLStd[4] - '0') * 10;

    std::pair<const void*, size_t> hdr;
    switch(clcStd) {
    case 120:
        hdr = std::make_pair(opencl1_2_c_amdgcn, opencl1_2_c_amdgcn_size);
        break;
    case 200:
        hdr = std::make_pair(opencl2_0_c_amdgcn, opencl2_0_c_amdgcn_size);
        break;
    default:
        buildLog_ += "Unsupported requested OpenCL C version (-cl-std).\n";
        return false;
    }

    File* pch = C->NewTempFile(DT_CL_HEADER);
    if (pch == NULL || !pch->WriteData((const char*) hdr.first, hdr.second)) {
        buildLog_ += "Error while opening the opencl-c header ";
        return false;
    }

    driverOptions.append(" -include-pch " + pch->Name());
    driverOptions.append(" -Xclang -fno-validate-pch");

    // Tokenize the options string into a vector of strings
    std::istringstream istrstr(driverOptions);
    std::istream_iterator<std::string> sit(istrstr), end;
    std::vector<std::string> params(sit, end);

    // Compile source to IR
    bool ret = C->CompileToLLVMBitcode(inputs, output, params);
    buildLog_ += C->Output();
    if (!ret) {
        buildLog_ += "Error: Failed to compile opencl source (from CL to LLVM IR).\n";
        return false;
    }

    llvmBinary_.assign(output->Buf().data(), output->Size());
    elfSectionType_ = amd::OclElf::LLVMIR;

    if (options->isDumpFlagSet(amd::option::DUMP_BC_ORIGINAL)) {
        std::ofstream f(options->getDumpFileName("_original.bc").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f.write(llvmBinary_.data(), llvmBinary_.size());
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the compiled IR failed.\n";
        }
    }

    if (clBinary()->saveSOURCE()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::SOURCE, sourceCode.data(), sourceCode.size());
    }
    if (clBinary()->saveLLVMIR()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
        // store the original compile options
        clBinary()->storeCompileOptions(compileOptions_);
    }
    return true;
}
#endif // defined(WITH_LIGHTNING_COMPILER)

bool
HSAILProgram::compileImpl(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
#if defined(WITH_LIGHTNING_COMPILER)
    return compileImpl_LC(sourceCode, headers, headerIncludeNames, options);
#else // !defined(WITH_LIGHTNING_COMPILER)
    acl_error errorCode;
    aclTargetInfo target;

    target = g_complibApi._aclGetTargetInfo(LP64_SWITCH("hsail","hsail64"),
        dev().deviceInfo().complibTarget_, &errorCode);

    //end if asic info is ready
    // We dump the source code for each program (param: headers)
    // into their filenames (headerIncludeNames) into the TEMP
    // folder specific to the OS and add the include path while
    // compiling

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();
    }

    //Create Binary
    binaryElf_ = g_complibApi._aclBinaryInit(sizeof(aclBinary),
        &target,
        &binOpts_,
        &errorCode);

    if( errorCode!=ACL_SUCCESS ) {
        buildLog_ += "Error while compiling opencl source:\
                     aclBinary init failure \n";
        LogWarning("aclBinaryInit failed");
        return false;
    }

    //Insert opencl into binary
    errorCode = g_complibApi._aclInsertSection(device().compiler(),
        binaryElf_,
        sourceCode.c_str(),
        strlen(sourceCode.c_str()),
        aclSOURCE);

    if ( errorCode != ACL_SUCCESS )    {
        buildLog_ += "Error while converting to BRIG: \
                     Inserting openCl Source \n";
    }

    //Set the options for the compiler
    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        this->compileOptions_.append(" -I");
        this->compileOptions_.append(tempFolder);
    }

    //Add only for CL2.0 and later
    if (options->oVariables->CLStd[2] >= '2') {
        std::stringstream opts;
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        compileOptions_.append(opts.str());
    }

    //Compile source to IR
    this->compileOptions_.append(preprocessorOptions(options));
    this->compileOptions_.append(codegenOptions(options));

    errorCode = g_complibApi._aclCompile(device().compiler(),
        binaryElf_,
        //"-Wf,--support_all_extensions",
        this->compileOptions_.c_str(),
        ACL_TYPE_OPENCL,
        ACL_TYPE_LLVMIR_BINARY,
        logFunction);
    buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler());
    if( errorCode!=ACL_SUCCESS ) {
        LogWarning("aclCompile failed");
        buildLog_ += "Error while compiling \
                     opencl source: Compiling CL to IR";
        return false;
    }
    // Save the binary in the interface class
    saveBinaryAndSetType(TYPE_COMPILED);
    return true;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}

#if defined(WITH_LIGHTNING_COMPILER)
#if defined(ATI_OS_LINUX)
static pthread_once_t once = PTHREAD_ONCE_INIT;

static void
checkLLVM_BIN()
{
    if (llvmBin_.empty()) {
        Dl_info info;
        if (dladdr((const void*)&amd::Device::init, &info)) {
            llvmBin_ = dirname(strdup(info.dli_fname));
            size_t pos = llvmBin_.rfind("lib");
            if (pos != std::string::npos) {
                llvmBin_.replace(pos, 3, "bin");
            }
        }
    }
#if defined(DEBUG)
    std::string clangExe(llvmBin_ + "/clang");
    struct stat buf;
    if (stat(clangExe.c_str(), &buf)) {
        std::string msg("Could not find the Clang binary in " + llvmBin_);
        LogWarning(msg.c_str());
    }
#endif // defined(DEBUG)
}
#endif // defined(ATI_OS_LINUX)

std::auto_ptr<amd::opencl_driver::Compiler>
HSAILProgram::newCompilerInstance()
{
#if defined(ATI_OS_LINUX)
    pthread_once(&once, checkLLVM_BIN);
#endif // defined(ATI_OS_LINUX)
    return std::auto_ptr<amd::opencl_driver::Compiler>(
        amd::opencl_driver::CompilerFactory().CreateAMDGPUCompiler(llvmBin_));
}
#endif // defined(WITH_LIGHTNING_COMPILER)

} // namespace roc
#endif // WITHOUT_GPU_BACKEND
<commit_msg>P4 to Git Change 1324274 by lmoriche@lmoriche_opencl_dev on 2016/10/08 15:25:08<commit_after>//
// Copyright (c) 2008 Advanced Micro Devices, Inc. All rights reserved.
//
#ifndef WITHOUT_HSA_BACKEND

#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#include "os/os.hpp"
#include "rocdevice.hpp"
#include "rocprogram.hpp"
#if defined(WITH_LIGHTNING_COMPILER)
#include "opencl1.2-c.amdgcn.inc"
#include "opencl2.0-c.amdgcn.inc"
#else // !defined(WITH_LIGHTNING_COMPILER)
#include "roccompilerlib.hpp"
#endif // !defined(WITH_LIGHTNING_COMPILER)
#include "utils/options.hpp"
#include <cstdio>

#if defined(ATI_OS_LINUX)
#include <dlfcn.h>
#include <libgen.h>
#endif // defined(ATI_OS_LINUX)

#if defined(WITH_LIGHTNING_COMPILER)
static std::string llvmBin_(amd::Os::getEnvironment("LLVM_BIN"));
#endif // defined(WITH_LIGHTNING_COMPILER)

//CLC_IN_PROCESS_CHANGE
extern int openclFrontEnd(const char* cmdline, std::string*, std::string* typeInfo = NULL);

namespace roc {

/* Temporary log function for the compiler library */
static void
logFunction(const char* msg, size_t size)
{
    std::cout<< "Compiler Log: " << msg << std::endl;
}

static int programsCount = 0;

#if defined(WITH_LIGHTNING_COMPILER)
bool
HSAILProgram::compileImpl_LC(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
    using namespace amd::opencl_driver;
    std::auto_ptr<Compiler> C(newCompilerInstance());
    std::vector<Data*> inputs;

    Data* input = C->NewBufferReference(DT_CL,
        sourceCode.c_str(), sourceCode.length());
    if (input == NULL) {
        buildLog_ += "Error while creating data from source code";
        return false;
    }

    inputs.push_back(input);

    Buffer* output = C->NewBuffer(DT_LLVM_BC);
    if (output == NULL) {
        buildLog_ += "Error while creating buffer for the LLVM bitcode";
        return false;
    }

    //Set the options for the compiler
    std::ostringstream ostrstr;
    std::copy(options->clangOptions.begin(), options->clangOptions.end(),
        std::ostream_iterator<std::string>(ostrstr, " "));

    ostrstr << " -m" << sizeof(void*) * 8;
    std::string driverOptions(ostrstr.str());

    const char* xLang = options->oVariables->XLang;
    if (xLang != NULL && strcmp(xLang, "cl")) {
        buildLog_ += "Unsupported OpenCL language.\n";
    }

    //FIXME_Nikolay: the program manager should be setting the language
    //driverOptions.append(" -x cl");

    driverOptions.append(" -cl-std=").append(options->oVariables->CLStd);

    // Set the -O#
    std::ostringstream optLevel;
    optLevel << " -O" << options->oVariables->OptLevel;
    driverOptions.append(optLevel.str());

    // Set the machine target
    driverOptions.append(" -mcpu=");
    driverOptions.append(dev().deviceInfo().machineTarget_);

    driverOptions.append(options->llvmOptions);

    driverOptions.append(preprocessorOptions(options));

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();

        Data* inc = C->NewFileReference(DT_CL_HEADER, headerFileNames[i]);
        if (inc == NULL) {
            buildLog_ += "Error while creating data from headers";
            return false;
        }
        inputs.push_back(inc);
    }

    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        driverOptions.append(" -I");
        driverOptions.append(tempFolder);
    }

    if (options->isDumpFlagSet(amd::option::DUMP_CL)) {
        std::ofstream f(options->getDumpFileName(".cl").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f << "/* Compiler options:\n" \
                   "-c -emit-llvm -target amdgcn-amd-amdhsa-opencl -x cl "
                   << driverOptions << " -include opencl-c.h "
                << "\n*/\n\n" << sourceCode;
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the OpenCL source failed.\n";
        }
    }

    //FIXME_lmoriche: has the CL option been validated?
    uint clcStd = (options->oVariables->CLStd[2] - '0') * 100
        + (options->oVariables->CLStd[4] - '0') * 10;

    std::pair<const void*, size_t> hdr;
    switch(clcStd) {
    case 100: case 110: case 120:
        hdr = std::make_pair(opencl1_2_c_amdgcn, opencl1_2_c_amdgcn_size);
        break;
    case 200:
        hdr = std::make_pair(opencl2_0_c_amdgcn, opencl2_0_c_amdgcn_size);
        break;
    default:
        buildLog_ += "Unsupported requested OpenCL C version (-cl-std).\n";
        return false;
    }

    File* pch = C->NewTempFile(DT_CL_HEADER);
    if (pch == NULL || !pch->WriteData((const char*) hdr.first, hdr.second)) {
        buildLog_ += "Error while opening the opencl-c header ";
        return false;
    }

    driverOptions.append(" -include-pch " + pch->Name());
    driverOptions.append(" -Xclang -fno-validate-pch");

    // Tokenize the options string into a vector of strings
    std::istringstream istrstr(driverOptions);
    std::istream_iterator<std::string> sit(istrstr), end;
    std::vector<std::string> params(sit, end);

    // Compile source to IR
    bool ret = C->CompileToLLVMBitcode(inputs, output, params);
    buildLog_ += C->Output();
    if (!ret) {
        buildLog_ += "Error: Failed to compile opencl source (from CL to LLVM IR).\n";
        return false;
    }

    llvmBinary_.assign(output->Buf().data(), output->Size());
    elfSectionType_ = amd::OclElf::LLVMIR;

    if (options->isDumpFlagSet(amd::option::DUMP_BC_ORIGINAL)) {
        std::ofstream f(options->getDumpFileName("_original.bc").c_str(), std::ios::trunc);
        if(f.is_open()) {
            f.write(llvmBinary_.data(), llvmBinary_.size());
        } else {
            buildLog_ +=
                "Warning: opening the file to dump the compiled IR failed.\n";
        }
    }

    if (clBinary()->saveSOURCE()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::SOURCE, sourceCode.data(), sourceCode.size());
    }
    if (clBinary()->saveLLVMIR()) {
        clBinary()->elfOut()->addSection(
            amd::OclElf::LLVMIR, llvmBinary_.data(), llvmBinary_.size(), false);
        // store the original compile options
        clBinary()->storeCompileOptions(compileOptions_);
    }
    return true;
}
#endif // defined(WITH_LIGHTNING_COMPILER)

bool
HSAILProgram::compileImpl(
    const std::string& sourceCode,
    const std::vector<const std::string*>& headers,
    const char** headerIncludeNames,
    amd::option::Options* options)
{
#if defined(WITH_LIGHTNING_COMPILER)
    return compileImpl_LC(sourceCode, headers, headerIncludeNames, options);
#else // !defined(WITH_LIGHTNING_COMPILER)
    acl_error errorCode;
    aclTargetInfo target;

    target = g_complibApi._aclGetTargetInfo(LP64_SWITCH("hsail","hsail64"),
        dev().deviceInfo().complibTarget_, &errorCode);

    //end if asic info is ready
    // We dump the source code for each program (param: headers)
    // into their filenames (headerIncludeNames) into the TEMP
    // folder specific to the OS and add the include path while
    // compiling

    //Find the temp folder for the OS
    std::string tempFolder = amd::Os::getEnvironment("TEMP");
    if (tempFolder.empty()) {
        tempFolder = amd::Os::getEnvironment("TMP");
        if (tempFolder.empty()) {
            tempFolder = WINDOWS_SWITCH(".","/tmp");;
        }
    }
    //Iterate through each source code and dump it into tmp
    std::fstream f;
    std::vector<std::string> headerFileNames(headers.size());
    std::vector<std::string> newDirs;
    for (size_t i = 0; i < headers.size(); ++i) {
        std::string headerPath = tempFolder;
        std::string headerIncludeName(headerIncludeNames[i]);
        // replace / in path with current os's file separator
        if ( amd::Os::fileSeparator() != '/') {
            for (std::string::iterator it = headerIncludeName.begin(),
                end = headerIncludeName.end();
                it != end;
                ++it) {
                if (*it == '/') *it = amd::Os::fileSeparator();
            }
        }
        size_t pos = headerIncludeName.rfind(amd::Os::fileSeparator());
        if (pos != std::string::npos) {
            headerPath += amd::Os::fileSeparator();
            headerPath += headerIncludeName.substr(0, pos);
            headerIncludeName = headerIncludeName.substr(pos+1);
        }
        if (!amd::Os::pathExists(headerPath)) {
            bool ret = amd::Os::createPath(headerPath);
            assert(ret && "failed creating path!");
            newDirs.push_back(headerPath);
        }
        std::string headerFullName
        = headerPath + amd::Os::fileSeparator() + headerIncludeName;
        headerFileNames[i] = headerFullName;
        f.open(headerFullName.c_str(), std::fstream::out);
        //Should we allow asserts
        assert(!f.fail() && "failed creating header file!");
        f.write(headers[i]->c_str(), headers[i]->length());
        f.close();
    }

    //Create Binary
    binaryElf_ = g_complibApi._aclBinaryInit(sizeof(aclBinary),
        &target,
        &binOpts_,
        &errorCode);

    if( errorCode!=ACL_SUCCESS ) {
        buildLog_ += "Error while compiling opencl source:\
                     aclBinary init failure \n";
        LogWarning("aclBinaryInit failed");
        return false;
    }

    //Insert opencl into binary
    errorCode = g_complibApi._aclInsertSection(device().compiler(),
        binaryElf_,
        sourceCode.c_str(),
        strlen(sourceCode.c_str()),
        aclSOURCE);

    if ( errorCode != ACL_SUCCESS )    {
        buildLog_ += "Error while converting to BRIG: \
                     Inserting openCl Source \n";
    }

    //Set the options for the compiler
    //Set the include path for the temp folder that contains the includes
    if(!headers.empty()) {
        this->compileOptions_.append(" -I");
        this->compileOptions_.append(tempFolder);
    }

    //Add only for CL2.0 and later
    if (options->oVariables->CLStd[2] >= '2') {
        std::stringstream opts;
        opts << " -D" << "CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE="
            << device().info().maxGlobalVariableSize_;
        compileOptions_.append(opts.str());
    }

    //Compile source to IR
    this->compileOptions_.append(preprocessorOptions(options));
    this->compileOptions_.append(codegenOptions(options));

    errorCode = g_complibApi._aclCompile(device().compiler(),
        binaryElf_,
        //"-Wf,--support_all_extensions",
        this->compileOptions_.c_str(),
        ACL_TYPE_OPENCL,
        ACL_TYPE_LLVMIR_BINARY,
        logFunction);
    buildLog_ += g_complibApi._aclGetCompilerLog(device().compiler());
    if( errorCode!=ACL_SUCCESS ) {
        LogWarning("aclCompile failed");
        buildLog_ += "Error while compiling \
                     opencl source: Compiling CL to IR";
        return false;
    }
    // Save the binary in the interface class
    saveBinaryAndSetType(TYPE_COMPILED);
    return true;
#endif // !defined(WITH_LIGHTNING_COMPILER)
}

#if defined(WITH_LIGHTNING_COMPILER)
#if defined(ATI_OS_LINUX)
static pthread_once_t once = PTHREAD_ONCE_INIT;

static void
checkLLVM_BIN()
{
    if (llvmBin_.empty()) {
        Dl_info info;
        if (dladdr((const void*)&amd::Device::init, &info)) {
            llvmBin_ = dirname(strdup(info.dli_fname));
            size_t pos = llvmBin_.rfind("lib");
            if (pos != std::string::npos) {
                llvmBin_.replace(pos, 3, "bin");
            }
        }
    }
#if defined(DEBUG)
    std::string clangExe(llvmBin_ + "/clang");
    struct stat buf;
    if (stat(clangExe.c_str(), &buf)) {
        std::string msg("Could not find the Clang binary in " + llvmBin_);
        LogWarning(msg.c_str());
    }
#endif // defined(DEBUG)
}
#endif // defined(ATI_OS_LINUX)

std::auto_ptr<amd::opencl_driver::Compiler>
HSAILProgram::newCompilerInstance()
{
#if defined(ATI_OS_LINUX)
    pthread_once(&once, checkLLVM_BIN);
#endif // defined(ATI_OS_LINUX)
    return std::auto_ptr<amd::opencl_driver::Compiler>(
        amd::opencl_driver::CompilerFactory().CreateAMDGPUCompiler(llvmBin_));
}
#endif // defined(WITH_LIGHTNING_COMPILER)

} // namespace roc
#endif // WITHOUT_GPU_BACKEND
<|endoftext|>