5 #include <sys/socket.h>
6 #include <netinet/in.h>
17 /* control.c - handle the control ports
18 * listen on udp port for packets with command to obey
19 * listen on tcp port for connections.
20 * when get connection, listen for command, and possibly return data
24 /* only allow one active tcp connection for now,
25 * but make sure it times out
29 static int tcp_listen;
31 static struct tcpcon {
33 char buf[1024]; /*for incoming command */
34 char host[1024]; /* host connection is from */
35 int buflen; /* how much has been read */
36 char *outbuf; /* outgoing data */
37 int outlen; /* size of outgoing data */
38 int outpos; /* how much sent so far */
39 time_t connect_time;/* when the connection was established */
45 void return_error(struct tcpcon *con, char *fmt, char *a, char *b, char *c)
49 extern char version[];
52 sprintf(buf, fmt, a, b, c);
53 sprintf(buf+strlen(buf), " (metad version %s)", version);
54 rv = (char*)malloc(strlen(buf)+2);
58 con->outlen = strlen(buf)+2;
63 static int address_ok(struct sockaddr_in *sa, char *host)
68 static char *tail = ".cse.unsw.edu.au";
70 if (ntohs(sa->sin_port) >= 1024 && geteuid() == 0)
72 if (sa->sin_addr.s_addr == htonl(0x7f000001))
74 strcpy(host, "localhost");
75 return 1; /* localhost */
77 he = gethostbyaddr((char*)&sa->sin_addr, 4, AF_INET);
80 strcpy(host, he->h_name);
81 he = gethostbyname(host);
84 for (a=0; he->h_addr_list[a] ; a++)
85 if (memcmp(&sa->sin_addr, he->h_addr_list[a], 4)==0)
87 /* well, we have a believeable name */
90 if (len > strlen(tail) && strcasecmp(tail, host+len - strlen(tail))== 0)
97 static void run_command(char *buf, char *host, struct tcpcon *con)
102 for (cp= buf; *cp ; cp++)
104 if (*cp == '\r' || *cp == '\n') *cp = 0;
106 wp = words = strsplit(buf, " ");
107 if (isdigit(wp[0][0]))
108 wp++; /* old gossip put a port number at the start for return info */
109 if (!do_command(wp, host, con))
111 /* possibly return error */
113 return_error(con, "unknown command %s", wp[0], NULL, NULL);
117 void nodelay(int socket)
120 f = fcntl(socket, F_GETFL, 0);
121 fcntl(socket, F_SETFL, f|O_NDELAY);
122 fcntl(socket, F_SETFD, 1); /* set close-on-exec */
127 udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
130 struct sockaddr_in sa;
131 memset(&sa, 0, sizeof(sa));
132 sa.sin_family = AF_INET;
133 sa.sin_port = udp_port();
135 if (bind(udp_sock, (struct sockaddr *)&sa, sizeof(sa)) != 0)
137 error("cannot bind udp port");
143 error("cannot create udp socket");
146 tcp_listen = socket(AF_INET, SOCK_STREAM, 0);
149 struct sockaddr_in sa;
152 memset(&sa, 0, sizeof(sa));
153 sa.sin_family = AF_INET;
154 sa.sin_port = tcp_port();
155 setsockopt(tcp_listen, SOL_SOCKET, SO_REUSEADDR, (char*)&i, 4);
156 if (bind(tcp_listen, (struct sockaddr *)&sa, sizeof(sa)) != 0)
158 error("cannot bind tcp port");
161 listen(tcp_listen, 5);
165 error("Cannot create tcp socket");
172 void control_close(void)
179 void check_control(void)
181 /* first check udp */
182 if (readyon(udp_sock))
187 struct sockaddr_in sa;
188 unsigned int salen = sizeof(sa);
189 n = recvfrom(udp_sock, buf, sizeof(buf)-1, 0, (struct sockaddr *)&sa, &salen );
190 if (n>0 && address_ok(&sa, host))
193 run_command(buf, host, NULL);
198 /* then check tcpcon or tcp_listen */
199 if (tcpcon.sock != -1)
203 if (tcpcon.connect_time + 120 < now)
208 if (tcpcon.outbuf) free(tcpcon.outbuf);
209 tcpcon.outbuf = NULL;
210 listenon(tcp_listen);
212 else if (tcpcon.outbuf)
214 if (canwrite(tcpcon.sock) && tcpcon.outpos < tcpcon.outlen)
216 int l = tcpcon.outlen - tcpcon.outpos;
217 if (l>1024) l = 1024;
218 l = write(tcpcon.sock, tcpcon.outbuf+tcpcon.outpos, l);
221 close(tcpcon.sock); tcpcon.sock = -1; free(tcpcon.outbuf);
222 tcpcon.outbuf = NULL;
226 if (tcpcon.outpos >= tcpcon.outlen)
228 close(tcpcon.sock); tcpcon.sock = -1; free(tcpcon.outbuf);
229 tcpcon.outbuf = NULL;
232 if (tcpcon.sock == -1)
233 listenon(tcp_listen);
235 writeon(tcpcon.sock);
237 else /* we are still reading a command */
239 if (readyon(tcpcon.sock))
241 int l = sizeof(tcpcon.buf) - tcpcon.buflen;
242 l = read(tcpcon.sock, tcpcon.buf+tcpcon.buflen, l-1);
245 close(tcpcon.sock); tcpcon.sock = -1;
250 if (l == 0 || strchr(tcpcon.buf, '\n') || strchr(tcpcon.buf, '\r') || strlen(tcpcon.buf) < l)
252 run_command(tcpcon.buf, tcpcon.host, &tcpcon);
253 if (tcpcon.outbuf == NULL)
255 tcpcon.outbuf = malloc(1);
256 tcpcon.outbuf[0] = 0;
263 if (tcpcon.sock == -1)
264 listenon(tcp_listen);
265 else if (tcpcon.outbuf)
266 writeon(tcpcon.sock);
268 listenon(tcpcon.sock);
273 if (readyon(tcp_listen))
275 struct sockaddr_in sa;
276 unsigned int salen = sizeof(sa);
278 tcpcon.outbuf = NULL;
279 tcpcon.sock = accept(tcp_listen, (struct sockaddr *)&sa, &salen);
280 if (tcpcon.sock >= 0)
282 nodelay(tcpcon.sock);
283 if (address_ok(&sa, tcpcon.host))
285 time(&tcpcon.connect_time);
286 listenon(tcpcon.sock);
287 waituntil(tcpcon.connect_time+122);
297 listenon(tcp_listen);
302 void set_reply(struct tcpcon *con, char *reply, int len)