summaryrefslogblamecommitdiffstats
path: root/src/server/ipc.c
blob: 3398615d86c23924e1527d7d86b279af2fcad21f (plain) (tree)























                                                               

                     


                    
                       
                      
 


                          






                         

                            


                         
                       

                                 



                           



                                      
                    
                                                                      




                                    



                                                         
 


                                                                               
                     
                                                                          










                                    


                                      
 





































                                                                                                
 

             
                            







                                                                   


                                                                                             



                                                                
 
                           

                      
                                                     


                                                                                 
                                   





                                                         
                                                   


                                                                             
                               


                      
                                          
 
                               



                                                                      
                                                 
                                                          
                                                      











                                                                                    
                                                                                                  



                                                                                                
                                                                                                       
                                                                                                       
















                                                                                                            
 
                                        
                                                                       


                                                                             


                                                                         
                                            
                               
                             
                                 

                  

                                              
 



                                                                                       
 
                               
                 
                                                       






                                                            
                                                                          












                                                                                                          
                                                                                                          
                                                                                                         





                                                              


                                                                                 


                                                

                                       
                          

                      
                



                                                                             
                               


                  
     




                            
                          
 























                                                                              





                                                            








                                                                                               
      
 
                   







                                                                     
     


                                                                        
 
                        
                 








                                                    
                                                                  







                                                                               








                                                                                               





                                                             
                                                                    







                                                                               






                                                                                             








                                                              
                                                

                      



                                                                 
     
 

                       
/*
 * This file is part of the Distributed Network Block Device 3
 *
 * Copyright(c) 2011-2012 Johann Latocha <johann@latocha.de>
 *
 * 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 <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <sys/stat.h>
#include <grp.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <libxml/parser.h>
#include <libxml/xpath.h>

#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);
}