1 /* The protocol family independent socket driver framework. */
3 * The table below lists all supported socket driver requests, along with
4 * information on whether the request handler may suspend the call for later
5 * processing, and which message layout is to be used for the request and reply
6 * messages for each call.
8 * Type May suspend Request layout Reply layout
9 * ---- ----------- -------------- ------------
10 * SDEV_SOCKET no socket socket_reply
11 * SDEV_SOCKETPAIR no socket socket_reply
12 * SDEV_BIND yes addr reply
13 * SDEV_CONNECT yes addr reply
14 * SDEV_LISTEN no simple reply
15 * SDEV_ACCEPT yes addr accept_reply
16 * SDEV_SEND yes sendrecv reply
17 * SDEV_RECV yes sendrecv recv_reply
18 * SDEV_IOCTL yes ioctl reply
19 * SDEV_SETSOCKOPT no getset reply
20 * SDEV_GETSOCKOPT no getset reply
21 * SDEV_GETSOCKNAME no getset reply
22 * SDEV_GETPEERNAME no getset reply
23 * SDEV_SHUTDOWN no simple reply
24 * SDEV_CLOSE yes simple reply
25 * SDEV_CANCEL n/a simple -
26 * SDEV_SELECT yes (special) select select_reply
28 * The request message layouts are prefixed with "m_vfs_lsockdriver_". The
29 * reply message layouts are prefixed with "m_lsockdriver_vfs_", and use
30 * message types of the format SDEV_{,SOCKET_,ACCEPT_,RECV_}REPLY, matching the
31 * listed reply layout. One exception is SDEV_CANCEL, which itself has no
32 * reply at all. The other exception is SDEV_SELECT, which has two reply
33 * codes: SDEV_SELECT1_REPLY (for immediate replies) and SDEV_SELECT2_REPLY
34 * (for late replies), both using the select_reply reply layout.
37 #include <minix/drivers.h>
38 #include <minix/sockdriver.h>
39 #include <sys/ioctl.h>
44 * Announce that we are up and running, after a fresh start or a restart.
47 sockdriver_announce(void)
49 static const char *sockdriver_prefix
= "drv.sck.";
50 char key
[DS_MAX_KEYLEN
], label
[DS_MAX_KEYLEN
];
53 /* Publish a driver up event. */
54 if ((r
= ds_retrieve_label_name(label
, sef_self())) != OK
)
55 panic("sockdriver: unable to get own label: %d", r
);
57 snprintf(key
, sizeof(key
), "%s%s", sockdriver_prefix
, label
);
58 if ((r
= ds_publish_u32(key
, DS_DRIVER_UP
, DSF_OVERWRITE
)) != OK
)
59 panic("sockdriver: unable to publish driver up event: %d", r
);
63 * Copy data from the caller into the local address space. Return OK or a
64 * negative error code.
67 sockdriver_copyin(const struct sockdriver_data
* __restrict data
, size_t off
,
68 void * __restrict ptr
, size_t len
)
72 assert(off
+ len
<= data
->_sd_len
);
73 assert(data
->_sd_endpt
!= SELF
);
74 assert(GRANT_VALID(data
->_sd_grant
));
76 return sys_safecopyfrom(data
->_sd_endpt
, data
->_sd_grant
, off
,
81 * Copy data from the local address space to the caller. Return OK or a
82 * negative error code.
85 sockdriver_copyout(const struct sockdriver_data
* __restrict data
, size_t off
,
86 const void * __restrict ptr
, size_t len
)
90 assert(off
+ len
<= data
->_sd_len
);
91 assert(data
->_sd_endpt
!= SELF
);
92 assert(GRANT_VALID(data
->_sd_grant
));
94 return sys_safecopyto(data
->_sd_endpt
, data
->_sd_grant
, off
,
99 * Copy data between the caller and the local address space, using a vector of
100 * at most SOCKDRIVER_IOV_MAX buffers. Return OK or an error code.
103 sockdriver_vcopy(const struct sockdriver_data
* __restrict data
, size_t off
,
104 const iovec_t
* __restrict iov
, unsigned int iovcnt
, int copyin
)
106 static struct vscp_vec vec
[SOCKDRIVER_IOV_MAX
];
110 assert(iovcnt
<= __arraycount(vec
));
112 /* We allow zero-element vectors, because we are nice. */
117 * Do not use a vector copy operation for single-element copies, as
118 * this saves the kernel from having to copy in the vector itself.
122 return sockdriver_copyin(data
, off
,
123 (void *)iov
->iov_addr
, iov
->iov_size
);
125 return sockdriver_copyout(data
, off
,
126 (const void *)iov
->iov_addr
, iov
->iov_size
);
129 assert(data
!= NULL
);
130 assert(data
->_sd_endpt
!= SELF
);
131 assert(GRANT_VALID(data
->_sd_grant
));
133 for (i
= 0; i
< iovcnt
; i
++, iov
++) {
135 vec
[i
].v_from
= data
->_sd_endpt
;
138 vec
[i
].v_from
= SELF
;
139 vec
[i
].v_to
= data
->_sd_endpt
;
141 vec
[i
].v_gid
= data
->_sd_grant
;
142 vec
[i
].v_offset
= off
;
143 vec
[i
].v_addr
= iov
->iov_addr
;
144 vec
[i
].v_bytes
= iov
->iov_size
;
146 off
+= iov
->iov_size
;
149 assert(off
<= data
->_sd_len
);
151 return sys_vsafecopy(vec
, iovcnt
);
155 * Copy data from the caller into the local address space, using a vector of
156 * buffers. Return OK or a negative error code.
159 sockdriver_vcopyin(const struct sockdriver_data
* __restrict data
, size_t off
,
160 const iovec_t
* __restrict iov
, unsigned int iovcnt
)
163 return sockdriver_vcopy(data
, off
, iov
, iovcnt
, TRUE
/*copyin*/);
167 * Copy data from the local address space to the caller, using a vector of
168 * buffers. Return OK or a negative error code.
171 sockdriver_vcopyout(const struct sockdriver_data
* __restrict data
, size_t off
,
172 const iovec_t
* __restrict iov
, unsigned int iovcnt
)
175 return sockdriver_vcopy(data
, off
, iov
, iovcnt
, FALSE
/*copyin*/);
179 * Copy data from the caller into the local address space, using socket option
180 * semantics: fail the call with EINVAL if the given 'optlen' is not equal to
181 * the given 'len'. Return OK or a negative error code.
184 sockdriver_copyin_opt(const struct sockdriver_data
* __restrict data
,
185 void * __restrict ptr
, size_t len
, socklen_t optlen
)
191 return sockdriver_copyin(data
, 0, ptr
, len
);
195 * Copy data from the local address space to the caller, using socket option
196 * semantics: limit the size of the copied-out data to the size pointed to by
197 * 'optlen', and return the possibly truncated size in 'optlen' on success.
198 * Return OK or a negative error code.
201 sockdriver_copyout_opt(const struct sockdriver_data
* __restrict data
,
202 const void * __restrict ptr
, size_t len
, socklen_t
* __restrict optlen
)
209 if ((r
= sockdriver_copyout(data
, 0, ptr
, len
)) == OK
)
216 * Compress a sockdriver_data structure to a smaller variant that stores only
217 * the fields that are not already stored redundantly in/as the given 'call'
218 * and 'len' parameters. The typical use case here this call suspension. In
219 * that case, the caller will already store 'call' and 'len' as is, and can
220 * save memory by storing a packed version of 'data' rather than that structure
221 * itself. Return OK on success, with 'pack' containing a compressed version
222 * of 'data'. Return EINVAL if the given parameters do not match; this would
223 * typically be a sign that the calling application messed up badly.
226 sockdriver_pack_data(struct sockdriver_packed_data
* pack
,
227 const struct sockdriver_call
* call
,
228 const struct sockdriver_data
* data
, size_t len
)
231 if (data
->_sd_endpt
!= call
->sc_endpt
)
233 if (data
->_sd_len
!= len
)
236 pack
->_spd_grant
= data
->_sd_grant
;
241 * Decompress a previously packed sockdriver data structure into a full
242 * sockdriver_data structure, with the help of the given 'call' and 'len'
243 * parameters. Return the unpacked version of 'pack' in 'data'. This function
247 sockdriver_unpack_data(struct sockdriver_data
* data
,
248 const struct sockdriver_call
* call
,
249 const struct sockdriver_packed_data
* pack
, size_t len
)
252 data
->_sd_endpt
= call
->sc_endpt
;
253 data
->_sd_grant
= pack
->_spd_grant
;
258 * Send a reply to a request.
261 send_reply(endpoint_t endpt
, int type
, message
* m_ptr
)
265 m_ptr
->m_type
= type
;
267 if ((r
= asynsend(endpt
, m_ptr
)) != OK
)
268 printf("sockdriver: sending reply to %d failed (%d)\n",
273 * Send a reply which takes only a result code and no additional reply fields.
276 send_generic_reply(endpoint_t endpt
, sockreq_t req
, int reply
)
280 assert(reply
!= SUSPEND
&& reply
!= EDONTREPLY
);
282 memset(&m
, 0, sizeof(m
));
283 m
.m_lsockdriver_vfs_reply
.req_id
= req
;
284 m
.m_lsockdriver_vfs_reply
.status
= reply
;
286 send_reply(endpt
, SDEV_REPLY
, &m
);
290 * Send a reply to an earlier suspended request which takes only a result code
291 * and no additional reply fields.
294 sockdriver_reply_generic(const struct sockdriver_call
* call
, int reply
)
297 send_generic_reply(call
->sc_endpt
, call
->sc_req
, reply
);
301 * Send a reply to a socket or a socketpair request. Since these calls may not
302 * be suspended, this function is used internally only.
305 send_socket_reply(endpoint_t endpt
, sockreq_t req
, sockid_t reply
,
310 assert(reply
!= SUSPEND
&& reply
!= EDONTREPLY
);
312 memset(&m
, 0, sizeof(m
));
313 m
.m_lsockdriver_vfs_socket_reply
.req_id
= req
;
314 m
.m_lsockdriver_vfs_socket_reply
.sock_id
= reply
;
315 m
.m_lsockdriver_vfs_socket_reply
.sock_id2
= reply2
;
317 send_reply(endpt
, SDEV_SOCKET_REPLY
, &m
);
321 * Send a reply to an earlier suspended accept request. The given reply is
322 * either a socket identifier (>= 0) or an error code (< 0). On success, an
323 * address must be given as 'addr', and its nonzero length must be given as
327 sockdriver_reply_accept(const struct sockdriver_call
* __restrict call
,
328 sockid_t reply
, struct sockaddr
* __restrict addr
, socklen_t addr_len
)
333 assert(reply
!= SUSPEND
&& reply
!= EDONTREPLY
);
336 * If the accept was successful, copy out the address, if requested.
337 * If the copy fails, send both a valid socket ID and an error to VFS.
338 * VFS will then close the newly created socket immediately, and return
339 * the error to the caller.
341 * While not particularly nice, the general behavior of closing the
342 * socket after accepting it seems to be common among other OSes for
343 * address copy errors. Most importantly, it frees the socket driver
344 * from having to deal with address copy errors itself.
346 * Letting VFS close the socket is also not all that great. However,
347 * it is the lesser evil compared to the two main alternatives: 1)
348 * immediately calling sdr_close() from here, which would seriously
349 * complicate writing socket drivers due to sockets disappearing from
350 * under it, so to speak, and 2) queuing a forged incoming SDEV_CLOSE
351 * request, for which we do not have the necessary infrastructure.
352 * Additionally, VFS may close the newly accepted socket when out of
353 * other required resources anyway, so logically this fits in well.
354 * The only real price to pay is a slightly uglier message protocol.
356 * Copying out the address *length* is not our responsibility at all;
357 * if VFS chooses to do this itself (as opposed to letting libc do it),
358 * it too will have to close the socket on failure, using a separate
359 * close call. This is always multithreading-safe because userland can
360 * not access the accepted socket yet anyway.
368 if (reply
== OK
&& GRANT_VALID(call
->_sc_grant
)) {
369 if (addr
== NULL
|| addr_len
== 0)
370 panic("libsockdriver: success but no address given");
372 if (addr_len
> call
->_sc_len
)
373 addr_len
= call
->_sc_len
; /* truncate addr and len */
376 reply
= sys_safecopyto(call
->sc_endpt
, call
->_sc_grant
,
377 0, (vir_bytes
)addr
, addr_len
);
379 /* Intentionally leave 'id' set on failure here. */
382 addr_len
= 0; /* not needed, but cleaner */
384 memset(&m
, 0, sizeof(m
));
385 m
.m_lsockdriver_vfs_accept_reply
.req_id
= call
->sc_req
;
386 m
.m_lsockdriver_vfs_accept_reply
.sock_id
= id
;
387 m
.m_lsockdriver_vfs_accept_reply
.status
= reply
;
388 m
.m_lsockdriver_vfs_accept_reply
.len
= addr_len
;
390 send_reply(call
->sc_endpt
, SDEV_ACCEPT_REPLY
, &m
);
394 * Send a reply to an earlier suspended receive call. The given reply code is
395 * the number of regular data bytes received (>= 0) or an error code (< 0).
396 * On success, for connectionless sockets, 'addr' must point to the source
397 * address and 'addr_len' must contain the address length; for connection-
398 * oriented sockets, 'addr_len' must be zero, in which case 'addr' is ignored.
401 sockdriver_reply_recv(const struct sockdriver_call
* __restrict call
,
402 int reply
, socklen_t ctl_len
, struct sockaddr
* __restrict addr
,
403 socklen_t addr_len
, int flags
)
408 assert(reply
!= SUSPEND
&& reply
!= EDONTREPLY
);
411 * If applicable, copy out the address. If this fails, the result is
412 * loss of the data received; in the case of AF_UNIX, this may include
413 * references to file descriptors already created in the receiving
414 * process. At least Linux and NetBSD behave this way as well, which
415 * is not an excuse to be lazy, but we need to change just about
416 * everything for the worse (including having additional grants just
417 * for storing lengths) in order to fully solve this corner case.
419 * TODO: a reasonable compromise might be to add a callback routine for
420 * closing file descriptors in any already-written control data. This
421 * would solve the worst aspect of the data loss, not the loss itself.
423 if (reply
>= 0 && addr_len
> 0 && GRANT_VALID(call
->_sc_grant
)) {
425 panic("libsockdriver: success but no address given");
427 if (addr_len
> call
->_sc_len
)
428 addr_len
= call
->_sc_len
; /* truncate addr and len */
430 if (addr_len
> 0 && (r
= sys_safecopyto(call
->sc_endpt
,
431 call
->_sc_grant
, 0, (vir_bytes
)addr
, addr_len
)) != OK
)
436 memset(&m
, 0, sizeof(m
));
437 m
.m_lsockdriver_vfs_recv_reply
.req_id
= call
->sc_req
;
438 m
.m_lsockdriver_vfs_recv_reply
.status
= reply
;
439 m
.m_lsockdriver_vfs_recv_reply
.ctl_len
= ctl_len
;
440 m
.m_lsockdriver_vfs_recv_reply
.addr_len
= addr_len
;
441 m
.m_lsockdriver_vfs_recv_reply
.flags
= flags
;
443 send_reply(call
->sc_endpt
, SDEV_RECV_REPLY
, &m
);
447 * Send a reply to a select request.
450 send_select_reply(const struct sockdriver_select
* sel
, int type
, sockid_t id
,
455 assert(ops
!= SUSPEND
&& ops
!= EDONTREPLY
);
457 memset(&m
, 0, sizeof(m
));
458 m
.m_lsockdriver_vfs_select_reply
.sock_id
= id
;
459 m
.m_lsockdriver_vfs_select_reply
.status
= ops
;
461 send_reply(sel
->ss_endpt
, type
, &m
);
465 * Send a reply to an earlier select call that requested notifications.
468 sockdriver_reply_select(const struct sockdriver_select
* sel
, sockid_t id
,
472 send_select_reply(sel
, SDEV_SELECT2_REPLY
, id
, ops
);
476 * Create a new socket. This call may not be suspended.
479 do_socket(const struct sockdriver
* __restrict sdp
,
480 const message
* __restrict m_ptr
)
484 if (sdp
->sdr_socket
!= NULL
)
485 r
= sdp
->sdr_socket(m_ptr
->m_vfs_lsockdriver_socket
.domain
,
486 m_ptr
->m_vfs_lsockdriver_socket
.type
,
487 m_ptr
->m_vfs_lsockdriver_socket
.protocol
,
488 m_ptr
->m_vfs_lsockdriver_socket
.user_endpt
);
492 send_socket_reply(m_ptr
->m_source
,
493 m_ptr
->m_vfs_lsockdriver_socket
.req_id
, r
, -1);
497 * Create a pair of connected sockets. Relevant for UNIX domain sockets only.
498 * This call may not be suspended.
501 do_socketpair(const struct sockdriver
* __restrict sdp
,
502 const message
* __restrict m_ptr
)
507 if (sdp
->sdr_socketpair
!= NULL
)
508 r
= sdp
->sdr_socketpair(m_ptr
->m_vfs_lsockdriver_socket
.domain
,
509 m_ptr
->m_vfs_lsockdriver_socket
.type
,
510 m_ptr
->m_vfs_lsockdriver_socket
.protocol
,
511 m_ptr
->m_vfs_lsockdriver_socket
.user_endpt
, sockid
);
520 send_socket_reply(m_ptr
->m_source
,
521 m_ptr
->m_vfs_lsockdriver_socket
.req_id
, sockid
[0], sockid
[1]);
525 * Bind a socket to a local address, or connect a socket to a remote address.
526 * In both cases, this call may be suspended by the socket driver, in which
527 * case sockdriver_reply_generic() must be used to reply later.
529 * For bind(2), POSIX is not entirely consistent regarding call suspension: the
530 * bind(2) call may return EINPROGRESS for nonblocking sockets, but this also
531 * suggests that blocking bind(2) calls may be interrupted by signals (as on
532 * MINIX3 they can be), yet EINTR is not defined as a valid return code for it.
535 do_bind_connect(const struct sockdriver
* __restrict sdp
,
536 const message
* __restrict m_ptr
)
538 int (*proc
)(sockid_t
, const struct sockaddr
* __restrict
, socklen_t
,
539 endpoint_t
, const struct sockdriver_call
* __restrict
);
540 struct sockdriver_call call
;
541 char buf
[SOCKADDR_MAX
];
545 endpoint_t user_endpt
;
548 call
.sc_endpt
= m_ptr
->m_source
;
549 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_addr
.req_id
;
551 id
= m_ptr
->m_vfs_lsockdriver_addr
.sock_id
;
552 grant
= m_ptr
->m_vfs_lsockdriver_addr
.grant
;
553 len
= m_ptr
->m_vfs_lsockdriver_addr
.len
;
554 user_endpt
= m_ptr
->m_vfs_lsockdriver_addr
.user_endpt
;
555 sflags
= m_ptr
->m_vfs_lsockdriver_addr
.sflags
;
557 switch (m_ptr
->m_type
) {
558 case SDEV_BIND
: proc
= sdp
->sdr_bind
; break;
559 case SDEV_CONNECT
: proc
= sdp
->sdr_connect
; break;
560 default: panic("expected bind or connect");
564 if (!GRANT_VALID(grant
) || len
== 0 || len
> sizeof(buf
))
567 r
= sys_safecopyfrom(m_ptr
->m_source
, grant
, 0, (vir_bytes
)buf
,
572 r
= proc(id
, (struct sockaddr
*)buf
, len
, user_endpt
,
573 (sflags
& SDEV_NONBLOCK
) ? NULL
: &call
);
578 assert(!(sflags
& SDEV_NONBLOCK
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
580 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
581 sockdriver_reply_generic(&call
, r
);
585 * Put a socket in listening mode. This call may not be suspended.
588 do_listen(const struct sockdriver
* __restrict sdp
,
589 const message
* __restrict m_ptr
)
593 if (sdp
->sdr_listen
!= NULL
)
594 r
= sdp
->sdr_listen(m_ptr
->m_vfs_lsockdriver_simple
.sock_id
,
595 m_ptr
->m_vfs_lsockdriver_simple
.param
/*backlog*/);
599 send_generic_reply(m_ptr
->m_source
,
600 m_ptr
->m_vfs_lsockdriver_simple
.req_id
, r
);
604 * Accept a connection on a listening socket, creating a new socket.
605 * This call may be suspended by the socket driver, in which case
606 * sockdriver_reply_accept() must be used to reply later.
609 do_accept(const struct sockdriver
* __restrict sdp
,
610 const message
* __restrict m_ptr
)
612 struct sockdriver_call call
;
613 char buf
[SOCKADDR_MAX
];
614 struct sockaddr
*addr
;
616 endpoint_t user_endpt
;
620 call
.sc_endpt
= m_ptr
->m_source
;
621 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_addr
.req_id
;
622 call
._sc_grant
= m_ptr
->m_vfs_lsockdriver_addr
.grant
;
623 call
._sc_len
= m_ptr
->m_vfs_lsockdriver_addr
.len
;
625 addr
= (struct sockaddr
*)buf
;
627 user_endpt
= m_ptr
->m_vfs_lsockdriver_addr
.user_endpt
;
628 sflags
= m_ptr
->m_vfs_lsockdriver_addr
.sflags
;
630 if (sdp
->sdr_accept
!= NULL
)
631 r
= sdp
->sdr_accept(m_ptr
->m_vfs_lsockdriver_addr
.sock_id
,
632 addr
, &len
, user_endpt
,
633 (sflags
& SDEV_NONBLOCK
) ? NULL
: &call
);
637 assert(!(sflags
& SDEV_NONBLOCK
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
639 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
640 sockdriver_reply_accept(&call
, r
, addr
, len
);
644 * Send regular and/or control data. This call may be suspended by the socket
645 * driver, in which case sockdriver_reply_generic() must be used to reply
649 do_send(const struct sockdriver
* __restrict sdp
,
650 const message
* __restrict m_ptr
)
652 struct sockdriver_call call
;
653 struct sockdriver_data data
, ctl_data
;
654 char buf
[SOCKADDR_MAX
];
655 struct sockaddr
*addr
;
656 cp_grant_id_t addr_grant
;
658 endpoint_t user_endpt
;
662 call
.sc_endpt
= m_ptr
->m_source
;
663 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_sendrecv
.req_id
;
665 data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.data_grant
;
666 data
._sd_endpt
= m_ptr
->m_source
;
667 data
._sd_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.data_len
;
669 /* The returned size must fit in an 'int'; truncate accordingly. */
670 if (data
._sd_len
> INT_MAX
)
671 data
._sd_len
= INT_MAX
;
673 ctl_data
._sd_endpt
= m_ptr
->m_source
;
674 ctl_data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.ctl_grant
;
675 ctl_data
._sd_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.ctl_len
;
677 id
= m_ptr
->m_vfs_lsockdriver_sendrecv
.sock_id
;
678 addr_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.addr_grant
;
679 addr_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.addr_len
;
680 user_endpt
= m_ptr
->m_vfs_lsockdriver_sendrecv
.user_endpt
;
681 flags
= m_ptr
->m_vfs_lsockdriver_sendrecv
.flags
;
684 if (GRANT_VALID(addr_grant
)) {
685 if (addr_len
== 0 || addr_len
> sizeof(buf
))
688 r
= sys_safecopyfrom(m_ptr
->m_source
, addr_grant
, 0,
689 (vir_bytes
)buf
, addr_len
);
690 addr
= (struct sockaddr
*)buf
;
697 if (sdp
->sdr_send
!= NULL
)
698 r
= sdp
->sdr_send(id
, &data
, data
._sd_len
, &ctl_data
,
699 ctl_data
._sd_len
, addr
, addr_len
, user_endpt
,
700 flags
, (flags
& MSG_DONTWAIT
) ? NULL
: &call
);
705 assert(!(flags
& MSG_DONTWAIT
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
707 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
708 sockdriver_reply_generic(&call
, r
);
712 * Receive regular and/or control data. This call may be suspended by the
713 * socket driver, in which case sockdriver_reply_recv() must be used to reply
717 do_recv(const struct sockdriver
* __restrict sdp
,
718 const message
* __restrict m_ptr
)
720 struct sockdriver_call call
;
721 struct sockdriver_data data
, ctl_data
;
722 char buf
[SOCKADDR_MAX
];
723 struct sockaddr
*addr
;
725 socklen_t ctl_len
, addr_len
;
726 endpoint_t user_endpt
;
729 call
.sc_endpt
= m_ptr
->m_source
;
730 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_sendrecv
.req_id
;
731 call
._sc_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.addr_grant
;
732 call
._sc_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.addr_len
;
734 data
._sd_endpt
= m_ptr
->m_source
;
735 data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.data_grant
;
736 data
._sd_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.data_len
;
738 /* The returned size must fit in an 'int'; truncate accordingly. */
739 if (data
._sd_len
> INT_MAX
)
740 data
._sd_len
= INT_MAX
;
742 ctl_data
._sd_endpt
= m_ptr
->m_source
;
743 ctl_data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_sendrecv
.ctl_grant
;
744 ctl_data
._sd_len
= m_ptr
->m_vfs_lsockdriver_sendrecv
.ctl_len
;
746 id
= m_ptr
->m_vfs_lsockdriver_sendrecv
.sock_id
;
747 ctl_len
= ctl_data
._sd_len
;
748 addr
= (struct sockaddr
*)buf
;
749 addr_len
= 0; /* the default: no source address */
750 user_endpt
= m_ptr
->m_vfs_lsockdriver_sendrecv
.user_endpt
;
751 flags
= m_ptr
->m_vfs_lsockdriver_sendrecv
.flags
;
753 if (sdp
->sdr_recv
!= NULL
)
754 r
= sdp
->sdr_recv(id
, &data
, data
._sd_len
, &ctl_data
, &ctl_len
,
755 addr
, &addr_len
, user_endpt
, &flags
,
756 (flags
& MSG_DONTWAIT
) ? NULL
: &call
);
760 assert(!(flags
& MSG_DONTWAIT
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
762 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
763 sockdriver_reply_recv(&call
, r
, ctl_len
, addr
, addr_len
,
768 * Process an I/O control call. This call may be suspended by the socket
769 * driver, in which case sockdriver_reply_generic() must be used to reply
773 do_ioctl(const struct sockdriver
* __restrict sdp
,
774 const message
* __restrict m_ptr
)
776 struct sockdriver_call call
;
777 struct sockdriver_data data
;
779 unsigned long request
;
780 endpoint_t user_endpt
;
783 call
.sc_endpt
= m_ptr
->m_source
;
784 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_ioctl
.req_id
;
786 id
= m_ptr
->m_vfs_lsockdriver_ioctl
.sock_id
;
787 request
= m_ptr
->m_vfs_lsockdriver_ioctl
.request
;
788 user_endpt
= m_ptr
->m_vfs_lsockdriver_ioctl
.user_endpt
;
789 sflags
= m_ptr
->m_vfs_lsockdriver_ioctl
.sflags
;
791 data
._sd_endpt
= m_ptr
->m_source
;
792 data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_ioctl
.grant
;
793 if (_MINIX_IOCTL_BIG(request
))
794 data
._sd_len
= _MINIX_IOCTL_SIZE_BIG(request
);
796 data
._sd_len
= _MINIX_IOCTL_SIZE(request
);
798 if (sdp
->sdr_ioctl
!= NULL
)
799 r
= sdp
->sdr_ioctl(id
, request
, &data
, user_endpt
,
800 (sflags
& SDEV_NONBLOCK
) ? NULL
: &call
);
804 assert(!(sflags
& SDEV_NONBLOCK
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
806 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
807 sockdriver_reply_generic(&call
, r
);
811 * Set socket options. This call may not be suspended.
814 do_setsockopt(const struct sockdriver
* __restrict sdp
,
815 const message
* __restrict m_ptr
)
817 struct sockdriver_data data
;
820 data
._sd_endpt
= m_ptr
->m_source
;
821 data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_getset
.grant
;
822 data
._sd_len
= m_ptr
->m_vfs_lsockdriver_getset
.len
;
824 if (sdp
->sdr_setsockopt
!= NULL
)
825 r
= sdp
->sdr_setsockopt(
826 m_ptr
->m_vfs_lsockdriver_getset
.sock_id
,
827 m_ptr
->m_vfs_lsockdriver_getset
.level
,
828 m_ptr
->m_vfs_lsockdriver_getset
.name
, &data
, data
._sd_len
);
832 send_generic_reply(m_ptr
->m_source
,
833 m_ptr
->m_vfs_lsockdriver_getset
.req_id
, r
);
837 * Retrieve socket options. This call may not be suspended.
840 do_getsockopt(const struct sockdriver
* __restrict sdp
,
841 const message
* __restrict m_ptr
)
843 struct sockdriver_data data
;
847 data
._sd_endpt
= m_ptr
->m_source
;
848 data
._sd_grant
= m_ptr
->m_vfs_lsockdriver_getset
.grant
;
849 data
._sd_len
= m_ptr
->m_vfs_lsockdriver_getset
.len
;
853 if (sdp
->sdr_setsockopt
!= NULL
)
854 r
= sdp
->sdr_getsockopt(
855 m_ptr
->m_vfs_lsockdriver_getset
.sock_id
,
856 m_ptr
->m_vfs_lsockdriver_getset
.level
,
857 m_ptr
->m_vfs_lsockdriver_getset
.name
, &data
, &len
);
862 * For these requests, the main reply code is used to return the
863 * resulting data length on success. The length will never large
864 * enough to overflow, and we save on API calls and messages this way.
867 assert(len
<= INT_MAX
);
871 panic("libsockdriver: invalid reply");
873 send_generic_reply(m_ptr
->m_source
,
874 m_ptr
->m_vfs_lsockdriver_getset
.req_id
, r
);
878 * Get local or remote address. This call may not be suspended.
881 do_getname(const struct sockdriver
* __restrict sdp
,
882 const message
* __restrict m_ptr
)
884 int (*proc
)(sockid_t
, struct sockaddr
* __restrict
,
885 socklen_t
* __restrict
);
886 char buf
[SOCKADDR_MAX
];
887 socklen_t addr_len
, len
;
890 switch (m_ptr
->m_type
) {
891 case SDEV_GETSOCKNAME
: proc
= sdp
->sdr_getsockname
; break;
892 case SDEV_GETPEERNAME
: proc
= sdp
->sdr_getpeername
; break;
893 default: panic("expected getsockname or getpeername");
896 /* The 'name' and 'level' message fields are unused for these calls. */
898 addr_len
= m_ptr
->m_vfs_lsockdriver_getset
.len
;
902 r
= proc(m_ptr
->m_vfs_lsockdriver_getset
.sock_id
,
903 (struct sockaddr
*)buf
, &len
);
909 panic("libsockdriver: success but no address given");
914 /* As above, use the reply code for the resulting length. */
915 if (addr_len
> 0 && (r
= sys_safecopyto(m_ptr
->m_source
,
916 m_ptr
->m_vfs_lsockdriver_getset
.grant
, 0, (vir_bytes
)buf
,
918 assert(addr_len
<= INT_MAX
);
921 * The Open Group wording has changed recently, now
922 * suggesting that when truncating the "stored address"
923 * the resulting length should be truncated as well.
928 panic("libsockdriver: invalid reply");
930 send_generic_reply(m_ptr
->m_source
,
931 m_ptr
->m_vfs_lsockdriver_getset
.req_id
, r
);
935 * Shut down socket send and receive operations. This call may not be
939 do_shutdown(const struct sockdriver
* __restrict sdp
,
940 const message
* __restrict m_ptr
)
944 if (sdp
->sdr_shutdown
!= NULL
)
945 r
= sdp
->sdr_shutdown(
946 m_ptr
->m_vfs_lsockdriver_simple
.sock_id
,
947 m_ptr
->m_vfs_lsockdriver_simple
.param
/*how*/);
951 send_generic_reply(m_ptr
->m_source
,
952 m_ptr
->m_vfs_lsockdriver_simple
.req_id
, r
);
956 * Close a socket. This call may be suspended by the socket driver, in which
957 * case sockdriver_reply_generic() must be used to reply later. Note that VFS
958 * currently does not support blocking close operations, and will mark all
959 * close operations as nonblocking. This will be changed in the future.
962 do_close(const struct sockdriver
* __restrict sdp
,
963 const message
* __restrict m_ptr
)
965 struct sockdriver_call call
;
968 call
.sc_endpt
= m_ptr
->m_source
;
969 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_simple
.req_id
;
971 sflags
= m_ptr
->m_vfs_lsockdriver_simple
.param
;
973 if (sdp
->sdr_close
!= NULL
)
974 r
= sdp
->sdr_close(m_ptr
->m_vfs_lsockdriver_simple
.sock_id
,
975 (sflags
& SDEV_NONBLOCK
) ? NULL
: &call
);
977 r
= OK
; /* exception: this must never fail */
979 assert(!(sflags
& SDEV_NONBLOCK
) || (r
!= SUSPEND
&& r
!= EDONTREPLY
));
981 if (r
!= SUSPEND
&& r
!= EDONTREPLY
)
982 sockdriver_reply_generic(&call
, r
);
986 * Cancel a previous operation which may currently be suspended. The cancel
987 * operation itself does not have a reply. Instead, if the provided operation
988 * was found to be currently suspended, that operation must be aborted and a
989 * reply (typically EINTR) must be sent for it. If no matching operation was
990 * found, no reply must be sent at all.
993 do_cancel(const struct sockdriver
* __restrict sdp
,
994 const message
* __restrict m_ptr
)
996 struct sockdriver_call call
;
998 call
.sc_endpt
= m_ptr
->m_source
;
999 call
.sc_req
= m_ptr
->m_vfs_lsockdriver_simple
.req_id
;
1001 /* The 'param' message field is unused by this request. */
1003 if (sdp
->sdr_cancel
!= NULL
)
1004 sdp
->sdr_cancel(m_ptr
->m_vfs_lsockdriver_simple
.sock_id
,
1009 * Process a select request. Select requests have their own rules with respect
1010 * to suspension and later notification. The basic idea is: an immediate reply
1011 * is always sent with the subset of requested operations that are ready. If
1012 * SDEV_NOTIFY is given, the remaining operations are to be combined with any
1013 * previous operations requested (with SDEV_NOTIFY) by the calling endpoint.
1014 * If any of the pending previous operations become ready, a late reply is sent
1015 * and only those ready operations are forgotten, leaving any other non-ready
1016 * operations for other late replies.
1019 do_select(const struct sockdriver
* __restrict sdp
,
1020 const message
* __restrict m_ptr
)
1022 struct sockdriver_select sel
;
1026 sel
.ss_endpt
= m_ptr
->m_source
;
1027 id
= m_ptr
->m_vfs_lsockdriver_select
.sock_id
;
1028 ops
= m_ptr
->m_vfs_lsockdriver_select
.ops
;
1030 if (sdp
->sdr_select
!= NULL
)
1031 r
= sdp
->sdr_select(id
, ops
,
1032 (ops
& SDEV_NOTIFY
) ? &sel
: NULL
);
1036 send_select_reply(&sel
, SDEV_SELECT1_REPLY
, id
, r
);
1040 * Return TRUE if the given endpoint may initiate socket requests.
1043 may_request(endpoint_t endpt
)
1047 * For now, we allow only VFS to initiate socket calls. In the future,
1048 * we may allow networked file systems to call into the network stack
1049 * directly. The sockdriver API has already been designed to allow for
1050 * that, but this check will then need to change. Ideally it would be
1051 * using some sort of ACL system. For now, this check prevents that
1052 * network drivers themselves create and use sockets.
1054 return (endpt
== VFS_PROC_NR
);
1058 * Process an incoming message, and (typically) send a reply.
1061 sockdriver_process(const struct sockdriver
* __restrict sdp
,
1062 const message
* __restrict m_ptr
, int ipc_status
)
1065 /* Handle notifications separately. */
1066 if (is_ipc_notify(ipc_status
)) {
1067 switch (m_ptr
->m_source
) {
1069 if (sdp
->sdr_alarm
!= NULL
)
1070 sdp
->sdr_alarm(m_ptr
->m_notify
.timestamp
);
1073 if (sdp
->sdr_other
!= NULL
)
1074 sdp
->sdr_other(m_ptr
, ipc_status
);
1077 return; /* do not send a reply */
1080 /* Is this a socket request from an acceptable party? */
1081 if (!IS_SDEV_RQ(m_ptr
->m_type
) || !may_request(m_ptr
->m_source
)) {
1082 if (sdp
->sdr_other
!= NULL
)
1083 sdp
->sdr_other(m_ptr
, ipc_status
);
1085 return; /* do not send a reply */
1089 * Process the request. If the request is not recognized, we cannot
1090 * send a reply either, because we do not know the reply message
1091 * format. Passing the request message to the sdr_other hook serves no
1092 * practical purpose either: if the request is legitimate, this library
1093 * should know about it.
1095 switch (m_ptr
->m_type
) {
1096 case SDEV_SOCKET
: do_socket(sdp
, m_ptr
); break;
1097 case SDEV_SOCKETPAIR
: do_socketpair(sdp
, m_ptr
); break;
1098 case SDEV_BIND
: do_bind_connect(sdp
, m_ptr
); break;
1099 case SDEV_CONNECT
: do_bind_connect(sdp
, m_ptr
); break;
1100 case SDEV_LISTEN
: do_listen(sdp
, m_ptr
); break;
1101 case SDEV_ACCEPT
: do_accept(sdp
, m_ptr
); break;
1102 case SDEV_SEND
: do_send(sdp
, m_ptr
); break;
1103 case SDEV_RECV
: do_recv(sdp
, m_ptr
); break;
1104 case SDEV_IOCTL
: do_ioctl(sdp
, m_ptr
); break;
1105 case SDEV_SETSOCKOPT
: do_setsockopt(sdp
, m_ptr
); break;
1106 case SDEV_GETSOCKOPT
: do_getsockopt(sdp
, m_ptr
); break;
1107 case SDEV_GETSOCKNAME
: do_getname(sdp
, m_ptr
); break;
1108 case SDEV_GETPEERNAME
: do_getname(sdp
, m_ptr
); break;
1109 case SDEV_SHUTDOWN
: do_shutdown(sdp
, m_ptr
); break;
1110 case SDEV_CLOSE
: do_close(sdp
, m_ptr
); break;
1111 case SDEV_CANCEL
: do_cancel(sdp
, m_ptr
); break;
1112 case SDEV_SELECT
: do_select(sdp
, m_ptr
); break;
1117 * Break out of the main loop after finishing the current request.
1120 sockdriver_terminate(void)
1129 * Main program of any socket driver.
1132 sockdriver_task(const struct sockdriver
* sdp
)
1137 /* The main message loop. */
1141 if ((r
= sef_receive_status(ANY
, &m
, &ipc_status
)) != OK
) {
1143 continue; /* sef_cancel() was called */
1145 panic("sockdriver: sef_receive_status failed: %d", r
);
1148 sockdriver_process(sdp
, &m
, ipc_status
);