blob: 9b610edc19e841b733fca068d5af1b0ac252dcbf [file] [log] [blame]
/*
* 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)