1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/*
Copyright (C) 1995,2000,02 Free Software Foundation, Inc.
This file is part of the GNU Hurd.
The GNU Hurd is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
The GNU Hurd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
#include <assert.h>
#include "pfinet.h"
#include <linux/socket.h>
#include <linux/net.h>
#ifndef NPROTO
#define NPROTO (PF_INET + 1)
#endif
struct net_proto_family *net_families[NPROTO];
/* Notice that a protocol family is live; this only works for inet here. */
int
sock_register (struct net_proto_family *fam)
{
assert (fam->family < NPROTO);
net_families[fam->family] = fam;
return 0;
}
struct socket *
sock_alloc (void)
{
static ino_t nextino; /* locked by global_lock */
struct socket *sock;
pthread_cond_t *c;
sock = malloc (sizeof *sock + sizeof (pthread_cond_t));
if (!sock)
return 0;
c = (void *) &sock[1];
pthread_cond_init (c, NULL);
bzero (sock, sizeof *sock);
sock->state = SS_UNCONNECTED;
sock->identity = MACH_PORT_NULL;
sock->refcnt = 1;
sock->wait = (void *) c;
if (nextino == 0)
nextino = 2;
sock->st_ino = nextino++;
return sock;
}
/* Create a sock_user structure, initialized from SOCK and ISROOT.
If NOINSTALL is set, don't put it in the portset.
We increment SOCK->refcnt iff CONSUME is zero. */
struct sock_user *
make_sock_user (struct socket *sock, int isroot, int noinstall, int consume)
{
error_t err;
struct sock_user *user;
assert (sock->refcnt != 0);
if (noinstall)
err = ports_create_port_noinstall (socketport_class, pfinet_bucket,
sizeof (struct sock_user), &user);
else
err = ports_create_port (socketport_class, pfinet_bucket,
sizeof (struct sock_user), &user);
if (err)
return 0;
/* We maintain a reference count in `struct socket' (a member not
in the original Linux structure), because there can be multiple
ports (struct sock_user, aka protids) pointing to the same socket.
The socket lives until all the ports die. */
if (! consume)
++sock->refcnt;
user->isroot = isroot;
user->sock = sock;
return user;
}
/* This is called from the port cleanup function below, and on
a newly allocated socket when something went wrong in its creation. */
void
sock_release (struct socket *sock)
{
if (--sock->refcnt != 0)
return;
if (sock->state != SS_UNCONNECTED)
sock->state = SS_DISCONNECTING;
if (sock->ops)
sock->ops->release(sock, NULL);
if (sock->identity != MACH_PORT_NULL)
mach_port_destroy (mach_task_self (), sock->identity);
free (sock);
}
/* Release the reference on the referenced socket. */
void
clean_socketport (void *arg)
{
struct sock_user *const user = arg;
pthread_mutex_lock (&global_lock);
sock_release (user->sock);
pthread_mutex_unlock (&global_lock);
}
|