Statistics
| Branch: | Revision:

root / control / tap-ctl-ipc.c @ abdb293f

History | View | Annotate | Download (5.3 kB)

1
/*
2
 * Copyright (c) 2008, XenSource Inc.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *     * Redistributions of source code must retain the above copyright
8
 *       notice, this list of conditions and the following disclaimer.
9
 *     * Redistributions in binary form must reproduce the above copyright
10
 *       notice, this list of conditions and the following disclaimer in the
11
 *       documentation and/or other materials provided with the distribution.
12
 *     * Neither the name of XenSource Inc. nor the names of its contributors
13
 *       may be used to endorse or promote products derived from this software
14
 *       without specific prior written permission.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
20
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28

    
29
#ifdef HAVE_CONFIG_H
30
#include "config.h"
31
#endif
32

    
33
#include <stdio.h>
34
#include <errno.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <fcntl.h>
39
#include <sys/un.h>
40
#include <sys/stat.h>
41
#include <sys/types.h>
42
#include <sys/socket.h>
43

    
44
#include "tap-ctl.h"
45
#include "blktap2.h"
46

    
47
int tap_ctl_debug = 0;
48

    
49
int
50
tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout)
51
{
52
        fd_set readfds;
53
        size_t offset = 0;
54
        int ret;
55

    
56
        while (offset < size) {
57
                FD_ZERO(&readfds);
58
                FD_SET(fd, &readfds);
59

    
60
                ret = select(fd + 1, &readfds, NULL, NULL, timeout);
61
                if (ret == -1)
62
                        break;
63
                else if (FD_ISSET(fd, &readfds)) {
64
                        ret = read(fd, buf + offset, size - offset);
65
                        if (ret <= 0)
66
                                break;
67
                        offset += ret;
68
                } else
69
                        break;
70
        }
71

    
72
        if (offset != size) {
73
                EPRINTF("failure reading data %zd/%zd\n", offset, size);
74
                return -EIO;
75
        }
76

    
77
        return 0;
78
}
79

    
80
int
81
tap_ctl_read_message(int fd, tapdisk_message_t *message,
82
                     struct timeval *timeout)
83
{
84
        size_t size = sizeof(tapdisk_message_t);
85
        int err;
86

    
87
        err = tap_ctl_read_raw(fd, message, size, timeout);
88
        if (err)
89
                return err;
90

    
91
        DBG("received '%s' message (uuid = %u)\n",
92
            tapdisk_message_name(message->type), message->cookie);
93

    
94
        return 0;
95
}
96

    
97
int
98
tap_ctl_write_message(int fd, tapdisk_message_t *message, struct timeval *timeout)
99
{
100
        fd_set writefds;
101
        int ret, len, offset;
102

    
103
        offset = 0;
104
        len    = sizeof(tapdisk_message_t);
105

    
106
        DBG("sending '%s' message (uuid = %u)\n",
107
            tapdisk_message_name(message->type), message->cookie);
108

    
109
        while (offset < len) {
110
                FD_ZERO(&writefds);
111
                FD_SET(fd, &writefds);
112

    
113
                /* we don't bother reinitializing tv. at worst, it will wait a
114
                 * bit more time than expected. */
115

    
116
                ret = select(fd + 1, NULL, &writefds, NULL, timeout);
117
                if (ret == -1)
118
                        break;
119
                else if (FD_ISSET(fd, &writefds)) {
120
                        ret = write(fd, message + offset, len - offset);
121
                        if (ret <= 0)
122
                                break;
123
                        offset += ret;
124
                } else
125
                        break;
126
        }
127

    
128
        if (offset != len) {
129
                EPRINTF("failure writing message\n");
130
                return -EIO;
131
        }
132

    
133
        return 0;
134
}
135

    
136
int
137
tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message,
138
                         struct timeval *timeout)
139
{
140
        int err;
141

    
142
        err = tap_ctl_write_message(sfd, message, timeout);
143
        if (err) {
144
                EPRINTF("failed to send '%s' message\n",
145
                        tapdisk_message_name(message->type));
146
                return err;
147
        }
148

    
149
        err = tap_ctl_read_message(sfd, message, timeout);
150
        if (err) {
151
                EPRINTF("failed to receive '%s' message\n",
152
                        tapdisk_message_name(message->type));
153
                return err;
154
        }
155

    
156
        return 0;
157
}
158

    
159
char *
160
tap_ctl_socket_name(int id)
161
{
162
        char *name;
163

    
164
        if (asprintf(&name, "%s/%s%d",
165
                     BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
166
                return NULL;
167

    
168
        return name;
169
}
170

    
171
int
172
tap_ctl_connect(const char *name, int *sfd)
173
{
174
        int fd, err;
175
        struct sockaddr_un saddr;
176

    
177
        *sfd = -1;
178

    
179
        fd = socket(AF_UNIX, SOCK_STREAM, 0);
180
        if (fd == -1) {
181
                EPRINTF("couldn't create socket for %s: %d\n", name, errno);
182
                return -errno;
183
        }
184

    
185
        memset(&saddr, 0, sizeof(saddr));
186
        saddr.sun_family = AF_UNIX;
187
        strcpy(saddr.sun_path, name);
188

    
189
        err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
190
        if (err) {
191
                EPRINTF("couldn't connect to %s: %d\n", name, errno);
192
                close(fd);
193
                return -errno;
194
        }
195

    
196
        *sfd = fd;
197
        return 0;
198
}
199

    
200
int
201
tap_ctl_connect_id(int id, int *sfd)
202
{
203
        int err;
204
        char *name;
205

    
206
        *sfd = -1;
207

    
208
        if (id < 0) {
209
                EPRINTF("invalid id %d\n", id);
210
                return -EINVAL;
211
        }
212

    
213
        name = tap_ctl_socket_name(id);
214
        if (!name) {
215
                EPRINTF("couldn't name socket for %d\n", id);
216
                return -ENOMEM;
217
        }
218

    
219
        err = tap_ctl_connect(name, sfd);
220

    
221
        free(name);
222

    
223
        return err;
224
}
225

    
226
int
227
tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message,
228
                                 struct timeval *timeout)
229
{
230
        int err, sfd;
231

    
232
        err = tap_ctl_connect_id(id, &sfd);
233
        if (err)
234
                return err;
235

    
236
        err = tap_ctl_send_and_receive(sfd, message, timeout);
237

    
238
        close(sfd);
239
        return err;
240
}