Add an async helper function to connect an rpc context to a program/version
parent
3b943d2f68
commit
8733f38d23
|
@ -78,6 +78,21 @@ void rpc_set_next_xid(struct rpc_context *rpc, uint32_t xid);
|
|||
* : data is NULL.
|
||||
*/
|
||||
int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc_cb cb, void *private_data);
|
||||
/*
|
||||
* Async function to connect to a specific RPC program/version
|
||||
* Function returns
|
||||
* 0 : The connection was initiated. Once the connection establish finishes, the callback will be invoked.
|
||||
* <0 : An error occured when trying to set up the connection. The callback will not be invoked.
|
||||
*
|
||||
* When the callback is invoked, status indicates the result:
|
||||
* RPC_STATUS_SUCCESS : The tcp connection was successfully established.
|
||||
* data is NULL.
|
||||
* RPC_STATUS_ERROR : The connection failed to establish.
|
||||
* data is the erro string.
|
||||
* RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete.
|
||||
* : data is NULL.
|
||||
*/
|
||||
int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data);
|
||||
/*
|
||||
* When disconnecting a connection in flight. All commands in flight will be called with the callback
|
||||
* and status RPC_STATUS_ERROR. Data will be the error string for the disconnection.
|
||||
|
|
149
lib/libnfs.c
149
lib/libnfs.c
|
@ -219,6 +219,155 @@ void nfs_destroy_context(struct nfs_context *nfs)
|
|||
free(nfs);
|
||||
}
|
||||
|
||||
struct rpc_cb_data {
|
||||
char *server;
|
||||
uint32_t program;
|
||||
uint32_t version;
|
||||
|
||||
rpc_cb cb;
|
||||
void *private_data;
|
||||
};
|
||||
|
||||
void free_rpc_cb_data(struct rpc_cb_data *data)
|
||||
{
|
||||
free(data->server);
|
||||
data->server = NULL;
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
{
|
||||
struct rpc_cb_data *data = private_data;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
/* Dont want any more callbacks even if the socket is closed */
|
||||
rpc->connect_cb = NULL;
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
if (status == RPC_STATUS_CANCEL) {
|
||||
data->cb(rpc, status, "Command was cancelled", data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
data->cb(rpc, status, NULL, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
}
|
||||
|
||||
static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
{
|
||||
struct rpc_cb_data *data = private_data;
|
||||
uint32_t rpc_port;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
if (status == RPC_STATUS_CANCEL) {
|
||||
data->cb(rpc, status, "Command was cancelled", data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
rpc_port = *(uint32_t *)command_data;
|
||||
if (rpc_port == 0) {
|
||||
rpc_set_error(rpc, "RPC error. Program is not available on %s", data->server);
|
||||
data->cb(rpc, RPC_STATUS_ERROR, rpc_get_error(rpc), data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
rpc_disconnect(rpc, "normal disconnect");
|
||||
if (rpc_connect_async(rpc, data->server, rpc_port, rpc_connect_program_4_cb, data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
{
|
||||
struct rpc_cb_data *data = private_data;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
if (status == RPC_STATUS_CANCEL) {
|
||||
data->cb(rpc, status, "Command was cancelled", data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
|
||||
{
|
||||
struct rpc_cb_data *data = private_data;
|
||||
|
||||
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||
|
||||
/* Dont want any more callbacks even if the socket is closed */
|
||||
rpc->connect_cb = NULL;
|
||||
|
||||
if (status == RPC_STATUS_ERROR) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
if (status == RPC_STATUS_CANCEL) {
|
||||
data->cb(rpc, status, "Command was cancelled", data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
|
||||
data->cb(rpc, status, command_data, data->private_data);
|
||||
free_rpc_cb_data(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data)
|
||||
{
|
||||
struct rpc_cb_data *data;
|
||||
|
||||
data = malloc(sizeof(struct rpc_cb_data));
|
||||
if (data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
memset(data, 0, sizeof(struct rpc_cb_data));
|
||||
data->server = strdup(server);
|
||||
data->program = program;
|
||||
data->version = version;
|
||||
|
||||
data->cb = cb;
|
||||
data->private_data = private_data;
|
||||
|
||||
if (rpc_connect_async(rpc, server, 111, rpc_connect_program_1_cb, data) != 0) {
|
||||
rpc_set_error(rpc, "Failed to start connection");
|
||||
free_rpc_cb_data(data);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_nfs_cb_data(struct nfs_cb_data *data)
|
||||
{
|
||||
if (data->saved_path != NULL) {
|
||||
|
|
Loading…
Reference in New Issue