Initial snarf.
[shack.git] / arch / x86 / runtime / x86_connection.c
blob820604ce67434ae8f9e9f6182c67256a2d82673e
1 /*
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.
21 /* System includes */
22 #include <assert.h>
23 #include <fcntl.h>
24 #include <netinet/in.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
34 /* Local includes */
35 #include "x86_connection.h"
36 #include "x86_net.h"
39 /* Protocol names */
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) {
53 char *p;
54 int size;
56 assert(conn != NULL);
57 assert(dest != NULL);
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;
67 } else {
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));
81 } else {
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) */
91 conn->io = -1;
92 conn->bidir = false;
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");
100 return(-1);
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");
106 return(-1);
109 /* Return success */
110 return(0);
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);
128 conn->bidir = true;
129 break;
130 case MIGRATE_SUSPEND:
131 case MIGRATE_CHECKPOINT:
132 conn->io = open(conn->name, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
133 if(conn->io < 0) {
134 perror("open_source_connection");
135 return(-1);
137 conn->bidir = false;
138 break;
141 /* We were successful */
142 return(0);
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 */
153 if(m->bidir) {
154 /* Socket connection */
155 conn->protocol = MIGRATE_TO_HOST;
156 } else {
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");
162 return(-1);
166 /* Setup IO data members */
167 conn->io = m->channel;
168 conn->bidir = m->bidir;
169 return(0);
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);
183 close(conn->io);
184 break;
185 case MIGRATE_SUSPEND:
186 case MIGRATE_CHECKPOINT:
187 close(conn->io);
188 break;
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);
203 assert(buf != NULL);
204 assert(size >= 0);
206 switch(conn->protocol) {
207 case MIGRATE_TO_HOST:
208 return(net_send_buffer(conn->io, buf, size));
209 break;
210 case MIGRATE_SUSPEND:
211 case MIGRATE_CHECKPOINT:
212 sent = write(conn->io, buf, size);
213 if(sent < 0) {
214 perror("send_buffer");
215 return(-1);
216 } else if(sent < size) {
217 fprintf(stderr, "send_buffer: Failed to transmit all required data\n");
218 return(-1);
220 return(0);
223 /* Something went wrong */
224 fprintf(stderr, "send_buffer: Bogus protocol, aborting.\n");
225 return(-1);
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);
236 assert(buf != NULL);
237 assert(size >= 0);
239 switch(conn->protocol) {
240 case MIGRATE_TO_HOST:
241 return(net_recv_buffer(conn->io, buf, size));
242 break;
243 case MIGRATE_SUSPEND:
244 case MIGRATE_CHECKPOINT:
245 rcvd = read(conn->io, buf, size);
246 if(rcvd < 0) {
247 perror("recv_buffer");
248 return(-1);
249 } else if(rcvd < size) {
250 fprintf(stderr, "recv_buffer: Failed to receive all expected data\n");
251 return(-1);
253 return(0);
256 /* Something went wrong */
257 fprintf(stderr, "recv_buffer: Bogus protocol, aborting.\n");
258 return(-1);
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);
270 assert(msg != NULL);
272 /* Construct the buffer message */
273 snprintf(buf, sizeof(buf), "%s\n", msg);
274 ++count;
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);
289 assert(size >= 0);
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);
295 ++p;
297 if(p > buffer && *(p - 1) == '\n') *(p - 1) = '\0';
299 /* Success! */
300 return(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);
322 return(0);
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);
332 assert(size >= 0);
333 if(send_int32(conn, size) < 0) return(-1);
334 while(size > 0) {
335 if(send_int32(conn, *values) < 0) return(-1);
336 ++values;
337 --size;
339 return(0);
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);
349 assert(size >= 0);
350 while(size > 0) {
351 if(recv_int32(conn, values) < 0) return(-1);
352 ++values;
353 --size;
355 return(0);