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
,
77 (char *)data
+ result
,
78 eventlist
.data
< data_size
- result
?
79 eventlist
.data
: data_size
- result
);
85 if (eventlist
.flags
& EV_EOF
)
86 return (result
< data_size
? -1 : 0);
89 } while (result
< data_size
);
95 * safe_read reads data from connection and tries to do it in the very safe
96 * and stable way. It uses kevent to ensure, that the data are availabe for
97 * reading. If the amount of data to be read is too large, then they would
101 safe_read(struct cached_connection_
*connection
, void *data
, size_t data_size
)
103 struct kevent eventlist
;
106 struct timespec timeout
;
112 timeout
.tv_sec
= NS_DEFAULT_CACHED_IO_TIMEOUT
;
116 nevents
= _kevent(connection
->read_queue
, NULL
, 0, &eventlist
,
118 if (nevents
== 1 && eventlist
.filter
== EVFILT_READ
) {
119 s_result
= _read(connection
->sockfd
,
120 (char *)data
+ result
,
121 eventlist
.data
<= data_size
- result
?
122 eventlist
.data
: data_size
- result
);
128 if (eventlist
.flags
& EV_EOF
)
129 return (result
< data_size
? -1 : 0);
132 } while (result
< data_size
);
138 * Sends the credentials information to the connection along with the
139 * communication element type.
142 send_credentials(struct cached_connection_
*connection
, int type
)
144 struct kevent eventlist
;
149 struct msghdr cred_hdr
;
154 char cred
[CMSG_SPACE(sizeof(struct cmsgcred
))];
157 memset(&cmsg
, 0, sizeof(cmsg
));
158 cmsg
.hdr
.cmsg_len
= CMSG_LEN(sizeof(struct cmsgcred
));
159 cmsg
.hdr
.cmsg_level
= SOL_SOCKET
;
160 cmsg
.hdr
.cmsg_type
= SCM_CREDS
;
162 memset(&cred_hdr
, 0, sizeof(struct msghdr
));
163 cred_hdr
.msg_iov
= &iov
;
164 cred_hdr
.msg_iovlen
= 1;
165 cred_hdr
.msg_control
= (caddr_t
)&cmsg
;
166 cred_hdr
.msg_controllen
= CMSG_SPACE(sizeof(struct cmsgcred
));
168 iov
.iov_base
= &type
;
169 iov
.iov_len
= sizeof(int);
171 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
172 NOTE_LOWAT
, sizeof(int), NULL
);
173 res
= _kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
175 nevents
= _kevent(connection
->write_queue
, NULL
, 0, &eventlist
, 1,
177 if (nevents
== 1 && eventlist
.filter
== EVFILT_WRITE
) {
178 result
= (_sendmsg(connection
->sockfd
, &cred_hdr
, 0) == -1) ?
180 EV_SET(&eventlist
, connection
->sockfd
, EVFILT_WRITE
, EV_ADD
,
182 _kevent(connection
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
189 * Opens the connection with the specified params. Initializes all kqueues.
191 struct cached_connection_
*
192 __open_cached_connection(struct cached_connection_params
const *params
)
194 struct cached_connection_
*retval
;
195 struct kevent eventlist
;
196 struct sockaddr_un client_address
;
197 int client_address_len
, client_socket
;
200 assert(params
!= NULL
);
202 client_socket
= _socket(PF_LOCAL
, SOCK_STREAM
, 0);
203 client_address
.sun_family
= PF_LOCAL
;
204 strncpy(client_address
.sun_path
, params
->socket_path
,
205 sizeof(client_address
.sun_path
));
206 client_address_len
= sizeof(client_address
.sun_family
) +
207 strlen(client_address
.sun_path
) + 1;
209 res
= _connect(client_socket
, (struct sockaddr
*)&client_address
,
212 _close(client_socket
);
215 _fcntl(client_socket
, F_SETFL
, O_NONBLOCK
);
217 retval
= malloc(sizeof(struct cached_connection_
));
218 assert(retval
!= NULL
);
219 memset(retval
, 0, sizeof(struct cached_connection_
));
221 retval
->sockfd
= client_socket
;
223 retval
->write_queue
= kqueue();
224 assert(retval
->write_queue
!= -1);
226 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_WRITE
, EV_ADD
, 0, 0, NULL
);
227 res
= _kevent(retval
->write_queue
, &eventlist
, 1, NULL
, 0, NULL
);
229 retval
->read_queue
= kqueue();
230 assert(retval
->read_queue
!= -1);
232 EV_SET(&eventlist
, retval
->sockfd
, EVFILT_READ
, EV_ADD
, 0, 0, NULL
);
233 res
= _kevent(retval
->read_queue
, &eventlist
, 1, NULL
, 0, NULL
);
239 __close_cached_connection(struct cached_connection_
*connection
)
241 assert(connection
!= NULL
);
243 _close(connection
->sockfd
);
244 _close(connection
->read_queue
);
245 _close(connection
->write_queue
);
250 * This function is very close to the cache_write function of the caching
251 * library, which is used in the caching daemon. It caches the data with the
252 * specified key in the cache entry with entry_name.
255 __cached_write(struct cached_connection_
*connection
, const char *entry_name
,
256 const char *key
, size_t key_size
, const char *data
, size_t data_size
)
263 result
= send_credentials(connection
, CET_WRITE_REQUEST
);
267 name_size
= strlen(entry_name
);
268 result
= safe_write(connection
, &name_size
, sizeof(size_t));
272 result
= safe_write(connection
, &key_size
, sizeof(size_t));
276 result
= safe_write(connection
, &data_size
, sizeof(size_t));
280 result
= safe_write(connection
, entry_name
, name_size
);
284 result
= safe_write(connection
, key
, key_size
);
288 result
= safe_write(connection
, data
, data_size
);
292 result
= safe_read(connection
, &error_code
, sizeof(int));
301 * This function is very close to the cache_read function of the caching
302 * library, which is used in the caching daemon. It reads cached data with the
303 * specified key from the cache entry with entry_name.
306 __cached_read(struct cached_connection_
*connection
, const char *entry_name
,
307 const char *key
, size_t key_size
, char *data
, size_t *data_size
)
309 size_t name_size
, result_size
;
310 int error_code
, rec_error_code
;
313 assert(connection
!= NULL
);
317 result
= send_credentials(connection
, CET_READ_REQUEST
);
321 name_size
= strlen(entry_name
);
322 result
= safe_write(connection
, &name_size
, sizeof(size_t));
326 result
= safe_write(connection
, &key_size
, sizeof(size_t));
330 result
= safe_write(connection
, entry_name
, name_size
);
334 result
= safe_write(connection
, key
, key_size
);
338 result
= safe_read(connection
, &rec_error_code
, sizeof(int));
342 if (rec_error_code
!= 0) {
343 error_code
= rec_error_code
;
347 result
= safe_read(connection
, &result_size
, sizeof(size_t));
351 if (result_size
> *data_size
) {
352 *data_size
= result_size
;
357 result
= safe_read(connection
, data
, result_size
);
361 *data_size
= result_size
;
369 * Initializes the mp_write_session. For such a session the new connection
370 * would be opened. The data should be written to the session with
371 * __cached_mp_write function. The __close_cached_mp_write_session function
372 * should be used to submit session and __abandon_cached_mp_write_session - to
373 * abandon it. When the session is submitted, the whole se
375 struct cached_connection_
*
376 __open_cached_mp_write_session(struct cached_connection_params
const *params
,
377 const char *entry_name
)
379 struct cached_connection_
*connection
, *retval
;
385 connection
= __open_cached_connection(params
);
386 if (connection
== NULL
)
388 connection
->mp_flag
= 1;
390 result
= send_credentials(connection
, CET_MP_WRITE_SESSION_REQUEST
);
394 name_size
= strlen(entry_name
);
395 result
= safe_write(connection
, &name_size
, sizeof(size_t));
399 result
= safe_write(connection
, entry_name
, name_size
);
403 result
= safe_read(connection
, &error_code
, sizeof(int));
412 __close_cached_connection(connection
);
419 * Adds new portion of data to the opened write session
422 __cached_mp_write(struct cached_connection_
*ws
, const char *data
,
430 request
= CET_MP_WRITE_SESSION_WRITE_REQUEST
;
431 result
= safe_write(ws
, &request
, sizeof(int));
435 result
= safe_write(ws
, &data_size
, sizeof(size_t));
439 result
= safe_write(ws
, data
, data_size
);
443 result
= safe_read(ws
, &error_code
, sizeof(int));
452 * Abandons all operations with the write session. All data, that were written
453 * to the session before, are discarded.
456 __abandon_cached_mp_write_session(struct cached_connection_
*ws
)
461 notification
= CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION
;
462 result
= safe_write(ws
, ¬ification
, sizeof(int));
463 __close_cached_connection(ws
);
468 * Gracefully closes the write session. The data, that were previously written
469 * to the session, are committed.
472 __close_cached_mp_write_session(struct cached_connection_
*ws
)
477 notification
= CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION
;
478 result
= safe_write(ws
, ¬ification
, sizeof(int));
479 __close_cached_connection(ws
);
483 struct cached_connection_
*
484 __open_cached_mp_read_session(struct cached_connection_params
const *params
,
485 const char *entry_name
)
487 struct cached_connection_
*connection
, *retval
;
493 connection
= __open_cached_connection(params
);
494 if (connection
== NULL
)
496 connection
->mp_flag
= 1;
498 result
= send_credentials(connection
, CET_MP_READ_SESSION_REQUEST
);
502 name_size
= strlen(entry_name
);
503 result
= safe_write(connection
, &name_size
, sizeof(size_t));
507 result
= safe_write(connection
, entry_name
, name_size
);
511 result
= safe_read(connection
, &error_code
, sizeof(int));
520 __close_cached_connection(connection
);
527 __cached_mp_read(struct cached_connection_
*rs
, char *data
, size_t *data_size
)
530 int error_code
, rec_error_code
;
534 request
= CET_MP_READ_SESSION_READ_REQUEST
;
535 result
= safe_write(rs
, &request
, sizeof(int));
539 result
= safe_read(rs
, &rec_error_code
, sizeof(int));
543 if (rec_error_code
!= 0) {
544 error_code
= rec_error_code
;
548 result
= safe_read(rs
, &result_size
, sizeof(size_t));
552 if (result_size
> *data_size
) {
553 *data_size
= result_size
;
558 result
= safe_read(rs
, data
, result_size
);
562 *data_size
= result_size
;
570 __close_cached_mp_read_session(struct cached_connection_
*rs
)
573 __close_cached_connection(rs
);