lib/tsocket: add tsocket_sendto_send/recv()
[ira/wip.git] / lib / tsocket / tsocket_sendto.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2009
5
6      ** NOTE! The following LGPL license applies to the tevent
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 3 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "replace.h"
25 #include "system/network.h"
26 #include "tsocket.h"
27 #include "tsocket_internal.h"
28
29 struct tsocket_sendto_state {
30         /* this structs are owned by the caller */
31         struct {
32                 struct tsocket_context *sock;
33                 const uint8_t *buf;
34                 size_t len;
35                 const struct tsocket_address *dst;
36         } caller;
37
38         ssize_t ret;
39 };
40
41 static int tsocket_sendto_state_destructor(struct tsocket_sendto_state *state)
42 {
43         if (state->caller.sock) {
44                 tsocket_set_writeable_handler(state->caller.sock, NULL, NULL);
45         }
46         ZERO_STRUCT(state->caller);
47
48         return 0;
49 }
50
51 static void tsocket_sendto_handler(struct tsocket_context *sock,
52                                    void *private_data);
53
54 struct tevent_req *tsocket_sendto_send(struct tsocket_context *sock,
55                                        TALLOC_CTX *mem_ctx,
56                                        const uint8_t *buf,
57                                        size_t len,
58                                        const struct tsocket_address *dst)
59 {
60         struct tevent_req *req;
61         struct tsocket_sendto_state *state;
62         int ret;
63         int err;
64         bool dummy;
65
66         req = tevent_req_create(mem_ctx, &state,
67                                 struct tsocket_sendto_state);
68         if (!req) {
69                 return NULL;
70         }
71
72         state->caller.sock      = sock;
73         state->caller.buf       = buf;
74         state->caller.len       = len;
75         state->caller.dst       = dst;
76         state->ret              = -1;
77
78         talloc_set_destructor(state, tsocket_sendto_state_destructor);
79
80         ret = tsocket_set_writeable_handler(sock,
81                                             tsocket_sendto_handler,
82                                             req);
83         err = tsocket_error_from_errno(ret, errno, &dummy);
84         if (tevent_req_error(req, err)) {
85                 goto post;
86         }
87
88         return req;
89
90  post:
91         return tevent_req_post(req, sock->event.ctx);
92 }
93
94 static void tsocket_sendto_handler(struct tsocket_context *sock,
95                                    void *private_data)
96 {
97         struct tevent_req *req = talloc_get_type(private_data,
98                                  struct tevent_req);
99         struct tsocket_sendto_state *state = tevent_req_data(req,
100                                              struct tsocket_sendto_state);
101         ssize_t ret;
102         int err;
103         bool retry;
104
105         ret = tsocket_sendto(state->caller.sock,
106                              state->caller.buf,
107                              state->caller.len,
108                              state->caller.dst);
109         err = tsocket_error_from_errno(ret, errno, &retry);
110         if (retry) {
111                 /* retry later */
112                 return;
113         }
114         if (tevent_req_error(req, err)) {
115                 return;
116         }
117
118         state->ret = ret;
119
120         tevent_req_done(req);
121 }
122
123 ssize_t tsocket_sendto_recv(struct tevent_req *req, int *perrno)
124 {
125         struct tsocket_sendto_state *state = tevent_req_data(req,
126                                              struct tsocket_sendto_state);
127         ssize_t ret;
128
129         ret = tsocket_simple_int_recv(req, perrno);
130         if (ret == 0) {
131                 ret = state->ret;
132         }
133
134         tevent_req_received(req);
135         return ret;
136 }