s3: Convert cli_oplock_break_waiter to smbXcli
[metze/samba/wip.git] / source3 / libsmb / clioplock.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB client oplock functions
4    Copyright (C) Andrew Tridgell 2001
5
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.
10
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.
15
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/>.
18 */
19
20 #include "includes.h"
21 #include "../lib/util/tevent_ntstatus.h"
22 #include "async_smb.h"
23 #include "libsmb/libsmb.h"
24 #include "../libcli/smb/smbXcli_base.h"
25
26 struct cli_smb_oplock_break_waiter_state {
27         uint16_t fnum;
28         uint8_t level;
29 };
30
31 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq);
32
33 struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx,
34                                                     struct event_context *ev,
35                                                     struct cli_state *cli)
36 {
37         struct tevent_req *req, *subreq;
38         struct cli_smb_oplock_break_waiter_state *state;
39
40         req = tevent_req_create(mem_ctx, &state,
41                                 struct cli_smb_oplock_break_waiter_state);
42         if (req == NULL) {
43                 return NULL;
44         }
45
46         /*
47          * Create a fake SMB request that we will never send out. This is only
48          * used to be set into the pending queue with the right mid.
49          */
50         subreq = smb1cli_req_create(mem_ctx, ev, cli->conn, 0, 0, 0, 0, 0, 0,
51                                     0, NULL, NULL, 0, NULL, 0, NULL);
52         if (tevent_req_nomem(subreq, req)) {
53                 return tevent_req_post(req, ev);
54         }
55         smb1cli_req_set_mid(subreq, 0xffff);
56
57         if (!smbXcli_req_set_pending(subreq)) {
58                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
59                 return tevent_req_post(req, ev);
60         }
61         tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req);
62         return req;
63 }
64
65 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq)
66 {
67         struct tevent_req *req = tevent_req_callback_data(
68                 subreq, struct tevent_req);
69         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
70                 req, struct cli_smb_oplock_break_waiter_state);
71         struct iovec *iov;
72         uint8_t wct;
73         uint16_t *vwv;
74         NTSTATUS status;
75
76         status = smb1cli_req_recv(subreq, state,
77                                   &iov, /* piov */
78                                   NULL, /* phdr */
79                                   &wct,
80                                   &vwv,
81                                   NULL, /* pvwv_offset */
82                                   NULL, /* pnum_bytes */
83                                   NULL, /* pbytes */
84                                   NULL, /* pbytes_offset */
85                                   NULL, /* pinbuf */
86                                   NULL, 0); /* expected */
87         TALLOC_FREE(subreq);
88         if (!NT_STATUS_IS_OK(status)) {
89                 tevent_req_nterror(req, status);
90                 return;
91         }
92         if (wct < 8) {
93                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
94                 return;
95         }
96         state->fnum = SVAL(vwv+2, 0);
97         state->level = CVAL(vwv+3, 1);
98         tevent_req_done(req);
99 }
100
101 NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req,
102                                           uint16_t *pfnum,
103                                           uint8_t *plevel)
104 {
105         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
106                 req, struct cli_smb_oplock_break_waiter_state);
107         NTSTATUS status;
108
109         if (tevent_req_is_nterror(req, &status)) {
110                 return status;
111         }
112         *pfnum = state->fnum;
113         *plevel = state->level;
114         return NT_STATUS_OK;
115 }
116
117 /****************************************************************************
118 send an ack for an oplock break request
119 ****************************************************************************/
120
121 struct cli_oplock_ack_state {
122         uint16_t vwv[8];
123 };
124
125 static void cli_oplock_ack_done(struct tevent_req *subreq);
126
127 struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx,
128                                        struct tevent_context *ev,
129                                        struct cli_state *cli,
130                                        uint16_t fnum, uint8_t level)
131 {
132         struct tevent_req *req, *subreq;
133         struct cli_oplock_ack_state *state;
134
135         req = tevent_req_create(mem_ctx, &state, struct cli_oplock_ack_state);
136         if (req == NULL) {
137                 return NULL;
138         }
139         SCVAL(state->vwv+0, 0, 0xff);
140         SCVAL(state->vwv+0, 1, 0);
141         SSVAL(state->vwv+1, 0, 0);
142         SSVAL(state->vwv+2, 0, fnum);
143         SCVAL(state->vwv+3, 0, LOCKING_ANDX_OPLOCK_RELEASE);
144         SCVAL(state->vwv+3, 1, level);
145         SIVAL(state->vwv+4, 0, 0); /* timeout */
146         SSVAL(state->vwv+6, 0, 0); /* unlockcount */
147         SSVAL(state->vwv+7, 0, 0); /* lockcount */
148
149         subreq = cli_smb_send(state, ev, cli, SMBlockingX, 0, 8, state->vwv,
150                               0, NULL);
151         if (tevent_req_nomem(subreq, req)) {
152                 return tevent_req_post(req, ev);
153         }
154         tevent_req_set_callback(subreq, cli_oplock_ack_done, req);
155         return req;
156 }
157
158 static void cli_oplock_ack_done(struct tevent_req *subreq)
159 {
160         struct tevent_req *req = tevent_req_callback_data(
161                 subreq, struct tevent_req);
162         NTSTATUS status;
163
164         status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
165         TALLOC_FREE(subreq);
166         if (!NT_STATUS_IS_OK(status)) {
167                 tevent_req_nterror(req, status);
168                 return;
169         }
170         tevent_req_done(req);
171 }
172
173 NTSTATUS cli_oplock_ack_recv(struct tevent_req *req)
174 {
175         return tevent_req_simple_recv_ntstatus(req);
176 }
177