Beispiel #1
0
int Server::close(struct evhttp_request *req){
	HttpQuery query(req);
	std::string cname = query.get_str("cname", "");

	Channel *channel = this->get_channel_by_name(cname);
	if(!channel){
		log_warn("channel %s not found", cname.c_str());
		struct evbuffer *buf = evhttp_request_get_output_buffer(req);
		evbuffer_add_printf(buf, "channel[%s] not connected\n", cname.c_str());
		evhttp_send_reply(req, 404, "Not Found", buf);
		return 0;
	}
	log_debug("close channel: %s, subs: %d", cname.c_str(), channel->subs.size);
		
	// response to publisher
	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	evbuffer_add_printf(buf, "ok %d\n", channel->seq_next);
	evhttp_send_reply(req, 200, "OK", buf);
	
	channel->close();
	this->free_channel(channel);

	return 0;
}
Beispiel #2
0
void Subscriber::send_chunk(int seq, const char *type, const char *content){
	struct evbuffer *buf = evhttp_request_get_output_buffer(this->req);
	
	if(this->type == POLL){
		if(!this->callback.empty()){
			evbuffer_add_printf(buf, "%s(", this->callback.c_str());
		}
	}else if(this->type == IFRAME){
		evbuffer_add_printf(buf, "%s", iframe_chunk_prefix.c_str());
	}
	
	evbuffer_add_printf(buf,
		"{\"type\":\"%s\",\"cname\":\"%s\",\"seq\":%d,\"content\":\"%s\"}",
		type, this->channel->name.c_str(), seq, content);

	if(this->type == POLL){
		if(!this->callback.empty()){
			evbuffer_add_printf(buf, ");");
		}
	}else if(this->type == IFRAME){
		evbuffer_add_printf(buf, "%s", iframe_chunk_suffix.c_str());
	}

	evbuffer_add_printf(buf, "\n");
	evhttp_send_reply_chunk(this->req, buf);

	this->idle = 0;
	if(this->type == POLL){
		this->close();
	}
}
/** Closure sent to main thread to request a reply to be sent to
 * a HTTP request.
 * Replies must be sent in the main loop in the main http thread,
 * this cannot be done from worker threads.
 */
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
{
    assert(!replySent && req);
    // Send event to main http thread to send reply message
    struct evbuffer* evb = evhttp_request_get_output_buffer(req);
    assert(evb);
    evbuffer_add(evb, strReply.data(), strReply.size());
    auto req_copy = req;
    HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
        evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
        // Re-enable reading from the socket. This is the second part of the libevent
        // workaround above.
        if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) {
            evhttp_connection* conn = evhttp_request_get_connection(req_copy);
            if (conn) {
                bufferevent* bev = evhttp_connection_get_bufferevent(conn);
                if (bev) {
                    bufferevent_enable(bev, EV_READ | EV_WRITE);
                }
            }
        }
    });
    ev->trigger(nullptr);
    replySent = true;
    req = nullptr; // transferred back to main thread
}
Beispiel #4
0
int Server::broadcast(struct evhttp_request *req){
	if(evhttp_request_get_command(req) != EVHTTP_REQ_GET){
		evhttp_send_reply(req, 405, "Invalid Method", NULL);
		return 0;
	}
	
	HttpQuery query(req);
	const char *content = query.get_str("content", "");
	log_debug("%s:%d broadcast, content: %s",
		req->remote_host, req->remote_port, content);
	
	LinkedList<Channel *>::Iterator it = used_channels.iterator();
	while(Channel *channel = it.next()){
		if(channel->idle < ServerConfig::channel_idles){
			channel->idle = ServerConfig::channel_idles;
		}
		channel->send("broadcast", content, false);
	}

	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	evbuffer_add_printf(buf, "ok\n");
	evhttp_send_reply(req, 200, "OK", buf);

	return 0;
}
Beispiel #5
0
void Subscriber::start(){
	bufferevent_enable(req->evcon->bufev, EV_READ);
	evhttp_connection_set_closecb(req->evcon, on_sub_disconnect, this);
	evhttp_add_header(req->output_headers, "Connection", "keep-alive");
	//evhttp_add_header(req->output_headers, "Cache-Control", "no-cache");
	//evhttp_add_header(req->output_headers, "Expires", "0");
	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	evhttp_send_reply_start(req, HTTP_OK, "OK");

	if(this->type == POLL){
		//
	}else if(this->type == IFRAME){
		struct evbuffer *buf = evhttp_request_get_output_buffer(this->req);
		evbuffer_add_printf(buf, "%s\n", iframe_header.c_str());
		evhttp_send_reply_chunk(this->req, buf);
	}
	
	// send buffered messages
	if(this->seq_next == 0){
		this->seq_next = channel->seq_next;
	}
	if(!channel->msg_list.empty() && channel->seq_next != this->seq_next){
		this->send_old_msgs();
	}
}
void EvHttpSyncClient::post(const std::string& sURI, const std::string& sData)
{
    struct evhttp_request* pReq = newReqest();
    if (!pReq)
    {
        return;
    }
    
    int rv = evbuffer_add(evhttp_request_get_output_buffer(pReq),
                                 sData.c_str(), sData.length());
    if (rv != 0) 
    {
        setError(ST_ERROR, "evhttp_add_buffer FAILED");
        return;
    }

    rv = evhttp_make_request(m_pConn, pReq, EVHTTP_REQ_POST, sURI.c_str());
    if (rv != 0) 
    {
        setError(ST_ERROR, "evhttp_make_request FAILED");
        return;
    }

    rv = event_base_dispatch(m_evbase);
    if (rv != 0)
    {
        FX_LOG(WARN, "event loop failed: [%d]", rv);
    }
}
Beispiel #7
0
void httpHandler(evhttp_request *request, void *arg) {
	GithubWebhooks * parent = static_cast<GithubWebhooks*>(arg);
	std::string githubHeader;

	auto *inputHeader = evhttp_request_get_input_headers(request);
	for (auto header = inputHeader->tqh_first; header; header = header->next.tqe_next)
	{
		auto headerName = toLower(std::string(header->key));
		if (headerName == "x-github-event")
			githubHeader = std::string(header->value);
	}

	if (githubHeader.empty())
	{
		auto *output = evhttp_request_get_output_buffer(request);
		evhttp_send_reply(request, HTTP_BADREQUEST, "Not a github webhook", output);
		evbuffer_add_printf(output, "X-GitHub-Event is missing");
		return;
	}

	auto *input = evhttp_request_get_input_buffer(request);
	auto *output = evhttp_request_get_output_buffer(request);
	size_t length = evbuffer_get_length(input);

	std::vector<char> buffer;
	buffer.resize(length);
	evbuffer_remove(input, buffer.data(), length);

	std::string textResponse;
	auto formatStatus = GithubWebhookFormatter::FormatWebhookMessage(githubHeader, buffer, textResponse);

	switch (formatStatus)
	{
	case GithubWebhookFormatter::FormatResult::JSONParseError:
		LOG(ERROR) << "Can't parse json payload";
		evhttp_send_reply(request, HTTP_INTERNAL, "Can't parse json payload", output);
		evbuffer_add_printf(output, "Can't parse json");
		return;

	case GithubWebhookFormatter::FormatResult::OK:
		parent->SendMessage(textResponse);

	case GithubWebhookFormatter::FormatResult::IgnoredHook:
		evhttp_send_reply(request, HTTP_OK, "OK", output);
	}
}
void ping_handler(struct evhttp_request *req, void *arg){

	string ping = "ok"; 
	struct evbuffer * buf = evhttp_request_get_output_buffer(req); 
	evbuffer_add_printf(buf, "%s", ping.c_str());

	evhttp_send_reply(req, HTTP_OK, "OK", buf);
}
Beispiel #9
0
int Server::pub(struct evhttp_request *req, bool encoded){
	if(evhttp_request_get_command(req) != EVHTTP_REQ_GET){
		evhttp_send_reply(req, 405, "Invalid Method", NULL);
		return 0;
	}
	
	HttpQuery query(req);
	const char *cb = query.get_str("cb", NULL);
	std::string cname = query.get_str("cname", "");
	const char *content = query.get_str("content", "");
	
	Channel *channel = NULL;
	channel = this->get_channel_by_name(cname);
	if(!channel){
		channel = this->new_channel(cname);
		if(!channel){
			evhttp_send_reply(req, 429, "Too Many Channels", NULL);
			return 0;
		}
		int expires = ServerConfig::channel_timeout;
		log_debug("auto sign channel on pub, cname:%s, t:%s, expires:%d",
			cname.c_str(), channel->token.c_str(), expires);
		channel->idle = expires/CHANNEL_CHECK_INTERVAL;
		/*
		struct evbuffer *buf = evhttp_request_get_output_buffer(req);
		log_trace("cname[%s] not connected, not pub content: %s", cname.c_str(), content);
		evbuffer_add_printf(buf, "cname[%s] not connected\n", cname.c_str());
		evhttp_send_reply(req, 404, "Not Found", buf);
		return 0;
		*/
	}
	log_debug("%s:%d pub %s, seq: %d, subs: %d, content: %s",
		req->remote_host, req->remote_port,
		channel->name.c_str(), channel->seq_next, channel->subs.size, content);
		
	// response to publisher
	evhttp_add_header(req->output_headers, "Content-Type", "text/javascript; charset=utf-8");
	struct evbuffer * buf = evhttp_request_get_output_buffer(req);
	if(cb){
		evbuffer_add_printf(buf, "%s(", cb);
	}
	evbuffer_add_printf(buf, "{\"type\":\"ok\"}");
	if(cb){
		evbuffer_add(buf, ");\n", 3);
	}else{
		evbuffer_add(buf, "\n", 1);
	}
	evhttp_send_reply(req, 200, "OK", buf);

	// push to subscribers
	if(channel->idle < ServerConfig::channel_idles){
		channel->idle = ServerConfig::channel_idles;
	}
	channel->send("data", content, encoded);
	return 0;
}
Beispiel #10
0
// Sends JSON to the client (also `free`s the JSON object)
static void send_reply_json(struct evhttp_request *request,
                            int code,
                            const char *message,
                            json_t *json) {
  struct evbuffer *buf = evhttp_request_get_output_buffer(request);
  char *json_str = json_dumps(json, JSON_COMPACT);
  json_decref(json);
  evbuffer_add(buf, json_str, strlen(json_str));
  free(json_str);
  send_reply(request, code, message, buf);
}
Beispiel #11
0
int Server::ping(struct evhttp_request *req){
	HttpQuery query(req);
	const char *cb = query.get_str("cb", DEFAULT_JSONP_CALLBACK);

	struct evbuffer * buf = evhttp_request_get_output_buffer(req);
	evbuffer_add_printf(buf,
		"%s({\"type\":\"ping\",\"sub_timeout\":%d});\n",
		cb,
		ServerConfig::polling_timeout);
	evhttp_send_reply(req, HTTP_OK, "OK", buf);
	return 0;
}
Beispiel #12
0
/** Closure sent to main thread to request a reply to be sent to
 * a HTTP request.
 * Replies must be sent in the main loop in the main http thread,
 * this cannot be done from worker threads.
 */
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
{
    assert(!replySent && req);
    // Send event to main http thread to send reply message
    struct evbuffer* evb = evhttp_request_get_output_buffer(req);
    assert(evb);
    evbuffer_add(evb, strReply.data(), strReply.size());
    HTTPEvent* ev = new HTTPEvent(eventBase, true,
        std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
    ev->trigger(0);
    replySent = true;
    req = 0; // transferred back to main thread
}
Beispiel #13
0
int Server::sign(struct evhttp_request *req){
	HttpQuery query(req);
	int expires = query.get_int("expires", -1);
	const char *cb = query.get_str("cb", NULL);
	std::string cname = query.get_str("cname", "");

	if(expires <= 0){
		expires = ServerConfig::channel_timeout;
	}
	
	Channel *channel = this->get_channel_by_name(cname);
	if(!channel){
		channel = this->new_channel(cname);
	}	
	if(!channel){
		evhttp_send_reply(req, 429, "Too Many Channels", NULL);
		return 0;
	}

	if(channel->idle == -1){
		log_debug("%s:%d sign cname:%s, t:%s, expires:%d",
			req->remote_host, req->remote_port,
			cname.c_str(), channel->token.c_str(), expires);
	}else{
		log_debug("%s:%d re-sign cname:%s, t:%s, expires:%d",
			req->remote_host, req->remote_port,
			cname.c_str(), channel->token.c_str(), expires);
	}
	channel->idle = expires/CHANNEL_CHECK_INTERVAL;

	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	if(cb){
		evbuffer_add_printf(buf, "%s(", cb);
	}
	evbuffer_add_printf(buf,
		"{\"type\":\"sign\",\"cname\":\"%s\",\"seq\":%d,\"token\":\"%s\",\"expires\":%d,\"sub_timeout\":%d}",
		channel->name.c_str(),
		channel->msg_seq_min(),
		channel->token.c_str(),
		expires,
		ServerConfig::polling_timeout);
	if(cb){
		evbuffer_add(buf, ");\n", 3);
	}else{
		evbuffer_add(buf, "\n", 1);
	}
	evhttp_send_reply(req, 200, "OK", buf);

	return 0;
}
    static Variant HHVM_METHOD(EventHttpRequest, getOutputBuffer) {
        event_buffer_t *buf;
        EventHttpRequestResourceData *event_http_request_resource_data = FETCH_RESOURCE(this_, EventHttpRequestResourceData, s_event_http_request);

        if((buf = evhttp_request_get_output_buffer((evhttp_request_t *) event_http_request_resource_data->getInternalResourceData())) == NULL){
            return Variant();
        }

        Object event_buffer = ObjectData::newInstance(Unit::lookupClass(String("EventBuffer").get()));
        Resource resource = Resource(NEWOBJ(InternalResourceData(buf)));
        SET_RESOURCE(event_buffer, resource, s_event_buffer);
        InternalResourceData *resource_data = FETCH_RESOURCE(event_buffer, InternalResourceData, s_event_buffer);
        resource_data->isInternal = true;
        return event_buffer;
    }
Beispiel #15
0
void Server::add_presence(PresenceType type, const std::string &cname){
	if(psubs.empty()){
		return;
	}

	LinkedList<PresenceSubscriber *>::Iterator it = psubs.iterator();
	while(PresenceSubscriber *psub = it.next()){
		struct evbuffer *buf = evhttp_request_get_output_buffer(psub->req);
		evbuffer_add_printf(buf, "%d %s\n", type, cname.c_str());
		evhttp_send_reply_chunk(psub->req, buf);
		//struct evbuffer *output = bufferevent_get_output(req->evcon->bufev);
		//if(evbuffer_get_length(output) > MAX_OUTPUT_BUFFER){
		//  close_presence_subscriber();
		//}
	}
}
Beispiel #16
0
int Server::check(struct evhttp_request *req){
	HttpQuery query(req);
	std::string cname = query.get_str("cname", "");

	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");

	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	Channel *channel = this->get_channel_by_name(cname);
	if(channel && channel->idle != -1){
		evbuffer_add_printf(buf, "{\"%s\": 1}\n", cname.c_str());
	}else{
		evbuffer_add_printf(buf, "{}\n");
	}
	evhttp_send_reply(req, 200, "OK", buf);

	return 0;
}
Beispiel #17
0
void Subscriber::send_old_msgs(){
	std::vector<std::string>::iterator it = channel->msg_list.end();
	int msg_seq_min = channel->seq_next - channel->msg_list.size();
	if(Channel::SEQ_GT(this->seq_next, channel->seq_next) || Channel::SEQ_LT(this->seq_next, msg_seq_min)){
		this->seq_next = msg_seq_min;
	}
	log_debug("send old msg: [%d, %d]", this->seq_next, channel->seq_next - 1);
	it -= (channel->seq_next - this->seq_next);

	struct evbuffer *buf = evhttp_request_get_output_buffer(this->req);
	if(this->type == POLL){
		if(!this->callback.empty()){
			evbuffer_add_printf(buf, "%s(", this->callback.c_str());
		}
		evbuffer_add_printf(buf, "[");
		for(/**/; it != channel->msg_list.end(); it++, this->seq_next++){
			std::string &msg = *it;
			evbuffer_add_printf(buf,
				"{\"type\":\"data\",\"cname\":\"%s\",\"seq\":%d,\"content\":\"%s\"}",
				this->channel->name.c_str(),
				this->seq_next,
				msg.c_str());
			if(this->seq_next != channel->seq_next - 1){
				evbuffer_add(buf, ",", 1);
			}
		}
		evbuffer_add_printf(buf, "]");
		if(!this->callback.empty()){
			evbuffer_add_printf(buf, ");");
		}
		evbuffer_add_printf(buf, "\n");
		evhttp_send_reply_chunk(this->req, buf);
		this->close();
	}else if(this->type == IFRAME || this->type == STREAM){
		for(/**/; it != channel->msg_list.end(); it++, this->seq_next++){
			std::string &msg = *it;
			this->send_chunk(this->seq_next, "data", msg.c_str());
		}
	}
}
Beispiel #18
0
void Subscriber::send_error_reply(int sub_type, struct evhttp_request *req, const char *cb, const std::string &cname, const char *type, const char *content){
	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	
	if(sub_type == POLL){
		evbuffer_add_printf(buf, "%s(", cb);
	}else if(sub_type == IFRAME){
		evbuffer_add_printf(buf, "%s", iframe_chunk_prefix.c_str());
	}
	
	evbuffer_add_printf(buf,
		"{\"type\":\"%s\",\"cname\":\"%s\",\"seq\":%d,\"content\":\"%s\"}",
		type, cname.c_str(), 0, content);

	if(sub_type == POLL){
		evbuffer_add_printf(buf, ");");
	}else if(sub_type == IFRAME){
		evbuffer_add_printf(buf, "%s", iframe_chunk_suffix.c_str());
	}

	evbuffer_add_printf(buf, "\n");
	evhttp_send_reply(req, HTTP_OK, "OK", buf);
}
Beispiel #19
0
void Server::requestHandler( evhttp_request* evRequest, void* serverPtr)
{
    Server* server = (Server*)serverPtr;

    Request::TYPE type = Request::GET;
    if( evRequest->type != evhttp_cmd_type::EVHTTP_REQ_GET)
        type = Request::OTHER;

    std::string evUri = evRequest->uri;
    std::string uri = resm::UriHelper::removeDuplicateSlashes( evUri);
    Request request( type, uri);
    Response response = server->_httpRequestHandler.handle( request);

    evhttp_add_header( evRequest->output_headers, "Content-Type", "application/javascript; charset=utf-8");
//	evhttp_add_header( request->output_headers, "Content-Type", "application/json; charset=utf-8");
    auto *evResponse = evhttp_request_get_output_buffer( evRequest);
    if (!evResponse)
        return;

    evbuffer_add_printf( evResponse, "%s", response.getBody().c_str());
    evhttp_send_reply( evRequest, response.getStatus(), response.getReason().c_str(), evResponse);
}
Beispiel #20
0
int Server::info(struct evhttp_request *req){
	HttpQuery query(req);
	std::string cname = query.get_str("cname", "");

	evhttp_add_header(req->output_headers, "Content-Type", "text/html; charset=utf-8");
	struct evbuffer *buf = evhttp_request_get_output_buffer(req);
	if(!cname.empty()){
		Channel *channel = this->get_channel_by_name(cname);
		int onlines = channel? channel->subs.size : 0;
		evbuffer_add_printf(buf,
			"{\"cname\": \"%s\", \"subscribers\": %d}\n",
			cname.c_str(),
			onlines);
	}else{
		evbuffer_add_printf(buf,
			"{\"version\": \"%s\", \"channels\": %d, \"subscribers\": %d}\n",
			ICOMET_VERSION,
			used_channels.size,
			subscribers);
	}
	evhttp_send_reply(req, 200, "OK", buf);

	return 0;
}
Beispiel #21
0
//Main
int main(int argc, char *argv[])
{
    //Get args
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <snapshot_file>\n", argv[0]);
        return 1;
    }
    snap_path = argv[1];

    //Allocate memory
    fprintf(stderr, "Allocating arena with size %.2f MBytes ...\n", (float)m / CHAR_BIT / MEGA);
    Bloom = malloc( (m + ( CHAR_BIT - 1)) / CHAR_BIT ); // Ceil byte length: bytes = bits + 7 / 8


    //Load or create snapshot file
    if (!access(snap_path, F_OK)) {
        fputs("Loading snapshot...\n", stderr);
        if (LoadSnap(Bloom, snap_path)) {
            fputs("Unable to load snapshot!\n", stderr);
            return -1;
        }
        fputs("Snapshot loaded.\n", stderr);
    } else {
        fputs("Initializing new file storage...\n", stderr);
        size_t shouldwrite = (m + (CHAR_BIT - 1)) / CHAR_BIT;
        memset(Bloom, 0, shouldwrite); 

        if (SaveSnap(Bloom, snap_path)) {
            fputs("Unable to save initial snapshot!\n", stderr);
            return -1;
        }
        fputs("Initial snapshot written.\n", stderr);
    }


    void OnReq(struct evhttp_request *req, void *arg)
    {
        struct evbuffer *OutBuf = evhttp_request_get_output_buffer(req);
        if (!OutBuf) {
            evhttp_send_reply(req, HTTP_BADREQUEST, "Bad Request", OutBuf);
            return;
        }
        struct evkeyvalq *Headers = evhttp_request_get_output_headers(req);
        if (!Headers) {
            evhttp_send_reply(req, HTTP_INTERNAL, "Internal Error", OutBuf);
            return;
        }
        const struct evhttp_uri *HTTPURI =  evhttp_request_get_evhttp_uri(req);
        if (!HTTPURI) {
            evhttp_send_reply(req, HTTP_BADREQUEST, "Bad Request", OutBuf);
            return;
        }
        const char *path =  evhttp_uri_get_path(HTTPURI);
        if (!path) {
            evhttp_send_reply(req, HTTP_BADREQUEST, "Bad Request", OutBuf);
        }
        const char *query_string = evhttp_uri_get_query(HTTPURI);
        if (!query_string) {
            evhttp_send_reply(req, HTTP_BADREQUEST, "Element Required", OutBuf);
            return;
        }
        struct evkeyvalq params;
        evhttp_parse_query_str(query_string, &params);
        const char *element = evhttp_find_header(&params, "e");
        if (!element) {
            evhttp_clear_headers(&params);
            evhttp_send_reply(req, HTTP_BADREQUEST, "Element Required", OutBuf);
            return;
        }

        int i;
        const char* (*Operation)(bloom_cell *, size_t []) = NULL;
        for (i=0; i< sizeof HandlerTable/ sizeof HandlerTable[0] ; i++)
            if (strncmp(HandlerTable[i][0], path, STR_MAX) == 0) {
                Operation = HandlerTable[i][1];
                break;
            }
        if (!Operation) {
            evhttp_clear_headers(&params);
            evhttp_send_reply(req, HTTP_NOTFOUND, "Not Found", OutBuf);
            return;
        }

        const char *response = Operation(Bloom, Hashes(element));

        evhttp_add_header(Headers, MIME_TYPE);
        evbuffer_add_printf(OutBuf, response);
        evhttp_send_reply(req, HTTP_OK, "OK", OutBuf);
        evhttp_clear_headers(&params);
    };

    if (!(base = event_base_new()))
        crash("Couldn't create an event_base: exiting\n", -1);

    if (!(http = evhttp_new(base)))
        crash("Couldn't create evhttp. Exiting.\n", -1);
    evhttp_set_gencb(http, OnReq, NULL);

    if (!(handle = evhttp_bind_socket_with_handle(http, BIND_ADDRESS, BIND_PORT)))
        crash("couldn't bind to port 8888. Exiting.\n", -1);

    if (signal(SIGINT, term_handler) == SIG_ERR)
        crash("Unable to set SIGINT handler!", -1);

    if (signal(SIGTERM, term_handler) == SIG_ERR)
        crash("Unable to set SIGTERM handler!", -1);

    if (signal(SIGCHLD, child_collector) == SIG_ERR)
        crash("Unable to set SIGCHLD handler!", -1);
    
    //This signal handled by event loop in order to avoid malloc deadlock
    if ((dump_event = evsignal_new(base, SIGUSR1, dump_handler, NULL)) == NULL)
        crash("Unable to create SIGUSR1 handler!", -1);
    else 
        if (event_add(dump_event, NULL) == -1)
            crash("Unable to add SIGUSR1 handler!", -1);

    if (event_base_dispatch(base) == -1)
        crash("Failed to run message loop.\n", -1);

    fputs("Exiting...\n", stderr);
    SaveSnap(Bloom, snap_path);
    evhttp_del_accept_socket(http, handle);
    evhttp_free(http);
    event_free(dump_event);
    event_base_free(base);
    free(Bloom);
    return 0;
}
Beispiel #22
0
/*
 ******************************************************************************
 * dgadmin_rest_sync_dmc_agent --                                             *//**
 *
 * \brief This routine constructs new request and sends to REST server.
 *
 * \param [in]	req_body_buf	A pointer to request input body buffer.
 * \param [in]  cmd_type	The method of the HTTP request.
 * \param [in]  uri		The URI of the HTTP request.
 *
 * \retval 0 	Success
 * \retval >0 	Failure
 *
 *****************************************************************************/
int dgadmin_rest_sync_dmc_agent(char *req_body_buf, 
                                enum evhttp_cmd_type cmd_type, 
                                const char *uri)
{
	struct evhttp_request *new_request = NULL;
	struct evbuffer *new_req_body = NULL;
	char ip_addr_str[]="127.0.0.1";
	dgadmin_rest_sync_response_args_t args;
	int ret = DOVE_STATUS_OK;

	do
	{
		/* step 1 - construct a new request */
		memset(&args, 0, sizeof(args));
		new_request = evhttp_request_new(dgadmin_rest_sync_response_handler, &args);
		if (new_request == NULL)
		{
            log_notice(ServiceUtilLogLevel,"ERROR");
			ret = DOVE_STATUS_NO_MEMORY;
			break;
		}
		if (req_body_buf != NULL)
		{
			new_req_body = evbuffer_new();
			if (new_req_body == NULL)
			{
				evhttp_request_free(new_request);
				ret = DOVE_STATUS_NO_MEMORY;
                log_notice(ServiceUtilLogLevel,"ERROR");
				break;
			}
			evbuffer_add(new_req_body, req_body_buf, strlen(req_body_buf));
			evbuffer_add_buffer(evhttp_request_get_output_buffer(new_request), new_req_body);
		}

		/* step 2 - forward the new request to local REST handler */

		log_notice(ServiceUtilLogLevel, "Routing %s REQ to local REST handler[%s]", uri, ip_addr_str);
		ret = dove_rest_request_and_syncprocess(ip_addr_str, g_dgwy_rest_port,
                                                cmd_type, uri,
                                                new_request, NULL,
                                                DGADMIN_REST_SYNC_CONNECT_TIMEOUT);
		if (new_req_body)
		{
			evbuffer_free(new_req_body);
		}

		if (ret)
		{
			ret = DOVE_STATUS_ERROR;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}
		if ((args.res_code != HTTP_OK) && (args.res_code != 201))
		{
			ret = DOVE_STATUS_ERROR;
            log_notice(ServiceUtilLogLevel,"ERROR");
			break;
		}
	} while (0);

	if (args.req_body_buf)
	{
		free(args.req_body_buf);
	}
	return ret;
}
/*
 ******************************************************************************
 * dps_rest_client_fill_evhttp --                                         *//**
 *
 * \brief This routine crate the HTTP Request from the JSON Body
 *
 * \param req: The EVHTTP_REQUEST
 * \param js_res: The JSON Body of the Request
 * \param remote_ip_string: The DPS IP Address to send the request to.
 *
 * \return PyObject
 *
 *****************************************************************************/
