1 /*
2 * The Wackamole Program.
3 *
4 * The contents of this file are subject to the CNDS Open Source
5 * License, Version 1.0 (the ``License''); you may not use
6 * this file except in compliance with the License. You may obtain a
7 * copy of the License at:
8 *
9 * http://www.backhand.org/wackamole/license/
10 *
11 * or in the file ``license.txt'' found in this distribution.
12 *
13 * Software distributed under the License is distributed on an AS IS basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
17 *
18 * The Creators of Wackamole are:
19 * Yair Amir, Ryan Caudy, Aashima Munjal and Theo Schlossnagle.
20 *
21 * Copyright (C) 2000-2001 The Johns Hopkins University
22 * All Rights Reserved.
23 *
24 * This product uses the Spread toolkit, developed by Spread Concepts LLC.
25 * For more information about Spread see http://www.spread.org
26 *
27 * Wackamole development was partially funded by a grant from the Defense
28 * Advanced Research Projects Agency (DARPA) to Johns Hopkins University. The
29 * U.S. Government retains certain rights in this software.
30 *
31 */
32 #include "config.h"
33 #include "wackamole.h"
34 #include "configuration.h"
35 #include "control.h"
36 #include "apue.h"
37 #include "alarm.h"
38 #include "wackatrl.h"
39
40 extern mailbox Mbox;
41 extern int spread_lock;
42
43 typedef struct {
44 int size;
45 int written;
46 char *buffer;
47 } write_struct;
48
49 typedef struct {
50 char operation;
51 char state;
52 union {
53 write_struct writing;
54 int retint;
55 } data;
56 } control_state;
57
create_control_socket(const char * filename)58 void create_control_socket(const char *filename) {
59 int fd;
60 if((fd = serv_listen(filename)) < 0) {
61 wack_alarm(PRINT, "disabling wackatrl support.");
62 return;
63 }
64 E_attach_fd(fd, READ_FD, handle_control_connect, 0, NULL, HIGH_PRIORITY);
65 }
handle_control_connect(int fd,int code,void * data)66 void handle_control_connect(int fd, int code, void *data) {
67 int nfd, ret, ioctl_cmd;
68 control_state *state;
69 nfd = serv_accept(fd);
70 if(nfd < 0) {
71 wack_alarm(PRINT, "error receiving wackatrl session");
72 return;
73 }
74 ioctl_cmd = 1;
75 #ifdef WIN32
76 ret = ioctlsocket(nfd, FIONBIO, &ioctl_cmd);
77 #else
78 ret = ioctl(nfd, FIONBIO, &ioctl_cmd);
79 #endif
80 wack_alarm(WACK_DEBUG, "starting wackatrl session");
81 state = calloc(1, sizeof(control_state));
82 state->operation = READ_COMMAND;
83 state->state = READ_FD;
84 E_attach_fd(nfd, READ_FD, handle_control_session,
85 0, (void *)state, HIGH_PRIORITY);
86 E_attach_fd(nfd, WRITE_FD, handle_control_session,
87 0, (void *)state, HIGH_PRIORITY);
88 E_deactivate_fd(nfd, WRITE_FD);
89 }
90
set_event_mask(int fd,control_state * sess)91 static int set_event_mask(int fd, control_state *sess) {
92 if(sess->state == READ_FD) {
93 E_activate_fd(fd, READ_FD);
94 E_deactivate_fd(fd, WRITE_FD);
95 } else if(sess->state == WRITE_FD) {
96 E_activate_fd(fd, WRITE_FD);
97 E_deactivate_fd(fd, READ_FD);
98 } else {
99 wack_alarm(PRINT, "Unknown session state: %d", sess->state);
100 return -1;
101 }
102 return 0;
103 }
104
105 #define sprintif(a,b,c) do {\
106 memcpy(a+(*(c)), (b).ifname, IFNAMSIZ); (*c)+=IFNAMSIZ; \
107 memcpy(a+(*(c)), &((b).ipaddr.s_addr), sizeof(int)); (*c)+=sizeof(int); \
108 memcpy(a+(*(c)), &((b).bcast.s_addr), sizeof(int)); (*c)+=sizeof(int); \
109 memcpy(a+(*(c)), &((b).netmask.s_addr), sizeof(int)); (*c)+=sizeof(int); \
110 } while (0);
111
set_state_wack_service_state(control_state * sess)112 static void set_state_wack_service_state(control_state *sess) {
113 sess->state = WRITE_FD;
114 sess->data.retint = htonl(-1);
115 if(sess->operation == WACK_SERVICE_FAILURE) {
116 sess->data.retint = htonl(0);
117 spread_lock = 1;
118 E_detach_fd(Mbox, READ_FD);
119 SP_disconnect(Mbox);
120 Mbox=-1;
121 Clean_up();
122 } else if(sess->operation == WACK_SERVICE_SUCCESS) {
123 sess->data.retint = htonl(0);
124 spread_lock = 0;
125 }
126 Spread_reconnect(-8);
127 }
set_state_wack_state(control_state * sess)128 static void set_state_wack_state(control_state *sess) {
129 int netint, len=0, i, j;
130 struct interface temp;
131 sess->state = WRITE_FD;
132 sess->data.writing.size = sizeof(int) +
133 Num_pseudo*(sizeof(int)+(IFNAMSIZ+3*sizeof(int))*(MAX_DEP_IF+2));
134 sess->data.writing.written = 0;
135 sess->data.writing.buffer = malloc(sess->data.writing.size);
136 /* How much we will write - minus the this int itself */
137 netint = htonl(sess->data.writing.size - sizeof(int));
138 memcpy(sess->data.writing.buffer+len, &netint, sizeof(int)); len+=sizeof(int);
139 for(i=0;i<Num_pseudo;i++) {
140 /* Claim priority */
141 netint = htonl(Allocation_table[i].claim_priority);
142 memcpy(sess->data.writing.buffer+len,&netint,sizeof(int)); len+=sizeof(int);
143 /* Real info */
144 memcpy(&temp, &Allocation_table[i].real_if, sizeof(struct interface));
145 sprintif(sess->data.writing.buffer, temp, &len);
146 /* Master VIF */
147 memcpy(&temp, &Allocation_table[i].pseudo_if, sizeof(struct interface));
148 sprintif(sess->data.writing.buffer, temp, &len);
149 /* Other VIFs */
150 for(j=0;j<MAX_DEP_IF;j++) {
151 memcpy(&temp, &Allocation_table[i].extra_ifs[j],sizeof(struct interface));
152 sprintif(sess->data.writing.buffer, temp, &len);
153 }
154 }
155 wack_alarm(WACK_DEBUG, "Going to write state: %d bytes, filled %d",
156 sess->data.writing.size, len);
157 }
158
new_command(control_state * sess)159 static int new_command(control_state *sess) {
160 switch(sess->operation) {
161 case GET_WACK_STATE:
162 set_state_wack_state(sess);
163 break;
164 case WACK_SERVICE_FAILURE:
165 set_state_wack_service_state(sess);
166 break;
167 case WACK_SERVICE_SUCCESS:
168 set_state_wack_service_state(sess);
169 break;
170 default:
171 return -1;
172 }
173 return 0;
174 }
175
handle_control_session(int fd,int code,void * data)176 void handle_control_session(int fd, int code, void *data) {
177 int ret;
178 control_state *sess = (control_state *)data;
179
180 switch(sess->state) {
181 case READ_FD:
182 switch(sess->operation) {
183 case READ_COMMAND:
184 ret = read(fd, &sess->operation, 1);
185 if(ret == 0) goto close_clean;
186 if(ret < 0) {
187 if(errno == EAGAIN || errno == EWOULDBLOCK)
188 return;
189 goto error;
190 }
191 if(new_command(sess)) goto error;
192 if(set_event_mask(fd, sess)) goto error;
193 break;
194 default:
195 goto error;
196 }
197 break;
198 case WRITE_FD:
199 switch(sess->operation) {
200 case GET_WACK_STATE:
201 ret = write(fd, sess->data.writing.buffer+sess->data.writing.written,
202 sess->data.writing.size-sess->data.writing.written);
203 if(ret == 0) goto error;
204 if(ret<0) {
205 if(errno == EAGAIN || errno == EWOULDBLOCK)
206 return;
207 goto error;
208 }
209 sess->data.writing.written += ret;
210 if(sess->data.writing.written == sess->data.writing.size) {
211 free(sess->data.writing.buffer);
212 sess->operation = READ_COMMAND;
213 sess->state = READ_FD;
214 if(set_event_mask(fd, sess)) goto error;
215 }
216 break;
217 case WACK_SERVICE_FAILURE:
218 case WACK_SERVICE_SUCCESS:
219 ret = write(fd, &sess->data.retint, sizeof(int));
220 if(ret == 0) goto error;
221 if(ret<0) {
222 if(errno == EAGAIN || errno == EWOULDBLOCK)
223 return;
224 goto error;
225 }
226 if(ret != sizeof(int)) goto error;
227 sess->operation = READ_COMMAND;
228 sess->state = READ_FD;
229 if(set_event_mask(fd, sess)) goto error;
230 break;
231 default:
232 goto error;
233 }
234 break;
235 default:
236 goto error;
237 }
238 return;
239 error:
240 wack_alarm(PRINT, "control session error: [fd=%d] %s\n\tState=%d, Operation=%d",
241 fd, strerror(errno), sess->state, sess->operation);
242 close_clean:
243 E_detach_fd(fd, READ_FD);
244 E_detach_fd(fd, WRITE_FD);
245 free(sess);
246 close(fd);
247 }
248
249