2 * virt-agent - common host/guest RPC functions
4 * Copyright IBM Corp. 2010
7 * Adam Litke <aglitke@linux.vnet.ibm.com>
8 * Michael Roth <mdroth@linux.vnet.ibm.com>
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
15 #include "virtagent-common.h"
25 typedef struct VARPCState
{
26 char hdr
[VA_HDR_LEN_MAX
];
38 enum va_rpc_type rpc_type
;
45 static void va_rpc_read_handler(void *opaque
);
46 static void va_rpc_send_handler(void *opaque
);
48 static int end_of_header(char *buf
, int end_pos
)
50 return !strncmp(buf
+(end_pos
-2), "\n\r\n", 3);
53 static void va_rpc_hdr_init(VARPCState
*s
) {
57 /* essentially ignored in the context of virtagent, but might as well */
58 if (s
->rpc_type
== VA_RPC_REQUEST
) {
59 preamble
= "POST /RPC2 HTTP/1.1";
60 } else if (s
->rpc_type
== VA_RPC_RESPONSE
) {
61 preamble
= "HTTP/1.1 200 OK";
67 s
->hdr_len
= sprintf(s
->hdr
,
69 "Content-Type: text/xml" EOL
70 "Content-Length: %u" EOL EOL
,
72 (uint32_t)s
->content_len
);
75 static void va_rpc_parse_hdr(VARPCState
*s
)
80 for (i
= 0; i
< VA_HDR_LEN_MAX
; ++i
) {
81 if (s
->hdr
[i
] != '\n') {
83 line_buf
[line_pos
++] = s
->hdr
[i
];
86 if (strncmp(line_buf
, "Content-Length: ", 16) == 0) {
87 s
->content_len
= atoi(&line_buf
[16]);
95 static VARPCState
*va_rpc_state_new(VARPCData
*data
, int fd
,
96 enum va_rpc_type rpc_type
, bool read
)
98 VARPCState
*s
= qemu_mallocz(sizeof(VARPCState
));
100 s
->rpc_type
= rpc_type
;
103 if (s
->data
== NULL
) {
108 s
->state
= VA_READ_START
;
111 s
->state
= VA_SEND_START
;
112 if (rpc_type
== VA_RPC_REQUEST
) {
113 s
->content
= XMLRPC_MEMBLOCK_CONTENTS(char, s
->data
->send_req_xml
);
114 s
->content_len
= XMLRPC_MEMBLOCK_SIZE(char, s
->data
->send_req_xml
);
115 } else if (rpc_type
== VA_RPC_RESPONSE
) {
116 s
->content
= XMLRPC_MEMBLOCK_CONTENTS(char, s
->data
->send_resp_xml
);
117 s
->content_len
= XMLRPC_MEMBLOCK_SIZE(char, s
->data
->send_resp_xml
);
119 LOG("unknown rcp type");
123 if (s
->hdr_len
== 0) {
124 LOG("failed to initialize http header");
135 /* called by va_rpc_read_handler after reading requests */
136 static int va_rpc_send_response(VARPCData
*data
, int fd
)
138 VARPCState
*s
= va_rpc_state_new(data
, fd
, VA_RPC_RESPONSE
, VA_SEND
);
142 LOG("failed to set up RPC state");
145 TRACE("setting up send handler for RPC request");
146 vp_set_fd_handler(fd
, NULL
, va_rpc_send_handler
, s
);
151 static void va_rpc_read_handler_completion(VARPCState
*s
) {
154 if (s
->rpc_type
== VA_RPC_REQUEST
) {
155 /* server read request, call it's cb function then set up
156 * a send handler for the rpc response if there weren't any
157 * communication errors
160 s
->data
->cb(s
->data
);
162 if (s
->data
->status
== VA_RPC_STATUS_OK
) {
163 ret
= va_rpc_send_response(s
->data
, s
->fd
);
165 LOG("error setting up send handler for rpc response");
168 LOG("error reading rpc request, skipping response");
169 vp_set_fd_handler(s
->fd
, NULL
, NULL
, NULL
);
173 } else if (s
->rpc_type
== VA_RPC_RESPONSE
) {
174 /* client read response, call it's cb function and complete
178 s
->data
->cb(s
->data
);
180 vp_set_fd_handler(s
->fd
, NULL
, NULL
, NULL
);
184 LOG("unknown rpc_type");
186 if (s
->content
!= NULL
) {
187 qemu_free(s
->content
);
192 static void va_rpc_read_handler(void *opaque
)
194 VARPCState
*s
= opaque
;
197 TRACE("called with opaque: %p", opaque
);
201 s
->state
= VA_READ_HDR
;
203 while((ret
= read(s
->fd
, s
->hdr
+ s
->hdr_pos
, 1)) > 0
204 && s
->hdr_pos
< VA_HDR_LEN_MAX
) {
206 if (end_of_header(s
->hdr
, s
->hdr_pos
- 1)) {
211 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
) {
214 LOG("error reading connection: %s", strerror(errno
));
217 } else if (ret
== 0) {
218 LOG("connected closed unexpectedly");
220 } else if (s
->hdr_pos
>= VA_HDR_LEN_MAX
) {
221 LOG("http header too long");
226 if (s
->content_len
== -1) {
227 LOG("malformed http header");
229 } else if (s
->content_len
> VA_CONTENT_LEN_MAX
) {
230 LOG("http content length too long");
233 s
->content
= qemu_mallocz(s
->content_len
);
234 s
->state
= VA_READ_BODY
;
237 while(s
->content_pos
< s
->content_len
) {
238 ret
= read(s
->fd
, s
->content
+ s
->content_pos
,
239 s
->content_len
- s
->content_pos
);
241 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
245 LOG("error reading connection: %s", strerror(errno
));
248 } else if (ret
== 0) {
249 LOG("connection closed unexpectedly:"
250 " read %u bytes, expected %u bytes",
251 (unsigned int)s
->content_pos
, (unsigned int)s
->content_len
);
254 s
->content_pos
+= ret
;
257 if (s
->rpc_type
== VA_RPC_REQUEST
) {
258 s
->data
->req_xml
= s
->content
;
259 s
->data
->req_xml_len
= s
->content_len
;
260 } else if (s
->rpc_type
== VA_RPC_RESPONSE
) {
261 s
->data
->resp_xml
= s
->content
;
262 s
->data
->resp_xml_len
= s
->content_len
;
264 s
->data
->status
= VA_RPC_STATUS_OK
;
267 LOG("unknown state");
272 s
->data
->status
= VA_RPC_STATUS_ERR
;
274 va_rpc_read_handler_completion(s
);
277 /* called by va_rpc_send_handler after sending requests */
278 static int va_rpc_read_response(VARPCData
*data
, int fd
)
280 VARPCState
*s
= va_rpc_state_new(data
, fd
, VA_RPC_RESPONSE
, VA_READ
);
284 LOG("failed to set up RPC state");
287 TRACE("setting up read handler for RPC response");
288 vp_set_fd_handler(fd
, NULL
, va_rpc_read_handler
, s
);
293 static void va_rpc_send_handler_completion(VARPCState
*s
) {
296 if (s
->rpc_type
== VA_RPC_REQUEST
) {
297 /* client sent request. free request's memblock, and set up read
298 * handler for server response if there weren't any communication
301 XMLRPC_MEMBLOCK_FREE(char, s
->data
->send_req_xml
);
302 if (s
->data
->status
== VA_RPC_STATUS_OK
) {
303 ret
= va_rpc_read_response(s
->data
, s
->fd
);
305 LOG("error setting up read handler for rpc response");
309 s
->data
->cb(s
->data
);
311 LOG("error sending rpc request, skipping response");
312 vp_set_fd_handler(s
->fd
, NULL
, NULL
, NULL
);
316 } else if (s
->rpc_type
== VA_RPC_RESPONSE
) {
317 /* server sent response. call it's cb once more, then free
318 * response's memblock and complete the RPC
321 s
->data
->cb(s
->data
);
323 XMLRPC_MEMBLOCK_FREE(char, s
->data
->send_resp_xml
);
324 vp_set_fd_handler(s
->fd
, NULL
, NULL
, NULL
);
328 LOG("unknown rpc_type");
333 static void va_rpc_send_handler(void *opaque
)
335 VARPCState
*s
= opaque
;
338 TRACE("called with opaque: %p", opaque
);
342 s
->state
= VA_SEND_HDR
;
345 ret
= write(s
->fd
, s
->hdr
+ s
->hdr_pos
, s
->hdr_len
- s
->hdr_pos
);
350 } while (s
->hdr_pos
< s
->hdr_len
);
352 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
) {
355 LOG("error reading connection: %s", strerror(errno
));
358 } else if (ret
== 0) {
359 LOG("connected closed unexpectedly");
362 s
->state
= VA_SEND_BODY
;
366 ret
= write(s
->fd
, s
->content
+ s
->content_pos
,
367 s
->content_len
- s
->content_pos
);
371 s
->content_pos
+= ret
;
372 } while (s
->content_pos
< s
->content_len
);
374 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
|| errno
== EINTR
) {
377 LOG("error reading connection: %s", strerror(errno
));
380 } else if (ret
== 0) {
381 LOG("connected closed unexpectedly");
384 s
->data
->status
= VA_RPC_STATUS_OK
;
388 LOG("unknown state");
393 s
->data
->status
= VA_RPC_STATUS_ERR
;
395 va_rpc_send_handler_completion(s
);
398 /* called by rpc client
399 * one callback to data->cb after response is read.
400 * data and data->send_req_xml should be allocated by caller,
401 * callee will de-allocate these after calling data->cb(data)
403 * if non-zero returned however, caller should free data and hanging refs
405 int va_rpc_send_request(VARPCData
*data
, int fd
)
407 VARPCState
*s
= va_rpc_state_new(data
, fd
, VA_RPC_REQUEST
, VA_SEND
);
411 LOG("failed to set up RPC state");
414 TRACE("setting up send handler for RPC request");
415 vp_set_fd_handler(fd
, NULL
, va_rpc_send_handler
, s
);
420 /* called by rpc server
421 * one callback to current data->cb after read, one callback after send.
422 * data should be allocated by caller, data->send_resp_xml should be
423 * allocated by first data->cb(data) callback, "callee" will de-allocate
424 * data and data->send_resp_xml after sending rpc response
426 * if non-zero returned however, caller should free data and hanging refs
428 int va_rpc_read_request(VARPCData
*data
, int fd
)
430 VARPCState
*s
= va_rpc_state_new(data
, fd
, VA_RPC_REQUEST
, VA_READ
);
434 LOG("failed to set up RPC state");
437 TRACE("setting up read handler for RPC request");
438 vp_set_fd_handler(fd
, va_rpc_read_handler
, NULL
, s
);