]> git.neil.brown.name Git - metad.git/blob - stream.c
Assorted reformating
[metad.git] / stream.c
1
2 #include        "metad.h"
3 #include        <netdb.h>
4 #include        <sys/socket.h>
5 #include        <netinet/in.h>
6 #include        <fcntl.h>
7 #ifdef SOLARIS
8 #include        <sys/fcntl.h>
9 #else
10 #include        <sys/file.h>
11 #endif
12
13 typedef struct stream_opts
14 {
15         int     proto;  /* always TCP */
16         int     port;
17         int     backlog;
18         int     sock;
19         int     newsock;
20 } *stream_t;
21
22 #define c(sv) ((stream_t)((sv)->classinfo))
23
24 static int stream_opt(service_t sv, char *opt)
25 {
26         /* port= */
27         char *protos = "tcp";
28         if (strncmp(opt, "port=", 5) == 0) {
29                 char *ep;
30                 int port;
31                 struct servent *se;
32                 port = strtoul(opt+5, &ep, 10);
33                 if (opt[5] && !*ep) {
34                         c(sv)->port = htons(port);
35                         return 1;
36                 }
37                 se = getservbyname(opt+5, protos);
38                 if (se) {
39                         c(sv)->port = se->s_port;
40                         return 1;
41                 }
42         }
43         if (strncmp(opt, "backlog=", 8) == 0) {
44                 char *ep;
45                 c(sv)->backlog = strtoul(opt+8, &ep, 10);
46                 if (opt[8] && !*ep)
47                         return 1;
48         }
49         return 0;
50 }
51
52 static void stream_register(service_t sv)
53 {
54         /* create a socket and bind it */
55         stream_t s = sv->classinfo;
56         struct sockaddr_in addr;
57         int opt;
58
59         if (s->sock >=0 || s->port <= 0)
60                 return;
61         s->sock = socket(AF_INET, SOCK_STREAM, s->proto);
62         if (s->sock < 0)
63                 return;
64         opt = 1;
65         setsockopt(s->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));
66
67         memset(&addr, 0, sizeof(addr));
68         addr.sin_family = AF_INET;
69         addr.sin_port = s->port;
70         if (bind(s->sock, (struct sockaddr *)&addr, sizeof(addr))) {
71                 close(s->sock);
72                 s->sock = -1;
73                 return;
74         }
75
76         if (listen(s->sock, s->backlog)<0) {
77                 close(s->sock);
78                 s->sock = -1;
79                 return;
80         }
81         nodelay(s->sock);
82 }
83
84 static void stream_unregister(service_t sv)
85 {
86         stream_t s = sv->classinfo;
87         if (s->sock>=0)
88                 close(s->sock);
89         s->sock = -1;
90 }
91
92 static void stream_check(service_t sv)
93 {
94         stream_t s = sv->classinfo;
95
96         if (s->sock >=0) {
97                 if (readyon(s->sock)) {
98                         char *env[3];
99                         env[0] = "METAD_REASON=connect";
100                         env[1] = "METAD_ARG=";
101                         env[2] = NULL;
102                         if (new_proc(sv, env) == -1)
103                                 if (s->newsock >= 0) {
104                                         close(s->newsock);
105                                         s->newsock = -1;
106                                 }
107                 }
108                 listenon(s->sock);
109         }
110 }
111
112 static int stream_prefork(service_t sv)
113 {
114         int f;
115         stream_t s = sv->classinfo;
116         if (s->sock < 0)
117                 return -2;
118
119         s->newsock = accept(s->sock, NULL, 0);
120         if (s->newsock < 0)
121                 return -2;
122         /* disable NDELAY which might be inherited */
123         f = fcntl(s->newsock, F_GETFL, 0);
124         f &= ~O_NDELAY;
125         fcntl(s->newsock, F_SETFL, f);
126         return 0;
127 }
128
129 static void stream_init(service_t to)
130 {
131         /* set up defaults */
132         stream_t n;
133         n = (stream_t)malloc(sizeof(struct stream_opts));
134
135         n->proto = IPPROTO_TCP;
136         n->backlog = 10;
137         n->port = 0;
138         n->sock = -1;
139         n->newsock = -1;
140
141         to->classinfo = n;
142 }
143
144 static void stream_copy(service_t from, service_t to)
145 {
146         /* copy state */
147
148         c(to)->sock = c(from)->sock;
149         c(from)->sock = -1;
150 }
151
152 static void stream_freestate(service_t sv)
153 {
154         stream_t s = sv->classinfo;
155         if (s->sock >= 0)
156                 close(s->sock);
157         free(s);
158 }
159
160 static void stream_newparent(service_t sv, proc_t p)
161 {
162         if (c(sv)->newsock >= 0) {
163                 close(c(sv)->newsock);
164                 c(sv)->newsock = -1;
165         }
166 }
167
168 static void stream_newchild(service_t sv)
169 {
170         close(c(sv)->sock);
171         if (c(sv)->newsock < 0)
172                 exit(2);
173         dup2(c(sv)->newsock, 0);
174         dup2(c(sv)->newsock, 1);
175         if (c(sv)->newsock > 1)
176                 close(c(sv)->newsock);
177
178 }
179
180 static void stream_send(service_t sv)
181 {
182         send_byte(2);   /*stream */
183         send_int(c(sv)->proto);
184         send_int(ntohs(c(sv)->port));
185         send_int(c(sv)->backlog);
186         send_int(c(sv)->sock>=0);
187 }
188
189 struct class stream_class = {
190         .class          = "stream",
191         .c_process_opt  = stream_opt,
192         .register_service= stream_register,
193         .c_check_service= stream_check,
194         .init_state     = stream_init,
195         .copy_state     = stream_copy,
196         .free_state     = stream_freestate,
197         .send_class     = stream_send,
198         .disable_service= stream_unregister,
199         .new_parent     = stream_newparent,
200         .new_child      = stream_newchild,
201         .prefork        = stream_prefork,
202 };
203