mbohun
9/3/2012 - 5:02 AM

test_ldap_threads-synchronous.cpp

test_ldap_threads-synchronous.cpp

#ifdef _WIN32
#include <windows.h>
#endif //WIN32

#include <iostream>
#include <sstream>

#include <stdio.h>
#include <time.h>
#include <ctype.h>

#define LDAP_DEPRECATED 1 //AAA needs this
#include <ldap.h>
#include <lber.h> //for LDAP_CALL LDAP_CALLBACK (only mozilla SDK?)

#define TEST_LDAP_HOST "192.168.1.179"
#define TEST_LDAP_PORT LDAP_PORT //default 389

#define TEST_LDAP_BASE_DN "dc=aaa,dc=test,dc=mbohun"
#define TEST_LDAP_USER_DN "cn=Administrator,cn=Users,dc=aaa,dc=test,dc=mbohun"
#define TEST_LDAP_USER_PASSWORD "abcABC666"

#define TEST_LDAP_FILTER "(sAMAccountName=tim)"

#define TEST_LDAP_TCP_TIMEOUT 12 //seconds

#define TEST_LDAP_REFERRAL_FILTER "ldap://ref.aaa.test.mbohun/DC=ref,DC=aaa,DC=test,DC=mbohun"

int dummy = 0;

/*
  suggestions:
  * add referrals filter (easy) (a set of referral URL to follow, ignore rest)

*/

//simple filter for now, of course this is just a concept, we will have a proper set of URLs
static int is_valid_referral_url(const char* url) {
        return (0 == strncmp(TEST_LDAP_REFERRAL_FILTER, url, sizeof(TEST_LDAP_REFERRAL_FILTER)));
}

static int rebind_callback (LDAP* h,
                                    const char* url,
                                    ber_tag_t req,
                                    ber_int_t msgid,
                                    void *args) { //use args instead of global vars!!!
/*
        //check referral url against filter
        if (!is_valid_referral_url(url)) {
                std::cout << "rebind_callback, skipping:" << url << std::endl;
                return LDAP_SUCCESS;
        } else {
                std::cout << "rebind_callback, match:" << url << std::endl;
        }
*/
        //NOTE: synchronous bind
        const int r = ldap_simple_bind_s(h,
                                         TEST_LDAP_USER_DN,
                                         TEST_LDAP_USER_PASSWORD);
/*
        std::cout << "rebind_callback:" << r
                  << ", (LDAP_SUCCESS=" << LDAP_SUCCESS << ")"
                  << std::endl;
*/
        //TODO: handle error
        return r;
}

int get_device_serial_number (void* args);

//DWORD WINAPI get_device_serial_number (LPVOID args);

int main(int argc, char* argv[]) {

        //spawn 100 threads and search for device id for a given user

        char* users[] = {"billy", "bob", "cal", "danny", "elm", "matt",
                         "tammy", "ted", "tim", "tom", "tony", "trevor"
        };

        const int i = (int)(11.0*rand()/(RAND_MAX+1.0));
        get_device_serial_number(users[i]);


/*
        HANDLE threads[100];
        DWORD thread_id[100];

        memset(threads, 0, sizeof(threads)/sizeof(threads[0]));

        for (int t = 0; t < 100; t++ ) {
                const int i = (int)(11.0*rand()/(RAND_MAX+1.0));



                threads[t] = CreateThread(NULL,
                                          0,
                                          get_device_serial_number,
                                          users[i],
                                          0,
                                          &thread_id[t]);

        }

        WaitForMultipleObjects(100, threads, TRUE, INFINITE);
*/
        return 0;

}


//      char* result = 0;

//      get_device_serial_number(argv[1], &result);
//      if (0 == result) {
//              return -1;
//      }

//      std::cout << argv[1] << ":" << result << std::endl;
//      free (result);

