summaryrefslogtreecommitdiff
path: root/protocol.c
blob: 88dcb5901f21cdad17cc4ec26c8ffcf6ba45f3ab (plain)
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/* netio - creates socket ports via the filesystem
   Copyright (C) 2002 Moritz Schulte <moritz@duesseldorf.ccc.de>
 
   This program 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 of the
   License, or * (at your option) any later version.
 
   This program 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-1307
   USA */

#include <hurd/netfs.h>
#include <hurd/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include "netio.h"
#include "lib.h"
#include "node.h"

/* Connect the node *NODE with style STYLE (SOCK_STREAM or
   SOCK_DGRAM).  Used by protocol_socket_open_{tcp,udp}.  Return 0 on
   success or an error code.  */
error_t
protocol_socket_open_std (struct node *node, int style)
{
  extern pf_t socket_server;
  socket_t sock;
  addr_port_t aport;
  error_t err;
  struct sockaddr_in addr;
  struct hostent *hostinfo;

  hostinfo = gethostbyname (node->nn->host);
  if (hostinfo == NULL)
    {
      err = h_errno;
      goto out;
    }

  if ((err = socket_create (socket_server, style, 0, &sock)))
    goto out;
  addr.sin_family = AF_INET;
  addr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
  addr.sin_port = htons (node->nn->port);
  if ((err = socket_create_address (sock, addr.sin_family,
				    (char *) &addr, sizeof (addr), &aport)))
    goto out;
  if ((err = socket_connect (sock, aport)))
    goto out;

  node->nn->sock = sock;
  node->nn->addr = aport;

  /* FIXME:  cleanup missing?  */

 out:
  return err;
}

/* Open a TCP socket for *NODE.  Return 0 on success or an error code.  */
error_t
protocol_socket_open_tcp (struct node *node)
{
  return protocol_socket_open_std (node, SOCK_STREAM);
}

/* Open a UDP socket for *NODE.  Return 0 on success or an error code.  */
error_t
protocol_socket_open_udp (struct node *node)
{
  return protocol_socket_open_std (node, SOCK_DGRAM);
}

/* Store the protocol node for the protocol specified by NAME in
   *NODE.  Return 0 on success or ENOENT if the node could not be
   found.  */
error_t
protocol_find_node (char *name, struct node **node)
{
  struct node *np;
  for (np = netfs_root_node->nn->entries;
       np && strcmp (np->nn->protocol->name, name);
       np = np->next);
  if (! np)
    return ENOENT;
  *node = np;
  return 0;
}

/* Register a protocol specified by ID and NAME, creating an according
   node.  Sockets for that protocol get opened by SOCKET_OPEN_FUNC.
   Return 0 on success or an error code.  */
error_t
protocol_register (int id, char *name,
		   error_t (*socket_open_func) (struct node *node))
{
  error_t err;
  struct protocol *protocol;
  err = my_malloc (sizeof (struct protocol), (void **) &protocol);
  if (err)
    return err;
  protocol->name = strdup (name);
  if (! protocol->name)
    {
      free (protocol);
      return ENOMEM;
    }
  err = node_make_protocol_node (netfs_root_node, protocol);
  if (err)
    {
      free (protocol->name);
      free (protocol);
      return err;
    }
  protocol->id = id;
  protocol->socket_open = socket_open_func;
  return 0;
}

/* Unregister the protocol specified by NAME, drop the reference to
   the protocol node.  Return 0 on success or ENOENT if that protocol
   could not be found.  */
error_t
protocol_unregister (char *name)
{
  struct node *np;
  error_t err;
  err = protocol_find_node (name, &np);
  if (err)
    return err;
  netfs_nrele (np);
  return 0;
}

/* Register the protocols - create according nodes.  Return 0 on
   success or an error code.  */
error_t
protocol_register_protocols (void)
{
  return (protocol_register (PROTOCOL_ID_TCP, "tcp",
			     protocol_socket_open_tcp)
	  || protocol_register (PROTOCOL_ID_UDP, "udp",
				protocol_socket_open_udp));
}