5917 User-mode SMB server
[unleashed.git] / usr / src / lib / libfakekernel / common / ksocket.c
blob53bcf875761aac29ff4dfbb3e2bc5e1c59d71578
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 #include <sys/cred.h>
30 #include <sys/errno.h>
31 #include <sys/socket.h>
32 #include <sys/ksocket.h>
33 #include <sys/debug.h>
34 #include <sys/kmem.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <umem.h>
39 #define _KSOCKET_MAGIC 0xabcdef09
41 #define KSOCKET_VALID(ks) (ks->kso_magic == _KSOCKET_MAGIC)
42 #define KSTOSO(ks) (ks->kso_fd)
44 #ifndef SS_CLOSING
45 #define SS_CLOSING 0x00010000
46 #endif
49 * NB: you can't cast this into a sonode like you can with a normal
50 * ksocket_t, but no correct code should ever do that anyway.
51 * The ksocket_t type is opaque to prevent exactly that.
53 struct __ksocket {
54 uint32_t kso_magic;
55 uint32_t kso_count;
56 uint32_t kso_state;
57 int kso_fd;
58 kmutex_t kso_lock;
59 kcondvar_t kso_closing_cv;
62 static umem_cache_t *ksocket_cache = NULL;
64 /*ARGSUSED*/
65 static int
66 _ksocket_ctor(void *buf, void *arg, int flags)
68 ksocket_t sock = buf;
70 bzero(sock, sizeof (*sock));
71 mutex_init(&sock->kso_lock, NULL, MUTEX_DEFAULT, NULL);
72 cv_init(&sock->kso_closing_cv, NULL, CV_DEFAULT, NULL);
73 return (0);
76 /*ARGSUSED*/
77 static void
78 _ksocket_dtor(void *buf, void *arg)
80 ksocket_t sock = buf;
82 mutex_destroy(&sock->kso_lock);
83 cv_destroy(&sock->kso_closing_cv);
86 #pragma init(_ksocket_init)
87 int
88 _ksocket_init(void)
90 ksocket_cache = umem_cache_create("ksocket",
91 sizeof (struct __ksocket), 0,
92 _ksocket_ctor, _ksocket_dtor, NULL, NULL, NULL, 0);
93 VERIFY(ksocket_cache != NULL);
94 return (0);
97 #pragma fini(_ksocket_fini)
98 int
99 _ksocket_fini(void)
101 umem_cache_destroy(ksocket_cache);
102 return (0);
105 static ksocket_t
106 _ksocket_create(int fd)
108 ksocket_t ks;
110 ks = umem_cache_alloc(ksocket_cache, 0);
111 VERIFY(ks != NULL);
112 ks->kso_magic = _KSOCKET_MAGIC;
113 ks->kso_count = 1;
114 ks->kso_fd = fd;
115 return (ks);
118 static void
119 _ksocket_destroy(ksocket_t ks)
121 ASSERT(ks->kso_count == 1);
122 umem_cache_free(ksocket_cache, ks);
126 ksocket_socket(ksocket_t *ksp, int domain, int type, int protocol, int flags,
127 struct cred *cr)
129 int fd;
130 ksocket_t ks;
132 /* All Solaris components should pass a cred for this operation. */
133 ASSERT(cr != NULL);
135 ASSERT(flags == KSOCKET_SLEEP || flags == KSOCKET_NOSLEEP);
137 fd = socket(domain, type, protocol);
138 if (fd < 0) {
139 *ksp = NULL;
140 return (errno);
143 ks = _ksocket_create(fd);
144 *ksp = ks;
145 return (0);
149 * This is marked NODIRECT so the main program linking with this library
150 * can provide its own "bind helper" function. See: fksmbd_ksock.c
152 /* ARGSUSED */
154 ksocket_bind_helper(int fd, struct sockaddr *addr, uint_t addrlen)
156 return (EACCES);
160 ksocket_bind(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
161 struct cred *cr)
163 int err = 0;
165 /* All Solaris components should pass a cred for this operation. */
166 ASSERT(cr != NULL);
168 if (!KSOCKET_VALID(ks))
169 return (ENOTSOCK);
171 if (bind(KSTOSO(ks), addr, addrlen) != 0)
172 err = errno;
174 if (err == EACCES) {
175 err = ksocket_bind_helper(KSTOSO(ks), addr, addrlen);
178 return (err);
182 ksocket_listen(ksocket_t ks, int backlog, struct cred *cr)
184 /* All Solaris components should pass a cred for this operation. */
185 ASSERT(cr != NULL);
187 if (!KSOCKET_VALID(ks))
188 return (ENOTSOCK);
190 if (listen(KSTOSO(ks), backlog) != 0)
191 return (errno);
193 return (0);
197 ksocket_accept(ksocket_t ks, struct sockaddr *addr,
198 socklen_t *addrlenp, ksocket_t *nks, struct cred *cr)
200 int fd;
202 /* All Solaris components should pass a cred for this operation. */
203 ASSERT(cr != NULL);
205 *nks = NULL;
207 if (!KSOCKET_VALID(ks))
208 return (ENOTSOCK);
210 if (addr != NULL && addrlenp == NULL)
211 return (EFAULT);
213 fd = accept(KSTOSO(ks), addr, addrlenp);
214 if (fd < 0)
215 return (errno);
217 *nks = _ksocket_create(fd);
219 return (0);
223 ksocket_connect(ksocket_t ks, struct sockaddr *addr, socklen_t addrlen,
224 struct cred *cr)
226 /* All Solaris components should pass a cred for this operation. */
227 ASSERT(cr != NULL);
229 if (!KSOCKET_VALID(ks))
230 return (ENOTSOCK);
232 if (connect(KSTOSO(ks), addr, addrlen) != 0)
233 return (errno);
235 return (0);
239 ksocket_send(ksocket_t ks, void *msg, size_t msglen, int flags,
240 size_t *sent, struct cred *cr)
242 ssize_t error;
244 /* All Solaris components should pass a cred for this operation. */
245 ASSERT(cr != NULL);
247 if (!KSOCKET_VALID(ks)) {
248 if (sent != NULL)
249 *sent = 0;
250 return (ENOTSOCK);
253 error = send(KSTOSO(ks), msg, msglen, flags);
254 if (error < 0) {
255 if (sent != NULL)
256 *sent = 0;
257 return (errno);
260 if (sent != NULL)
261 *sent = (size_t)error;
262 return (0);
266 ksocket_sendto(ksocket_t ks, void *msg, size_t msglen, int flags,
267 struct sockaddr *name, socklen_t namelen, size_t *sent, struct cred *cr)
269 ssize_t error;
271 /* All Solaris components should pass a cred for this operation. */
272 ASSERT(cr != NULL);
274 if (!KSOCKET_VALID(ks)) {
275 if (sent != NULL)
276 *sent = 0;
277 return (ENOTSOCK);
280 error = sendto(KSTOSO(ks), msg, msglen, flags, name, namelen);
281 if (error < 0) {
282 if (sent != NULL)
283 *sent = 0;
284 return (errno);
287 if (sent != NULL)
288 *sent = (size_t)error;
289 return (0);
293 ksocket_sendmsg(ksocket_t ks, struct nmsghdr *msg, int flags,
294 size_t *sent, struct cred *cr)
296 ssize_t error;
298 /* All Solaris components should pass a cred for this operation. */
299 ASSERT(cr != NULL);
301 if (!KSOCKET_VALID(ks)) {
302 if (sent != NULL)
303 *sent = 0;
304 return (ENOTSOCK);
307 error = sendmsg(KSTOSO(ks), msg, flags);
308 if (error < 0) {
309 if (sent != NULL)
310 *sent = 0;
311 return (errno);
314 if (sent != NULL)
315 *sent = (size_t)error;
316 return (0);
320 ksocket_recv(ksocket_t ks, void *msg, size_t msglen, int flags,
321 size_t *recvd, struct cred *cr)
323 ssize_t error;
325 /* All Solaris components should pass a cred for this operation. */
326 ASSERT(cr != NULL);
328 if (!KSOCKET_VALID(ks)) {
329 if (recvd != NULL)
330 *recvd = 0;
331 return (ENOTSOCK);
334 error = recv(KSTOSO(ks), msg, msglen, flags);
335 if (error < 0) {
336 if (recvd != NULL)
337 *recvd = 0;
338 return (errno);
341 if (recvd != NULL)
342 *recvd = (size_t)error;
343 return (0);
347 ksocket_recvfrom(ksocket_t ks, void *msg, size_t msglen, int flags,
348 struct sockaddr *name, socklen_t *namelen, size_t *recvd, struct cred *cr)
350 ssize_t error;
352 /* All Solaris components should pass a cred for this operation. */
353 ASSERT(cr != NULL);
355 if (!KSOCKET_VALID(ks)) {
356 if (recvd != NULL)
357 *recvd = 0;
358 return (ENOTSOCK);
361 error = recvfrom(KSTOSO(ks), msg, msglen, flags, name, namelen);
362 if (error != 0) {
363 if (recvd != NULL)
364 *recvd = 0;
365 return (errno);
368 if (recvd != NULL)
369 *recvd = (ssize_t)error;
370 return (0);
374 ksocket_recvmsg(ksocket_t ks, struct nmsghdr *msg, int flags, size_t *recvd,
375 struct cred *cr)
377 ssize_t error;
379 /* All Solaris components should pass a cred for this operation. */
380 ASSERT(cr != NULL);
382 if (!KSOCKET_VALID(ks)) {
383 if (recvd != NULL)
384 *recvd = 0;
385 return (ENOTSOCK);
388 error = recvmsg(KSTOSO(ks), msg, flags);
389 if (error < 0) {
390 if (recvd != NULL)
391 *recvd = 0;
392 return (errno);
395 if (recvd != NULL)
396 *recvd = (size_t)error;
397 return (0);
401 ksocket_shutdown(ksocket_t ks, int how, struct cred *cr)
403 /* All Solaris components should pass a cred for this operation. */
404 ASSERT(cr != NULL);
406 if (!KSOCKET_VALID(ks))
407 return (ENOTSOCK);
409 if (shutdown(KSTOSO(ks), how) != 0)
410 return (errno);
412 return (0);
416 ksocket_close(ksocket_t ks, struct cred *cr)
418 int fd;
420 /* All Solaris components should pass a cred for this operation. */
421 ASSERT(cr != NULL);
423 mutex_enter(&ks->kso_lock);
425 if (!KSOCKET_VALID(ks)) {
426 mutex_exit(&ks->kso_lock);
427 return (ENOTSOCK);
430 ks->kso_state |= SS_CLOSING;
433 * The real ksocket wakes up everything.
434 * It seems the only way we can do that
435 * is to go ahead and close the FD.
437 fd = ks->kso_fd;
438 ks->kso_fd = -1;
439 (void) close(fd);
441 while (ks->kso_count > 1)
442 cv_wait(&ks->kso_closing_cv, &ks->kso_lock);
444 mutex_exit(&ks->kso_lock);
445 _ksocket_destroy(ks);
447 return (0);
451 ksocket_getsockname(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
452 struct cred *cr)
454 /* All Solaris components should pass a cred for this operation. */
455 ASSERT(cr != NULL);
457 if (!KSOCKET_VALID(ks))
458 return (ENOTSOCK);
460 if (addrlen == NULL || (addr == NULL && *addrlen != 0))
461 return (EFAULT);
463 if (getsockname(KSTOSO(ks), addr, addrlen) != 0)
464 return (errno);
466 return (0);
470 ksocket_getpeername(ksocket_t ks, struct sockaddr *addr, socklen_t *addrlen,
471 struct cred *cr)
473 /* All Solaris components should pass a cred for this operation. */
474 ASSERT(cr != NULL);
476 if (!KSOCKET_VALID(ks))
477 return (ENOTSOCK);
479 if (addrlen == NULL || (addr == NULL && *addrlen != 0))
480 return (EFAULT);
482 if (getpeername(KSTOSO(ks), addr, addrlen) != 0)
483 return (errno);
485 return (0);
489 ksocket_setsockopt(ksocket_t ks, int level, int optname, const void *optval,
490 int optlen, struct cred *cr)
492 /* All Solaris components should pass a cred for this operation. */
493 ASSERT(cr != NULL);
495 if (!KSOCKET_VALID(ks))
496 return (ENOTSOCK);
498 if (optval == NULL)
499 optlen = 0;
501 if (setsockopt(KSTOSO(ks), level, optname, optval, optlen) != 0)
502 return (errno);
504 return (0);
507 void
508 ksocket_hold(ksocket_t ks)
510 if (!mutex_owned(&ks->kso_lock)) {
511 mutex_enter(&ks->kso_lock);
512 ks->kso_count++;
513 mutex_exit(&ks->kso_lock);
514 } else
515 ks->kso_count++;
518 void
519 ksocket_rele(ksocket_t ks)
522 * When so_count equals 1 means no thread working on this ksocket
524 VERIFY3U(ks->kso_count, >, 1);
526 if (!mutex_owned(&ks->kso_lock)) {
527 mutex_enter(&ks->kso_lock);
528 if (--ks->kso_count == 1)
529 cv_signal(&ks->kso_closing_cv);
530 mutex_exit(&ks->kso_lock);
531 } else {
532 if (--ks->kso_count == 1)
533 cv_signal(&ks->kso_closing_cv);