chiark / gitweb /
daemonize, versioncmp: Generally useful functions from tripe.
[mLib] / conn.c
1 /* -*-c-*-
2  *
3  * $Id: conn.c,v 1.10 2004/04/08 01:36:11 mdw Exp $
4  *
5  * Nonblocking connect handling
6  *
7  * (c) 1999 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the mLib utilities library.
13  *
14  * mLib is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * mLib is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with mLib; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Header files ------------------------------------------------------*/
31
32 #include <errno.h>
33 #include <limits.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include <sys/types.h>
39 #include <sys/socket.h>
40
41 #include <unistd.h>
42 #include <fcntl.h>
43
44 #include "conn.h"
45 #include "sel.h"
46
47 /*----- Main code ---------------------------------------------------------*/
48
49 /* --- @conn_connect@ --- *
50  *
51  * Arguments:   @int fd@ = file descriptor to try to connect
52  *              @unsigned mode@ = what we can do to the file
53  *              @void *p@ = pointer to connection context
54  *
55  * Returns:     ---
56  *
57  * Use:         Handles select results for pending connections.
58  */
59
60 static void conn_connect(int fd, unsigned mode, void *p)
61 {
62 #ifndef PATH_MAX
63 #  define PATH_MAX 1024
64 #endif
65
66   conn *c = p;
67   char buf[PATH_MAX + 8]; /* Big enough */
68   size_t sinsz;
69
70   sinsz = sizeof(buf);
71   sel_rmfile(&c->writer);
72   if (getpeername(fd, (struct sockaddr *)buf, &sinsz) < 0) {
73     int err;
74     size_t errsz = sizeof(err);
75     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errsz) == 0)
76       errno = err;
77     close(fd);
78     c->func(-1, c->p);
79   } else
80     c->func(fd, c->p);
81 }
82
83 /* --- @conn_fd@ --- *
84  *
85  * Arguments:   @conn *c@ = pointer to connection block
86  *              @sel_state *s@ = pointer to select state to attach to
87  *              @int fd@ = file descriptor of socket
88  *              @void (*func)(int fd, void *p) = handler function
89  *              @void *p@ = argument for the handler function
90  *
91  * Returns:     ---
92  *
93  * Use:         Sets up a nonblocking connect job.  The socket should have a
94  *              connect pending for it already.
95  */
96
97 void conn_fd(conn *c, sel_state *s, int fd,
98              void (*func)(int /*fd*/, void */*p*/),
99              void *p)
100 {
101   c->func = func;
102   c->p = p;
103   sel_initfile(s, &c->writer, fd, SEL_WRITE, conn_connect, c);
104   sel_addfile(&c->writer);
105 }
106
107 /* --- @conn_init@ --- *
108  *
109  * Arguments:   @conn *c@ = pointer to connection block
110  *              @sel_state *s@ = pointer to select state to attach to
111  *              @int fd@ = file descriptor of socket to connect
112  *              @struct sockaddr *dst@ = destination address
113  *              @int dsz@ = size of destination address
114  *              @void (*func)(int fd, void *p) = handler function
115  *              @void *p@ = argument for the handler function
116  *
117  * Returns:     Zero on success, nonzero on failure.
118  *
119  * Use:         Sets up a nonblocking connect job.  The socket should already
120  *              be bound if you care about that sort of thing.  When the
121  *              connection completes, the handler function is called with the
122  *              connected socket as an argument.  If the connect fails rather
123  *              than completes, the socket is closed, and the handler is
124  *              informed of this by being passed a negative file descriptor.
125  *              In either case, the select job is then removed.
126  */
127
128 int conn_init(conn *c, sel_state *s, int fd,
129               struct sockaddr *dst, int dsz,
130               void (*func)(int /*fd*/, void */*p*/),
131               void *p)
132 {
133   int f;
134
135   if ((f = fcntl(fd, F_GETFL)) < 0 || fcntl(fd, F_SETFL, f | O_NONBLOCK))
136     goto fail;
137
138   if (!connect(fd, dst, dsz))
139     func(fd, p);
140   else if (errno != EINPROGRESS)
141     goto fail;
142   else
143     conn_fd(c, s, fd, func, p);
144   return (0);
145
146 fail:
147   close(fd);
148   return (-1);
149 }
150
151 /* --- @conn_kill@ --- *
152  *
153  * Arguments:   @conn *c@ = pointer to connection to dispose of
154  *
155  * Returns:     ---
156  *
157  * Use:         Disposes of a connection when it's not wanted any more.
158  */
159
160 void conn_kill(conn *c)
161 {
162   if (c->writer.fd != -1) {
163     close(c->writer.fd);
164     sel_rmfile(&c->writer);
165     c->writer.fd = -1;
166   }
167 }
168
169 /*----- That's all, folks -------------------------------------------------*/