1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (c) 2002 Cray Inc.
6 * This file is part of Portals, http://www.sf.net/projects/sandiaportals/
8 * Portals is free software; you can redistribute it and/or
9 * modify it under the terms of version 2.1 of the GNU Lesser General
10 * Public License as published by the Free Software Foundation.
12 * Portals is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Portals; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This file provides a simple stateful connection manager which
24 builds tcp connections on demand and leaves them open for
25 future use. It also provides the machinery to allow peers
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <connection.h>
45 /* global variable: acceptor port */
46 unsigned short tcpnal_acceptor_port = 988;
49 /* Function: compare_connection
50 * Arguments: connection c: a connection in the hash table
51 * ptl_process_id_t: an id to verify agains
52 * Returns: 1 if the connection is the one requested, 0 otherwise
54 * compare_connection() tests for collisions in the hash table
56 static int compare_connection(void *arg1, void *arg2)
59 unsigned int * id = arg2;
60 return((c->ip==id[0]) && (c->port==id[1]));
64 /* Function: connection_key
65 * Arguments: ptl_process_id_t id: an id to hash
66 * Returns: a not-particularily-well-distributed hash
69 static unsigned int connection_key(unsigned int *id)
75 /* Function: remove_connection
76 * Arguments: c: the connection to remove
78 void remove_connection(void *arg)
85 hash_table_remove(c->m->connections,id);
91 /* Function: read_connection:
92 * Arguments: c: the connection to read from
93 * dest: the buffer to read into
94 * len: the number of bytes to read
95 * Returns: success as 1, or failure as 0
97 * read_connection() reads data from the connection, continuing
98 * to read partial results until the request is satisfied or
99 * it errors. TODO: this read should be covered by signal protection.
101 int read_connection(connection c,
109 if((rc=syscall(SYS_read, c->fd, dest+offset, len-offset))<=0){
113 remove_connection(c);
118 } while (offset<len);
123 static int connection_input(void *d)
126 return((*c->m->handler)(c->m->handler_arg,c));
130 /* Function: allocate_connection
131 * Arguments: t: tcpnal the allocation is occuring in the context of
132 * dest: portal endpoint address for this connection
133 * fd: open file descriptor for the socket
134 * Returns: an allocated connection structure
136 * just encompasses the action common to active and passive
137 * connections of allocation and placement in the global table
139 static connection allocate_connection(manager m,
144 connection c=malloc(sizeof(struct connection));
152 register_io_handler(fd,READ_HANDLER,connection_input,c);
153 hash_table_insert(m->connections,c,id);
158 /* Function: new_connection
159 * Arguments: t: opaque argument holding the tcpname
160 * Returns: 1 in order to reregister for new connection requests
162 * called when the bound service socket recieves
163 * a new connection request, it always accepts and
164 * installs a new connection
166 static int new_connection(void *z)
169 struct sockaddr_in s;
170 int len=sizeof(struct sockaddr_in);
171 int fd=accept(m->bound,(struct sockaddr *)&s,&len);
172 unsigned int nid=*((unsigned int *)&s.sin_addr);
173 /* cfs specific hack */
174 //unsigned short pid=s.sin_port;
175 allocate_connection(m,htonl(nid),0/*pid*/,fd);
180 /* Function: force_tcp_connection
181 * Arguments: t: tcpnal
182 * dest: portals endpoint for the connection
183 * Returns: an allocated connection structure, either
184 * a pre-existing one, or a new connection
186 connection force_tcp_connection(manager m,
191 struct sockaddr_in addr;
194 port = tcpnal_acceptor_port;
199 if (!(c=hash_table_find(m->connections,id))){
202 bzero((char *) &addr, sizeof(addr));
203 addr.sin_family = AF_INET;
204 addr.sin_addr.s_addr = htonl(ip);
205 addr.sin_port = htons(port);
207 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
208 perror("tcpnal socket failed");
212 (struct sockaddr *)&addr,
213 sizeof(struct sockaddr_in)))
215 perror("tcpnal connect");
218 return(allocate_connection(m,ip,port,fd));
224 /* Function: bind_socket
225 * Arguments: t: the nal state for this interface
226 * port: the port to attempt to bind to
227 * Returns: 1 on success, or 0 on error
229 * bind_socket() attempts to allocate and bind a socket to the requested
230 * port, or dynamically assign one from the kernel should the port be
231 * zero. Sets the bound and bound_handler elements of m.
233 * TODO: The port should be an explicitly sized type.
235 static int bind_socket(manager m,unsigned short port)
237 struct sockaddr_in addr;
238 int alen=sizeof(struct sockaddr_in);
240 if ((m->bound = socket(AF_INET, SOCK_STREAM, 0)) < 0)
243 bzero((char *) &addr, sizeof(addr));
244 addr.sin_family = AF_INET;
245 addr.sin_addr.s_addr = 0;
246 addr.sin_port = port;
248 if (bind(m->bound,(struct sockaddr *)&addr,alen)<0){
249 perror ("tcpnal bind");
253 getsockname(m->bound,(struct sockaddr *)&addr, &alen);
255 m->bound_handler=register_io_handler(m->bound,READ_HANDLER,
258 m->port=addr.sin_port;
263 /* Function: shutdown_connections
264 * Arguments: m: the manager structure
266 * close all connections and reclaim resources
268 void shutdown_connections(manager m)
271 remove_io_handler(m->bound_handler);
272 hash_destroy_table(m->connections,remove_connection);
277 /* Function: init_connections
278 * Arguments: t: the nal state for this interface
279 * port: the port to attempt to bind to
280 * Returns: a newly allocated manager structure, or
281 * zero if the fixed port could not be bound
283 manager init_connections(unsigned short pid,
284 int (*input)(void *, void *),
287 manager m=(manager)malloc(sizeof(struct manager));
288 m->connections=hash_create_table(compare_connection,connection_key);
291 if (bind_socket(m,pid)) return(m);