xref: /dflybsd-src/lib/libc/net/nscachedcli.c (revision 3e7e41796563d188c56ba2080021feda4a2aace9)
1ed5d5720SPeter Avalos /*-
2ed5d5720SPeter Avalos  * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
3ed5d5720SPeter Avalos  * All rights reserved.
4ed5d5720SPeter Avalos  *
5ed5d5720SPeter Avalos  * Redistribution and use in source and binary forms, with or without
6ed5d5720SPeter Avalos  * modification, are permitted provided that the following conditions
7ed5d5720SPeter Avalos  * are met:
8ed5d5720SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
9ed5d5720SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
10ed5d5720SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
11ed5d5720SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
12ed5d5720SPeter Avalos  *    documentation and/or other materials provided with the distribution.
13ed5d5720SPeter Avalos  *
14ed5d5720SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15ed5d5720SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16ed5d5720SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ed5d5720SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18ed5d5720SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19ed5d5720SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20ed5d5720SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21ed5d5720SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22ed5d5720SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23ed5d5720SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24ed5d5720SPeter Avalos  * SUCH DAMAGE.
25ed5d5720SPeter Avalos  *
26ed5d5720SPeter Avalos  * $FreeBSD: src/lib/libc/net/nscachedcli.c,v 1.3 2006/12/04 17:08:43 ume Exp $
27ed5d5720SPeter Avalos  */
28ed5d5720SPeter Avalos 
29ed5d5720SPeter Avalos #include "namespace.h"
30ed5d5720SPeter Avalos #include <sys/types.h>
31ed5d5720SPeter Avalos #include <sys/socket.h>
32ed5d5720SPeter Avalos #include <sys/event.h>
33*3e7e4179Szrj #include <sys/time.h>
34ed5d5720SPeter Avalos #include <sys/uio.h>
35ed5d5720SPeter Avalos #include <sys/un.h>
36ed5d5720SPeter Avalos #include <assert.h>
37ed5d5720SPeter Avalos #include <errno.h>
38ed5d5720SPeter Avalos #include <fcntl.h>
39ed5d5720SPeter Avalos #include <stdlib.h>
40ed5d5720SPeter Avalos #include <string.h>
41ed5d5720SPeter Avalos #include <unistd.h>
42ed5d5720SPeter Avalos #include "un-namespace.h"
43ed5d5720SPeter Avalos #include "nscachedcli.h"
44ed5d5720SPeter Avalos 
45ed5d5720SPeter Avalos #define NS_DEFAULT_CACHED_IO_TIMEOUT	4
46ed5d5720SPeter Avalos 
47ed5d5720SPeter Avalos static int safe_write(struct cached_connection_ *, const void *, size_t);
48ed5d5720SPeter Avalos static int safe_read(struct cached_connection_ *, void *, size_t);
49ed5d5720SPeter Avalos static int send_credentials(struct cached_connection_ *, int);
50ed5d5720SPeter Avalos 
51ed5d5720SPeter Avalos /*
52ed5d5720SPeter Avalos  * safe_write writes data to the specified connection and tries to do it in
53ed5d5720SPeter Avalos  * the very safe manner. We ensure, that we can write to the socket with
54ed5d5720SPeter Avalos  * kevent. If the data_size can't be sent in one piece, then it would be
55ed5d5720SPeter Avalos  * splitted.
56ed5d5720SPeter Avalos  */
57ed5d5720SPeter Avalos static int
safe_write(struct cached_connection_ * connection,const void * data,size_t data_size)58ed5d5720SPeter Avalos safe_write(struct cached_connection_ *connection, const void *data,
59ed5d5720SPeter Avalos     size_t data_size)
60ed5d5720SPeter Avalos {
61ed5d5720SPeter Avalos 	struct kevent eventlist;
62ed5d5720SPeter Avalos 	int nevents;
63ed5d5720SPeter Avalos 	size_t result;
64ed5d5720SPeter Avalos 	ssize_t s_result;
65ed5d5720SPeter Avalos 	struct timespec timeout;
66ed5d5720SPeter Avalos 
67ed5d5720SPeter Avalos 	if (data_size == 0)
68ed5d5720SPeter Avalos 		return (0);
69ed5d5720SPeter Avalos 
70ed5d5720SPeter Avalos 	timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
71ed5d5720SPeter Avalos 	timeout.tv_nsec = 0;
72ed5d5720SPeter Avalos 	result = 0;
73ed5d5720SPeter Avalos 	do {
74ed5d5720SPeter Avalos 		nevents = _kevent(connection->write_queue, NULL, 0, &eventlist,
75ed5d5720SPeter Avalos 		    1, &timeout);
76ed5d5720SPeter Avalos 		if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
77f8c95d28SSascha Wildner 			s_result = _write(connection->sockfd,
78f8c95d28SSascha Wildner 			    (char *)data + result,
79ed5d5720SPeter Avalos 			    eventlist.data < data_size - result ?
80ed5d5720SPeter Avalos 			    eventlist.data : data_size - result);
81ed5d5720SPeter Avalos 			if (s_result == -1)
82ed5d5720SPeter Avalos 				return (-1);
83ed5d5720SPeter Avalos 			else
84ed5d5720SPeter Avalos 				result += s_result;
85ed5d5720SPeter Avalos 
86ed5d5720SPeter Avalos 			if (eventlist.flags & EV_EOF)
87ed5d5720SPeter Avalos 				return (result < data_size ? -1 : 0);
88ed5d5720SPeter Avalos 		} else
89ed5d5720SPeter Avalos 			return (-1);
90ed5d5720SPeter Avalos 	} while (result < data_size);
91ed5d5720SPeter Avalos 
92ed5d5720SPeter Avalos 	return (0);
93ed5d5720SPeter Avalos }
94ed5d5720SPeter Avalos 
95ed5d5720SPeter Avalos /*
96ed5d5720SPeter Avalos  * safe_read reads data from connection and tries to do it in the very safe
97ed5d5720SPeter Avalos  * and stable way. It uses kevent to ensure, that the data are availabe for
98ed5d5720SPeter Avalos  * reading. If the amount of data to be read is too large, then they would
99ed5d5720SPeter Avalos  * be splitted.
100ed5d5720SPeter Avalos  */
101ed5d5720SPeter Avalos static int
safe_read(struct cached_connection_ * connection,void * data,size_t data_size)102ed5d5720SPeter Avalos safe_read(struct cached_connection_ *connection, void *data, size_t data_size)
103ed5d5720SPeter Avalos {
104ed5d5720SPeter Avalos 	struct kevent eventlist;
105ed5d5720SPeter Avalos 	size_t result;
106ed5d5720SPeter Avalos 	ssize_t s_result;
107ed5d5720SPeter Avalos 	struct timespec timeout;
108ed5d5720SPeter Avalos 	int nevents;
109ed5d5720SPeter Avalos 
110ed5d5720SPeter Avalos 	if (data_size == 0)
111ed5d5720SPeter Avalos 		return (0);
112ed5d5720SPeter Avalos 
113ed5d5720SPeter Avalos 	timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
114ed5d5720SPeter Avalos 	timeout.tv_nsec = 0;
115ed5d5720SPeter Avalos 	result = 0;
116ed5d5720SPeter Avalos 	do {
117ed5d5720SPeter Avalos 		nevents = _kevent(connection->read_queue, NULL, 0, &eventlist,
118ed5d5720SPeter Avalos 		    1, &timeout);
119ed5d5720SPeter Avalos 		if (nevents == 1 && eventlist.filter == EVFILT_READ) {
120f8c95d28SSascha Wildner 			s_result = _read(connection->sockfd,
121f8c95d28SSascha Wildner 			    (char *)data + result,
122ed5d5720SPeter Avalos 			    eventlist.data <= data_size - result ?
123ed5d5720SPeter Avalos 			    eventlist.data : data_size - result);
124ed5d5720SPeter Avalos 			if (s_result == -1)
125ed5d5720SPeter Avalos 				return (-1);
126ed5d5720SPeter Avalos 			else
127ed5d5720SPeter Avalos 				result += s_result;
128ed5d5720SPeter Avalos 
129ed5d5720SPeter Avalos 			if (eventlist.flags & EV_EOF)
130ed5d5720SPeter Avalos 				return (result < data_size ? -1 : 0);
131ed5d5720SPeter Avalos 		} else
132ed5d5720SPeter Avalos 			return (-1);
133ed5d5720SPeter Avalos 	} while (result < data_size);
134ed5d5720SPeter Avalos 
135ed5d5720SPeter Avalos 	return (0);
136ed5d5720SPeter Avalos }
137ed5d5720SPeter Avalos 
138ed5d5720SPeter Avalos /*
139ed5d5720SPeter Avalos  * Sends the credentials information to the connection along with the
140ed5d5720SPeter Avalos  * communication element type.
141ed5d5720SPeter Avalos  */
142ed5d5720SPeter Avalos static int
send_credentials(struct cached_connection_ * connection,int type)143ed5d5720SPeter Avalos send_credentials(struct cached_connection_ *connection, int type)
144ed5d5720SPeter Avalos {
145ed5d5720SPeter Avalos 	struct kevent eventlist;
146ed5d5720SPeter Avalos 	int nevents;
147ed5d5720SPeter Avalos 	ssize_t result;
148cf515c3aSJohn Marino 	int res __unused;
149ed5d5720SPeter Avalos 
150ed5d5720SPeter Avalos 	struct msghdr cred_hdr;
151ed5d5720SPeter Avalos 	struct iovec iov;
152ed5d5720SPeter Avalos 
153ed5d5720SPeter Avalos 	struct {
154ed5d5720SPeter Avalos 		struct cmsghdr hdr;
155ed5d5720SPeter Avalos 		char cred[CMSG_SPACE(sizeof(struct cmsgcred))];
156ed5d5720SPeter Avalos 	} cmsg;
157ed5d5720SPeter Avalos 
158ed5d5720SPeter Avalos 	memset(&cmsg, 0, sizeof(cmsg));
159ed5d5720SPeter Avalos 	cmsg.hdr.cmsg_len =  CMSG_LEN(sizeof(struct cmsgcred));
160ed5d5720SPeter Avalos 	cmsg.hdr.cmsg_level = SOL_SOCKET;
161ed5d5720SPeter Avalos 	cmsg.hdr.cmsg_type = SCM_CREDS;
162ed5d5720SPeter Avalos 
163ed5d5720SPeter Avalos 	memset(&cred_hdr, 0, sizeof(struct msghdr));
164ed5d5720SPeter Avalos 	cred_hdr.msg_iov = &iov;
165ed5d5720SPeter Avalos 	cred_hdr.msg_iovlen = 1;
166ed5d5720SPeter Avalos 	cred_hdr.msg_control = (caddr_t)&cmsg;
167ed5d5720SPeter Avalos 	cred_hdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
168ed5d5720SPeter Avalos 
169ed5d5720SPeter Avalos 	iov.iov_base = &type;
170ed5d5720SPeter Avalos 	iov.iov_len = sizeof(int);
171ed5d5720SPeter Avalos 
172ed5d5720SPeter Avalos 	EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
173ed5d5720SPeter Avalos 	    NOTE_LOWAT, sizeof(int), NULL);
174ed5d5720SPeter Avalos 	res = _kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
175ed5d5720SPeter Avalos 
176ed5d5720SPeter Avalos 	nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 1,
177ed5d5720SPeter Avalos 	    NULL);
178ed5d5720SPeter Avalos 	if (nevents == 1 && eventlist.filter == EVFILT_WRITE) {
179ed5d5720SPeter Avalos 		result = (_sendmsg(connection->sockfd, &cred_hdr, 0) == -1) ?
180ed5d5720SPeter Avalos 		    -1 : 0;
181ed5d5720SPeter Avalos 		EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
182ed5d5720SPeter Avalos 		    0, 0, NULL);
183ed5d5720SPeter Avalos 		_kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
184ed5d5720SPeter Avalos 		return (result);
185ed5d5720SPeter Avalos 	} else
186ed5d5720SPeter Avalos 		return (-1);
187ed5d5720SPeter Avalos }
188ed5d5720SPeter Avalos 
189ed5d5720SPeter Avalos /*
190ed5d5720SPeter Avalos  * Opens the connection with the specified params. Initializes all kqueues.
191ed5d5720SPeter Avalos  */
192ed5d5720SPeter Avalos struct cached_connection_ *
__open_cached_connection(struct cached_connection_params const * params)193ed5d5720SPeter Avalos __open_cached_connection(struct cached_connection_params const *params)
194ed5d5720SPeter Avalos {
195ed5d5720SPeter Avalos 	struct cached_connection_ *retval;
196ed5d5720SPeter Avalos 	struct kevent eventlist;
197ed5d5720SPeter Avalos 	struct sockaddr_un client_address;
198ed5d5720SPeter Avalos 	int client_address_len, client_socket;
199ed5d5720SPeter Avalos 	int res;
200ed5d5720SPeter Avalos 
201ed5d5720SPeter Avalos 	assert(params != NULL);
202ed5d5720SPeter Avalos 
203ed5d5720SPeter Avalos 	client_socket = _socket(PF_LOCAL, SOCK_STREAM, 0);
204ed5d5720SPeter Avalos 	client_address.sun_family = PF_LOCAL;
205ed5d5720SPeter Avalos 	strncpy(client_address.sun_path, params->socket_path,
206ed5d5720SPeter Avalos 	    sizeof(client_address.sun_path));
207ed5d5720SPeter Avalos 	client_address_len = sizeof(client_address.sun_family) +
208ed5d5720SPeter Avalos 	    strlen(client_address.sun_path) + 1;
209ed5d5720SPeter Avalos 
210ed5d5720SPeter Avalos 	res = _connect(client_socket, (struct sockaddr *)&client_address,
211ed5d5720SPeter Avalos 	    client_address_len);
212ed5d5720SPeter Avalos 	if (res == -1) {
213ed5d5720SPeter Avalos 		_close(client_socket);
214ed5d5720SPeter Avalos 		return (NULL);
215ed5d5720SPeter Avalos 	}
216ed5d5720SPeter Avalos 	_fcntl(client_socket, F_SETFL, O_NONBLOCK);
217ed5d5720SPeter Avalos 
218ed5d5720SPeter Avalos 	retval = malloc(sizeof(struct cached_connection_));
219ed5d5720SPeter Avalos 	assert(retval != NULL);
220ed5d5720SPeter Avalos 	memset(retval, 0, sizeof(struct cached_connection_));
221ed5d5720SPeter Avalos 
222ed5d5720SPeter Avalos 	retval->sockfd = client_socket;
223ed5d5720SPeter Avalos 
224ed5d5720SPeter Avalos 	retval->write_queue = kqueue();
225ed5d5720SPeter Avalos 	assert(retval->write_queue != -1);
226ed5d5720SPeter Avalos 
227ed5d5720SPeter Avalos 	EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
228ed5d5720SPeter Avalos 	res = _kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL);
229ed5d5720SPeter Avalos 
230ed5d5720SPeter Avalos 	retval->read_queue = kqueue();
231ed5d5720SPeter Avalos 	assert(retval->read_queue != -1);
232ed5d5720SPeter Avalos 
233ed5d5720SPeter Avalos 	EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
234ed5d5720SPeter Avalos 	res = _kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL);
235ed5d5720SPeter Avalos 
236ed5d5720SPeter Avalos 	return (retval);
237ed5d5720SPeter Avalos }
238ed5d5720SPeter Avalos 
239ed5d5720SPeter Avalos void
__close_cached_connection(struct cached_connection_ * connection)240ed5d5720SPeter Avalos __close_cached_connection(struct cached_connection_ *connection)
241ed5d5720SPeter Avalos {
242ed5d5720SPeter Avalos 	assert(connection != NULL);
243ed5d5720SPeter Avalos 
244ed5d5720SPeter Avalos 	_close(connection->sockfd);
245ed5d5720SPeter Avalos 	_close(connection->read_queue);
246ed5d5720SPeter Avalos 	_close(connection->write_queue);
247ed5d5720SPeter Avalos 	free(connection);
248ed5d5720SPeter Avalos }
249ed5d5720SPeter Avalos 
250ed5d5720SPeter Avalos /*
251ed5d5720SPeter Avalos  * This function is very close to the cache_write function of the caching
252ed5d5720SPeter Avalos  * library, which is used in the caching daemon. It caches the data with the
253ed5d5720SPeter Avalos  * specified key in the cache entry with entry_name.
254ed5d5720SPeter Avalos  */
255ed5d5720SPeter Avalos int
__cached_write(struct cached_connection_ * connection,const char * entry_name,const char * key,size_t key_size,const char * data,size_t data_size)256ed5d5720SPeter Avalos __cached_write(struct cached_connection_ *connection, const char *entry_name,
257ed5d5720SPeter Avalos     const char *key, size_t key_size, const char *data, size_t data_size)
258ed5d5720SPeter Avalos {
259ed5d5720SPeter Avalos 	size_t name_size;
260ed5d5720SPeter Avalos 	int error_code;
261ed5d5720SPeter Avalos 	int result;
262ed5d5720SPeter Avalos 
263ed5d5720SPeter Avalos 	error_code = -1;
264ed5d5720SPeter Avalos 	result = send_credentials(connection, CET_WRITE_REQUEST);
265ed5d5720SPeter Avalos 	if (result != 0)
266ed5d5720SPeter Avalos 		goto fin;
267ed5d5720SPeter Avalos 
268ed5d5720SPeter Avalos 	name_size = strlen(entry_name);
269ed5d5720SPeter Avalos 	result = safe_write(connection, &name_size, sizeof(size_t));
270ed5d5720SPeter Avalos 	if (result != 0)
271ed5d5720SPeter Avalos 		goto fin;
272ed5d5720SPeter Avalos 
273ed5d5720SPeter Avalos 	result = safe_write(connection, &key_size, sizeof(size_t));
274ed5d5720SPeter Avalos 	if (result != 0)
275ed5d5720SPeter Avalos 		goto fin;
276ed5d5720SPeter Avalos 
277ed5d5720SPeter Avalos 	result = safe_write(connection, &data_size, sizeof(size_t));
278ed5d5720SPeter Avalos 	if (result != 0)
279ed5d5720SPeter Avalos 		goto fin;
280ed5d5720SPeter Avalos 
281ed5d5720SPeter Avalos 	result = safe_write(connection, entry_name, name_size);
282ed5d5720SPeter Avalos 	if (result != 0)
283ed5d5720SPeter Avalos 		goto fin;
284ed5d5720SPeter Avalos 
285ed5d5720SPeter Avalos 	result = safe_write(connection, key, key_size);
286ed5d5720SPeter Avalos 	if (result != 0)
287ed5d5720SPeter Avalos 		goto fin;
288ed5d5720SPeter Avalos 
289ed5d5720SPeter Avalos 	result = safe_write(connection, data, data_size);
290ed5d5720SPeter Avalos 	if (result != 0)
291ed5d5720SPeter Avalos 		goto fin;
292ed5d5720SPeter Avalos 
293ed5d5720SPeter Avalos 	result = safe_read(connection, &error_code, sizeof(int));
294ed5d5720SPeter Avalos 	if (result != 0)
295ed5d5720SPeter Avalos 		error_code = -1;
296ed5d5720SPeter Avalos 
297ed5d5720SPeter Avalos fin:
298ed5d5720SPeter Avalos 	return (error_code);
299ed5d5720SPeter Avalos }
300ed5d5720SPeter Avalos 
301ed5d5720SPeter Avalos /*
302ed5d5720SPeter Avalos  * This function is very close to the cache_read function of the caching
303ed5d5720SPeter Avalos  * library, which is used in the caching daemon. It reads cached data with the
304ed5d5720SPeter Avalos  * specified key from the cache entry with entry_name.
305ed5d5720SPeter Avalos  */
306ed5d5720SPeter Avalos int
__cached_read(struct cached_connection_ * connection,const char * entry_name,const char * key,size_t key_size,char * data,size_t * data_size)307ed5d5720SPeter Avalos __cached_read(struct cached_connection_ *connection, const char *entry_name,
308ed5d5720SPeter Avalos     const char *key, size_t key_size, char *data, size_t *data_size)
309ed5d5720SPeter Avalos {
310ed5d5720SPeter Avalos 	size_t name_size, result_size;
311ed5d5720SPeter Avalos 	int error_code, rec_error_code;
312ed5d5720SPeter Avalos 	int result;
313ed5d5720SPeter Avalos 
314ed5d5720SPeter Avalos 	assert(connection != NULL);
315ed5d5720SPeter Avalos 	result = 0;
316ed5d5720SPeter Avalos 	error_code = -1;
317ed5d5720SPeter Avalos 
318ed5d5720SPeter Avalos 	result = send_credentials(connection, CET_READ_REQUEST);
319ed5d5720SPeter Avalos 	if (result != 0)
320ed5d5720SPeter Avalos 		goto fin;
321ed5d5720SPeter Avalos 
322ed5d5720SPeter Avalos 	name_size = strlen(entry_name);
323ed5d5720SPeter Avalos 	result = safe_write(connection, &name_size, sizeof(size_t));
324ed5d5720SPeter Avalos 	if (result != 0)
325ed5d5720SPeter Avalos 		goto fin;
326ed5d5720SPeter Avalos 
327ed5d5720SPeter Avalos 	result = safe_write(connection, &key_size, sizeof(size_t));
328ed5d5720SPeter Avalos 	if (result != 0)
329ed5d5720SPeter Avalos 		goto fin;
330ed5d5720SPeter Avalos 
331ed5d5720SPeter Avalos 	result = safe_write(connection, entry_name, name_size);
332ed5d5720SPeter Avalos 	if (result != 0)
333ed5d5720SPeter Avalos 		goto fin;
334ed5d5720SPeter Avalos 
335ed5d5720SPeter Avalos 	result = safe_write(connection, key, key_size);
336ed5d5720SPeter Avalos 	if (result != 0)
337ed5d5720SPeter Avalos 		goto fin;
338ed5d5720SPeter Avalos 
339ed5d5720SPeter Avalos 	result = safe_read(connection, &rec_error_code, sizeof(int));
340ed5d5720SPeter Avalos 	if (result != 0)
341ed5d5720SPeter Avalos 		goto fin;
342ed5d5720SPeter Avalos 
343ed5d5720SPeter Avalos 	if (rec_error_code != 0) {
344ed5d5720SPeter Avalos 		error_code = rec_error_code;
345ed5d5720SPeter Avalos 		goto fin;
346ed5d5720SPeter Avalos 	}
347ed5d5720SPeter Avalos 
348ed5d5720SPeter Avalos 	result = safe_read(connection, &result_size, sizeof(size_t));
349ed5d5720SPeter Avalos 	if (result != 0)
350ed5d5720SPeter Avalos 		goto fin;
351ed5d5720SPeter Avalos 
352ed5d5720SPeter Avalos 	if (result_size > *data_size) {
353ed5d5720SPeter Avalos 		*data_size = result_size;
354ed5d5720SPeter Avalos 		error_code = -2;
355ed5d5720SPeter Avalos 		goto fin;
356ed5d5720SPeter Avalos 	}
357ed5d5720SPeter Avalos 
358ed5d5720SPeter Avalos 	result = safe_read(connection, data, result_size);
359ed5d5720SPeter Avalos 	if (result != 0)
360ed5d5720SPeter Avalos 		goto fin;
361ed5d5720SPeter Avalos 
362ed5d5720SPeter Avalos 	*data_size = result_size;
363ed5d5720SPeter Avalos 	error_code = 0;
364ed5d5720SPeter Avalos 
365ed5d5720SPeter Avalos fin:
366ed5d5720SPeter Avalos 	return (error_code);
367ed5d5720SPeter Avalos }
368ed5d5720SPeter Avalos 
369ed5d5720SPeter Avalos /*
370ed5d5720SPeter Avalos  * Initializes the mp_write_session. For such a session the new connection
371ed5d5720SPeter Avalos  * would be opened. The data should be written to the session with
372ed5d5720SPeter Avalos  * __cached_mp_write function. The __close_cached_mp_write_session function
373ed5d5720SPeter Avalos  * should be used to submit session and __abandon_cached_mp_write_session - to
374ed5d5720SPeter Avalos  * abandon it. When the session is submitted, the whole se
375ed5d5720SPeter Avalos  */
376ed5d5720SPeter Avalos struct cached_connection_ *
__open_cached_mp_write_session(struct cached_connection_params const * params,const char * entry_name)377ed5d5720SPeter Avalos __open_cached_mp_write_session(struct cached_connection_params const *params,
378ed5d5720SPeter Avalos     const char *entry_name)
379ed5d5720SPeter Avalos {
380ed5d5720SPeter Avalos 	struct cached_connection_ *connection, *retval;
381ed5d5720SPeter Avalos 	size_t name_size;
382ed5d5720SPeter Avalos 	int error_code;
383ed5d5720SPeter Avalos 	int result;
384ed5d5720SPeter Avalos 
385ed5d5720SPeter Avalos 	retval = NULL;
386ed5d5720SPeter Avalos 	connection = __open_cached_connection(params);
387ed5d5720SPeter Avalos 	if (connection == NULL)
388ed5d5720SPeter Avalos 		return (NULL);
389ed5d5720SPeter Avalos 	connection->mp_flag = 1;
390ed5d5720SPeter Avalos 
391ed5d5720SPeter Avalos 	result = send_credentials(connection, CET_MP_WRITE_SESSION_REQUEST);
392ed5d5720SPeter Avalos 	if (result != 0)
393ed5d5720SPeter Avalos 		goto fin;
394ed5d5720SPeter Avalos 
395ed5d5720SPeter Avalos 	name_size = strlen(entry_name);
396ed5d5720SPeter Avalos 	result = safe_write(connection, &name_size, sizeof(size_t));
397ed5d5720SPeter Avalos 	if (result != 0)
398ed5d5720SPeter Avalos 		goto fin;
399ed5d5720SPeter Avalos 
400ed5d5720SPeter Avalos 	result = safe_write(connection, entry_name, name_size);
401ed5d5720SPeter Avalos 	if (result != 0)
402ed5d5720SPeter Avalos 		goto fin;
403ed5d5720SPeter Avalos 
404ed5d5720SPeter Avalos 	result = safe_read(connection, &error_code, sizeof(int));
405ed5d5720SPeter Avalos 	if (result != 0)
406ed5d5720SPeter Avalos 		goto fin;
407ed5d5720SPeter Avalos 
408ed5d5720SPeter Avalos 	if (error_code != 0)
409ed5d5720SPeter Avalos 		result = error_code;
410ed5d5720SPeter Avalos 
411ed5d5720SPeter Avalos fin:
412ed5d5720SPeter Avalos 	if (result != 0)
413ed5d5720SPeter Avalos 		__close_cached_connection(connection);
414ed5d5720SPeter Avalos 	else
415ed5d5720SPeter Avalos 		retval = connection;
416ed5d5720SPeter Avalos 	return (retval);
417ed5d5720SPeter Avalos }
418ed5d5720SPeter Avalos 
419ed5d5720SPeter Avalos /*
420ed5d5720SPeter Avalos  * Adds new portion of data to the opened write session
421ed5d5720SPeter Avalos  */
422ed5d5720SPeter Avalos int
__cached_mp_write(struct cached_connection_ * ws,const char * data,size_t data_size)423ed5d5720SPeter Avalos __cached_mp_write(struct cached_connection_ *ws, const char *data,
424ed5d5720SPeter Avalos     size_t data_size)
425ed5d5720SPeter Avalos {
426ed5d5720SPeter Avalos 	int request, result;
427ed5d5720SPeter Avalos 	int error_code;
428ed5d5720SPeter Avalos 
429ed5d5720SPeter Avalos 	error_code = -1;
430ed5d5720SPeter Avalos 
431ed5d5720SPeter Avalos 	request = CET_MP_WRITE_SESSION_WRITE_REQUEST;
432ed5d5720SPeter Avalos 	result = safe_write(ws, &request, sizeof(int));
433ed5d5720SPeter Avalos 	if (result != 0)
434ed5d5720SPeter Avalos 		goto fin;
435ed5d5720SPeter Avalos 
436ed5d5720SPeter Avalos 	result = safe_write(ws, &data_size, sizeof(size_t));
437ed5d5720SPeter Avalos 	if (result != 0)
438ed5d5720SPeter Avalos 		goto fin;
439ed5d5720SPeter Avalos 
440ed5d5720SPeter Avalos 	result = safe_write(ws, data, data_size);
441ed5d5720SPeter Avalos 	if (result != 0)
442ed5d5720SPeter Avalos 		goto fin;
443ed5d5720SPeter Avalos 
444ed5d5720SPeter Avalos 	result = safe_read(ws, &error_code, sizeof(int));
445ed5d5720SPeter Avalos 	if (result != 0)
446ed5d5720SPeter Avalos 		error_code = -1;
447ed5d5720SPeter Avalos 
448ed5d5720SPeter Avalos fin:
449ed5d5720SPeter Avalos 	return (error_code);
450ed5d5720SPeter Avalos }
451ed5d5720SPeter Avalos 
452ed5d5720SPeter Avalos /*
453ed5d5720SPeter Avalos  * Abandons all operations with the write session. All data, that were written
454ed5d5720SPeter Avalos  * to the session before, are discarded.
455ed5d5720SPeter Avalos  */
456ed5d5720SPeter Avalos int
__abandon_cached_mp_write_session(struct cached_connection_ * ws)457ed5d5720SPeter Avalos __abandon_cached_mp_write_session(struct cached_connection_ *ws)
458ed5d5720SPeter Avalos {
459ed5d5720SPeter Avalos 	int notification;
460ed5d5720SPeter Avalos 	int result;
461ed5d5720SPeter Avalos 
462ed5d5720SPeter Avalos 	notification = CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION;
463ed5d5720SPeter Avalos 	result = safe_write(ws, &notification, sizeof(int));
464ed5d5720SPeter Avalos 	__close_cached_connection(ws);
465ed5d5720SPeter Avalos 	return (result);
466ed5d5720SPeter Avalos }
467ed5d5720SPeter Avalos 
468ed5d5720SPeter Avalos /*
469ed5d5720SPeter Avalos  * Gracefully closes the write session. The data, that were previously written
470ed5d5720SPeter Avalos  * to the session, are committed.
471ed5d5720SPeter Avalos  */
472ed5d5720SPeter Avalos int
__close_cached_mp_write_session(struct cached_connection_ * ws)473ed5d5720SPeter Avalos __close_cached_mp_write_session(struct cached_connection_ *ws)
474ed5d5720SPeter Avalos {
475ed5d5720SPeter Avalos 	int notification;
476cf515c3aSJohn Marino 	int result __unused;
477ed5d5720SPeter Avalos 
478ed5d5720SPeter Avalos 	notification = CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION;
479ed5d5720SPeter Avalos 	result = safe_write(ws, &notification, sizeof(int));
480ed5d5720SPeter Avalos 	__close_cached_connection(ws);
481ed5d5720SPeter Avalos 	return (0);
482ed5d5720SPeter Avalos }
483ed5d5720SPeter Avalos 
484ed5d5720SPeter Avalos struct cached_connection_ *
__open_cached_mp_read_session(struct cached_connection_params const * params,const char * entry_name)485ed5d5720SPeter Avalos __open_cached_mp_read_session(struct cached_connection_params const *params,
486ed5d5720SPeter Avalos 	const char *entry_name)
487ed5d5720SPeter Avalos {
488ed5d5720SPeter Avalos 	struct cached_connection_ *connection, *retval;
489ed5d5720SPeter Avalos 	size_t name_size;
490ed5d5720SPeter Avalos 	int error_code;
491ed5d5720SPeter Avalos 	int result;
492ed5d5720SPeter Avalos 
493ed5d5720SPeter Avalos 	retval = NULL;
494ed5d5720SPeter Avalos 	connection = __open_cached_connection(params);
495ed5d5720SPeter Avalos 	if (connection == NULL)
496ed5d5720SPeter Avalos 		return (NULL);
497ed5d5720SPeter Avalos 	connection->mp_flag = 1;
498ed5d5720SPeter Avalos 
499ed5d5720SPeter Avalos 	result = send_credentials(connection, CET_MP_READ_SESSION_REQUEST);
500ed5d5720SPeter Avalos 	if (result != 0)
501ed5d5720SPeter Avalos 		goto fin;
502ed5d5720SPeter Avalos 
503ed5d5720SPeter Avalos 	name_size = strlen(entry_name);
504ed5d5720SPeter Avalos 	result = safe_write(connection, &name_size, sizeof(size_t));
505ed5d5720SPeter Avalos 	if (result != 0)
506ed5d5720SPeter Avalos 		goto fin;
507ed5d5720SPeter Avalos 
508ed5d5720SPeter Avalos 	result = safe_write(connection, entry_name, name_size);
509ed5d5720SPeter Avalos 	if (result != 0)
510ed5d5720SPeter Avalos 		goto fin;
511ed5d5720SPeter Avalos 
512ed5d5720SPeter Avalos 	result = safe_read(connection, &error_code, sizeof(int));
513ed5d5720SPeter Avalos 	if (result != 0)
514ed5d5720SPeter Avalos 		goto fin;
515ed5d5720SPeter Avalos 
516ed5d5720SPeter Avalos 	if (error_code != 0)
517ed5d5720SPeter Avalos 		result = error_code;
518ed5d5720SPeter Avalos 
519ed5d5720SPeter Avalos fin:
520ed5d5720SPeter Avalos 	if (result != 0)
521ed5d5720SPeter Avalos 		__close_cached_connection(connection);
522ed5d5720SPeter Avalos 	else
523ed5d5720SPeter Avalos 		retval = connection;
524ed5d5720SPeter Avalos 	return (retval);
525ed5d5720SPeter Avalos }
526ed5d5720SPeter Avalos 
527ed5d5720SPeter Avalos int
__cached_mp_read(struct cached_connection_ * rs,char * data,size_t * data_size)528ed5d5720SPeter Avalos __cached_mp_read(struct cached_connection_ *rs, char *data, size_t *data_size)
529ed5d5720SPeter Avalos {
530ed5d5720SPeter Avalos 	size_t result_size;
531ed5d5720SPeter Avalos 	int error_code, rec_error_code;
532ed5d5720SPeter Avalos 	int request, result;
533ed5d5720SPeter Avalos 
534ed5d5720SPeter Avalos 	error_code = -1;
535ed5d5720SPeter Avalos 	request = CET_MP_READ_SESSION_READ_REQUEST;
536ed5d5720SPeter Avalos 	result = safe_write(rs, &request, sizeof(int));
537ed5d5720SPeter Avalos 	if (result != 0)
538ed5d5720SPeter Avalos 		goto fin;
539ed5d5720SPeter Avalos 
540ed5d5720SPeter Avalos 	result = safe_read(rs, &rec_error_code, sizeof(int));
541ed5d5720SPeter Avalos 	if (result != 0)
542ed5d5720SPeter Avalos 		goto fin;
543ed5d5720SPeter Avalos 
544ed5d5720SPeter Avalos 	if (rec_error_code != 0) {
545ed5d5720SPeter Avalos 		error_code = rec_error_code;
546ed5d5720SPeter Avalos 		goto fin;
547ed5d5720SPeter Avalos 	}
548ed5d5720SPeter Avalos 
549ed5d5720SPeter Avalos 	result = safe_read(rs, &result_size, sizeof(size_t));
550ed5d5720SPeter Avalos 	if (result != 0)
551ed5d5720SPeter Avalos 		goto fin;
552ed5d5720SPeter Avalos 
553ed5d5720SPeter Avalos 	if (result_size > *data_size) {
554ed5d5720SPeter Avalos 		*data_size = result_size;
555ed5d5720SPeter Avalos 		error_code = -2;
556ed5d5720SPeter Avalos 		goto fin;
557ed5d5720SPeter Avalos 	}
558ed5d5720SPeter Avalos 
559ed5d5720SPeter Avalos 	result = safe_read(rs, data, result_size);
560ed5d5720SPeter Avalos 	if (result != 0)
561ed5d5720SPeter Avalos 		goto fin;
562ed5d5720SPeter Avalos 
563ed5d5720SPeter Avalos 	*data_size = result_size;
564ed5d5720SPeter Avalos 	error_code = 0;
565ed5d5720SPeter Avalos 
566ed5d5720SPeter Avalos fin:
567ed5d5720SPeter Avalos 	return (error_code);
568ed5d5720SPeter Avalos }
569ed5d5720SPeter Avalos 
570ed5d5720SPeter Avalos int
__close_cached_mp_read_session(struct cached_connection_ * rs)571ed5d5720SPeter Avalos __close_cached_mp_read_session(struct cached_connection_ *rs)
572ed5d5720SPeter Avalos {
573ed5d5720SPeter Avalos 
574ed5d5720SPeter Avalos 	__close_cached_connection(rs);
575ed5d5720SPeter Avalos 	return (0);
576ed5d5720SPeter Avalos }
577