diff options
author | sr | 2012-08-30 00:36:54 +0200 |
---|---|---|
committer | sr | 2012-08-30 00:36:54 +0200 |
commit | 5b9b2174512d97399c68172bffe91cf928b1400a (patch) | |
tree | bf2cb9a7ae67cfe922fc7d2a6dcb432eaad4a2d9 /src/server/ipc.c | |
parent | Fix linebreak, add comment (diff) | |
download | dnbd3-5b9b2174512d97399c68172bffe91cf928b1400a.tar.gz dnbd3-5b9b2174512d97399c68172bffe91cf928b1400a.tar.xz dnbd3-5b9b2174512d97399c68172bffe91cf928b1400a.zip |
[SERVER] Set _FILE_OFFSET_BITS=64 so that images >4GiB will be handled properly on 32bit
[SERVER] Change IPC interface to be able to handle more than 1 request per connection
[SERVER] Change IPC interface to use select() so it can handle multiple connections at the same time
[SERVER] Re-Implement dnbd3_add_image() to work with image list
[SERVER] Add lots of sanity/safety checks and error messages when loading/adding an image
Diffstat (limited to 'src/server/ipc.c')
-rw-r--r-- | src/server/ipc.c | 843 |
1 files changed, 529 insertions, 314 deletions
diff --git a/src/server/ipc.c b/src/server/ipc.c index 98584a6..e7474e8 100644 --- a/src/server/ipc.c +++ b/src/server/ipc.c @@ -29,6 +29,8 @@ #include <pthread.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> #include <libxml/parser.h> #include <libxml/xpath.h> @@ -39,57 +41,76 @@ #include "utils.h" #include "memlog.h" -void* dnbd3_ipc_receive() -{ - GSList *iterator = NULL; +static int server_sock = -1; +static volatile int keep_running = 1; +static char *payload = NULL; - struct tm * timeinfo; - char time_buff[64], rid[20], ipaddr[100]; +static int ipc_receive(int client_sock); +static int get_highest_fd(GSList *sockets); +static int send_reply(int client_sock, void *data_in, int len); +static int recv_data(int client_sock, void *buffer_out, int len); - dnbd3_ipc_t header; - int server_sock, client_sock; +static int get_highest_fd(GSList *sockets) +{ + GSList *iterator; + int max = 0; - struct timeval timeout; - timeout.tv_sec = 2; - timeout.tv_usec = 0; + for (iterator = sockets; iterator; iterator = iterator->next) + { + const int fd = (int)(size_t)iterator->data; + if (fd > max) + max = fd; + } + return max; +} + +void *dnbd3_ipc_mainloop() +{ + payload = malloc(MAX_PAYLOAD); + if (payload == NULL) + { + memlogf("[CRITICAL] Couldn't allocate IPC payload buffer. IPC disabled."); + pthread_exit((void *)0); + return NULL; + } #ifdef IPC_TCP - struct sockaddr_in server, client; - unsigned int len = sizeof(client); - - // Create socket - if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - perror("ERROR: IPC socket"); - exit(EXIT_FAILURE); - } - - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; // IPv4 - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(IPC_PORT); // set port number - - int optval = 1; - setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); - - // Bind to socket - if (bind(server_sock, (struct sockaddr*) &server, sizeof(server)) < 0) - { - perror("ERROR: IPC bind"); - exit(EXIT_FAILURE); - } - - // Listen on socket - if (listen(server_sock, 5) < 0) - { - perror("ERROR: IPC listen"); - exit(EXIT_FAILURE); - } + struct sockaddr_in server, client; + socklen_t len = sizeof(client); + + // Create socket + if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + perror("ERROR: IPC socket"); + exit(EXIT_FAILURE); + } + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; // IPv4 + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(IPC_PORT); // set port number + + const int optval = 1; + setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + // Bind to socket + if (bind(server_sock, (struct sockaddr *)&server, sizeof(server)) < 0) + { + perror("ERROR: IPC bind"); + exit(EXIT_FAILURE); + } + + // Listen on socket + if (listen(server_sock, 5) < 0) + { + perror("ERROR: IPC listen"); + exit(EXIT_FAILURE); + } #else - struct sockaddr_un server, client; - unsigned int len = sizeof(client); + struct sockaddr_un server, client; + socklen_t len = sizeof(client); - // Create socket + // Create socket if ((server_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { perror("ERROR: IPC socket"); @@ -128,288 +149,481 @@ void* dnbd3_ipc_receive() } #endif - while (1) - { - int size; - char* buf; - xmlDocPtr doc; - xmlNodePtr root_node, images_node, clients_node, tmp_node, log_parent_node, log_node; - xmlChar *xmlbuff; - int buffersize; - - // Accept connection - if ((client_sock = accept(server_sock, &client, &len)) < 0) - { - perror("ERROR: IPC accept"); - exit(EXIT_FAILURE); - } - - setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)); - setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)); - - recv(client_sock, &header, sizeof(header), MSG_WAITALL); - header.cmd = ntohl(header.cmd); - header.size = ntohl(header.size); - header.error = ntohl(header.error); - - switch (header.cmd) - { - case IPC_EXIT: - memlogf("INFO: Server shutdown...\n"); - header.size = ntohl(0); - header.error = ntohl(0); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - close(client_sock); - close(server_sock); - dnbd3_cleanup(); - break; - - case IPC_RELOAD: - header.size = ntohl(0); - header.error = ntohl(ERROR_UNKNOWN); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - close(client_sock); - break; - - case IPC_INFO: - doc = xmlNewDoc(BAD_CAST "1.0"); - root_node = xmlNewNode(NULL, BAD_CAST "info"); - xmlDocSetRootElement(doc, root_node); - - // Images - images_node = xmlNewNode(NULL, BAD_CAST "images"); - xmlAddChild(root_node, images_node); - pthread_spin_lock(&_spinlock); - for (iterator = _dnbd3_images; iterator; iterator = iterator->next) - { - const dnbd3_image_t *image = iterator->data; - sprintf(rid,"%d",image->rid); - timeinfo = localtime(&image->atime); - strftime(time_buff,64,"%d.%m.%y %H:%M:%S",timeinfo); - tmp_node = xmlNewNode(NULL, BAD_CAST "image"); - xmlNewProp(tmp_node, BAD_CAST "name", BAD_CAST image->name); - xmlNewProp(tmp_node, BAD_CAST "atime", BAD_CAST time_buff); - xmlNewProp(tmp_node, BAD_CAST "rid", BAD_CAST rid); - xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST image->file); - xmlNewProp(tmp_node, BAD_CAST "servers", BAD_CAST "???"); - xmlNewProp(tmp_node, BAD_CAST "cache", BAD_CAST image->cache_file); - xmlAddChild(images_node, tmp_node); + // Run connection-accepting loop + + fd_set all_sockets, readset, exceptset; + + GSList *sockets = NULL, *iterator; + + int client_sock, ret, flags; + int maxfd = server_sock + 1; + int error_count = 0; + + struct timeval client_timeout, select_timeout; + client_timeout.tv_sec = 0; + client_timeout.tv_usec = 500 * 1000; + + FD_ZERO(&all_sockets); + FD_SET(server_sock, &all_sockets); + + // Make listening socket non-blocking + flags = fcntl(server_sock, F_GETFL, 0); + if (flags == -1) + flags = 0; + fcntl(server_sock, F_SETFL, flags | O_NONBLOCK); + + xmlInitParser(); + + while (keep_running) + { + readset = exceptset = all_sockets; + select_timeout.tv_sec = 4; + select_timeout.tv_usec = 0; + ret = select(maxfd, &readset, NULL, &exceptset, &select_timeout); + while (ret > 0) + { + --ret; + if (FD_ISSET(server_sock, &readset)) + { + // Accept connection + if ((client_sock = accept(server_sock, &client, &len)) < 0) + { + if (errno != EAGAIN) + { + memlogf("[ERROR] Error accepting an IPC connection"); + if (++error_count > 10) + goto end_loop; + } + continue; + } + error_count = 0; + // Apply read/write timeout + setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &client_timeout, sizeof(client_timeout)); + setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &client_timeout, sizeof(client_timeout)); + // Make new connection blocking + flags = fcntl(client_sock, F_GETFL, 0); + if (flags == -1) + flags = 0; + fcntl(client_sock, F_SETFL, flags & ~(int)O_NONBLOCK); + sockets = g_slist_prepend(sockets, (void *)(size_t)client_sock); + if (client_sock >= maxfd) + maxfd = client_sock + 1; + FD_SET(client_sock, &all_sockets); } - // Clients - clients_node = xmlNewNode(NULL, BAD_CAST "clients"); - log_node = xmlAddChild(root_node, clients_node); - for (iterator = _dnbd3_clients; iterator; iterator = iterator->next) + else if (FD_ISSET(server_sock, &exceptset)) { - dnbd3_client_t *client = iterator->data; - if (client->image) + memlogf("[ERROR] An exception occurred on the IPC listening socket."); + if (++error_count > 10) + goto end_loop; + } + else + { + // Must be an active IPC connection + int del = -1; + for (iterator = sockets; iterator; iterator = iterator->next) + { + if (del != -1) + { + // Delete a previously closed connection from list (delayed, otherwise list might get messed up) + sockets = g_slist_remove(sockets, (void *)(size_t)del); + del = -1; + maxfd = get_highest_fd(sockets) + 1; + } + client_sock = (int)(size_t)iterator->data; + if (FD_ISSET(client_sock, &readset)) + { + // Client sending data + if (!ipc_receive(client_sock)) + { + // Connection has been closed + close(client_sock); + del = client_sock; + FD_CLR(client_sock, &all_sockets); + } + } + else if (FD_ISSET(client_sock, &exceptset)) + { + // Something unexpected happened, just close connection + close(client_sock); + del = client_sock; + FD_CLR(client_sock, &all_sockets); + } + } + if (del != -1) { - tmp_node = xmlNewNode(NULL, BAD_CAST "client"); - *ipaddr = '\0'; - inet_ntop(client->addrtype, client->ipaddr, ipaddr, 100); - xmlNewProp(tmp_node, BAD_CAST "ip", BAD_CAST ipaddr); - xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST client->image->file); - xmlAddChild(clients_node, tmp_node); + // In case last socket was closed during iteration + sockets = g_slist_remove(sockets, (void *)(size_t)del); + maxfd = get_highest_fd(sockets) + 1; } } + } // End select loop + } // End mainloop + +end_loop: + memlogf("[INFO] Shutting down IPC interface."); + if (server_sock != -1) + { + close(server_sock); + server_sock = -1; + } + + free(payload); + xmlCleanupParser(); + pthread_exit((void *)0); + return NULL; +} + +void dnbd3_ipc_shutdown() +{ + keep_running = 0; + if (server_sock == -1) + return; + close(server_sock); + server_sock = -1; +} + +/** + * Send message to client, return !=0 on success, 0 on failure + */ +static int send_reply(int client_sock, void *data_in, int len) +{ + if (len <= 0) // Nothing to send + return 1; + char *data = data_in; // Needed for pointer arithmetic + int ret, i; + for (i = 0; i < 3; ++i) // Retry at most 3 times, each try takes at most 0.5 seconds (socket timeout) + { + ret = send(client_sock, data, len, 0); + if (ret == 0) // Connection closed + return 0; + if (ret < 0) + { + if (errno != EAGAIN) // Some unexpected error + return 0; + usleep(1000); // 1ms + continue; + } + len -= ret; + if (len <= 0) // Sent everything + return 1; + data += ret; // move target buffer pointer + } + return 0; +} + +/** + * Receive data from client, return !=0 on success, 0 on failure + */ +static int recv_data(int client_sock, void *buffer_out, int len) +{ + if (len <= 0) // Nothing to receive + return 1; + char *data = buffer_out; // Needed for pointer arithmetic + int ret, i; + for (i = 0; i < 3; ++i) // Retry at most 3 times, each try takes at most 0.5 seconds (socket timeout) + { + ret = recv(client_sock, data, len, MSG_WAITALL); + if (ret == 0) // Connection closed + return 0; + if (ret < 0) + { + if (errno != EAGAIN) // Some unexpected error + return 0; + usleep(1000); // 1ms + continue; + } + len -= ret; + if (len <= 0) // Received everything + return 1; + data += ret; // move target buffer pointer + } + return 0; +} + +/** + * Returns !=0 if send/recv successful, 0 on any kind of network failure + */ +static int ipc_receive(int client_sock) +{ + GSList *iterator = NULL; + + struct tm *timeinfo; + char time_buff[64], rid[20], ipaddr[100]; + + dnbd3_ipc_t header; + + uint32_t cmd; + + int ret, locked; + int return_value = 0; + xmlDocPtr doc = NULL; + xmlNodePtr root_node, images_node, clients_node, tmp_node, log_parent_node, log_node; + xmlChar *xmlbuff; + int buffersize; + + ret = recv(client_sock, &header, sizeof(header), MSG_WAITALL); + if (ret != sizeof(header)) + return ((ret < 0 && errno == EAGAIN) ? 1 : 0); + cmd = ntohl(header.cmd); // Leave header.cmd in network byte order for reply + header.size = ntohl(header.size); + + header.error = htonl(ERROR_UNSPECIFIED_ERROR); // Default value of error, so remember to set it for the reply if call succeeded + + if (header.size != 0) + { + // Message has payload, receive it + if (header.size > MAX_PAYLOAD) + { + memlogf("[WARNING] IPC command with payload of %u bytes ignored.", (unsigned int)header.size); + return 0; + } + if (!recv_data(client_sock, payload, header.size)) + return 0; + } + + switch (cmd) + { + case IPC_EXIT: + memlogf("[INFO] Server shutdown by IPC request"); + header.size = ntohl(0); + header.error = ntohl(0); + return_value = send_reply(client_sock, &header, sizeof(header)); + dnbd3_cleanup(); + break; + + case IPC_INFO: + locked = 0; + xmlbuff = NULL; + doc = xmlNewDoc(BAD_CAST "1.0"); + if (doc == NULL) + goto get_info_reply_cleanup; + root_node = xmlNewNode(NULL, BAD_CAST "info"); + if (root_node == NULL) + goto get_info_reply_cleanup; + xmlDocSetRootElement(doc, root_node); + + // Images + images_node = xmlNewNode(NULL, BAD_CAST "images"); + if (images_node == NULL) + goto get_info_reply_cleanup; + xmlAddChild(root_node, images_node); + locked = 1; + pthread_spin_lock(&_spinlock); + for (iterator = _dnbd3_images; iterator; iterator = iterator->next) + { + const dnbd3_image_t *image = iterator->data; + sprintf(rid, "%d", image->rid); + timeinfo = localtime(&image->atime); + strftime(time_buff, 64, "%d.%m.%y %H:%M:%S", timeinfo); + tmp_node = xmlNewNode(NULL, BAD_CAST "image"); + if (tmp_node == NULL) + goto get_info_reply_cleanup; + xmlNewProp(tmp_node, BAD_CAST "name", BAD_CAST image->name); + xmlNewProp(tmp_node, BAD_CAST "atime", BAD_CAST time_buff); + xmlNewProp(tmp_node, BAD_CAST "rid", BAD_CAST rid); + xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST image->file); + xmlNewProp(tmp_node, BAD_CAST "servers", BAD_CAST "???"); + xmlNewProp(tmp_node, BAD_CAST "cache", BAD_CAST image->cache_file); + xmlAddChild(images_node, tmp_node); + } + // Clients + clients_node = xmlNewNode(NULL, BAD_CAST "clients"); + if (clients_node == NULL) + goto get_info_reply_cleanup; + xmlAddChild(root_node, clients_node); + for (iterator = _dnbd3_clients; iterator; iterator = iterator->next) + { + dnbd3_client_t *client = iterator->data; + if (client->image) + { + tmp_node = xmlNewNode(NULL, BAD_CAST "client"); + if (tmp_node == NULL) + goto get_info_reply_cleanup; + *ipaddr = '\0'; + inet_ntop(client->addrtype, client->ipaddr, ipaddr, 100); + xmlNewProp(tmp_node, BAD_CAST "ip", BAD_CAST ipaddr); + xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST client->image->file); + xmlAddChild(clients_node, tmp_node); + } + } + pthread_spin_unlock(&_spinlock); + locked = 0; + + // Log + log_parent_node = xmlNewChild(root_node, NULL, BAD_CAST "log", NULL); + if (log_parent_node == NULL) + goto get_info_reply_cleanup; + char *log = fetchlog(0); + if (log == NULL) + log = "LOG IS NULL"; + log_node = xmlNewCDataBlock(doc, BAD_CAST log, strlen(log)); + if (log_node == NULL) + goto get_info_reply_cleanup; + xmlAddChild(log_parent_node, log_node); + + // Dump and send + xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); + header.size = htonl(buffersize); + header.error = htonl(0); + +get_info_reply_cleanup: + if (locked) pthread_spin_unlock(&_spinlock); + // Send reply + return_value = send_reply(client_sock, &header, sizeof(header)); + if (return_value && xmlbuff) + return_value = send_reply(client_sock, xmlbuff, buffersize); + // Cleanup + xmlFree(xmlbuff); + xmlFreeDoc(doc); + free(log); + break; + + case IPC_ADDIMG: + case IPC_DELIMG: + if (header.size == 0) + { + header.size = htonl(0); + header.error = htonl(ERROR_MISSING_ARGUMENT); + return_value = send_reply(client_sock, &header, sizeof(header)); + break; + } + doc = xmlReadMemory(payload, header.size, "noname.xml", NULL, 0); - // Log - log_parent_node = xmlNewChild(root_node, NULL, BAD_CAST "log", NULL); - char *log = fetchlog(0); - if (log == NULL) log = "LOG IS NULL"; - log_node = xmlNewCDataBlock(doc, BAD_CAST log, strlen(log)); - xmlAddChild(log_parent_node, log_node); - - // Dump and send - xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); - header.size = htonl(buffersize); - header.error = htonl(0); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - send(client_sock, (char *) xmlbuff, buffersize, MSG_WAITALL); - - // Cleanup - close(client_sock); - xmlFree(xmlbuff); - xmlFreeDoc(doc); - free(log); - break; - - case IPC_ADDIMG: - pthread_spin_lock(&_spinlock); - - // Parse reply - buf = malloc(header.size); - size = recv(client_sock, buf, header.size, MSG_WAITALL); - doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0); - - if (doc) - { -// xmlDocDump(stdout, doc_config); - - xmlXPathContextPtr xpathCtx; - xmlXPathObjectPtr xpathObj; - xmlChar* xpathExpr; - xmlNodeSetPtr nodes; - xmlNodePtr cur; - - xpathExpr = BAD_CAST "/info/images/image"; - xpathCtx = xmlXPathNewContext(doc); - xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); - - nodes = xpathObj->nodesetval; - cur = nodes->nodeTab[0]; - if(cur->type == XML_ELEMENT_NODE) - { - dnbd3_image_t image; - memset(&image, 0, sizeof(dnbd3_image_t)); - image.name = (char *) xmlGetNoNsProp(cur, BAD_CAST "name"); - image.rid = atoi((char *) xmlGetNoNsProp(cur, BAD_CAST "rid")); - image.file = (char *) xmlGetNoNsProp(cur, BAD_CAST "file"); - image.cache_file = (char *) xmlGetNoNsProp(cur, BAD_CAST "cache"); - header.error = htonl(dnbd3_add_image(&image, _config_file_name)); - } + if (doc) + { + xmlXPathContextPtr xpathCtx = NULL; + xmlXPathObjectPtr xpathObj = NULL; + xmlNodeSetPtr nodes = NULL; + xmlNodePtr cur = NULL; - xmlXPathFreeObject(xpathObj); - xmlXPathFreeContext(xpathCtx); - } - - header.size = htonl(0); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - - // Cleanup - pthread_spin_unlock(&_spinlock); - close(client_sock); - xmlFreeDoc(doc); - xmlCleanupParser(); - free(buf); - break; - - case IPC_DELIMG: - pthread_spin_lock(&_spinlock); - - // Parse reply - buf = malloc(header.size); - size = recv(client_sock, buf, header.size, MSG_WAITALL); - doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0); - - if (doc) - { -// xmlDocDump(stdout, doc_config); - - xmlXPathContextPtr xpathCtx; - xmlXPathObjectPtr xpathObj; - xmlChar* xpathExpr; - xmlNodeSetPtr nodes; - xmlNodePtr cur; - - xpathExpr = BAD_CAST "/info/images/image"; - xpathCtx = xmlXPathNewContext(doc); - xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); - - nodes = xpathObj->nodesetval; - cur = nodes->nodeTab[0]; - if(cur->type == XML_ELEMENT_NODE) + xpathCtx = xmlXPathNewContext(doc); + if (xpathCtx == NULL) + goto add_del_cleanup; + xpathObj = xmlXPathEvalExpression(BAD_CAST "/info/images/image", xpathCtx); + if (xpathObj == NULL) + goto add_del_cleanup; + nodes = xpathObj->nodesetval; + if (nodes == NULL || nodes->nodeNr < 1) + goto add_del_cleanup; + cur = nodes->nodeTab[0]; + if (cur->type == XML_ELEMENT_NODE) + { + dnbd3_image_t image; + memset(&image, 0, sizeof(dnbd3_image_t)); + image.name = (char *)xmlGetNoNsProp(cur, BAD_CAST "name"); + char *rid_str = (char *)xmlGetNoNsProp(cur, BAD_CAST "rid"); + image.file = (char *)xmlGetNoNsProp(cur, BAD_CAST "file"); + image.cache_file = (char *)xmlGetNoNsProp(cur, BAD_CAST "cache"); + if (image.name && rid_str && image.file && image.cache_file) { - dnbd3_image_t image; - memset(&image, 0, sizeof(dnbd3_image_t)); - image.name = (char *) xmlGetNoNsProp(cur, BAD_CAST "name"); - image.rid = atoi((char *) xmlGetNoNsProp(cur, BAD_CAST "rid")); - image.file = (char *) xmlGetNoNsProp(cur, BAD_CAST "file"); - image.cache_file = (char *) xmlGetNoNsProp(cur, BAD_CAST "cache"); - header.error = htonl(dnbd3_del_image(&image, _config_file_name)); + image.rid = atoi(rid_str); + if (cmd == IPC_ADDIMG) + header.error = htonl(dnbd3_add_image(&image, _config_file_name)); + else + header.error = htonl(dnbd3_del_image(&image, _config_file_name)); } + else + header.error = htonl(ERROR_MISSING_ARGUMENT); + xmlFree(image.name); + xmlFree(rid_str); + xmlFree(image.file); + xmlFree(image.cache_file); + } + else + header.error = htonl(ERROR_MISSING_ARGUMENT); - xmlXPathFreeObject(xpathObj); - xmlXPathFreeContext(xpathCtx); - } - - header.size = htonl(0); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - - // Cleanup - pthread_spin_unlock(&_spinlock); - close(client_sock); - xmlFreeDoc(doc); - xmlCleanupParser(); - free(buf); - break; - - default: - memlogf("ERROR: Unknown command: %i\n", header.cmd); - header.size = htonl(0); - header.error = htonl(ERROR_UNKNOWN); - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - close(client_sock); - break; - - } - } - close(server_sock); - pthread_exit((void *) 0); +add_del_cleanup: + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + xmlFreeDoc(doc); + } + else + header.error = htonl(ERROR_INVALID_XML); + + header.size = htonl(0); + return_value = send_reply(client_sock, &header, sizeof(header)); + break; + + default: + memlogf("[ERROR] Unknown IPC command: %u", (unsigned int)header.cmd); + header.size = htonl(0); + header.error = htonl(ERROR_UNKNOWN_COMMAND); + return_value = send_reply(client_sock, &header, sizeof(header)); + break; + + } + return return_value; } void dnbd3_ipc_send(int cmd) { - int client_sock, size; + int client_sock, size; #ifdef IPC_TCP - struct sockaddr_in server; - - // Create socket - if ((client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - perror("ERROR: IPC socket"); - exit(EXIT_FAILURE); - } - - memset(&server, 0, sizeof(server)); - server.sin_family = AF_INET; // IPv4 - server.sin_addr.s_addr = inet_addr("127.0.0.1"); - server.sin_port = htons(IPC_PORT); // set port number - - // Connect to server - if (connect(client_sock, (struct sockaddr *) &server, sizeof(server)) < 0) - { - perror("ERROR: IPC connect"); - exit(EXIT_FAILURE); - } + struct sockaddr_in server; + struct timeval client_timeout; + + // Create socket + if ((client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + perror("ERROR: IPC socket"); + exit(EXIT_FAILURE); + } + + client_timeout.tv_sec = 4; + client_timeout.tv_usec = 0; + setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &client_timeout, sizeof(client_timeout)); + setsockopt(client_sock, SOL_SOCKET, SO_SNDTIMEO, &client_timeout, sizeof(client_timeout)); + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; // IPv4 + server.sin_addr.s_addr = inet_addr("127.0.0.1"); + server.sin_port = htons(IPC_PORT); // set port number + + // Connect to server + if (connect(client_sock, (struct sockaddr *)&server, sizeof(server)) < 0) + { + perror("ERROR: IPC connect"); + exit(EXIT_FAILURE); + } #else - struct sockaddr_un server; - - // Create socket - if ((client_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - { - perror("ERROR: IPC socket"); - exit(EXIT_FAILURE); - } - server.sun_family = AF_UNIX; - strcpy(server.sun_path, UNIX_SOCKET); - - // Connect to server - if (connect(client_sock, &server, sizeof(server.sun_family) + strlen(server.sun_path)) < 0) - { - perror("ERROR: IPC connect"); - exit(EXIT_FAILURE); - } + struct sockaddr_un server; + + // Create socket + if ((client_sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: IPC socket"); + exit(EXIT_FAILURE); + } + server.sun_family = AF_UNIX; + strcpy(server.sun_path, UNIX_SOCKET); + + // Connect to server + if (connect(client_sock, &server, sizeof(server.sun_family) + strlen(server.sun_path)) < 0) + { + perror("ERROR: IPC connect"); + exit(EXIT_FAILURE); + } #endif - // Send message - dnbd3_ipc_t header; - header.cmd = htonl(cmd); - header.size = 0; - header.error = 0; - send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); - recv(client_sock, &header, sizeof(header), MSG_WAITALL); - header.cmd = ntohl(header.cmd); - header.size = ntohl(header.size); - header.error = ntohl(header.error); - - if (cmd == IPC_INFO && header.size > 0) - { - char* buf = malloc(header.size+1); - size = recv(client_sock, buf, header.size, MSG_WAITALL); - xmlDocPtr doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0); - buf[header.size] = 0; + // Send message + dnbd3_ipc_t header; + header.cmd = htonl(cmd); + header.size = 0; + header.error = 0; + send(client_sock, (char *)&header, sizeof(header), MSG_WAITALL); + recv(client_sock, &header, sizeof(header), MSG_WAITALL); + header.cmd = ntohl(header.cmd); + header.size = ntohl(header.size); + header.error = ntohl(header.error); + + if (cmd == IPC_INFO && header.size > 0) + { + char *buf = malloc(header.size + 1); + size = recv(client_sock, buf, header.size, MSG_WAITALL); + xmlDocPtr doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0); + buf[header.size] = 0; if (doc) { @@ -417,7 +631,7 @@ void dnbd3_ipc_send(int cmd) xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; - xmlChar* xpathExpr; + xmlChar *xpathExpr; xmlNodeSetPtr nodes; xmlNodePtr cur; @@ -425,7 +639,8 @@ void dnbd3_ipc_send(int cmd) xpathExpr = BAD_CAST "/info/log"; xpathCtx = xmlXPathNewContext(doc); xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); - if (xpathObj->nodesetval && xpathObj->nodesetval->nodeTab && xpathObj->nodesetval->nodeTab[0]) { + if (xpathObj->nodesetval && xpathObj->nodesetval->nodeTab && xpathObj->nodesetval->nodeTab[0]) + { printf("--- Last log lines ----\n%s\n\n", xmlNodeGetContent(xpathObj->nodesetval->nodeTab[0])); } xmlXPathFreeObject(xpathObj); @@ -439,9 +654,9 @@ void dnbd3_ipc_send(int cmd) printf("========================================\n"); nodes = xpathObj->nodesetval; n = (nodes) ? nodes->nodeNr : 0; - for(i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) + if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { cur = nodes->nodeTab[i]; xmlChar *atime = xmlGetNoNsProp(cur, BAD_CAST "atime"); @@ -463,9 +678,9 @@ void dnbd3_ipc_send(int cmd) printf("=============================\n"); nodes = xpathObj->nodesetval; n = (nodes) ? nodes->nodeNr : 0; - for(i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) + if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { cur = nodes->nodeTab[i]; xmlChar *ip = xmlGetNoNsProp(cur, BAD_CAST "ip"); @@ -489,7 +704,7 @@ void dnbd3_ipc_send(int cmd) printf("ERROR: Failed to parse reply\n-----------\n%s\n-------------\n", buf); } - } + } - close(client_sock); + close(client_sock); } |