s3:rpc_client: add rpccli_is_connected()
[Samba.git] / source3 / rpc_client / rpc_transport_sock.c
blob5132504a85f24c4d4cdd1d89a9a30abde5842460
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC client transport over a socket
4 * Copyright (C) Volker Lendecke 2009
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
22 #undef DBGC_CLASS
23 #define DBGC_CLASS DBGC_RPC_CLI
25 struct rpc_transport_sock_state {
26 int fd;
27 int timeout;
30 static void rpc_sock_disconnect(struct rpc_transport_sock_state *s)
32 if (s->fd != -1) {
33 close(s->fd);
34 s->fd = -1;
38 static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
40 rpc_sock_disconnect(s);
41 return 0;
44 static bool rpc_sock_is_connected(void *priv)
46 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
47 priv, struct rpc_transport_sock_state);
49 if (sock_transp->fd == -1) {
50 return false;
53 return true;
56 struct rpc_sock_read_state {
57 struct rpc_transport_sock_state *transp;
58 ssize_t received;
61 static void rpc_sock_read_done(struct tevent_req *subreq);
63 static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
64 struct event_context *ev,
65 uint8_t *data, size_t size,
66 void *priv)
68 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
69 priv, struct rpc_transport_sock_state);
70 struct tevent_req *req, *subreq;
71 struct rpc_sock_read_state *state;
72 struct timeval endtime;
74 req = tevent_req_create(mem_ctx, &state, struct rpc_sock_read_state);
75 if (req == NULL) {
76 return NULL;
78 if (!rpc_sock_is_connected(sock_transp)) {
79 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
80 return tevent_req_post(req, ev);
82 state->transp = sock_transp;
83 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
84 subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
85 if (subreq == NULL) {
86 goto fail;
89 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
90 goto fail;
93 tevent_req_set_callback(subreq, rpc_sock_read_done, req);
94 return req;
95 fail:
96 TALLOC_FREE(req);
97 return NULL;
100 static void rpc_sock_read_done(struct tevent_req *subreq)
102 struct tevent_req *req = tevent_req_callback_data(
103 subreq, struct tevent_req);
104 struct rpc_sock_read_state *state = tevent_req_data(
105 req, struct rpc_sock_read_state);
106 int err;
108 /* We must free subreq in this function as there is
109 a timer event attached to it. */
111 state->received = async_recv_recv(subreq, &err);
113 if (state->received == -1) {
114 TALLOC_FREE(subreq);
115 rpc_sock_disconnect(state->transp);
116 tevent_req_nterror(req, map_nt_error_from_unix(err));
117 return;
119 TALLOC_FREE(subreq);
120 tevent_req_done(req);
123 static NTSTATUS rpc_sock_read_recv(struct tevent_req *req, ssize_t *preceived)
125 struct rpc_sock_read_state *state = tevent_req_data(
126 req, struct rpc_sock_read_state);
127 NTSTATUS status;
129 if (tevent_req_is_nterror(req, &status)) {
130 return status;
132 *preceived = state->received;
133 return NT_STATUS_OK;
136 struct rpc_sock_write_state {
137 struct rpc_transport_sock_state *transp;
138 ssize_t sent;
141 static void rpc_sock_write_done(struct tevent_req *subreq);
143 static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
144 struct event_context *ev,
145 const uint8_t *data, size_t size,
146 void *priv)
148 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
149 priv, struct rpc_transport_sock_state);
150 struct tevent_req *req, *subreq;
151 struct rpc_sock_write_state *state;
152 struct timeval endtime;
154 req = tevent_req_create(mem_ctx, &state, struct rpc_sock_write_state);
155 if (req == NULL) {
156 return NULL;
158 if (!rpc_sock_is_connected(sock_transp)) {
159 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
160 return tevent_req_post(req, ev);
162 state->transp = sock_transp;
163 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
164 subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
165 if (subreq == NULL) {
166 goto fail;
169 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
170 goto fail;
173 tevent_req_set_callback(subreq, rpc_sock_write_done, req);
174 return req;
175 fail:
176 TALLOC_FREE(req);
177 return NULL;
180 static void rpc_sock_write_done(struct tevent_req *subreq)
182 struct tevent_req *req = tevent_req_callback_data(
183 subreq, struct tevent_req);
184 struct rpc_sock_write_state *state = tevent_req_data(
185 req, struct rpc_sock_write_state);
186 int err;
188 /* We must free subreq in this function as there is
189 a timer event attached to it. */
191 state->sent = async_send_recv(subreq, &err);
193 if (state->sent == -1) {
194 TALLOC_FREE(subreq);
195 rpc_sock_disconnect(state->transp);
196 tevent_req_nterror(req, map_nt_error_from_unix(err));
197 return;
199 TALLOC_FREE(subreq);
200 tevent_req_done(req);
203 static NTSTATUS rpc_sock_write_recv(struct tevent_req *req, ssize_t *psent)
205 struct rpc_sock_write_state *state = tevent_req_data(
206 req, struct rpc_sock_write_state);
207 NTSTATUS status;
209 if (tevent_req_is_nterror(req, &status)) {
210 return status;
212 *psent = state->sent;
213 return NT_STATUS_OK;
216 NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
217 struct rpc_cli_transport **presult)
219 struct rpc_cli_transport *result;
220 struct rpc_transport_sock_state *state;
222 result = talloc(mem_ctx, struct rpc_cli_transport);
223 if (result == NULL) {
224 return NT_STATUS_NO_MEMORY;
226 state = talloc(result, struct rpc_transport_sock_state);
227 if (state == NULL) {
228 TALLOC_FREE(result);
229 return NT_STATUS_NO_MEMORY;
231 result->priv = state;
233 state->fd = fd;
234 state->timeout = 10000; /* 10 seconds. */
235 talloc_set_destructor(state, rpc_transport_sock_state_destructor);
237 result->trans_send = NULL;
238 result->trans_recv = NULL;
239 result->write_send = rpc_sock_write_send;
240 result->write_recv = rpc_sock_write_recv;
241 result->read_send = rpc_sock_read_send;
242 result->read_recv = rpc_sock_read_recv;
243 result->is_connected = rpc_sock_is_connected;
245 *presult = result;
246 return NT_STATUS_OK;
249 int rpccli_set_sock_timeout(struct rpc_pipe_client *cli, int timeout)
251 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
252 struct rpc_transport_sock_state);
253 int orig_timeout;
254 if (!state) {
255 return 0;
257 orig_timeout = state->timeout;
258 state->timeout = timeout;
259 return orig_timeout;
262 void rpccli_close_sock_fd(struct rpc_pipe_client *cli)
264 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
265 struct rpc_transport_sock_state);
266 if (state) {
267 if (state->fd != -1) {
268 close(state->fd);
269 state->fd = -1;
272 return;
275 bool rpc_pipe_tcp_connection_ok(struct rpc_pipe_client *cli)
277 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
278 struct rpc_transport_sock_state);
279 if (state && state->fd != -1) {
280 return true;
283 return false;