/* * This file is part of the Distributed Network Block Device 3 * * Copyright(c) 2011-2012 Johann Latocha * * This file may be licensed under the terms of of the * GNU General Public License Version 2 (the ``GPL''). * * Software distributed under the License is distributed * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either * express or implied. See the GPL for the specific language * governing rights and limitations. * * You should have received a copy of the GPL along with this * program. If not, go to http://www.gnu.org/licenses/gpl.html * or write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipc.h" #include "config.h" #include "server.h" #include "utils.h" void* dnbd3_ipc_receive() { GSList *iterator = NULL; struct tm * timeinfo; char time_buff[64]; dnbd3_ipc_t header; int server_sock, client_sock; struct timeval timeout; timeout.tv_sec = 2; timeout.tv_usec = 0; #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); } #else struct sockaddr_un server, client; unsigned int len = sizeof(client); // Create socket if ((server_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); unlink(UNIX_SOCKET); // Bind to socket if (bind(server_sock, &server, sizeof(server.sun_family) + strlen(server.sun_path)) < 0) { perror("ERROR: IPC bind"); exit(EXIT_FAILURE); } // Listen on socket if (listen(server_sock, 5) < 0) { perror("ERROR: IPC listen"); exit(EXIT_FAILURE); } // Set groupID and permissions on ipc socket struct group *grp; grp = getgrnam(UNIX_SOCKET_GROUP); if (grp == NULL) { printf("WARN: Group '%s' not found.\n", UNIX_SOCKET_GROUP); } else { chmod(UNIX_SOCKET, 0775); chown(UNIX_SOCKET, -1, grp->gr_gid); } #endif while (1) { int i = 0, size = 0; // 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: printf("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: printf("INFO: Reloading configuration...\n"); dnbd3_reload_config(_config_file_name); header.size = ntohl(0); header.error = ntohl(0); send(client_sock, (char *) &header, sizeof(header), MSG_WAITALL); close(client_sock); break; case IPC_INFO: pthread_spin_lock(&_spinlock); xmlDocPtr doc_info; xmlNodePtr root_node, images_node, clients_node, tmp_node; xmlChar *xmlbuff; int buffersize; doc_info = xmlNewDoc(BAD_CAST "1.0"); root_node = xmlNewNode(NULL, BAD_CAST "info"); xmlDocSetRootElement(doc_info, root_node); // Images images_node = xmlNewNode(NULL, BAD_CAST "images"); xmlAddChild(root_node, images_node); for (i = 0; i < _num_images; i++) { char vid[20], rid[20]; sprintf(vid,"%d",_images[i].vid); sprintf(rid,"%d",_images[i].rid); timeinfo = localtime(&_images[i].atime); strftime(time_buff,64,"%d.%m.%y %H:%M:%S",timeinfo); tmp_node = xmlNewNode(NULL, BAD_CAST "image"); xmlNewProp(tmp_node, BAD_CAST "group", BAD_CAST _images[i].group); xmlNewProp(tmp_node, BAD_CAST "atime", BAD_CAST time_buff); xmlNewProp(tmp_node, BAD_CAST "vid", BAD_CAST vid); xmlNewProp(tmp_node, BAD_CAST "rid", BAD_CAST rid); xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST _images[i].file); xmlNewProp(tmp_node, BAD_CAST "servers", BAD_CAST _images[i].serverss); xmlNewProp(tmp_node, BAD_CAST "cache", BAD_CAST _images[i].cache_file); xmlAddChild(images_node, tmp_node); } // Clients clients_node = xmlNewNode(NULL, BAD_CAST "clients"); 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"); xmlNewProp(tmp_node, BAD_CAST "ip", BAD_CAST client->ip); xmlNewProp(tmp_node, BAD_CAST "file", BAD_CAST client->image->file); xmlAddChild(clients_node, tmp_node); } } // Dump and send xmlDocDumpFormatMemory(doc_info, &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 pthread_spin_unlock(&_spinlock); close(client_sock); xmlFree(xmlbuff); xmlFreeDoc(doc_info); break; case IPC_CONFIG: pthread_spin_lock(&_spinlock); // Parse reply char* buf = malloc(header.size); size = recv(client_sock, buf, header.size, MSG_WAITALL); xmlDocPtr doc_config = xmlReadMemory(buf, size, "noname.xml", NULL, 0); if (doc_config) { // xmlDocDump(stdout, doc_config); xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; xmlChar* xpathExpr; xmlNodeSetPtr nodes; xmlNodePtr cur; xpathExpr = BAD_CAST "/info/images/image"; xpathCtx = xmlXPathNewContext(doc_config); xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); nodes = xpathObj->nodesetval; cur = nodes->nodeTab[0]; if(cur->type == XML_ELEMENT_NODE) { dnbd3_image_t image; image.group = (char *) xmlGetNoNsProp(cur, BAD_CAST "group"); image.vid = atoi((char *) xmlGetNoNsProp(cur, BAD_CAST "vid")); image.rid = atoi((char *) xmlGetNoNsProp(cur, BAD_CAST "rid")); image.file = (char *) xmlGetNoNsProp(cur, BAD_CAST "file"); image.serverss = (char *) xmlGetNoNsProp(cur, BAD_CAST "servers"); image.cache_file = (char *) xmlGetNoNsProp(cur, BAD_CAST "cache"); header.error = htonl(dnbd3_add_image(&image, _config_file_name)); } 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_config); xmlCleanupParser(); free(buf); break; default: printf("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); } void dnbd3_ipc_send(int cmd) { 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); } #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); } #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); if (cmd == IPC_INFO && header.size > 0) { char* buf = malloc(header.size); size = recv(client_sock, buf, header.size, MSG_WAITALL); xmlDocPtr doc = xmlReadMemory(buf, size, "noname.xml", NULL, 0); if (doc) { int n, i; xmlXPathContextPtr xpathCtx; xmlXPathObjectPtr xpathObj; xmlChar* xpathExpr; xmlNodeSetPtr nodes; xmlNodePtr cur; // Print images xpathExpr = BAD_CAST "/info/images/image"; xpathCtx = xmlXPathNewContext(doc); xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); printf("Exported images (atime, vid, rid, file):\n"); printf("========================================\n"); nodes = xpathObj->nodesetval; n = (nodes) ? nodes->nodeNr : 0; for(i = 0; i < n; ++i) { if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { cur = nodes->nodeTab[i]; xmlChar *atime = xmlGetNoNsProp(cur, BAD_CAST "atime"); xmlChar *vid = xmlGetNoNsProp(cur, BAD_CAST "vid"); xmlChar *rid = xmlGetNoNsProp(cur, BAD_CAST "rid"); xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file"); printf("%s\t%s\t%s\t%s\n", atime, vid, rid, file); } } printf("\nNumber images: %d\n\n", n); xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); // Print clients xpathExpr = BAD_CAST "/info/clients/client"; xpathCtx = xmlXPathNewContext(doc); xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); printf("Connected clients (ip, file):\n"); printf("=============================\n"); nodes = xpathObj->nodesetval; n = (nodes) ? nodes->nodeNr : 0; for(i = 0; i < n; ++i) { if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { cur = nodes->nodeTab[i]; xmlChar *ip = xmlGetNoNsProp(cur, BAD_CAST "ip"); xmlChar *file = xmlGetNoNsProp(cur, BAD_CAST "file"); printf("%s\t%s\n", ip, file); } } printf("\nNumber clients: %d\n\n", n); // Cleanup xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); xmlCleanupParser(); // xmlDocDump(stdout, doc); } else { printf("ERROR: Failed to parse reply\n"); } } close(client_sock); }