tsocket: optimize tdgram_bsd a lot
[ira/wip.git] / lib / tsocket / tsocket_recvfrom.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_recvfrom_state {
30         /* this structs are owned by the caller */
31         struct {
32                 struct tsocket_context *sock;
33         } caller;
34
35         uint8_t *buf;
36         size_t len;
37         struct tsocket_address *src;
38 };
39
40 static int tsocket_recvfrom_state_destructor(struct tsocket_recvfrom_state *state)
41 {
42         if (state->caller.sock) {
43                 tsocket_set_readable_handler(state->caller.sock, NULL, NULL);
44         }
45         ZERO_STRUCT(state->caller);
46
47         return 0;
48 }
49
50 static void tsocket_recvfrom_handler(struct tsocket_context *sock,
51                                      void *private_data);
52
53 struct tevent_req *tsocket_recvfrom_send(struct tsocket_context *sock,
54                                          TALLOC_CTX *mem_ctx)
55 {
56         struct tevent_req *req;
57         struct tsocket_recvfrom_state *state;
58         int ret;
59         int err;
60         bool dummy;
61
62         req = tevent_req_create(mem_ctx, &state,
63                                 struct tsocket_recvfrom_state);
64         if (!req) {
65                 return NULL;
66         }
67
68         state->caller.sock      = sock;
69         state->buf              = NULL;
70         state->len              = 0;
71         state->src              = NULL;
72
73         talloc_set_destructor(state, tsocket_recvfrom_state_destructor);
74
75         ret = tsocket_set_readable_handler(sock,
76                                            tsocket_recvfrom_handler,
77                                            req);
78         err = tsocket_error_from_errno(ret, errno, &dummy);
79         if (tevent_req_error(req, err)) {
80                 goto post;
81         }
82
83         return req;
84
85  post:
86         return tevent_req_post(req, sock->event.ctx);
87 }
88
89 static void tsocket_recvfrom_handler(struct tsocket_context *sock,
90                                      void *private_data)
91 {
92         struct tevent_req *req = talloc_get_type(private_data,
93                                  struct tevent_req);
94         struct tsocket_recvfrom_state *state = tevent_req_data(req,
95                                                struct tsocket_recvfrom_state);
96         ssize_t ret;
97         int err;
98         bool retry;
99
100         ret = tsocket_pending(state->caller.sock);
101         if (ret == 0) {
102                 /* retry later */
103                 return;
104         }
105         err = tsocket_error_from_errno(ret, errno, &retry);
106         if (retry) {
107                 /* retry later */
108                 return;
109         }
110         if (tevent_req_error(req, err)) {
111                 return;
112         }
113
114         state->buf = talloc_array(state, uint8_t, ret);
115         if (tevent_req_nomem(state->buf, req)) {
116                 return;
117         }
118         state->len = ret;
119
120         ret = tsocket_recvfrom(state->caller.sock,
121                                state->buf,
122                                state->len,
123                                state,
124                                &state->src);
125         err = tsocket_error_from_errno(ret, errno, &retry);
126         if (retry) {
127                 /* retry later */
128                 return;
129         }
130         if (tevent_req_error(req, err)) {
131                 return;
132         }
133
134         if (ret != state->len) {
135                 tevent_req_error(req, EIO);
136                 return;
137         }
138
139         tevent_req_done(req);
140 }
141
142 ssize_t tsocket_recvfrom_recv(struct tevent_req *req,
143                               int *perrno,
144                               TALLOC_CTX *mem_ctx,
145                               uint8_t **buf,
146                               struct tsocket_address **src)
147 {
148         struct tsocket_recvfrom_state *state = tevent_req_data(req,
149                                                struct tsocket_recvfrom_state);
150         ssize_t ret;
151
152         ret = tsocket_simple_int_recv(req, perrno);
153         if (ret == 0) {
154                 *buf = talloc_move(mem_ctx, &state->buf);
155                 ret = state->len;
156                 if (src) {
157                         *src = talloc_move(mem_ctx, &state->src);
158                 }
159         }
160
161         tevent_req_received(req);
162         return ret;
163 }
164