int get_device_serial_number (void* args) {

//DWORD WINAPI get_device_serial_number (LPVOID args) {

        char* username = (char*)args;

        std::stringstream ss;
        ss << "(sAMAccountName=";
        ss << username;
        ss << ")";

        std::string s = ss.str();
        const char* search_filter = s.c_str();
        //std::cout << "using search filter:" << search_filter << std::endl;

        LDAP* h = ldap_init(TEST_LDAP_HOST, TEST_LDAP_PORT);
        if (NULL == h) {
                perror("ldap_init");
                return -1;
        }

        int v = LDAP_VERSION3;
        ldap_set_option(h, LDAP_OPT_PROTOCOL_VERSION, &v);

        struct timeval t = {TEST_LDAP_TCP_TIMEOUT, 0};
        ldap_set_option(h, LDAP_OPT_NETWORK_TIMEOUT, &t);

        //Question: How does automatic following of referrals mix with synchronous search?
        ldap_set_option(h, LDAP_OPT_REFERRALS, LDAP_OPT_ON); //LDAP_OPT_ON (default?) / LDAP_OPT_OFF
        ldap_set_rebind_proc(h, rebind_callback, &dummy); //OpenLDAP SDK

        if (ldap_simple_bind_s(h, TEST_LDAP_USER_DN, TEST_LDAP_USER_PASSWORD) != LDAP_SUCCESS ) {
                ldap_perror(h, "ldap_simple_bind_s" );
                return -1;
        }

        LDAPMessage* res =0;

        char* attribute_filter[] = {"sAMAccountType", NULL };

        int rc;
        for (int retry = 0; retry < 3; retry++) {
                // unfortunatelly this is returning sometimes
                // "ldap_search_ext_s: Operations error"
                rc = ldap_search_ext_s(h,
                                       TEST_LDAP_BASE_DN,
                                       LDAP_SCOPE_SUBTREE, //scope: LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
                                       search_filter,
                                       attribute_filter, //NOTE: for now return all attributes (NULL), later fix m_ppLdapQueryAttribName,
                                       0,
                                       NULL,
                                       NULL,
                                       &t,// LDAP_NO_LIMIT,
                                       0, // LDAP_NO_LIMIT,
                                       &res);

                if (LDAP_SUCCESS != rc) {
                        if (retry < 2) {
                                std::cerr << "ldap_search_ext_s:" << ldap_err2string(rc)
                                          << ", attempt:" << retry
                                          << std::endl;
                                continue;
                        }

                        std::cerr << "ldap_search_ext_s:" << ldap_err2string(rc)
                                  << std::endl;

                        ldap_unbind_s(h);
                        return -1;
                } else {
                        break;
                }
        }

        int done = 0;

        for (LDAPMessage* msg = ldap_first_message(h, res);
             ((0 == done) && (NULL!= msg));
             msg = ldap_next_message(h, msg) ) {

                char* dn = 0;
                int msgtype = ldap_msgtype(msg);
                switch (msgtype) {

                case LDAP_RES_SEARCH_ENTRY:
                        //std::cout << "LDAP_RES_SEARCH_ENTRY" << std::endl;

                        BerElement* ber;
                        LDAPMessage* entry;
                        entry = ldap_first_entry(h, res);

                        for (char* a = ldap_first_attribute(h, entry, &ber);
                             a != NULL;
                             a = ldap_next_attribute(h, entry, ber) ) {

                                char** vals;
                                if (NULL != (vals = ldap_get_values(h, entry, a))) {
                                        for (int i = 0; vals[i] != NULL; i++ ) {
                                                std::cout << username;
                                                std::cout << ":" << vals[i] << std::endl; //fix this
                                        }
                                        ldap_value_free(vals);
                                }
                                ldap_memfree(a);
                        }

                        if (ber != NULL) {
                                ber_free(ber, 0);
                        }

                        done = 1;

                        break;

                case LDAP_RES_SEARCH_REFERENCE:
                        // we are not using manual processing of referrals
                        //std::cout << "LDAP_RES_SEARCH_REFERENCE (ignored)" << std::endl;
                        break;

                case LDAP_RES_SEARCH_RESULT:
                        //std::cout << "LDAP_RES_SEARCH_RESULT" << std::endl;

                        char* matched_msg;
                        char* error_msg;
                        char** referrals;
                        LDAPControl** serverctrls;

                        int parse_result_rc;
                        parse_result_rc = ldap_parse_result(h,
                                                            msg,
                                                            &rc,
                                                            &matched_msg,
                                                            &error_msg,
                                                            &referrals, //
                                                            &serverctrls,
                                                            1); //freeit: 0=don't free, 1=free

                        if (LDAP_SUCCESS != parse_result_rc) {
                                std::cerr << "ldap_parse_result:"
                                          << ldap_err2string(parse_result_rc)
                                          << std::endl;

                                ldap_unbind(h);
                                return -1;
                        }

                        /*
                        // Check the results of the LDAP search operation.
                        if ( rc != LDAP_SUCCESS ) {
                                fprintf( stderr, "ldap_search_ext: %s\n", ldap_err2string( rc ) );
                                if ( error_msg != NULL & *error_msg != '\0' ) {
                                        fprintf( stderr, "%s\n", error_msg );
                                }
                                if ( matched_msg != NULL && *matched_msg != '\0' ) {
                                        fprintf( stderr, "Part of the DN that matches an existing entry: %s\n", matched_msg );
                                }
                        } else {
                                printf( "Search completed successfully.\n"
                                        "Entries found: %d\n"
                                        "Search references returned: %d\n",
                                        num_entries, num_refs );
                        }
                        */

                        //it should finish anyway because we are at the end of a for loop
                        done = 1;
                        break;

                default: //well?
                        std::cout << "default?" << std::endl;
                        break;
                }

        }

        ldap_unbind_s(h);
        return 0;
}