Add support for UNIX Domain Sockets to the C lib. Contributed by Thomas Cort
This commit is contained in:
parent
5aff633a0b
commit
f531dba2d2
20 changed files with 1412 additions and 35 deletions
|
@ -1,3 +1,6 @@
|
|||
20100714:
|
||||
mknod /dev/uds c 18 0
|
||||
chmod 666 /dev/uds
|
||||
20100713:
|
||||
/usr/src/etc/rc updated: copy it (or merge it) to /etc/rc.
|
||||
/usr/src/etc/system.conf updated to include boot sys services: copy
|
||||
|
|
|
@ -22,6 +22,7 @@ SRCS+= \
|
|||
getnetbyaddr.c \
|
||||
getnetbyname.c \
|
||||
getnetent.c \
|
||||
getpeereid.c \
|
||||
getpeername.c \
|
||||
getproto.c \
|
||||
getprotoent.c \
|
||||
|
@ -42,6 +43,7 @@ SRCS+= \
|
|||
rcmd.c \
|
||||
recv.c \
|
||||
recvfrom.c \
|
||||
recvmsg.c \
|
||||
res_comp.c \
|
||||
res_init.c \
|
||||
res_mkquery.c \
|
||||
|
@ -49,10 +51,12 @@ SRCS+= \
|
|||
res_send.c \
|
||||
ruserok.c \
|
||||
send.c \
|
||||
sendmsg.c \
|
||||
sendto.c \
|
||||
servxcheck.c \
|
||||
sethostent.c \
|
||||
setsockopt.c \
|
||||
shutdown.c \
|
||||
socket.c \
|
||||
socketpair.c \
|
||||
strcasecmp.c
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <net/netlib.h>
|
||||
#include <net/gen/in.h>
|
||||
|
@ -18,6 +20,9 @@
|
|||
static int _tcp_accept(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len);
|
||||
|
||||
static int _uds_accept(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len);
|
||||
|
||||
int accept(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len)
|
||||
{
|
||||
|
@ -28,6 +33,10 @@ int accept(int socket, struct sockaddr *_RESTRICT address,
|
|||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
return r;
|
||||
|
||||
r= _uds_accept(socket, address, address_len);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
return r;
|
||||
|
||||
/* Unfortunately, we have to return EOPNOTSUPP for a socket that
|
||||
* does not support accept (such as a UDP socket) and ENOTSOCK for
|
||||
* filedescriptors that do not refer to a socket.
|
||||
|
@ -77,3 +86,45 @@ static int _tcp_accept(int socket, struct sockaddr *_RESTRICT address,
|
|||
getpeername(s1, address, address_len);
|
||||
return s1;
|
||||
}
|
||||
|
||||
static int _uds_accept(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len)
|
||||
{
|
||||
int s1;
|
||||
int r;
|
||||
struct sockaddr_un uds_addr;
|
||||
socklen_t len;
|
||||
|
||||
memset(&uds_addr, '\0', sizeof(struct sockaddr_un));
|
||||
|
||||
r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uds_addr.sun_family != AF_UNIX) {
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len= *address_len;
|
||||
if (len > sizeof(struct sockaddr_un))
|
||||
len = sizeof(struct sockaddr_un);
|
||||
|
||||
memcpy(address, &uds_addr, len);
|
||||
*address_len= len;
|
||||
|
||||
s1= open(UDS_DEVICE, O_RDWR);
|
||||
if (s1 == -1)
|
||||
return s1;
|
||||
|
||||
r= ioctl(s1, NWIOSUDSACCEPT, address);
|
||||
if (r == -1) {
|
||||
int ioctl_errno = errno;
|
||||
close(s1);
|
||||
errno = ioctl_errno;
|
||||
return r;
|
||||
}
|
||||
|
||||
return s1;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <net/gen/in.h>
|
||||
|
@ -10,6 +16,10 @@
|
|||
#include <net/gen/tcp_io.h>
|
||||
#include <net/gen/udp.h>
|
||||
#include <net/gen/udp_io.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <minix/config.h>
|
||||
#include <minix/const.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
|
@ -17,12 +27,15 @@ static int _tcp_bind(int socket, const struct sockaddr *address,
|
|||
socklen_t address_len, nwio_tcpconf_t *tcpconfp);
|
||||
static int _udp_bind(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len, nwio_udpopt_t *udpoptp);
|
||||
static int _uds_bind(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len, struct sockaddr_un *uds_addr);
|
||||
|
||||
int bind(int socket, const struct sockaddr *address, socklen_t address_len)
|
||||
{
|
||||
int r;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct sockaddr_un uds_addr;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
|
@ -50,6 +63,14 @@ int bind(int socket, const struct sockaddr *address, socklen_t address_len)
|
|||
return _udp_bind(socket, address, address_len, &udpopt);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
return r;
|
||||
return _uds_bind(socket, address, address_len, &uds_addr);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "bind: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -151,3 +172,183 @@ static int _udp_bind(int socket, const struct sockaddr *address,
|
|||
r= ioctl(socket, NWIOSUDPOPT, &udpopt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int in_group(uid_t uid, gid_t gid)
|
||||
{
|
||||
int r, i;
|
||||
int size;
|
||||
gid_t *list;
|
||||
|
||||
size = sysconf(_SC_NGROUPS_MAX);
|
||||
list = malloc(size * sizeof(gid_t));
|
||||
|
||||
if (list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r= getgroups(size, list);
|
||||
if (r == -1) {
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
if (gid == list[i]) {
|
||||
free(list);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int _uds_bind(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len, struct sockaddr_un *uds_addr)
|
||||
{
|
||||
mode_t bits, perm_bits, access_desired;
|
||||
struct stat buf;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
char real_sun_path[PATH_MAX+1];
|
||||
char *realpath_result;
|
||||
int i, r, shift;
|
||||
int null_found;
|
||||
int did_mknod;
|
||||
|
||||
if (address == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sun_family is always supposed to be AF_UNIX */
|
||||
if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* an empty path is not supported */
|
||||
if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the path must be a null terminated string for realpath to work */
|
||||
for (null_found = i = 0;
|
||||
i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
|
||||
if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
|
||||
null_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!null_found) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the realpath(3) of the socket file.
|
||||
*/
|
||||
|
||||
realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
|
||||
real_sun_path);
|
||||
if (realpath_result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
|
||||
|
||||
/*
|
||||
* input parameters look good -- create the socket file on the
|
||||
* file system
|
||||
*/
|
||||
|
||||
did_mknod = 0;
|
||||
|
||||
r = mknod(((struct sockaddr_un *) address)->sun_path,
|
||||
S_IFSOCK|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, 0);
|
||||
|
||||
if (r == -1) {
|
||||
if (errno == EEXIST) {
|
||||
/* file already exists, verify that it is a socket */
|
||||
|
||||
r = stat(((struct sockaddr_un *) address)->sun_path,
|
||||
&buf);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISSOCK(buf.st_mode)) {
|
||||
errno = EADDRINUSE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check permissions the permissions of the
|
||||
* socket file.
|
||||
*/
|
||||
|
||||
/* read + write access */
|
||||
access_desired = R_BIT | W_BIT;
|
||||
|
||||
euid = geteuid();
|
||||
egid = getegid();
|
||||
|
||||
if (euid == -1 || egid == -1) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bits = buf.st_mode;
|
||||
|
||||
if (euid == ((uid_t) 0)) {
|
||||
perm_bits = R_BIT | W_BIT;
|
||||
} else {
|
||||
if (euid == buf.st_uid) {
|
||||
shift = 6; /* owner */
|
||||
} else if (egid == buf.st_gid) {
|
||||
shift = 3; /* group */
|
||||
} else if (in_group(euid, buf.st_gid)) {
|
||||
shift = 3; /* suppl. groups */
|
||||
} else {
|
||||
shift = 0; /* other */
|
||||
}
|
||||
|
||||
perm_bits =
|
||||
(bits >> shift) & (R_BIT | W_BIT | X_BIT);
|
||||
}
|
||||
|
||||
if ((perm_bits | access_desired) != perm_bits) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if we get here permissions are OK */
|
||||
|
||||
} else {
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
did_mknod = 1;
|
||||
}
|
||||
|
||||
/* perform the bind */
|
||||
r= ioctl(socket, NWIOSUDSADDR, (void *) address);
|
||||
|
||||
if (r == -1 && did_mknod) {
|
||||
|
||||
/* bind() failed in pfs, so we roll back the
|
||||
* file system change
|
||||
*/
|
||||
unlink(((struct sockaddr_un *) address)->sun_path);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <net/gen/in.h>
|
||||
|
@ -12,12 +16,16 @@
|
|||
#include <net/gen/udp.h>
|
||||
#include <net/gen/udp_io.h>
|
||||
|
||||
#include <minix/const.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static int _tcp_connect(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len, nwio_tcpconf_t *tcpconfp);
|
||||
static int _udp_connect(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len, nwio_udpopt_t *udpoptp);
|
||||
static int _uds_connect(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len);
|
||||
|
||||
int connect(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len)
|
||||
|
@ -47,6 +55,21 @@ int connect(int socket, const struct sockaddr *address,
|
|||
}
|
||||
return _udp_connect(socket, address, address_len, &udpopt);
|
||||
}
|
||||
|
||||
r= _uds_connect(socket, address, address_len);
|
||||
if (r != -1 ||
|
||||
(errno != ENOTTY && errno != EBADIOCTL &&
|
||||
errno != EAFNOSUPPORT))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "connect: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -136,3 +159,148 @@ static int _udp_connect(int socket, const struct sockaddr *address,
|
|||
r= ioctl(socket, NWIOSUDPOPT, &udpopt);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int in_group(uid_t uid, gid_t gid)
|
||||
{
|
||||
int r, i;
|
||||
int size;
|
||||
gid_t *list;
|
||||
|
||||
size = sysconf(_SC_NGROUPS_MAX);
|
||||
list = malloc(size * sizeof(gid_t));
|
||||
|
||||
if (list == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r= getgroups(size, list);
|
||||
if (r == -1) {
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < r; i++) {
|
||||
if (gid == list[i]) {
|
||||
free(list);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _uds_connect(int socket, const struct sockaddr *address,
|
||||
socklen_t address_len)
|
||||
{
|
||||
mode_t bits, perm_bits, access_desired;
|
||||
struct stat buf;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
char real_sun_path[PATH_MAX+1];
|
||||
char *realpath_result;
|
||||
int i, r, shift;
|
||||
int null_found;
|
||||
|
||||
if (address == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sun_family is always supposed to be AF_UNIX */
|
||||
if (((struct sockaddr_un *) address)->sun_family != AF_UNIX) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* an empty path is not supported */
|
||||
if (((struct sockaddr_un *) address)->sun_path[0] == '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the path must be a null terminated string for realpath to work */
|
||||
for (null_found = i = 0;
|
||||
i < sizeof(((struct sockaddr_un *) address)->sun_path); i++) {
|
||||
|
||||
if (((struct sockaddr_un *) address)->sun_path[i] == '\0') {
|
||||
null_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!null_found) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the realpath(3) of the socket file.
|
||||
*/
|
||||
|
||||
realpath_result = realpath(((struct sockaddr_un *) address)->sun_path,
|
||||
real_sun_path);
|
||||
if (realpath_result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(((struct sockaddr_un *) address)->sun_path, real_sun_path);
|
||||
|
||||
/*
|
||||
* input parameters look good -- check the permissions of the
|
||||
* socket file. emulate eaccess() (i.e. the access(2) function
|
||||
* with effective UID/GID).
|
||||
*/
|
||||
|
||||
access_desired = R_BIT | W_BIT; /* read + write access */
|
||||
|
||||
euid = geteuid();
|
||||
egid = getegid();
|
||||
|
||||
if (euid == -1 || egid == -1) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r= stat(((struct sockaddr_un *) address)->sun_path, &buf);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISSOCK(buf.st_mode)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bits = buf.st_mode;
|
||||
|
||||
if (euid == ((uid_t) 0)) {
|
||||
perm_bits = R_BIT | W_BIT;
|
||||
} else {
|
||||
if (euid == buf.st_uid) {
|
||||
shift = 6; /* owner */
|
||||
} else if (egid == buf.st_gid) {
|
||||
shift = 3; /* group */
|
||||
} else if (in_group(euid, buf.st_gid)) {
|
||||
shift = 3; /* suppl. groups */
|
||||
} else {
|
||||
shift = 0; /* other */
|
||||
}
|
||||
|
||||
perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
|
||||
}
|
||||
|
||||
if ((perm_bits | access_desired) != perm_bits) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* perform the connect */
|
||||
r= ioctl(socket, NWIOSUDSCONN, (void *) address);
|
||||
return r;
|
||||
}
|
||||
|
|
35
lib/libc/ip/getpeereid.c
Normal file
35
lib/libc/ip/getpeereid.c
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
/*
|
||||
* get the effective user ID and effective group ID of a peer
|
||||
* connected through a Unix domain socket.
|
||||
*/
|
||||
int getpeereid(int sd, uid_t *euid, gid_t *egid) {
|
||||
int rc;
|
||||
struct ucred cred;
|
||||
socklen_t ucred_length;
|
||||
|
||||
/* Initialize Data Structures */
|
||||
ucred_length = sizeof(struct ucred);
|
||||
memset(&cred, '\0', ucred_length);
|
||||
|
||||
/* Validate Input Parameters */
|
||||
if (euid == NULL || egid == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
} /* getsockopt will handle validating 'sd' */
|
||||
|
||||
/* Get the credentials of the peer at the other end of 'sd' */
|
||||
rc = getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &cred, &ucred_length);
|
||||
if (rc == 0) {
|
||||
/* Success - return the results */
|
||||
*euid = cred.uid;
|
||||
*egid = cred.gid;
|
||||
return 0;
|
||||
} else {
|
||||
/* Failure - getsockopt takes care of setting errno */
|
||||
return -1;
|
||||
}
|
||||
}
|
|
@ -9,20 +9,25 @@
|
|||
#include <net/gen/tcp.h>
|
||||
#include <net/gen/tcp_io.h>
|
||||
#include <net/gen/udp.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static int _tcp_getpeername(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconfp);
|
||||
|
||||
static int _uds_getpeername(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
|
||||
|
||||
int getpeername(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len)
|
||||
{
|
||||
int r;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
struct sockaddr_un uds_addr;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -33,6 +38,19 @@ int getpeername(int socket, struct sockaddr *_RESTRICT address,
|
|||
&tcpconf);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSPADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
return _uds_getpeername(socket, address, address_len,
|
||||
&uds_addr);
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "getpeername: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -67,3 +85,23 @@ static int _tcp_getpeername(int socket, struct sockaddr *_RESTRICT address,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _uds_getpeername(int socket, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
|
||||
{
|
||||
socklen_t len;
|
||||
|
||||
if (uds_addr->sun_family != AF_UNIX)
|
||||
{
|
||||
errno= ENOTCONN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len= *address_len;
|
||||
if (len > sizeof(struct sockaddr_un))
|
||||
len = sizeof(struct sockaddr_un);
|
||||
|
||||
memcpy(address, uds_addr, len);
|
||||
*address_len= len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,31 +18,68 @@
|
|||
#include <net/gen/tcp.h>
|
||||
#include <net/gen/tcp_io.h>
|
||||
#include <net/gen/udp.h>
|
||||
|
||||
#include <sys/un.h>
|
||||
|
||||
/*
|
||||
#define DEBUG 0
|
||||
*/
|
||||
|
||||
/*
|
||||
getsockname...
|
||||
*/
|
||||
int getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
static int _tcp_getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconfp);
|
||||
|
||||
static int _uds_getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
|
||||
|
||||
int getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len)
|
||||
{
|
||||
int r;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
socklen_t len;
|
||||
struct sockaddr_in sin;
|
||||
struct sockaddr_un uds_addr;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"mnx_getsockname: ioctl fd %d.\n", fd);
|
||||
#endif
|
||||
if (ioctl(fd, NWIOGTCPCONF, &tcpconf)==-1) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"mnx_getsockname: error %d\n", errno);
|
||||
|
||||
r= ioctl(fd, NWIOGTCPCONF, &tcpconf);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _tcp_getsockname(fd, address, address_len, &tcpconf);
|
||||
}
|
||||
|
||||
r= ioctl(fd, NWIOGUDSADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _uds_getsockname(fd, address, address_len, &uds_addr);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "getsockname: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
return (-1);
|
||||
}
|
||||
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int _tcp_getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, nwio_tcpconf_t *tcpconf)
|
||||
{
|
||||
socklen_t len;
|
||||
struct sockaddr_in sin;
|
||||
|
||||
#ifdef DEBUG1
|
||||
fprintf(stderr, "mnx_getsockname: from %s, %u",
|
||||
inet_ntoa(tcpconf.nwtc_remaddr),
|
||||
|
@ -51,14 +88,11 @@ int getsockname(int fd, struct sockaddr *_RESTRICT address,
|
|||
inet_ntoa(tcpconf.nwtc_locaddr),
|
||||
ntohs(tcpconf.nwtc_locport));
|
||||
#endif
|
||||
/*
|
||||
addr->sin_addr.s_addr = tcpconf.nwtc_remaddr ;
|
||||
addr->sin_port = tcpconf.nwtc_locport;
|
||||
*/
|
||||
|
||||
memset(&sin, '\0', sizeof(sin));
|
||||
sin.sin_family= AF_INET;
|
||||
sin.sin_addr.s_addr= tcpconf.nwtc_locaddr ;
|
||||
sin.sin_port= tcpconf.nwtc_locport;
|
||||
sin.sin_addr.s_addr= tcpconf->nwtc_locaddr ;
|
||||
sin.sin_port= tcpconf->nwtc_locport;
|
||||
|
||||
len= *address_len;
|
||||
if (len > sizeof(sin))
|
||||
|
@ -69,10 +103,23 @@ int getsockname(int fd, struct sockaddr *_RESTRICT address,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _uds_getsockname(int fd, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
|
||||
{
|
||||
socklen_t len;
|
||||
|
||||
if (uds_addr->sun_family != AF_UNIX)
|
||||
{
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
len= *address_len;
|
||||
if (len > sizeof(struct sockaddr_un))
|
||||
len = sizeof(struct sockaddr_un);
|
||||
|
||||
memcpy(address, uds_addr, len);
|
||||
*address_len= len;
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <net/gen/in.h>
|
||||
|
@ -13,12 +14,16 @@
|
|||
#include <net/gen/udp.h>
|
||||
#include <net/gen/udp_io.h>
|
||||
|
||||
#include <minix/type.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static int _tcp_getsockopt(int socket, int level, int option_name,
|
||||
void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
|
||||
static int _udp_getsockopt(int socket, int level, int option_name,
|
||||
void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
|
||||
static int _uds_getsockopt(int socket, int level, int option_name,
|
||||
void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
|
||||
static void getsockopt_copy(void *return_value, size_t return_len,
|
||||
void *_RESTRICT option_value, socklen_t *_RESTRICT option_len);
|
||||
|
||||
|
@ -28,9 +33,10 @@ int getsockopt(int socket, int level, int option_name,
|
|||
int r;
|
||||
nwio_tcpopt_t tcpopt;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct sockaddr_un uds_addr;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -42,7 +48,7 @@ int getsockopt(int socket, int level, int option_name,
|
|||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDPOPT, &udpopt);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -53,6 +59,19 @@ int getsockopt(int socket, int level, int option_name,
|
|||
option_value, option_len);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
return _uds_getsockopt(socket, level, option_name,
|
||||
option_value, option_len);
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "getsockopt: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -141,7 +160,7 @@ static int _udp_getsockopt(int socket, int level, int option_name,
|
|||
|
||||
if (level == SOL_SOCKET && option_name == SO_TYPE)
|
||||
{
|
||||
i = SOCK_DGRAM; /* this is a TCP socket */
|
||||
i = SOCK_DGRAM; /* this is a UDP socket */
|
||||
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
@ -153,3 +172,83 @@ static int _udp_getsockopt(int socket, int level, int option_name,
|
|||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _uds_getsockopt(int socket, int level, int option_name,
|
||||
void *_RESTRICT option_value, socklen_t *_RESTRICT option_len)
|
||||
{
|
||||
int i, r;
|
||||
size_t size;
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
|
||||
{
|
||||
r= ioctl(socket, NWIOGUDSRCVBUF, &size);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
getsockopt_copy(&size, sizeof(size), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
|
||||
{
|
||||
r= ioctl(socket, NWIOGUDSSNDBUF, &size);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
getsockopt_copy(&size, sizeof(size), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_TYPE)
|
||||
{
|
||||
r= ioctl(socket, NWIOGUDSSOTYPE, &i);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_PEERCRED)
|
||||
{
|
||||
struct ucred cred;
|
||||
|
||||
r= ioctl(socket, NWIOGUDSPEERCRED, &cred);
|
||||
if (r == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
getsockopt_copy(&cred, sizeof(struct ucred), option_value,
|
||||
option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
|
||||
{
|
||||
i = 1; /* as long as nobody is listen()ing on the address,
|
||||
* it can be reused without waiting for a
|
||||
* timeout to expire.
|
||||
*/
|
||||
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
|
||||
{
|
||||
i = 1; /* option is always 'on' */
|
||||
getsockopt_copy(&i, sizeof(i), option_value, option_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "_uds_getsocketopt: level %d, name %d\n",
|
||||
level, option_name);
|
||||
#endif
|
||||
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ int listen(int socket, int backlog)
|
|||
if (r != -1 || errno != EBADIOCTL)
|
||||
return r;
|
||||
|
||||
r= ioctl(socket, NWIOSUDSBLOG, &backlog);
|
||||
if (r != -1 || errno != EBADIOCTL)
|
||||
return r;
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "listen: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
|
|
@ -5,4 +5,3 @@ ssize_t recv(int socket, void *buffer, size_t length, int flags)
|
|||
{
|
||||
return recvfrom(socket, buffer, length, flags, NULL, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@ static ssize_t _tcp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
|||
static ssize_t _udp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
||||
int flags, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, nwio_udpopt_t *udpoptp);
|
||||
static ssize_t _uds_recvfrom_conn(int socket, void *_RESTRICT buffer,
|
||||
size_t length, int flags, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr);
|
||||
static ssize_t _uds_recvfrom_dgram(int socket, void *_RESTRICT buffer,
|
||||
size_t length, int flags, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len);
|
||||
|
||||
ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
||||
int flags, struct sockaddr *_RESTRICT address,
|
||||
|
@ -33,6 +39,8 @@ ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
|||
int r;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct sockaddr_un uds_addr;
|
||||
int uds_sotype = -1;
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvfrom: for fd %d\n", socket);
|
||||
|
@ -56,6 +64,24 @@ ssize_t recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
|||
address, address_len, &udpopt);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uds_sotype == SOCK_DGRAM) {
|
||||
return _uds_recvfrom_dgram(socket, buffer,
|
||||
length, flags, address, address_len);
|
||||
} else {
|
||||
return _uds_recvfrom_conn(socket, buffer,
|
||||
length, flags, address, address_len,
|
||||
&uds_addr);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvfrom: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -197,3 +223,70 @@ static ssize_t _udp_recvfrom(int socket, void *_RESTRICT buffer, size_t length,
|
|||
return length;
|
||||
}
|
||||
|
||||
static ssize_t _uds_recvfrom_conn(int socket, void *_RESTRICT buffer,
|
||||
size_t length, int flags, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len, struct sockaddr_un *uds_addr)
|
||||
{
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
/* for connection oriented unix domain sockets (SOCK_STREAM /
|
||||
* SOCK_SEQPACKET)
|
||||
*/
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvfrom(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = read(socket, buffer, length);
|
||||
|
||||
if (r >= 0 && address != NULL)
|
||||
{
|
||||
|
||||
len= *address_len;
|
||||
if (len > sizeof(struct sockaddr_un))
|
||||
len= sizeof(struct sockaddr_un);
|
||||
memcpy(address, uds_addr, len);
|
||||
*address_len= sizeof(struct sockaddr_un);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t _uds_recvfrom_dgram(int socket, void *_RESTRICT buffer,
|
||||
size_t length, int flags, struct sockaddr *_RESTRICT address,
|
||||
socklen_t *_RESTRICT address_len)
|
||||
{
|
||||
int r;
|
||||
size_t len;
|
||||
|
||||
/* for connectionless unix domain sockets (SOCK_DGRAM) */
|
||||
|
||||
if (flags != 0)
|
||||
{
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvfrom(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = read(socket, buffer, length);
|
||||
|
||||
if (r >= 0 && address != NULL)
|
||||
{
|
||||
len= *address_len;
|
||||
if (len > sizeof(struct sockaddr_un))
|
||||
len= sizeof(struct sockaddr_un);
|
||||
ioctl(socket, NWIOGUDSFADDR, address);
|
||||
*address_len= sizeof(struct sockaddr_un);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
95
lib/libc/ip/recvmsg.c
Normal file
95
lib/libc/ip/recvmsg.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
#undef NDEBUG
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/ioctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags);
|
||||
static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags);
|
||||
|
||||
ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
|
||||
{
|
||||
int r;
|
||||
int uds_sotype;
|
||||
|
||||
if (msg == NULL) {
|
||||
errno= EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uds_sotype == SOCK_DGRAM) {
|
||||
return _uds_recvmsg_dgram(socket, msg, flags);
|
||||
} else {
|
||||
return _uds_recvmsg_conn(socket, msg, flags);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvmsg: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t _uds_recvmsg_conn(int socket, struct msghdr *msg, int flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvmsg(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = readv(socket, msg->msg_iov, msg->msg_iovlen);
|
||||
|
||||
if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
|
||||
{
|
||||
getpeername(socket, msg->msg_name, &msg->msg_namelen);
|
||||
}
|
||||
|
||||
msg->msg_flags = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t _uds_recvmsg_dgram(int socket, struct msghdr *msg, int flags)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "recvmsg(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = readv(socket, msg->msg_iov, msg->msg_iovlen);
|
||||
|
||||
if (r >= 0 && msg->msg_name && msg->msg_namelen > 0)
|
||||
{
|
||||
ioctl(socket, NWIOGUDSFADDR, msg->msg_name);
|
||||
msg->msg_namelen= sizeof(struct sockaddr_un);
|
||||
|
||||
}
|
||||
|
||||
msg->msg_flags = 0;
|
||||
|
||||
return r;
|
||||
}
|
|
@ -5,4 +5,3 @@ ssize_t send(int socket, const void *buffer, size_t length, int flags)
|
|||
{
|
||||
return sendto(socket, buffer, length, flags, NULL, 0);
|
||||
}
|
||||
|
||||
|
|
139
lib/libc/ip/sendmsg.c
Normal file
139
lib/libc/ip/sendmsg.c
Normal file
|
@ -0,0 +1,139 @@
|
|||
#undef NDEBUG
|
||||
|
||||
#include <errno.h>
|
||||
#include <net/ioctl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg,
|
||||
int flags);
|
||||
static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg,
|
||||
int flags);
|
||||
|
||||
ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
|
||||
{
|
||||
int r;
|
||||
int uds_sotype;
|
||||
|
||||
if (msg == NULL) {
|
||||
errno= EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uds_sotype == SOCK_DGRAM) {
|
||||
return _uds_sendmsg_dgram(socket, msg, flags);
|
||||
} else {
|
||||
return _uds_sendmsg_conn(socket, msg, flags);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendmsg: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ssize_t _uds_sendmsg_conn(int socket, const struct msghdr *msg,
|
||||
int flags)
|
||||
{
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendmsg(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
/* Silently ignore destination, if given. */
|
||||
|
||||
return writev(socket, msg->msg_iov, msg->msg_iovlen);
|
||||
}
|
||||
|
||||
static ssize_t _uds_sendmsg_dgram(int socket, const struct msghdr *msg,
|
||||
int flags)
|
||||
{
|
||||
char real_sun_path[PATH_MAX+1];
|
||||
char *realpath_result;
|
||||
char *dest_addr;
|
||||
int null_found;
|
||||
int i, r;
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendmsg(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
dest_addr = msg->msg_name;
|
||||
if (dest_addr == NULL) {
|
||||
errno= EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sun_family is always supposed to be AF_UNIX */
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* an empty path is not supported */
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the path must be a null terminated string for realpath to work */
|
||||
for (null_found = i = 0;
|
||||
i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
|
||||
null_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!null_found) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
realpath_result = realpath(
|
||||
((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
|
||||
|
||||
if (realpath_result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set the target address */
|
||||
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* do the send */
|
||||
return writev(socket, msg->msg_iov, msg->msg_iovlen);
|
||||
}
|
|
@ -24,6 +24,10 @@ static ssize_t _tcp_sendto(int socket, const void *message, size_t length,
|
|||
static ssize_t _udp_sendto(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len,
|
||||
nwio_udpopt_t *udpoptp);
|
||||
static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
|
||||
static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len);
|
||||
|
||||
ssize_t sendto(int socket, const void *message, size_t length, int flags,
|
||||
const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||
|
@ -31,6 +35,8 @@ ssize_t sendto(int socket, const void *message, size_t length, int flags,
|
|||
int r;
|
||||
nwio_tcpopt_t tcpopt;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct sockaddr_un uds_addr;
|
||||
int uds_sotype = -1;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
|
@ -50,6 +56,24 @@ ssize_t sendto(int socket, const void *message, size_t length, int flags,
|
|||
dest_addr, dest_len, &udpopt);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSSOTYPE, &uds_sotype);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uds_sotype == SOCK_DGRAM) {
|
||||
|
||||
return _uds_sendto_dgram(socket, message,
|
||||
length, flags,dest_addr, dest_len);
|
||||
} else {
|
||||
|
||||
return _uds_sendto_conn(socket, message,
|
||||
length, flags, dest_addr, dest_len);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendto: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -158,3 +182,96 @@ static ssize_t _udp_sendto(int socket, const void *message, size_t length,
|
|||
return length;
|
||||
}
|
||||
|
||||
static ssize_t _uds_sendto_conn(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||
{
|
||||
|
||||
/* for connection oriented unix domain sockets (SOCK_STREAM /
|
||||
* SOCK_SEQPACKET)
|
||||
*/
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendto(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Silently ignore destination, if given. */
|
||||
|
||||
return write(socket, message, length);
|
||||
}
|
||||
|
||||
static ssize_t _uds_sendto_dgram(int socket, const void *message, size_t length,
|
||||
int flags, const struct sockaddr *dest_addr, socklen_t dest_len)
|
||||
{
|
||||
char real_sun_path[PATH_MAX+1];
|
||||
char *realpath_result;
|
||||
int null_found;
|
||||
int i, r;
|
||||
|
||||
/* for connectionless unix domain sockets (SOCK_DGRAM) */
|
||||
|
||||
if (flags != 0) {
|
||||
#if DEBUG
|
||||
fprintf(stderr, "sendto(uds): flags not implemented\n");
|
||||
#endif
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dest_addr == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sun_family is always supposed to be AF_UNIX */
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_family != AF_UNIX) {
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* an empty path is not supported */
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_path[0] == '\0') {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* the path must be a null terminated string for realpath to work */
|
||||
for (null_found = i = 0;
|
||||
i < sizeof(((struct sockaddr_un *) dest_addr)->sun_path); i++) {
|
||||
if (((struct sockaddr_un *) dest_addr)->sun_path[i] == '\0') {
|
||||
null_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!null_found) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
realpath_result = realpath(
|
||||
((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
|
||||
|
||||
if (realpath_result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(real_sun_path) >= UNIX_PATH_MAX) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(((struct sockaddr_un *) dest_addr)->sun_path, real_sun_path);
|
||||
|
||||
/* set the target address */
|
||||
r= ioctl(socket, NWIOSUDSTADDR, (void *) dest_addr);
|
||||
if (r == -1) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* do the send */
|
||||
return write(socket, message, length);
|
||||
}
|
||||
|
|
|
@ -20,15 +20,19 @@ static int _tcp_setsockopt(int socket, int level, int option_name,
|
|||
static int _udp_setsockopt(int socket, int level, int option_name,
|
||||
const void *option_value, socklen_t option_len);
|
||||
|
||||
static int _uds_setsockopt(int socket, int level, int option_name,
|
||||
const void *option_value, socklen_t option_len);
|
||||
|
||||
int setsockopt(int socket, int level, int option_name,
|
||||
const void *option_value, socklen_t option_len)
|
||||
{
|
||||
int r;
|
||||
nwio_tcpopt_t tcpopt;
|
||||
nwio_udpopt_t udpopt;
|
||||
struct sockaddr_un uds_addr;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPOPT, &tcpopt);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -40,7 +44,7 @@ int setsockopt(int socket, int level, int option_name,
|
|||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDPOPT, &udpopt);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -51,6 +55,19 @@ int setsockopt(int socket, int level, int option_name,
|
|||
option_value, option_len);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
return _uds_setsockopt(socket, level, option_name,
|
||||
option_value, option_len);
|
||||
}
|
||||
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "setsockopt: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -178,3 +195,76 @@ static int _udp_setsockopt(int socket, int level, int option_name,
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int _uds_setsockopt(int socket, int level, int option_name,
|
||||
const void *option_value, socklen_t option_len)
|
||||
{
|
||||
int i;
|
||||
size_t size;
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_RCVBUF)
|
||||
{
|
||||
if (option_len != sizeof(size))
|
||||
{
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size= *(size_t *)option_value;
|
||||
return ioctl(socket, NWIOSUDSRCVBUF, &size);
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_SNDBUF)
|
||||
{
|
||||
if (option_len != sizeof(size))
|
||||
{
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
size= *(size_t *)option_value;
|
||||
return ioctl(socket, NWIOSUDSSNDBUF, &size);
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_REUSEADDR)
|
||||
{
|
||||
if (option_len != sizeof(i))
|
||||
{
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
i= *(int *)option_value;
|
||||
if (!i)
|
||||
{
|
||||
/* At the moment there is no way to turn off
|
||||
* reusing addresses.
|
||||
*/
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (level == SOL_SOCKET && option_name == SO_PASSCRED)
|
||||
{
|
||||
if (option_len != sizeof(i))
|
||||
{
|
||||
errno= EINVAL;
|
||||
return -1;
|
||||
}
|
||||
i= *(int *)option_value;
|
||||
if (!i)
|
||||
{
|
||||
/* credentials can always be received. */
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "_uds_setsocketopt: level %d, name %d\n",
|
||||
level, option_name);
|
||||
#endif
|
||||
|
||||
errno= ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -2,22 +2,25 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <net/gen/in.h>
|
||||
#include <net/gen/tcp.h>
|
||||
#include <net/gen/tcp_io.h>
|
||||
|
||||
#define DEBUG 1
|
||||
#define DEBUG 0
|
||||
|
||||
static int _tcp_shutdown(int socket, int how);
|
||||
static int _uds_shutdown(int socket, int how);
|
||||
|
||||
int shutdown(int socket, int how)
|
||||
{
|
||||
int r;
|
||||
struct sockaddr_un uds_addr;
|
||||
nwio_tcpconf_t tcpconf;
|
||||
|
||||
r= ioctl(socket, NWIOGTCPCONF, &tcpconf);
|
||||
if (r != -1 || errno != ENOTTY)
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
|
@ -26,6 +29,18 @@ int shutdown(int socket, int how)
|
|||
}
|
||||
return _tcp_shutdown(socket, how);
|
||||
}
|
||||
|
||||
r= ioctl(socket, NWIOGUDSADDR, &uds_addr);
|
||||
if (r != -1 || (errno != ENOTTY && errno != EBADIOCTL))
|
||||
{
|
||||
if (r == -1)
|
||||
{
|
||||
/* Bad file descriptor */
|
||||
return -1;
|
||||
}
|
||||
return _uds_shutdown(socket, how);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "shutdown: not implemented for fd %d\n", socket);
|
||||
#endif
|
||||
|
@ -51,4 +66,7 @@ static int _tcp_shutdown(int socket, int how)
|
|||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int _uds_shutdown(int socket, int how)
|
||||
{
|
||||
return ioctl(socket, NWIOSUDSSHUT, &how);
|
||||
}
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
#include <sys/socket.h>
|
||||
|
||||
#include <net/netlib.h>
|
||||
#include <net/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static int _tcp_socket(int protocol);
|
||||
static int _udp_socket(int protocol);
|
||||
static int _uds_socket(int type, int protocol);
|
||||
|
||||
int socket(int domain, int type, int protocol)
|
||||
{
|
||||
|
@ -19,7 +21,7 @@ int socket(int domain, int type, int protocol)
|
|||
fprintf(stderr, "socket: domain %d, type %d, protocol %d\n",
|
||||
domain, type, protocol);
|
||||
#endif
|
||||
if (domain != AF_INET)
|
||||
if (domain != AF_INET && domain != AF_UNIX)
|
||||
{
|
||||
#if DEBUG
|
||||
fprintf(stderr, "socket: bad domain %d\n", domain);
|
||||
|
@ -27,10 +29,15 @@ int socket(int domain, int type, int protocol)
|
|||
errno= EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
if (type == SOCK_STREAM)
|
||||
|
||||
if (domain == AF_UNIX && (type == SOCK_STREAM ||
|
||||
type == SOCK_DGRAM || type == SOCK_SEQPACKET))
|
||||
return _uds_socket(type, protocol);
|
||||
|
||||
if (domain == AF_INET && type == SOCK_STREAM)
|
||||
return _tcp_socket(protocol);
|
||||
|
||||
if (type == SOCK_DGRAM)
|
||||
if (domain == AF_INET && type == SOCK_DGRAM)
|
||||
return _udp_socket(protocol);
|
||||
|
||||
#if DEBUG
|
||||
|
@ -88,3 +95,38 @@ static int _udp_socket(int protocol)
|
|||
return fd;
|
||||
}
|
||||
|
||||
static int _uds_socket(int type, int protocol)
|
||||
{
|
||||
int fd, r;
|
||||
if (protocol != 0)
|
||||
{
|
||||
#if DEBUG
|
||||
fprintf(stderr, "socket(uds): bad protocol %d\n", protocol);
|
||||
#endif
|
||||
errno= EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd= open(UDS_DEVICE, O_RDWR);
|
||||
if (fd == -1) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* set the type for the socket via ioctl (SOCK_DGRAM,
|
||||
* SOCK_STREAM, SOCK_SEQPACKET, etc)
|
||||
*/
|
||||
r= ioctl(fd, NWIOSUDSTYPE, &type);
|
||||
if (r == -1) {
|
||||
int ioctl_errno;
|
||||
|
||||
/* if that failed rollback socket creation */
|
||||
ioctl_errno= errno;
|
||||
close(fd);
|
||||
|
||||
/* return the error thrown by the call to ioctl */
|
||||
errno= ioctl_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
|
135
lib/libc/ip/socketpair.c
Normal file
135
lib/libc/ip/socketpair.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <net/ioctl.h>
|
||||
#include <net/netlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
static int _uds_socketpair(int type, int protocol, int sv[2]);
|
||||
|
||||
/*
|
||||
* Create a pair of connected sockets
|
||||
*/
|
||||
int socketpair(int domain, int type, int protocol, int sv[2]) {
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr, "socketpair: domain %d, type %d, protocol %d\n",
|
||||
domain, type, protocol);
|
||||
#endif
|
||||
|
||||
if (domain != AF_UNIX)
|
||||
{
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (domain == AF_UNIX &&
|
||||
(type == SOCK_STREAM || type == SOCK_SEQPACKET))
|
||||
return _uds_socketpair(type, protocol, sv);
|
||||
|
||||
#if DEBUG
|
||||
fprintf(stderr,
|
||||
"socketpair: nothing for domain %d, type %d, protocol %d\n",
|
||||
domain, type, protocol);
|
||||
#endif
|
||||
|
||||
errno= EPROTOTYPE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _uds_socketpair(int type, int protocol, int sv[2])
|
||||
{
|
||||
dev_t dev;
|
||||
int r, i;
|
||||
struct stat sbuf;
|
||||
|
||||
if (protocol != 0)
|
||||
{
|
||||
#if DEBUG
|
||||
fprintf(stderr, "socketpair(uds): bad protocol %d\n", protocol);
|
||||
#endif
|
||||
errno= EPROTONOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* in this 'for' loop two unconnected sockets are created */
|
||||
for (i = 0; i < 2; i++) {
|
||||
sv[i]= open(UDS_DEVICE, O_RDWR);
|
||||
if (sv[i] == -1) {
|
||||
int open_errno = errno;
|
||||
|
||||
if (i == 1) {
|
||||
/* if we failed to open() the 2nd
|
||||
* socket, we need to close the 1st
|
||||
*/
|
||||
close(sv[0]);
|
||||
errno = open_errno;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set the type for the socket via ioctl
|
||||
* (SOCK_STREAM, SOCK_SEQPACKET, etc)
|
||||
*/
|
||||
r= ioctl(sv[i], NWIOSUDSTYPE, &type);
|
||||
if (r == -1) {
|
||||
int ioctl_errno;
|
||||
|
||||
/* if that failed rollback socket creation */
|
||||
ioctl_errno= errno;
|
||||
close(sv[i]);
|
||||
|
||||
if (i == 1) {
|
||||
/* if we just closed the 2nd socket, we
|
||||
* need to close the 1st
|
||||
*/
|
||||
close(sv[0]);
|
||||
}
|
||||
|
||||
/* return the error thrown by the call to ioctl */
|
||||
errno= ioctl_errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
r= fstat(sv[1], &sbuf);
|
||||
if (r == -1) {
|
||||
int fstat_errno;
|
||||
|
||||
/* if that failed rollback socket creation */
|
||||
fstat_errno= errno;
|
||||
|
||||
close(sv[0]);
|
||||
close(sv[1]);
|
||||
|
||||
/* return the error thrown by the call to fstat */
|
||||
errno= fstat_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev = sbuf.st_dev;
|
||||
|
||||
/* connect the sockets sv[0] and sv[1] */
|
||||
r= ioctl(sv[0], NWIOSUDSPAIR, &dev);
|
||||
if (r == -1) {
|
||||
int ioctl_errno;
|
||||
|
||||
/* if that failed rollback socket creation */
|
||||
ioctl_errno= errno;
|
||||
|
||||
close(sv[0]);
|
||||
close(sv[1]);
|
||||
|
||||
/* return the error thrown by the call to ioctl */
|
||||
errno= ioctl_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue