2 x86 Migration Connection runtime
3 Copyright (C) 2002,2001 Justin David Smith, Caltech
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include <netinet/in.h>
28 #include <sys/socket.h>
30 #include <sys/types.h>
35 #include "x86_connection.h"
40 static const char *host_proto
= "host://";
41 static const char *suspend_proto
= "suspend://";
42 static const char *checkpoint_proto
= "checkpoint://";
45 /*** Connection Setup ***/
48 /* Setup the migration connection based on the URL-style descriptor
49 we were given. Returns zero on success, -1 if the input URL
50 could not be parsed. Results are stored in conn. */
51 int setup_connection(migrate_connection
*conn
, const char *dest
) {
59 /* Check which protocol we should use */
60 if(strncmp(dest
, host_proto
, strlen(host_proto
)) == 0) {
61 conn
->protocol
= MIGRATE_TO_HOST
;
62 /* Check for a port number */
63 if((p
= strchr(dest
+ strlen(host_proto
), ':')) == NULL
) {
64 /* No port number specified */
65 strncpy(conn
->name
, dest
+ strlen(host_proto
), sizeof(conn
->name
));
66 conn
->port
= DEFAULT_SERVER_PORT
;
68 /* Copy only part up to the colon */
69 size
= p
- (dest
+ strlen(host_proto
));
70 if(size
> sizeof(conn
->name
)) size
= sizeof(conn
->name
);
71 strncpy(conn
->name
, dest
+ strlen(host_proto
), size
);
72 /* Extract port number */
73 conn
->port
= atoi(p
+ 1);
74 } /* Port number given? */
75 } else if(strncmp(dest
, suspend_proto
, strlen(suspend_proto
)) == 0) {
76 conn
->protocol
= MIGRATE_SUSPEND
;
77 strncpy(conn
->name
, dest
+ strlen(suspend_proto
), sizeof(conn
->name
));
78 } else if(strncmp(dest
, checkpoint_proto
, strlen(checkpoint_proto
)) == 0) {
79 conn
->protocol
= MIGRATE_CHECKPOINT
;
80 strncpy(conn
->name
, dest
+ strlen(checkpoint_proto
), sizeof(conn
->name
));
82 /* Unrecognized protocol name; guessing old-form protocol */
83 fprintf(stderr
, "migrate: Unrecognized protocol: \"%s\"\n", dest
);
84 fprintf(stderr
, "migrate: Guessing this is the old-form protocol\n");
85 conn
->protocol
= MIGRATE_TO_HOST
;
86 strncpy(conn
->name
, dest
, sizeof(conn
->name
));
87 conn
->port
= DEFAULT_SERVER_PORT
;
90 /* No known IO channels (yet) */
94 /* Make sure name is null-terminated */
95 conn
->name
[sizeof(conn
->name
) - 1] = '\0';
97 /* Verify name is not entirely bogus */
98 if(*conn
->name
== '\0') {
99 fprintf(stderr
, "migrate: Name is empty, cannot migrate\n");
103 /* Verify port number */
104 if(conn
->protocol
== MIGRATE_TO_HOST
&& (conn
->port
<= 0 || conn
->port
>= 0x10000)) {
105 fprintf(stderr
, "migrate: Invalid port number, cannot migrate\n");
115 /*** Dispatch Functions for Open/Close connection ***/
118 /* Open a new source connection */
119 int open_source_connection(migrate_connection
*conn
) {
121 assert(conn
!= NULL
);
123 /* Branch on the possible connection types */
124 switch(conn
->protocol
) {
125 case MIGRATE_TO_HOST
:
126 conn
->io
= net_open_connection(conn
->name
, conn
->port
);
127 if(conn
->io
< 0) return(-1);
130 case MIGRATE_SUSPEND
:
131 case MIGRATE_CHECKPOINT
:
132 conn
->io
= open(conn
->name
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
134 perror("open_source_connection");
141 /* We were successful */
147 /* Configure a connection on the destination side */
148 int open_dest_connection(migrate_connection
*conn
, Migrate
*m
) {
150 assert(conn
!= NULL
);
152 /* Branch on the possible connection types */
154 /* Socket connection */
155 conn
->protocol
= MIGRATE_TO_HOST
;
157 /* Reading from a file; we need to seek to the initial
158 offset we are supposed to be reading from. */
159 conn
->protocol
= MIGRATE_SUSPEND
;
160 if(lseek(m
->channel
, m
->initofs
, SEEK_SET
) != m
->initofs
) {
161 perror("open_dest_connection");
166 /* Setup IO data members */
167 conn
->io
= m
->channel
;
168 conn
->bidir
= m
->bidir
;
174 /* Close an existing connection */
175 void close_connection(migrate_connection
*conn
) {
177 assert(conn
!= NULL
);
179 /* Branch on the possible connection types */
180 switch(conn
->protocol
) {
181 case MIGRATE_TO_HOST
:
182 shutdown(conn
->io
, 2);
185 case MIGRATE_SUSPEND
:
186 case MIGRATE_CHECKPOINT
:
194 /*** IO/Communication ***/
197 /* Send a sized buffer out */
198 int send_buffer(migrate_connection
*conn
, const char *buf
, int size
) {
200 int sent
; /* Amount of data transmitted */
202 assert(conn
!= NULL
);
206 switch(conn
->protocol
) {
207 case MIGRATE_TO_HOST
:
208 return(net_send_buffer(conn
->io
, buf
, size
));
210 case MIGRATE_SUSPEND
:
211 case MIGRATE_CHECKPOINT
:
212 sent
= write(conn
->io
, buf
, size
);
214 perror("send_buffer");
216 } else if(sent
< size
) {
217 fprintf(stderr
, "send_buffer: Failed to transmit all required data\n");
223 /* Something went wrong */
224 fprintf(stderr
, "send_buffer: Bogus protocol, aborting.\n");
230 /* Receive/read a sized buffer in */
231 int recv_buffer(migrate_connection
*conn
, char *buf
, int size
) {
233 int rcvd
; /* Amount of data received */
235 assert(conn
!= NULL
);
239 switch(conn
->protocol
) {
240 case MIGRATE_TO_HOST
:
241 return(net_recv_buffer(conn
->io
, buf
, size
));
243 case MIGRATE_SUSPEND
:
244 case MIGRATE_CHECKPOINT
:
245 rcvd
= read(conn
->io
, buf
, size
);
247 perror("recv_buffer");
249 } else if(rcvd
< size
) {
250 fprintf(stderr
, "recv_buffer: Failed to receive all expected data\n");
256 /* Something went wrong */
257 fprintf(stderr
, "recv_buffer: Bogus protocol, aborting.\n");
263 /* Send a string over the network */
264 int send_string(migrate_connection
*conn
, const char *msg
) {
266 int count
= strlen(msg
); /* Number of bytes in msg */
267 char buf
[count
+ 2]; /* Real buffer to send */
269 assert(conn
!= NULL
);
272 /* Construct the buffer message */
273 snprintf(buf
, sizeof(buf
), "%s\n", msg
);
276 /* Send the string as a buffer */
277 return(send_buffer(conn
, buf
, count
));
282 /* Receive a string from the network */
283 int recv_string(migrate_connection
*conn
, char *buffer
, int size
) {
285 char *p
= buffer
; /* Pointer into result buffer */
287 assert(conn
!= NULL
);
288 assert(buffer
!= NULL
);
291 /* Receive some data */
292 memset(buffer
, '\0', size
);
293 while((p
== buffer
|| *(p
- 1) != '\n') && p
- buffer
< size
- 1) {
294 if(recv_buffer(conn
, p
, 1) < 0) return(-1);
297 if(p
> buffer
&& *(p
- 1) == '\n') *(p
- 1) = '\0';
305 /* Send an integer over the network */
306 int send_int32(migrate_connection
*conn
, unsigned int value
) {
308 assert(conn
!= NULL
);
309 value
= htonl(value
);
310 return(send_buffer(conn
, (char *)&value
, sizeof(unsigned int)));
315 /* Receive an int32 value */
316 int recv_int32(migrate_connection
*conn
, unsigned int *value
) {
318 assert(conn
!= NULL
);
319 assert(value
!= NULL
);
320 if(recv_buffer(conn
, (char *)value
, sizeof(unsigned int)) != 0) return(-1);
321 *value
= ntohl(*value
);
327 /* Send an integer block over the network, INCLUDING size parametre */
328 int send_int32_block(migrate_connection
*conn
, const unsigned int *values
, int size
) {
330 assert(conn
!= NULL
);
331 assert(values
!= NULL
);
333 if(send_int32(conn
, size
) < 0) return(-1);
335 if(send_int32(conn
, *values
) < 0) return(-1);
344 /* Receive an integer block over the network */
345 int recv_int32_block(migrate_connection
*conn
, unsigned int *values
, int size
) {
347 assert(conn
!= NULL
);
348 assert(values
!= NULL
);
351 if(recv_int32(conn
, values
) < 0) return(-1);