s3:rpc_client: add set_timeout hook to rpc_cli_transport
[Samba.git] / source3 / rpc_client / rpc_transport_sock.c
blob1c49412d209b314e65b973d860a2bde19895ba9c
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 static unsigned int rpc_sock_set_timeout(void *priv, unsigned int timeout)
58 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
59 priv, struct rpc_transport_sock_state);
60 int orig_timeout;
61 bool ok;
63 ok = rpc_sock_is_connected(sock_transp);
64 if (!ok) {
65 return 0;
68 orig_timeout = sock_transp->timeout;
70 sock_transp->timeout = timeout;
72 return orig_timeout;
75 struct rpc_sock_read_state {
76 struct rpc_transport_sock_state *transp;
77 ssize_t received;
80 static void rpc_sock_read_done(struct tevent_req *subreq);
82 static struct tevent_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
83 struct event_context *ev,
84 uint8_t *data, size_t size,
85 void *priv)
87 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
88 priv, struct rpc_transport_sock_state);
89 struct tevent_req *req, *subreq;
90 struct rpc_sock_read_state *state;
91 struct timeval endtime;
93 req = tevent_req_create(mem_ctx, &state, struct rpc_sock_read_state);
94 if (req == NULL) {
95 return NULL;
97 if (!rpc_sock_is_connected(sock_transp)) {
98 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
99 return tevent_req_post(req, ev);
101 state->transp = sock_transp;
102 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
103 subreq = async_recv_send(state, ev, sock_transp->fd, data, size, 0);
104 if (subreq == NULL) {
105 goto fail;
108 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
109 goto fail;
112 tevent_req_set_callback(subreq, rpc_sock_read_done, req);
113 return req;
114 fail:
115 TALLOC_FREE(req);
116 return NULL;
119 static void rpc_sock_read_done(struct tevent_req *subreq)
121 struct tevent_req *req = tevent_req_callback_data(
122 subreq, struct tevent_req);
123 struct rpc_sock_read_state *state = tevent_req_data(
124 req, struct rpc_sock_read_state);
125 int err;
127 /* We must free subreq in this function as there is
128 a timer event attached to it. */
130 state->received = async_recv_recv(subreq, &err);
132 if (state->received == -1) {
133 TALLOC_FREE(subreq);
134 rpc_sock_disconnect(state->transp);
135 tevent_req_nterror(req, map_nt_error_from_unix(err));
136 return;
138 TALLOC_FREE(subreq);
139 tevent_req_done(req);
142 static NTSTATUS rpc_sock_read_recv(struct tevent_req *req, ssize_t *preceived)
144 struct rpc_sock_read_state *state = tevent_req_data(
145 req, struct rpc_sock_read_state);
146 NTSTATUS status;
148 if (tevent_req_is_nterror(req, &status)) {
149 return status;
151 *preceived = state->received;
152 return NT_STATUS_OK;
155 struct rpc_sock_write_state {
156 struct rpc_transport_sock_state *transp;
157 ssize_t sent;
160 static void rpc_sock_write_done(struct tevent_req *subreq);
162 static struct tevent_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
163 struct event_context *ev,
164 const uint8_t *data, size_t size,
165 void *priv)
167 struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
168 priv, struct rpc_transport_sock_state);
169 struct tevent_req *req, *subreq;
170 struct rpc_sock_write_state *state;
171 struct timeval endtime;
173 req = tevent_req_create(mem_ctx, &state, struct rpc_sock_write_state);
174 if (req == NULL) {
175 return NULL;
177 if (!rpc_sock_is_connected(sock_transp)) {
178 tevent_req_nterror(req, NT_STATUS_CONNECTION_INVALID);
179 return tevent_req_post(req, ev);
181 state->transp = sock_transp;
182 endtime = timeval_current_ofs(0, sock_transp->timeout * 1000);
183 subreq = async_send_send(state, ev, sock_transp->fd, data, size, 0);
184 if (subreq == NULL) {
185 goto fail;
188 if (!tevent_req_set_endtime(subreq, ev, endtime)) {
189 goto fail;
192 tevent_req_set_callback(subreq, rpc_sock_write_done, req);
193 return req;
194 fail:
195 TALLOC_FREE(req);
196 return NULL;
199 static void rpc_sock_write_done(struct tevent_req *subreq)
201 struct tevent_req *req = tevent_req_callback_data(
202 subreq, struct tevent_req);
203 struct rpc_sock_write_state *state = tevent_req_data(
204 req, struct rpc_sock_write_state);
205 int err;
207 /* We must free subreq in this function as there is
208 a timer event attached to it. */
210 state->sent = async_send_recv(subreq, &err);
212 if (state->sent == -1) {
213 TALLOC_FREE(subreq);
214 rpc_sock_disconnect(state->transp);
215 tevent_req_nterror(req, map_nt_error_from_unix(err));
216 return;
218 TALLOC_FREE(subreq);
219 tevent_req_done(req);
222 static NTSTATUS rpc_sock_write_recv(struct tevent_req *req, ssize_t *psent)
224 struct rpc_sock_write_state *state = tevent_req_data(
225 req, struct rpc_sock_write_state);
226 NTSTATUS status;
228 if (tevent_req_is_nterror(req, &status)) {
229 return status;
231 *psent = state->sent;
232 return NT_STATUS_OK;
235 NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
236 struct rpc_cli_transport **presult)
238 struct rpc_cli_transport *result;
239 struct rpc_transport_sock_state *state;
241 result = talloc(mem_ctx, struct rpc_cli_transport);
242 if (result == NULL) {
243 return NT_STATUS_NO_MEMORY;
245 state = talloc(result, struct rpc_transport_sock_state);
246 if (state == NULL) {
247 TALLOC_FREE(result);
248 return NT_STATUS_NO_MEMORY;
250 result->priv = state;
252 state->fd = fd;
253 state->timeout = 10000; /* 10 seconds. */
254 talloc_set_destructor(state, rpc_transport_sock_state_destructor);
256 result->trans_send = NULL;
257 result->trans_recv = NULL;
258 result->write_send = rpc_sock_write_send;
259 result->write_recv = rpc_sock_write_recv;
260 result->read_send = rpc_sock_read_send;
261 result->read_recv = rpc_sock_read_recv;
262 result->is_connected = rpc_sock_is_connected;
263 result->set_timeout = rpc_sock_set_timeout;
265 *presult = result;
266 return NT_STATUS_OK;
269 int rpccli_set_sock_timeout(struct rpc_pipe_client *cli, int timeout)
271 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
272 struct rpc_transport_sock_state);
273 int orig_timeout;
274 if (!state) {
275 return 0;
277 orig_timeout = state->timeout;
278 state->timeout = timeout;
279 return orig_timeout;
282 void rpccli_close_sock_fd(struct rpc_pipe_client *cli)
284 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
285 struct rpc_transport_sock_state);
286 if (state) {
287 if (state->fd != -1) {
288 close(state->fd);
289 state->fd = -1;
292 return;
295 bool rpc_pipe_tcp_connection_ok(struct rpc_pipe_client *cli)
297 struct rpc_transport_sock_state *state = talloc_get_type(cli->transport->priv,
298 struct rpc_transport_sock_state);
299 if (state && state->fd != -1) {
300 return true;
303 return false;