source: vendor/3.6.23/libcli/echo/echo.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

File size: 6.0 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Echo example async client library
5
6 Copyright (C) 2010 Kai Blin <kai@samba.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "replace.h"
23#include "system/network.h"
24#include <tevent.h>
25#include "lib/tsocket/tsocket.h"
26#include "libcli/util/ntstatus.h"
27#include "libcli/echo/libecho.h"
28#include "lib/util/tevent_ntstatus.h"
29#include "libcli/util/error.h"
30
31/*
32 * Following the Samba convention for async functions, set up a state struct
33 * for this set of calls. The state is always called function_name_state for
34 * the set of async functions related to function_name_send().
35 */
36struct echo_request_state {
37 struct tevent_context *ev;
38 ssize_t orig_len;
39 struct tdgram_context *dgram;
40 char *message;
41};
42
43/* Declare callback functions used below. */
44static void echo_request_get_reply(struct tevent_req *subreq);
45static void echo_request_done(struct tevent_req *subreq);
46
47struct tevent_req *echo_request_send(TALLOC_CTX *mem_ctx,
48 struct tevent_context *ev,
49 const char *server_addr_string,
50 const char *message)
51{
52 struct tevent_req *req, *subreq;
53 struct echo_request_state *state;
54 struct tsocket_address *local_addr, *server_addr;
55 struct tdgram_context *dgram;
56 int ret;
57
58 /*
59 * Creating the initial tevent_req is the only place where returning
60 * NULL is allowed. Everything after that should return a more
61 * meaningful error using tevent_req_post().
62 */
63 req = tevent_req_create(mem_ctx, &state, struct echo_request_state);
64 if (req == NULL) {
65 return NULL;
66 }
67
68 /*
69 * We need to dispatch new async functions in the callbacks, hold
70 * on to the event context.
71 */
72 state->ev = ev;
73
74 /* libecho uses connected UDP sockets, take care of this here */
75 ret = tsocket_address_inet_from_strings(state, "ip", NULL, 0,
76 &local_addr);
77 if (ret != 0) {
78 tevent_req_nterror(req, map_nt_error_from_unix(ret));
79 return tevent_req_post(req, ev);
80 }
81
82 ret = tsocket_address_inet_from_strings(state, "ip", server_addr_string,
83 ECHO_PORT, &server_addr);
84 if (ret != 0) {
85 tevent_req_nterror(req, map_nt_error_from_unix(ret));
86 return tevent_req_post(req, ev);
87 }
88
89 ret = tdgram_inet_udp_socket(local_addr, server_addr, state, &dgram);
90 if (ret != 0) {
91 tevent_req_nterror(req, map_nt_error_from_unix(ret));
92 return tevent_req_post(req, ev);
93 }
94
95 state->dgram = dgram;
96 state->orig_len = strlen(message) + 1;
97
98 /* Start of a subrequest for the actual data sending */
99 subreq = tdgram_sendto_send(state, ev, dgram,
100 (const uint8_t *) message,
101 state->orig_len, NULL);
102 if (tevent_req_nomem(subreq, req)) {
103 return tevent_req_post(req, ev);
104 }
105
106 /*
107 * And tell tevent what to call when the subreq is done. Note that the
108 * original req structure is passed into the callback as callback data.
109 * This is used to get to the state struct in callbacks.
110 */
111 tevent_req_set_callback(subreq, echo_request_get_reply, req);
112 return req;
113}
114
115/*
116 * The following two callbacks both demonstrate the way of getting back the
117 * state struct in a callback function.
118 */
119
120static void echo_request_get_reply(struct tevent_req *subreq)
121{
122 /* Get the parent request struct from the callback data */
123 struct tevent_req *req = tevent_req_callback_data(subreq,
124 struct tevent_req);
125 /* And get the state struct from the parent request struct */
126 struct echo_request_state *state = tevent_req_data(req,
127 struct echo_request_state);
128 ssize_t len;
129 int err = 0;
130
131 len = tdgram_sendto_recv(subreq, &err);
132 TALLOC_FREE(subreq);
133
134 if (len == -1 && err != 0) {
135 tevent_req_nterror(req, map_nt_error_from_unix(err));
136 return;
137 }
138
139 if (len != state->orig_len) {
140 tevent_req_nterror(req, NT_STATUS_UNEXPECTED_NETWORK_ERROR);
141 return;
142 }
143
144 /* Send off the second subreq here, this time to receive the reply */
145 subreq = tdgram_recvfrom_send(state, state->ev, state->dgram);
146 if (tevent_req_nomem(subreq, req)) {
147 return;
148 }
149
150 /* And set the new callback */
151 tevent_req_set_callback(subreq, echo_request_done, req);
152 return;
153}
154
155static void echo_request_done(struct tevent_req *subreq)
156{
157 struct tevent_req *req = tevent_req_callback_data(subreq,
158 struct tevent_req);
159 struct echo_request_state *state = tevent_req_data(req,
160 struct echo_request_state);
161
162 ssize_t len;
163 int err = 0;
164
165 len = tdgram_recvfrom_recv(subreq, &err, state,
166 (uint8_t **)&state->message,
167 NULL);
168 TALLOC_FREE(subreq);
169
170 if (len == -1 && err != 0) {
171 tevent_req_nterror(req, map_nt_error_from_unix(err));
172 return;
173 }
174
175 state->message[len-1] = '\0';
176 /* Once the async function has completed, set tevent_req_done() */
177 tevent_req_done(req);
178}
179
180/*
181 * In the recv function, we usually need to move the data from the state struct
182 * to the memory area owned by the caller. Also, the function
183 * tevent_req_received() is called to take care of freeing the memory still
184 * associated with the request.
185 */
186
187NTSTATUS echo_request_recv(struct tevent_req *req,
188 TALLOC_CTX *mem_ctx,
189 char **message)
190{
191 struct echo_request_state *state = tevent_req_data(req,
192 struct echo_request_state);
193 NTSTATUS status;
194
195 if (tevent_req_is_nterror(req, &status)) {
196 tevent_req_received(req);
197 return status;
198 }
199
200 *message = talloc_move(mem_ctx, &state->message);
201 tevent_req_received(req);
202
203 return NT_STATUS_OK;
204}
Note: See TracBrowser for help on using the repository browser.