summaryrefslogblamecommitdiffstats
path: root/src/worker/main.cpp
blob: ff9704168fa3949145460fcfd68b421f2dd51d87 (plain) (tree)





































































































































































                                                                                
/*
 # Copyright (c) 2011 - OpenSLX Project, Computer Center University of Freiburg
 #
 # This program is free software distributed under the GPL version 2.
 # See http://gpl.openslx.org/
 #
 # If you have any feedback please consult http://feedback.openslx.org/ and
 # send your suggestions, praise, or complaints to feedback@openslx.org
 #
 # General information about OpenSLX can be found at http://openslx.org/
 */

#include <map>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <libgearman/gearman.h>

#include "../version.h"

using namespace std;

int _nbd_server_port;
map<string, int> _map; // map running nbd-servers: <exported image, port number>

static void *start_nbd_server(gearman_job_st *job, void *context,
        size_t *result_size, gearman_return_t *ret_ptr)
{
    cout << "[DEBUG] Received request from " << gearman_job_handle(job) << endl;

    if (gearman_job_workload_size(job) <= 0)
    {
        cerr << "[ERROR] No image given, aborting!" << endl;
        return NULL;
    }

    // prepare data
    char* req = (char*) gearman_job_workload(job);
    size_t req_size = gearman_job_workload_size(job);
    string *image = new string(req, req_size);
    int current_port = 0;
    cout << "[DEBUG] Requested image: " << *image << endl;

    // test if requested image exists
    int test = access(image->c_str(), 0);
    if (test != 0)
    {
        cerr << "[ERROR] Requested image not found, aborting!" << endl;
        char msg[] = "Requested image not found";
        gearman_job_send_data(job, msg, sizeof(msg));
        *ret_ptr = GEARMAN_WORK_FAIL;
        return NULL;
    }

    if (_map[*image] != 0)
    {
        // nbd-server already running
        cout << "[DEBUG] Requested nbd-server is already running on port "
                << _map[*image] << endl;
        current_port = _map[*image];
    }
    else
    {
        // start new nbd-server
        cout << "[DEBUG] Starting new nbd-server on port " << _nbd_server_port
                << endl;

        stringstream command;
        command << "nbd-server " << _nbd_server_port << " " << *image;
        cout << "[DEBUG] " << "Running command: " << command.str() << endl;
        system(command.str().c_str());

        current_port = _nbd_server_port;
        _map[*image] = _nbd_server_port;
        _nbd_server_port++;
    }

    // send port number to client
    cout << "[DEBUG] " << "Response with port number " << current_port << endl;
    char buf[32];
    snprintf(buf, sizeof(buf), "%d", current_port);
    gearman_job_send_data(job, buf, strlen(buf));

    *ret_ptr = GEARMAN_SUCCESS;
    return NULL;
}

static void usage(char *name)
{
    printf("usage: %s [-p] [-d] [-v]\n", name);
    printf("\t-p\t first port number for nbd-servers (default: 5001)\n");
    printf("\t-d\t start as daemon\n");
    printf("\t-v\t print version and exit\n");
}

int main(int argc, char* argv[])
{
    gearman_return_t result;
    gearman_worker_st worker;
    _nbd_server_port = 5001;
    bool as_daemon = false;

    // parse command line arguments
    int c;
    while ((c = getopt(argc, argv, "p:dv")) != -1)
    {
        switch (c)
        {
        case 'p':
            _nbd_server_port = atoi(optarg);
            break;
        case 'd':
            as_daemon = true;
            break;
        case 'v':
            printf("Version: %s\n", VERSION_STRING);
            exit(0);
        default:
            usage(argv[0]);
            exit(1);
        }
    }

    // initialize gearman worker
    if (gearman_worker_create(&worker) == NULL)
    {
        cerr << "[ERROR] Memory allocation failure on worker creation" << endl;
        exit(1);
    }
    result = gearman_worker_add_server(&worker, "127.0.0.1", 0);
    if (result != GEARMAN_SUCCESS)
    {
        cerr << "[ERROR] " << gearman_worker_error(&worker) << endl;
        exit(1);
    }
    result = gearman_worker_add_function(&worker, "start_nbd_server", 0,
            start_nbd_server, NULL);
    if (result != GEARMAN_SUCCESS)
    {
        cerr << "[ERROR] " << gearman_worker_error(&worker) << endl;
        exit(1);
    }
    cout << "[DEBUG] Worker is ready." << endl;
    if (as_daemon)
    {
        cout << "[DEBUG] Daemonize..." << endl;
        daemon(0, 0);
    }

    // main loop
    while (1)
    {
        result = gearman_worker_work(&worker);
        if (result != GEARMAN_SUCCESS)
        {
            cerr << "[ERROR] " << gearman_worker_error(&worker) << endl;
            break;
        }
    }

    // cleanup
    gearman_worker_free(&worker);
    cout << "[DEBUG] Worker has been freed." << endl;
}