| /* |
| * This file is part of the UCB release of Plan 9. It is subject to the license |
| * terms in the LICENSE file found in the top-level directory of this |
| * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No |
| * part of the UCB release of Plan 9, including this file, may be copied, |
| * modified, propagated, or distributed except according to the terms contained |
| * in the LICENSE file. |
| */ |
| /* posix */ |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <fcntl.h> |
| #include <sys/stat.h> |
| #include <sys/close_cb.h> |
| #include <ros/common.h> |
| #include <parlib/parlib.h> |
| |
| /* bsd extensions */ |
| #include <sys/uio.h> |
| #include <sys/socket.h> |
| #include <netinet/in.h> |
| |
| #include <sys/plan9_helpers.h> |
| |
| static void socket_init(void *arg) |
| { |
| static struct close_cb _sock_close_cb = {.func = _sock_fd_closed}; |
| |
| register_close_cb(&_sock_close_cb); |
| } |
| |
| /* Create a new socket of type TYPE in domain DOMAIN, using |
| protocol PROTOCOL. If PROTOCOL is zero, one is chosen automatically. |
| Returns a file descriptor for the new socket, or -1 for errors. */ |
| int __socket(int domain, int type, int protocol) |
| { |
| Rock *r; |
| int cfd, n; |
| int pfd[2]; |
| const char *net; |
| char msg[128]; |
| int open_flags; |
| static parlib_once_t once = PARLIB_ONCE_INIT; |
| |
| parlib_run_once(&once, socket_init, NULL); |
| |
| switch (domain) { |
| case PF_INET: |
| open_flags = O_RDWR; |
| open_flags |= (type & SOCK_CLOEXEC ? O_CLOEXEC : 0); |
| /* get a free network directory */ |
| switch (_sock_strip_opts(type)) { |
| case SOCK_DGRAM: |
| net = "udp"; |
| cfd = open("/net/udp/clone", open_flags); |
| /* All BSD UDP sockets are in 'headers' mode, where each |
| * packet has the remote addr:port, local addr:port and |
| * other info. */ |
| if (!(cfd < 0)) { |
| n = snprintf(msg, sizeof(msg), "headers"); |
| n = write(cfd, msg, n); |
| if (n < 0) { |
| perror("UDP socket headers failed"); |
| return -1; |
| } |
| if (lseek(cfd, 0, SEEK_SET) != 0) { |
| perror("UDP socket seek failed"); |
| return -1; |
| } |
| } |
| break; |
| case SOCK_STREAM: |
| net = "tcp"; |
| cfd = open("/net/tcp/clone", open_flags); |
| break; |
| default: |
| errno = EPROTONOSUPPORT; |
| return -1; |
| } |
| if (cfd < 0) { |
| return -1; |
| } |
| return _sock_data(cfd, net, domain, type, protocol, 0); |
| case PF_UNIX: |
| open_flags = 0; |
| open_flags |= (type & SOCK_CLOEXEC ? O_CLOEXEC : 0); |
| open_flags |= (type & SOCK_NONBLOCK ? O_CLOEXEC : 0); |
| if (pipe2(pfd, open_flags) < 0) |
| return -1; |
| r = _sock_newrock(pfd[0]); |
| r->domain = domain; |
| r->stype = _sock_strip_opts(type); |
| r->sopts = _sock_get_opts(type); |
| r->protocol = protocol; |
| r->other = pfd[1]; |
| return pfd[0]; |
| default: |
| errno = EPROTONOSUPPORT; |
| return -1; |
| } |
| } |
| |
| weak_alias(__socket, socket) |