Пример #1
0
/* This will immediately close a server socket and clean out any pending
 * requests that are waiting on that socket.
 * */
void force_disconnect(jsonrpc_server_t* server)
{
	if(!server) {
		ERR("Trying to disconnect a NULL server.\n");
		return;
	}

	// clear the netstring buffer when disconnecting
	free_netstring(server->buffer);
	server->buffer = NULL;

	server->status = JSONRPC_SERVER_DISCONNECTED;

	// close bufferevent
	bev_disconnect(server->bev);
	INFO("Disconnected from server %.*s:%d for conn %.*s.\n",
			STR(server->addr), server->port, STR(server->conn));


	/* clean out requests */
	jsonrpc_request_t* req = NULL;
	int key = 0;
	for (key=0; key < JSONRPC_DEFAULT_HTABLE_SIZE; key++) {
		for (req = request_table[key]; req != NULL; req = req->next) {
			if(req->server != NULL && req->server == server) {
				fail_request(JRPC_ERR_SERVER_DISCONNECT, req,
						"Failing request for server shutdown");
			}
		}
	}
}
Пример #2
0
void timeout_cb(int fd, short event, void *arg)
{
	jsonrpc_request_t* req = (jsonrpc_request_t*)arg;
	if(!req)
		return;

	if(!(req->server)) {
		ERR("No server defined for request\n");
		return;
	}

	if(schedule_retry(req)<0) {
		fail_request(JRPC_ERR_TIMEOUT, req, "Request timeout");
	}
}
Пример #3
0
void retry_cb(int fd, short event, void* arg)
{
	if(!arg)
		return;

	jsonrpc_request_t* req = (jsonrpc_request_t*)arg;

	if(!(req->cmd)) {
		ERR("request has no cmd\n");
		goto error;
	}

	DEBUG("retrying request: id=%d\n", req->id);

	if(jsonrpc_send(req->cmd->conn, req, 0)<0) {
		goto error;
	}

	CHECK_AND_FREE_EV(req->retry_ev);
	return;

error:
	fail_request(JRPC_ERR_SEND, req, "Retry failed to send request");
}
Пример #4
0
int handle_response(json_t* response)
{
	int retval = 0;
	jsonrpc_request_t* req = NULL;
	json_t* return_obj = NULL;
	json_t* internal = NULL;
	char* freeme = NULL;


	/* check if json object */
	if(!json_is_object(response)){
		WARN("jsonrpc response is not an object\n");
		return -1;
	}

	/* check version */
	json_t* version = json_object_get(response, "jsonrpc");
	if(!version) {
		WARN("jsonrpc response does not have a version.\n");
		retval = -1;
		goto end;
	}

	const char* version_s = json_string_value(version);
	if(!version_s){
		WARN("jsonrpc response version is not a string.\n");
		retval = -1;
		goto end;
	}

	if (strlen(version_s) != (sizeof(JSONRPC_VERSION)-1)
			|| strncmp(version_s, JSONRPC_VERSION, sizeof(JSONRPC_VERSION)-1) != 0) {
		WARN("jsonrpc response version is not %s. version: %s\n",
				JSONRPC_VERSION, version_s);
		retval = -1;
		goto end;
	}

	/* check for an id */
	json_t* _id = json_object_get(response, "id");
	if(!_id) {
		WARN("jsonrpc response does not have an id.\n");
		retval = -1;
		goto end;
	}

	int id = json_integer_value(_id);
	if (!(req = pop_request(id))) {
		/* don't fail the server for an unrecognized id */
		retval = 0;
		goto end;
	}

	return_obj = json_object();

	json_t* error = json_object_get(response, "error");
	// if the error value is null, we don't care
	bool _error = error && (json_typeof(error) != JSON_NULL);

	json_t* result = json_object_get(response, "result");

	if(_error) {
		json_object_set(return_obj, "error", error);
	}

	if(result) {
		json_object_set(return_obj, "result", result);
	}

	if ((!result && !_error) || (result && _error)) {
		WARN("bad response\n");
		internal = internal_error(JRPC_ERR_BAD_RESP, req->payload);
		json_object_update(return_obj, internal);
		if(internal) json_decref(internal);
	}

	pv_value_t val;

	if(jsontoval(&val, &freeme, return_obj)<0) {
		fail_request(
				JRPC_ERR_TO_VAL,
				req,
				"Failed to convert response json to pv\n");
		retval = -1;
		goto end;
	}

	char* error_s = NULL;

	if(send_to_script(&val, req->cmd)>=0) {
		goto free_and_end;
	}

	if(_error) {
		// get code from error
		json_t* _code = json_object_get(error, "code");
		if(_code) {
			int code = json_integer_value(_code);

			// check if code is in global_retry_ranges
			retry_range_t* tmpr;
			for(tmpr = global_retry_ranges;
					tmpr != NULL;
					tmpr = tmpr->next) {
				if((tmpr->start < tmpr->end
						&& tmpr->start <= code && code <= tmpr->end)
				|| (tmpr->end < tmpr->start
						&& tmpr->end <= code && code <= tmpr->start)
				|| (tmpr->start == tmpr->end && tmpr->start == code)) {
					if(schedule_retry(req)==0) {
						goto end;
					}
					break;
				}
			}

		}
		error_s = json_dumps(error, JSON_COMPACT);
		if(error_s) {
			WARN("Request received an error: \n%s\n", error_s);
			free(error_s);
		} else {
			fail_request(
					JRPC_ERR_BAD_RESP,
					req,
					"Could not convert 'error' response to string");
			retval = -1;
			goto end;
		}
	}


free_and_end:
	free_req_cmd(req->cmd);
	free_request(req);

end:
	if(freeme) free(freeme);
	if(return_obj) json_decref(return_obj);
	return retval;
}
Пример #5
0
void cmd_pipe_cb(int fd, short event, void *arg)
{
	struct jsonrpc_pipe_cmd *cmd;

	if (read(fd, &cmd, sizeof(cmd)) != sizeof(cmd)) {
		ERR("FATAL ERROR: failed to read from command pipe: %s\n",
				strerror(errno));
		return;
	}


	switch(cmd->type) {
	case CMD_CLOSE:
		if(cmd->server) {
			wait_close(cmd->server);
		}
		goto end;
		break;
	case CMD_RECONNECT:
		if(cmd->server) {
			wait_reconnect(cmd->server);
		}
		goto end;
		break;
	case CMD_CONNECT:
		if(cmd->server) {
			bev_connect(cmd->server);
		}
		goto end;
		break;
	case CMD_UPDATE_SERVER_GROUP:
		if(cmd->new_grp) {
			jsonrpc_server_group_t* old_grp = *global_server_group;
			*global_server_group = cmd->new_grp;
			free_server_group(&old_grp);
		}
		lock_release(jsonrpc_server_group_lock);
		goto end;
		break;

	case CMD_SEND:
		break;

	default:
		ERR("Unrecognized pipe command: %d\n", cmd->type);
		goto end;
		break;
	}

	/* command is SEND */

	jsonrpc_req_cmd_t* req_cmd = cmd->req_cmd;
	if(req_cmd == NULL) {
		ERR("req_cmd is NULL. Invalid send command\n");
		goto end;
	}

	jsonrpc_request_t* req = NULL;
	req = create_request(req_cmd);
	if (!req || !req->payload) {
		json_t* error = internal_error(JRPC_ERR_REQ_BUILD, NULL);
		pv_value_t val;
		char* freeme = NULL;
		jsontoval(&val, &freeme, error);
		if(req_cmd->route.len <=0 && send_to_script(&val, req_cmd)<0) {
			ERR("Failed to build request (method: %.*s, params: %.*s)\n",
					STR(req_cmd->method), STR(req_cmd->params));
		}
		if(freeme) free(freeme);
		if(error) json_decref(error);
		free_req_cmd(req_cmd);
		goto end;
	}

	int sent = jsonrpc_send(req_cmd->conn, req, req_cmd->notify_only);

	char* type;
	if (sent<0) {
		if (req_cmd->notify_only == false) {
			type = "Request";
		} else {
			type = "Notification";
		}
		WARN("%s could not be sent to connection group: %.*s\n",
				type, STR(req_cmd->conn));
		fail_request(JRPC_ERR_SEND, req, "Failed to send request");
	}

end:
	free_pipe_cmd(cmd);
}
Пример #6
0
int jsonrpc_send(str conn, jsonrpc_request_t* req, bool notify_only)
{
	char* json = (char*)json_dumps(req->payload, JSON_COMPACT);

	char* ns;
	size_t bytes;
	bytes = netstring_encode_new(&ns, json, (size_t)strlen(json));

	bool sent = false;
	jsonrpc_server_group_t* c_grp = NULL;
	if(global_server_group != NULL)
		c_grp = *global_server_group;
	jsonrpc_server_group_t* p_grp = NULL;
	jsonrpc_server_group_t* w_grp = NULL;
	jsonrpc_server_t* s = NULL;
	server_list_t* tried_servers = NULL;
	DEBUG("SENDING DATA\n");
	for(; c_grp != NULL; c_grp = c_grp->next) {

		if(strncmp(conn.s, c_grp->conn.s, c_grp->conn.len) != 0) continue;

		for(p_grp = c_grp->sub_group; p_grp != NULL; p_grp = p_grp->next)
		{
			w_grp = p_grp->sub_group;
			while(!sent) {
				loadbalance_by_weight(&s, w_grp, tried_servers);
				if (s == NULL || s->status != JSONRPC_SERVER_CONNECTED) {
					break;
				}

				if(bufferevent_write(s->bev, ns, bytes) == 0) {
					sent = true;
					if(!notify_only) {
						s->req_count++;
						if (s->hwm > 0 && s->req_count >= s->hwm) {
							WARN("%.*s:%d in connection group %.*s has exceeded its high water mark (%d)\n",
									STR(s->addr), s->port,
									STR(s->conn), s->hwm);
						}
					}
					req->server = s;
					break;
				} else {
					addto_server_list(s, &tried_servers);
				}
			}

			if (sent) {
				break;
			}

			WARN("Failed to send to priority group, %d\n", p_grp->priority);
			if(p_grp->next != NULL) {
				INFO("Proceeding to next priority group, %d\n",
						p_grp->next->priority);
			}
		}

		if (sent) {
			break;
		}

	}

	if(!sent) {
		WARN("Failed to send to connection group, \"%.*s\"\n",
				STR(conn));
		if(schedule_retry(req)<0) {
			fail_request(JRPC_ERR_RETRY, req, "Failed to schedule retry");
		}
	}

	free_server_list(tried_servers);
	if(ns) pkg_free(ns);
	if(json) free(json);

	if (sent && notify_only == false) {

		const struct timeval tv = ms_to_tv(req->timeout);

		req->timeout_ev = evtimer_new(global_ev_base, timeout_cb, (void*)req);
		if(event_add(req->timeout_ev, &tv)<0) {
			ERR("event_add failed while setting request timer (%s).",
					strerror(errno));
			return -1;
		}
	}

	return sent;
}