static void dps_rest_client_fill_evhttp(struct evhttp_request *req,
                                        json_t *js_res,
                                        char *remote_ip_string)
{
	char *res_body_str = NULL;
	struct evbuffer *retbuf = NULL;
	char host_header_str[64];

	log_debug(RESTHandlerLogLevel, "Enter");

	memset(host_header_str, 0, 64);
	do
	{
		if(js_res != NULL)
		{
			//add to the http request output buffer for sending
			res_body_str = json_dumps(js_res, JSON_PRESERVE_ORDER);
			if (NULL == res_body_str)
			{
				log_alert(RESTHandlerLogLevel, "JSON string is NULL or Bad");
				break;
			}
			retbuf = evbuffer_new();
			if (NULL == retbuf)
			{
				log_error(RESTHandlerLogLevel, "retbuf = evbuffer_new() ERROR");
				break;
			}
			//add to the http request output buffer for sending
			log_debug(RESTHandlerLogLevel,
			          "strlen(res_body_str) = %d, content is %s",
			          strlen((const char *)res_body_str), res_body_str);
			evbuffer_add(retbuf, res_body_str, strlen((const char *)res_body_str) + 1);
			evbuffer_add_buffer(evhttp_request_get_output_buffer(req), retbuf);
		}
		/* No need to add "content-length,
		 * as evhttp will add it for POST and PUT, and
		 * GET should not have it
		*/

		log_debug(RESTHandlerLogLevel,
		          "Remote DPS Node IP ==>> [%s : REST Port %d]",
		          remote_ip_string, DPS_REST_HTTPD_PORT);
		if (DPS_REST_HTTPD_PORT != HTTPD_DEFAULT_PORT)
		{
			sprintf(host_header_str,"%s:%d",
			        remote_ip_string,
			        DPS_REST_HTTPD_PORT);
		}
		else
		{
			sprintf(host_header_str,"%s",remote_ip_string);
		}
		log_debug(RESTHandlerLogLevel, "host_header_str %s", host_header_str);

		if(evhttp_find_header(req->output_headers, "Host") == NULL)
		{
			evhttp_add_header(evhttp_request_get_output_headers(req),
			                  "Host", host_header_str);
		}

		
		if(evhttp_find_header(req->output_headers, "Content-Type") == NULL)
		{
			evhttp_add_header(evhttp_request_get_output_headers(req), 
			"Content-Type", "application/json");
		}
	} while(0);

	if (res_body_str)
	{
		free(res_body_str);
	}

	log_debug(RESTHandlerLogLevel, "Exit");

	return;

}
Beispiel #24
0
static UniValue CallRPC(BaseRequestHandler *rh, const std::string& strMethod, const std::vector<std::string>& args)
{
    std::string host;
    // In preference order, we choose the following for the port:
    //     1. -rpcport
    //     2. port in -rpcconnect (ie following : in ipv4 or ]: in ipv6)
    //     3. default port for chain
    int port = BaseParams().RPCPort();
    SplitHostPort(gArgs.GetArg("-rpcconnect", DEFAULT_RPCCONNECT), port, host);
    port = gArgs.GetArg("-rpcport", port);

    // Obtain event base
    raii_event_base base = obtain_event_base();

    // Synchronously look up hostname
    raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
    evhttp_connection_set_timeout(evcon.get(), gArgs.GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));

    HTTPReply response;
    raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
    if (req == nullptr)
        throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif

    // Get credentials
    std::string strRPCUserColonPass;
    bool failedToGetAuthCookie = false;
    if (gArgs.GetArg("-rpcpassword", "") == "") {
        // Try fall back to cookie-based authentication if no password is provided
        if (!GetAuthCookie(&strRPCUserColonPass)) {
            failedToGetAuthCookie = true;
        }
    } else {
        strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
    }

    struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
    assert(output_headers);
    evhttp_add_header(output_headers, "Host", host.c_str());
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());

    // Attach request data
    std::string strRequest = rh->PrepareRequest(strMethod, args).write() + "\n";
    struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
    assert(output_buffer);
    evbuffer_add(output_buffer, strRequest.data(), strRequest.size());

    // check if we should use a special wallet endpoint
    std::string endpoint = "/";
    if (!gArgs.GetArgs("-rpcwallet").empty()) {
        std::string walletName = gArgs.GetArg("-rpcwallet", "");
        char *encodedURI = evhttp_uriencode(walletName.c_str(), walletName.size(), false);
        if (encodedURI) {
            endpoint = "/wallet/"+ std::string(encodedURI);
            free(encodedURI);
        }
        else {
            throw CConnectionFailed("uri-encode failed");
        }
    }
    int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, endpoint.c_str());
    req.release(); // ownership moved to evcon in above call
    if (r != 0) {
        throw CConnectionFailed("send http request failed");
    }

    event_base_dispatch(base.get());

    if (response.status == 0) {
        std::string responseErrorMessage;
        if (response.error != -1) {
            responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
        }
        throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
    } else if (response.status == HTTP_UNAUTHORIZED) {
        if (failedToGetAuthCookie) {
            throw std::runtime_error(strprintf(
                "Could not locate RPC credentials. No authentication cookie could be found, and RPC password is not set.  See -rpcpassword and -stdinrpcpass.  Configuration file: (%s)",
                GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));
        } else {
            throw std::runtime_error("Authorization failed: Incorrect rpcuser or rpcpassword");
        }
    } else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
        throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
    else if (response.body.empty())
        throw std::runtime_error("no response from server");

    // Parse reply
    UniValue valReply(UniValue::VSTR);
    if (!valReply.read(response.body))
        throw std::runtime_error("couldn't parse reply from server");
    const UniValue reply = rh->ProcessReply(valReply);
    if (reply.empty())
        throw std::runtime_error("expected reply to have result, error and id properties");

    return reply;
}
Beispiel #25
0
int
main(int argc, char **argv)
{
	int r;

	struct evhttp_uri *http_uri = NULL;
	const char *url = NULL, *data_file = NULL;
	const char *crt = "/etc/ssl/certs/ca-certificates.crt";
	const char *scheme, *host, *path, *query;
	char uri[256];
	int port;
	int retries = 0;
	int timeout = -1;

	SSL_CTX *ssl_ctx = NULL;
	SSL *ssl = NULL;
	struct bufferevent *bev;
	struct evhttp_connection *evcon = NULL;
	struct evhttp_request *req;
	struct evkeyvalq *output_headers;
	struct evbuffer *output_buffer;

	int i;
	int ret = 0;
	enum { HTTP, HTTPS } type = HTTP;

	for (i = 1; i < argc; i++) {
		if (!strcmp("-url", argv[i])) {
			if (i < argc - 1) {
				url = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-crt", argv[i])) {
			if (i < argc - 1) {
				crt = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-ignore-cert", argv[i])) {
			ignore_cert = 1;
		} else if (!strcmp("-data", argv[i])) {
			if (i < argc - 1) {
				data_file = argv[i + 1];
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-retries", argv[i])) {
			if (i < argc - 1) {
				retries = atoi(argv[i + 1]);
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-timeout", argv[i])) {
			if (i < argc - 1) {
				timeout = atoi(argv[i + 1]);
			} else {
				syntax();
				goto error;
			}
		} else if (!strcmp("-help", argv[i])) {
			syntax();
			goto error;
		}
	}

	if (!url) {
		syntax();
		goto error;
	}

#ifdef _WIN32
	{
		WORD wVersionRequested;
		WSADATA wsaData;
		int err;

		wVersionRequested = MAKEWORD(2, 2);

		err = WSAStartup(wVersionRequested, &wsaData);
		if (err != 0) {
			printf("WSAStartup failed with error: %d\n", err);
			goto error;
		}
	}
#endif // _WIN32

	http_uri = evhttp_uri_parse(url);
	if (http_uri == NULL) {
		err("malformed url");
		goto error;
	}

	scheme = evhttp_uri_get_scheme(http_uri);
	if (scheme == NULL || (strcasecmp(scheme, "https") != 0 &&
	                       strcasecmp(scheme, "http") != 0)) {
		err("url must be http or https");
		goto error;
	}

	host = evhttp_uri_get_host(http_uri);
	if (host == NULL) {
		err("url must have a host");
		goto error;
	}

	port = evhttp_uri_get_port(http_uri);
	if (port == -1) {
		port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
	}

	path = evhttp_uri_get_path(http_uri);
	if (strlen(path) == 0) {
		path = "/";
	}

	query = evhttp_uri_get_query(http_uri);
	if (query == NULL) {
		snprintf(uri, sizeof(uri) - 1, "%s", path);
	} else {
		snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
	}
	uri[sizeof(uri) - 1] = '\0';

#if OPENSSL_VERSION_NUMBER < 0x10100000L
	// Initialize OpenSSL
	SSL_library_init();
	ERR_load_crypto_strings();
	SSL_load_error_strings();
	OpenSSL_add_all_algorithms();
#endif

	/* This isn't strictly necessary... OpenSSL performs RAND_poll
	 * automatically on first use of random number generator. */
	r = RAND_poll();
	if (r == 0) {
		err_openssl("RAND_poll");
		goto error;
	}

	/* Create a new OpenSSL context */
	ssl_ctx = SSL_CTX_new(SSLv23_method());
	if (!ssl_ctx) {
		err_openssl("SSL_CTX_new");
		goto error;
	}

#ifndef _WIN32
	/* TODO: Add certificate loading on Windows as well */

	/* Attempt to use the system's trusted root certificates.
	 * (This path is only valid for Debian-based systems.) */
	if (1 != SSL_CTX_load_verify_locations(ssl_ctx, crt, NULL)) {
		err_openssl("SSL_CTX_load_verify_locations");
		goto error;
	}
	/* Ask OpenSSL to verify the server certificate.  Note that this
	 * does NOT include verifying that the hostname is correct.
	 * So, by itself, this means anyone with any legitimate
	 * CA-issued certificate for any website, can impersonate any
	 * other website in the world.  This is not good.  See "The
	 * Most Dangerous Code in the World" article at
	 * https://crypto.stanford.edu/~dabo/pubs/abstracts/ssl-client-bugs.html
	 */
	SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
	/* This is how we solve the problem mentioned in the previous
	 * comment.  We "wrap" OpenSSL's validation routine in our
	 * own routine, which also validates the hostname by calling
	 * the code provided by iSECPartners.  Note that even though
	 * the "Everything You've Always Wanted to Know About
	 * Certificate Validation With OpenSSL (But Were Afraid to
	 * Ask)" paper from iSECPartners says very explicitly not to
	 * call SSL_CTX_set_cert_verify_callback (at the bottom of
	 * page 2), what we're doing here is safe because our
	 * cert_verify_callback() calls X509_verify_cert(), which is
	 * OpenSSL's built-in routine which would have been called if
	 * we hadn't set the callback.  Therefore, we're just
	 * "wrapping" OpenSSL's routine, not replacing it. */
	SSL_CTX_set_cert_verify_callback(ssl_ctx, cert_verify_callback,
					  (void *) host);
#else // _WIN32
	(void)crt;
#endif // _WIN32

	// Create event base
	base = event_base_new();
	if (!base) {
		perror("event_base_new()");
		goto error;
	}

	// Create OpenSSL bufferevent and stack evhttp on top of it
	ssl = SSL_new(ssl_ctx);
	if (ssl == NULL) {
		err_openssl("SSL_new()");
		goto error;
	}

	#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
	// Set hostname for SNI extension
	SSL_set_tlsext_host_name(ssl, host);
	#endif

	if (strcasecmp(scheme, "http") == 0) {
		bev = bufferevent_socket_new(base, -1, BEV_OPT_CLOSE_ON_FREE);
	} else {
		type = HTTPS;
		bev = bufferevent_openssl_socket_new(base, -1, ssl,
			BUFFEREVENT_SSL_CONNECTING,
			BEV_OPT_CLOSE_ON_FREE|BEV_OPT_DEFER_CALLBACKS);
	}

	if (bev == NULL) {
		fprintf(stderr, "bufferevent_openssl_socket_new() failed\n");
		goto error;
	}

	bufferevent_openssl_set_allow_dirty_shutdown(bev, 1);

	// For simplicity, we let DNS resolution block. Everything else should be
	// asynchronous though.
	evcon = evhttp_connection_base_bufferevent_new(base, NULL, bev,
		host, port);
	if (evcon == NULL) {
		fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
		goto error;
	}

	if (retries > 0) {
		evhttp_connection_set_retries(evcon, retries);
	}
	if (timeout >= 0) {
		evhttp_connection_set_timeout(evcon, timeout);
	}

	// Fire off the request
	req = evhttp_request_new(http_request_done, bev);
	if (req == NULL) {
		fprintf(stderr, "evhttp_request_new() failed\n");
		goto error;
	}

	output_headers = evhttp_request_get_output_headers(req);
	evhttp_add_header(output_headers, "Host", host);
	evhttp_add_header(output_headers, "Connection", "close");

	if (data_file) {
		/* NOTE: In production code, you'd probably want to use
		 * evbuffer_add_file() or evbuffer_add_file_segment(), to
		 * avoid needless copying. */
		FILE * f = fopen(data_file, "rb");
		char buf[1024];
		size_t s;
		size_t bytes = 0;

		if (!f) {
			syntax();
			goto error;
		}

		output_buffer = evhttp_request_get_output_buffer(req);
		while ((s = fread(buf, 1, sizeof(buf), f)) > 0) {
			evbuffer_add(output_buffer, buf, s);
			bytes += s;
		}
		evutil_snprintf(buf, sizeof(buf)-1, "%lu", (unsigned long)bytes);
		evhttp_add_header(output_headers, "Content-Length", buf);
		fclose(f);
	}

	r = evhttp_make_request(evcon, req, data_file ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
	if (r != 0) {
		fprintf(stderr, "evhttp_make_request() failed\n");
		goto error;
	}

	event_base_dispatch(base);
	goto cleanup;

error:
	ret = 1;
cleanup:
	if (evcon)
		evhttp_connection_free(evcon);
	if (http_uri)
		evhttp_uri_free(http_uri);
	event_base_free(base);

	if (ssl_ctx)
		SSL_CTX_free(ssl_ctx);
	if (type == HTTP && ssl)
		SSL_free(ssl);
#if OPENSSL_VERSION_NUMBER < 0x10100000L
	EVP_cleanup();
	ERR_free_strings();

#ifdef EVENT__HAVE_ERR_REMOVE_THREAD_STATE
	ERR_remove_thread_state(NULL);
#else
	ERR_remove_state(0);
#endif
	CRYPTO_cleanup_all_ex_data();

	sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
#endif /*OPENSSL_VERSION_NUMBER < 0x10100000L */

#ifdef _WIN32
	WSACleanup();
#endif

	return ret;
}
Beispiel #26
0
UniValue CallRPC(const std::string& strMethod, const UniValue& params)
{
    std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT);
    int port = GetArg("-rpcport", BaseParams().RPCPort());

    // Obtain event base
    raii_event_base base = obtain_event_base();

    // Synchronously look up hostname
    raii_evhttp_connection evcon = obtain_evhttp_connection_base(base.get(), host, port);
    evhttp_connection_set_timeout(evcon.get(), GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));

    HTTPReply response;
    raii_evhttp_request req = obtain_evhttp_request(http_request_done, (void*)&response);
    if (req == NULL)
        throw std::runtime_error("create http request failed");
#if LIBEVENT_VERSION_NUMBER >= 0x02010300
    evhttp_request_set_error_cb(req.get(), http_error_cb);
#endif

    // Get credentials
    std::string strRPCUserColonPass;
    if (GetArg("-rpcpassword", "") == "") {
        // Try fall back to cookie-based authentication if no password is provided
        if (!GetAuthCookie(&strRPCUserColonPass)) {
            throw std::runtime_error(strprintf(
                _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
                    GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string().c_str()));

        }
    } else {
        strRPCUserColonPass = GetArg("-rpcuser", "") + ":" + GetArg("-rpcpassword", "");
    }

    struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req.get());
    assert(output_headers);
    evhttp_add_header(output_headers, "Host", host.c_str());
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());

    // Attach request data
    std::string strRequest = JSONRPCRequestObj(strMethod, params, 1).write() + "\n";
    struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req.get());
    assert(output_buffer);
    evbuffer_add(output_buffer, strRequest.data(), strRequest.size());

    int r = evhttp_make_request(evcon.get(), req.get(), EVHTTP_REQ_POST, "/");
    req.release(); // ownership moved to evcon in above call
    if (r != 0) {
        throw CConnectionFailed("send http request failed");
    }

    event_base_dispatch(base.get());

    if (response.status == 0)
        throw CConnectionFailed(strprintf("couldn't connect to server: %s (code %d)\n(make sure server is running and you are connecting to the correct RPC port)", http_errorstring(response.error), response.error));
    else if (response.status == HTTP_UNAUTHORIZED)
        throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
    else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
        throw std::runtime_error(strprintf("server returned HTTP error %d", response.status));
    else if (response.body.empty())
        throw std::runtime_error("no response from server");

    // Parse reply
    UniValue valReply(UniValue::VSTR);
    if (!valReply.read(response.body))
        throw std::runtime_error("couldn't parse reply from server");
    const UniValue& reply = valReply.get_obj();
    if (reply.empty())
        throw std::runtime_error("expected reply to have result, error and id properties");

    return reply;
}
Beispiel #27
0
static int upnpc_send_soap_request(upnpc_device_t * p, const char * url,
                                   const char * service,
                                   const char * method,
                                   const struct upnp_args * args, int arg_count)
{
	char action[128];
	char * body;
	const char fmt_soap[] = 
		"<?xml version=\"1.0\"?>\r\n"
		"<" SOAPPREFIX ":Envelope "
		"xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" "
		SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
		"<" SOAPPREFIX ":Body>"
		"<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">"
		"%s"
		"</" SERVICEPREFIX ":%s>"
		"</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>"
		"\r\n";
	int body_len;
	char hostname[MAXHOSTNAMELEN+1];
	char hostname_port[MAXHOSTNAMELEN+1+6];
	unsigned short port;
	char * path;
	unsigned int scope_id;
	char * args_xml = NULL;
	struct evhttp_request * req;
	struct evkeyvalq * headers;
	struct evbuffer * buffer;

	if(p->state & UPNPC_DEVICE_SOAP_REQ) {
		debug_printf("%s: another SOAP request in progress\n", __func__);
		return UPNPC_ERR_REQ_IN_PROGRESS;
	}

	if(arg_count > 0) {
		int i;
		size_t l, n;
		for(i = 0, l = 0; i < arg_count; i++) {
			/* <ELT>VAL</ELT> */
			l += strlen(args[i].elt) * 2 + strlen(args[i].val) + 5;
		}
		args_xml = malloc(++l);
		if(args_xml == NULL) {
			return -1;
		}
		for(i = 0, n = 0; i < arg_count && n < l; i++) {
			/* <ELT>VAL</ELT> */
			n += snprintf(args_xml + n, l - n, "<%s>%s</%s>",
			              args[i].elt, args[i].val, args[i].elt);
		}
	}

	body_len = snprintf(NULL, 0, fmt_soap, method, service, args_xml?args_xml:"", method);
	body = malloc(body_len + 1);
	if(body == NULL) {
		free(args_xml);
		return -1;
	}
	if(snprintf(body, body_len + 1, fmt_soap, method, service, args_xml?args_xml:"", method) != body_len) {
		debug_printf("%s: snprintf() returned strange value...\n", __func__);
	}
	free(args_xml);
	args_xml = NULL;
	if(!parseURL(url, hostname, &port, &path, &scope_id)) {
		free(body);
		return -1;
	}
	if(port != 80)
		snprintf(hostname_port, sizeof(hostname_port), "%s:%hu", hostname, port);
	else
		strncpy(hostname_port, hostname, sizeof(hostname_port));
	snprintf(action, sizeof(action), "\"%s#%s\"", service, method);
	if(p->soap_conn == NULL) {
		p->soap_conn = evhttp_connection_base_new(p->parent->base, NULL, hostname, port);
	}
	req = evhttp_request_new(upnpc_soap_response, p);
	headers = evhttp_request_get_output_headers(req);
	buffer = evhttp_request_get_output_buffer(req);
	evhttp_add_header(headers, "Host", hostname_port);
	evhttp_add_header(headers, "SOAPAction", action);
	evhttp_add_header(headers, "Content-Type", "text/xml");
	/*evhttp_add_header(headers, "User-Agent", "***");*/
	/*evhttp_add_header(headers, "Cache-Control", "no-cache");*/
	/*evhttp_add_header(headers, "Pragma", "no-cache");*/
	evbuffer_add(buffer, body, body_len);
	evhttp_make_request(p->soap_conn, req, EVHTTP_REQ_POST, path);
	free(body);
	p->state |= UPNPC_DEVICE_SOAP_REQ;
	return 0;
}
Beispiel #28
0
int rpc_call(struct rpc_context *context, 
    const struct rpc_target *dest, const struct method_t *method, 
    rpc_callback client_cb, void *data) {

    //TODO: check the protocol in dest->proto and do http
    // request only if dest->proto == HTTP
    int res = 1;
    struct evhttp_connection *evcon = NULL;
    struct evhttp_request *req = NULL;
    char *json_method = NULL;
    struct client_rpc_callback_with_data *ctx = NULL;

    //TODO: can be make http_connection as part of peer_t?
    evcon = evhttp_connection_base_new(
        context->base, NULL, dest->host, dest->port);
    if (!evcon) {
        goto cleanup;
    }
    ctx = (struct client_rpc_callback_with_data *)malloc(
        sizeof(struct client_rpc_callback_with_data));
    if(!ctx) {
        goto cleanup;
    }
    ctx->cb = client_cb;
    ctx->data = data;
    ctx->evcon = evcon;

    req = evhttp_request_new(http_request_done, ctx);
    if (!req) {
        goto cleanup;
    }

    char uri[256]; 
    snprintf(uri, sizeof(uri)-1, "http://%s:%d/rpc", dest->host, dest->port);
    
    json_method  = serialize_method_call(method);
    if(!json_method) {
        goto cleanup;
    }

    struct evbuffer *output_buffer = evhttp_request_get_output_buffer(req);
    evbuffer_add(output_buffer, json_method, strlen(json_method));

    char content_length[20];
    snprintf(content_length, sizeof(content_length)-1, "%d", (int)strlen(json_method));

    struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
    evhttp_add_header(output_headers, "Host", dest->host);
    evhttp_add_header(output_headers, "Connection", "close");
    evhttp_add_header(output_headers, "Content-Length", content_length);

    printf("Sending req %p with ctx = %p\n", req, ctx);
    int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, uri);
    if(!r) {
        res = 0;
    }

cleanup:
    if(json_method)
        free(json_method);
    if(res && ctx)
        free(ctx);
    if(res && evcon)
        evhttp_connection_free(evcon);
    if(res && req)
        evhttp_request_free(req);

    return res;
}