symbian-qemu-0.9.1-12/qemu-symbian-svp/migration-tcp.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU live migration
       
     3  *
       
     4  * Copyright IBM, Corp. 2008
       
     5  *
       
     6  * Authors:
       
     7  *  Anthony Liguori   <aliguori@us.ibm.com>
       
     8  *
       
     9  * This work is licensed under the terms of the GNU GPL, version 2.  See
       
    10  * the COPYING file in the top-level directory.
       
    11  *
       
    12  */
       
    13 
       
    14 #include "qemu-common.h"
       
    15 #include "qemu_socket.h"
       
    16 #include "migration.h"
       
    17 #include "qemu-char.h"
       
    18 #include "sysemu.h"
       
    19 #include "console.h"
       
    20 #include "buffered_file.h"
       
    21 #include "block.h"
       
    22 
       
    23 //#define DEBUG_MIGRATION_TCP
       
    24 
       
    25 #ifdef DEBUG_MIGRATION_TCP
       
    26 #define dprintf(fmt, ...) \
       
    27     do { printf("migration-tcp: " fmt, ## __VA_ARGS__); } while (0)
       
    28 #else
       
    29 #define dprintf(fmt, ...) \
       
    30     do { } while (0)
       
    31 #endif
       
    32 
       
    33 static int socket_errno(FdMigrationState *s)
       
    34 {
       
    35     return socket_error();
       
    36 }
       
    37 
       
    38 static int socket_write(FdMigrationState *s, const void * buf, size_t size)
       
    39 {
       
    40     return send(s->fd, buf, size, 0);
       
    41 }
       
    42 
       
    43 static int tcp_close(FdMigrationState *s)
       
    44 {
       
    45     dprintf("tcp_close\n");
       
    46     if (s->fd != -1) {
       
    47         close(s->fd);
       
    48         s->fd = -1;
       
    49     }
       
    50     return 0;
       
    51 }
       
    52 
       
    53 
       
    54 static void tcp_wait_for_connect(void *opaque)
       
    55 {
       
    56     FdMigrationState *s = opaque;
       
    57     int val, ret;
       
    58     socklen_t valsize = sizeof(val);
       
    59 
       
    60     dprintf("connect completed\n");
       
    61     do {
       
    62         ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &val, &valsize);
       
    63     } while (ret == -1 && (s->get_error(s)) == EINTR);
       
    64 
       
    65     if (ret < 0) {
       
    66         migrate_fd_error(s);
       
    67         return;
       
    68     }
       
    69 
       
    70     qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
       
    71 
       
    72     if (val == 0)
       
    73         migrate_fd_connect(s);
       
    74     else {
       
    75         dprintf("error connecting %d\n", val);
       
    76         migrate_fd_error(s);
       
    77     }
       
    78 }
       
    79 
       
    80 MigrationState *tcp_start_outgoing_migration(const char *host_port,
       
    81                                              int64_t bandwidth_limit,
       
    82                                              int async)
       
    83 {
       
    84     struct sockaddr_in addr;
       
    85     FdMigrationState *s;
       
    86     int ret;
       
    87 
       
    88     if (parse_host_port(&addr, host_port) < 0)
       
    89         return NULL;
       
    90 
       
    91     s = qemu_mallocz(sizeof(*s));
       
    92     if (s == NULL)
       
    93         return NULL;
       
    94 
       
    95     s->get_error = socket_errno;
       
    96     s->write = socket_write;
       
    97     s->close = tcp_close;
       
    98     s->mig_state.cancel = migrate_fd_cancel;
       
    99     s->mig_state.get_status = migrate_fd_get_status;
       
   100     s->mig_state.release = migrate_fd_release;
       
   101 
       
   102     s->state = MIG_STATE_ACTIVE;
       
   103     s->detach = !async;
       
   104     s->bandwidth_limit = bandwidth_limit;
       
   105     s->fd = socket(PF_INET, SOCK_STREAM, 0);
       
   106     if (s->fd == -1) {
       
   107         qemu_free(s);
       
   108         return NULL;
       
   109     }
       
   110 
       
   111     socket_set_nonblock(s->fd);
       
   112 
       
   113     if (s->detach == 1) {
       
   114         dprintf("detaching from monitor\n");
       
   115         monitor_suspend();
       
   116         s->detach = 2;
       
   117     }
       
   118 
       
   119     do {
       
   120         ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
       
   121         if (ret == -1)
       
   122             ret = -(s->get_error(s));
       
   123 
       
   124         if (ret == -EINPROGRESS || ret == -EWOULDBLOCK)
       
   125             qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
       
   126     } while (ret == -EINTR);
       
   127 
       
   128     if (ret < 0 && ret != -EINPROGRESS && ret != -EWOULDBLOCK) {
       
   129         dprintf("connect failed\n");
       
   130         close(s->fd);
       
   131         qemu_free(s);
       
   132         return NULL;
       
   133     } else if (ret >= 0)
       
   134         migrate_fd_connect(s);
       
   135 
       
   136     return &s->mig_state;
       
   137 }
       
   138 
       
   139 static void tcp_accept_incoming_migration(void *opaque)
       
   140 {
       
   141     struct sockaddr_in addr;
       
   142     socklen_t addrlen = sizeof(addr);
       
   143     int s = (unsigned long)opaque;
       
   144     QEMUFile *f;
       
   145     int c, ret;
       
   146 
       
   147     do {
       
   148         c = accept(s, (struct sockaddr *)&addr, &addrlen);
       
   149     } while (c == -1 && socket_error() == EINTR);
       
   150 
       
   151     dprintf("accepted migration\n");
       
   152 
       
   153     if (c == -1) {
       
   154         fprintf(stderr, "could not accept migration connection\n");
       
   155         return;
       
   156     }
       
   157 
       
   158     f = qemu_fopen_socket(c);
       
   159     if (f == NULL) {
       
   160         fprintf(stderr, "could not qemu_fopen socket\n");
       
   161         goto out;
       
   162     }
       
   163 
       
   164     vm_stop(0); /* just in case */
       
   165     ret = qemu_loadvm_state(f);
       
   166     if (ret < 0) {
       
   167         fprintf(stderr, "load of migration failed\n");
       
   168         goto out_fopen;
       
   169     }
       
   170     qemu_announce_self();
       
   171     dprintf("successfully loaded vm state\n");
       
   172 
       
   173     /* we've successfully migrated, close the server socket */
       
   174     qemu_set_fd_handler2(s, NULL, NULL, NULL, NULL);
       
   175     close(s);
       
   176 
       
   177     vm_start();
       
   178 
       
   179 out_fopen:
       
   180     qemu_fclose(f);
       
   181 out:
       
   182     close(c);
       
   183 }
       
   184 
       
   185 int tcp_start_incoming_migration(const char *host_port)
       
   186 {
       
   187     struct sockaddr_in addr;
       
   188     int val;
       
   189     int s;
       
   190 
       
   191     if (parse_host_port(&addr, host_port) < 0) {
       
   192         fprintf(stderr, "invalid host/port combination: %s\n", host_port);
       
   193         return -EINVAL;
       
   194     }
       
   195 
       
   196     s = socket(PF_INET, SOCK_STREAM, 0);
       
   197     if (s == -1)
       
   198         return -socket_error();
       
   199 
       
   200     val = 1;
       
   201     setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
       
   202 
       
   203     if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
       
   204         goto err;
       
   205 
       
   206     if (listen(s, 1) == -1)
       
   207         goto err;
       
   208 
       
   209     qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
       
   210                          (void *)(unsigned long)s);
       
   211 
       
   212     return 0;
       
   213 
       
   214 err:
       
   215     close(s);
       
   216     return -socket_error();
       
   217 }