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