2 * Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/lib/libc/net/nscachedcli.c,v 1.3 2006/12/04 17:08:43 ume Exp $
29 #include "namespace.h"
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/event.h>
41 #include "un-namespace.h"
42 #include "nscachedcli.h"
44 #define NS_DEFAULT_CACHED_IO_TIMEOUT 4
46 static int safe_write(struct cached_connection_
*, const void *, size_t);
47 static int safe_read(struct cached_connection_
*, void *, size_t);
48 static int send_credentials(struct cached_connection_
*, int);
51 * safe_write writes data to the specified connection and tries to do it in
52 * the very safe manner. We ensure, that we can write to the socket with
53 * kevent. If the data_size can't be sent in one piece, then it would be
57 safe_write(struct cached_connection_
*connection
, const void *data
,
60 struct kevent eventlist
;
64 struct timespec timeout
;
69 timeout
.tv_sec
= NS_DEFAULT_CACHED_IO_TIMEOUT
;
73 nevents
= _kevent(connection
->write_queue
, NULL
, 0, &eventlist
,
75 if ((nevents
== 1) && (eventlist
.filter
== EVFILT_WRITE
)) {
76 s_result
= _write(connection
->sockfd
, data
+ result
,
77 eventlist
.data
< data_size
- result
?
78 eventlist
.data
: data_size
- result
);
84 if (eventlist
.flags
& EV_EOF
)
85 return (result
< data_size
? -1 : 0);
88 } while (result
< data_size
);
94 * safe_read reads data from connection and tries to do it in the very safe
95 * and stable way. It uses kevent to ensure, that the data are availabe for
96 * reading. If the amount of data to be read is too large, then they would
100 safe_read(struct cached_connection_
*connection
, void *data
, size_t data_size
)
102 struct kevent eventlist
;
105 struct timespec timeout
;
111 timeout
.tv_sec
= NS_DEFAULT_CACHED_IO_TIMEOUT
;
115 nevents
= _kevent(connection
->read_queue
, NULL
, 0, &eventlist
,
117 if (nevents
== 1 && eventlist
.filter
== EVFILT_READ
) {
118 s_result
= _read(connection
->sockfd
, data
+ result
,
119 eventlist
.data
<= data_size
- result
?
120 eventlist
.data
: data_size
- result
);
126 if (eventlist
.flags
& EV_EOF
)
127 return (result
< data_size
? -1 : 0);
130 } while (result
< data_size
);
136 * Sends the credentials information to the connection along with the
137 * communication element type.
140 send_credentials(struct cached_connection_
*connection
, int type
)
142 struct kevent eventlist
;
147 struct msghdr cred_hdr
;
152 char cred
[CMSG_SPACE(sizeof(struct cmsgcred
))];
155 memset(&cmsg
, 0, sizeof(cmsg
));
156 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct cmsgcred
));
157 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
158 cmsg
.hdr
.cmsg_type
= SCM_CREDS
;
160 memset(&cred_hdr
, 0, sizeof(struct msghdr
));
161 cred_hdr
.msg_iov
= &iov
;
162 cred_hdr
.msg_iovlen
= 1;
163 cred_hdr
.msg_control
= (caddr_t
)&cmsg
;
164 cred_hdr
.msg_controllen
= CMSG_SPACE(sizeof(struct cmsgcred
));
166 iov
.iov_base
= &type
;
167 iov
.iov_len
= sizeof(int);
169 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
170 NOTE_LOWAT
, sizeof(int), NULL
);
171 res
= _kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
173 nevents
= _kevent(connection
->write_queue
, NULL
, 0, &eventlist
, 1,
175 if (nevents
== 1 && eventlist
.filter
== EVFILT_WRITE
) {
176 result
= (_sendmsg(connection
->sockfd
, &cred_hdr
, 0) == -1) ?
178 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
180 _kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
187 * Opens the connection with the specified params. Initializes all kqueues.
189 struct cached_connection_
*
190 __open_cached_connection(struct cached_connection_params
const *params
)
192 struct cached_connection_
*retval
;
193 struct kevent eventlist
;
194 struct sockaddr_un client_address
;
195 int client_address_len
, client_socket
;
198 assert(params
!= NULL
);
200 client_socket
= _socket(PF_LOCAL
, SOCK_STREAM
, 0);
201 client_address
.sun_family
= PF_LOCAL
;
202 strncpy(client_address
.sun_path
, params
->socket_path
,
203 sizeof(client_address
.sun_path
));
204 client_address_len
= sizeof(client_address
.sun_family
) +
205 strlen(client_address
.sun_path
) + 1;
207 res
= _connect(client_socket
, (struct sockaddr
*)&client_address
,
210 _close(client_socket
);
213 _fcntl(client_socket
, F_SETFL
, O_NONBLOCK
);
215 retval
= malloc(sizeof(struct cached_connection_
));
216 assert(retval
!= NULL
);
217 memset(retval
, 0, sizeof(struct cached_connection_
));
219 retval
->sockfd
= client_socket
;
221 retval
->write_queue
= kqueue();
222 assert(retval
->write_queue
!= -1);
224 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_WRITE
, EV_ADD
, 0, 0, NULL
);
225 res
= _kevent(retval
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
227 retval
->read_queue
= kqueue();
228 assert(retval
->read_queue
!= -1);
230 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_READ
, EV_ADD
, 0, 0, NULL
);
231 res
= _kevent(retval
->read_queue
, &eventlist
, 1, NULL
, 0, NULL
);
237 __close_cached_connection(struct cached_connection_
*connection
)
239 assert(connection
!= NULL
);
241 _close(connection
->sockfd
);
242 _close(connection
->read_queue
);
243 _close(connection
->write_queue
);
248 * This function is very close to the cache_write function of the caching
249 * library, which is used in the caching daemon. It caches the data with the
250 * specified key in the cache entry with entry_name.
253 __cached_write(struct cached_connection_
*connection
, const char *entry_name
,
254 const char *key
, size_t key_size
, const char *data
, size_t data_size
)
262 result
= send_credentials(connection
, CET_WRITE_REQUEST
);
266 name_size
= strlen(entry_name
);
267 result
= safe_write(connection
, &name_size
, sizeof(size_t));
271 result
= safe_write(connection
, &key_size
, sizeof(size_t));
275 result
= safe_write(connection
, &data_size
, sizeof(size_t));
279 result
= safe_write(connection
, entry_name
, name_size
);
283 result
= safe_write(connection
, key
, key_size
);
287 result
= safe_write(connection
, data
, data_size
);
291 result
= safe_read(connection
, &error_code
, sizeof(int));
300 * This function is very close to the cache_read function of the caching
301 * library, which is used in the caching daemon. It reads cached data with the
302 * specified key from the cache entry with entry_name.
305 __cached_read(struct cached_connection_
*connection
, const char *entry_name
,
306 const char *key
, size_t key_size
, char *data
, size_t *data_size
)
308 size_t name_size
, result_size
;
309 int error_code
, rec_error_code
;
312 assert(connection
!= NULL
);
316 result
= send_credentials(connection
, CET_READ_REQUEST
);
320 name_size
= strlen(entry_name
);
321 result
= safe_write(connection
, &name_size
, sizeof(size_t));
325 result
= safe_write(connection
, &key_size
, sizeof(size_t));
329 result
= safe_write(connection
, entry_name
, name_size
);
333 result
= safe_write(connection
, key
, key_size
);
337 result
= safe_read(connection
, &rec_error_code
, sizeof(int));
341 if (rec_error_code
!= 0) {
342 error_code
= rec_error_code
;
346 result
= safe_read(connection
, &result_size
, sizeof(size_t));
350 if (result_size
> *data_size
) {
351 *data_size
= result_size
;
356 result
= safe_read(connection
, data
, result_size
);
360 *data_size
= result_size
;
368 * Initializes the mp_write_session. For such a session the new connection
369 * would be opened. The data should be written to the session with
370 * __cached_mp_write function. The __close_cached_mp_write_session function
371 * should be used to submit session and __abandon_cached_mp_write_session - to
372 * abandon it. When the session is submitted, the whole se
374 struct cached_connection_
*
375 __open_cached_mp_write_session(struct cached_connection_params
const *params
,
376 const char *entry_name
)
378 struct cached_connection_
*connection
, *retval
;
384 connection
= __open_cached_connection(params
);
385 if (connection
== NULL
)
387 connection
->mp_flag
= 1;
389 result
= send_credentials(connection
, CET_MP_WRITE_SESSION_REQUEST
);
393 name_size
= strlen(entry_name
);
394 result
= safe_write(connection
, &name_size
, sizeof(size_t));
398 result
= safe_write(connection
, entry_name
, name_size
);
402 result
= safe_read(connection
, &error_code
, sizeof(int));
411 __close_cached_connection(connection
);
418 * Adds new portion of data to the opened write session
421 __cached_mp_write(struct cached_connection_
*ws
, const char *data
,
429 request
= CET_MP_WRITE_SESSION_WRITE_REQUEST
;
430 result
= safe_write(ws
, &request
, sizeof(int));
434 result
= safe_write(ws
, &data_size
, sizeof(size_t));
438 result
= safe_write(ws
, data
, data_size
);
442 result
= safe_read(ws
, &error_code
, sizeof(int));
451 * Abandons all operations with the write session. All data, that were written
452 * to the session before, are discarded.
455 __abandon_cached_mp_write_session(struct cached_connection_
*ws
)
460 notification
= CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION
;
461 result
= safe_write(ws
, ¬ification
, sizeof(int));
462 __close_cached_connection(ws
);
467 * Gracefully closes the write session. The data, that were previously written
468 * to the session, are committed.
471 __close_cached_mp_write_session(struct cached_connection_
*ws
)
476 notification
= CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION
;
477 result
= safe_write(ws
, ¬ification
, sizeof(int));
478 __close_cached_connection(ws
);
482 struct cached_connection_
*
483 __open_cached_mp_read_session(struct cached_connection_params
const *params
,
484 const char *entry_name
)
486 struct cached_connection_
*connection
, *retval
;
492 connection
= __open_cached_connection(params
);
493 if (connection
== NULL
)
495 connection
->mp_flag
= 1;
497 result
= send_credentials(connection
, CET_MP_READ_SESSION_REQUEST
);
501 name_size
= strlen(entry_name
);
502 result
= safe_write(connection
, &name_size
, sizeof(size_t));
506 result
= safe_write(connection
, entry_name
, name_size
);
510 result
= safe_read(connection
, &error_code
, sizeof(int));
519 __close_cached_connection(connection
);
526 __cached_mp_read(struct cached_connection_
*rs
, char *data
, size_t *data_size
)
529 int error_code
, rec_error_code
;
533 request
= CET_MP_READ_SESSION_READ_REQUEST
;
534 result
= safe_write(rs
, &request
, sizeof(int));
538 result
= safe_read(rs
, &rec_error_code
, sizeof(int));
542 if (rec_error_code
!= 0) {
543 error_code
= rec_error_code
;
547 result
= safe_read(rs
, &result_size
, sizeof(size_t));
551 if (result_size
> *data_size
) {
552 *data_size
= result_size
;
557 result
= safe_read(rs
, data
, result_size
);
561 *data_size
= result_size
;
569 __close_cached_mp_read_session(struct cached_connection_
*rs
)
572 __close_cached_connection(rs
);