RPM Package Manager, CVS Repository
/cvs/
____________________________________________________________________________
Server: rpm5.org Name: Jeff Johnson
Root: /v/rpm/cvs Email: jbj@rpm5.org
Module: rpm Date: 17-Sep-2010 20:48:02
Branch: HEAD Handle: 2010091718480101
Modified files:
rpm CHANGES
rpm/rpmdb rpmmdb.c
Log:
- mongo: bundle up the mongo-c-driver in rpmdb/rpmmdb.c.
Summary:
Revision Changes Path
1.3446 +1 -0 rpm/CHANGES
1.2 +2513 -0 rpm/rpmdb/rpmmdb.c
____________________________________________________________________________
patch -p0 <<'@@ .'
Index: rpm/CHANGES
============================================================================
$ cvs diff -u -r1.3445 -r1.3446 CHANGES
--- rpm/CHANGES 17 Sep 2010 18:15:34 -0000 1.3445
+++ rpm/CHANGES 17 Sep 2010 18:48:01 -0000 1.3446
@@ -1,4 +1,5 @@
5.3.3 -> 5.4a1:
+ - jbj: mongo: bundle up the mongo-c-driver in rpmdb/rpmmdb.c.
- jbj: mongo: stub-in AutoFu sufficient to get WITH_MONGO defined.
- jbj: mongo: stub-in a rpmmdb object to carry the Mongo DB C driver.
- jbj: mongo: stub-in a mongo spewage alias as --wdj:srpm.mongo.
@@ .
patch -p0 <<'@@ .'
Index: rpm/rpmdb/rpmmdb.c
============================================================================
$ cvs diff -u -r1.1 -r1.2 rpmmdb.c
--- rpm/rpmdb/rpmmdb.c 17 Sep 2010 16:17:02 -0000 1.1
+++ rpm/rpmdb/rpmmdb.c 17 Sep 2010 18:48:02 -0000 1.2
@@ -4,6 +4,12 @@
#include "system.h"
+#include <setjmp.h> /* XXX FIXME: AutoFu? */
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
#include <rpmiotypes.h>
#include <rpmio.h> /* for *Pool methods */
#include <rpmlog.h>
@@ -19,6 +25,2513 @@
/*@unchecked@*/ /*@relnull@*/
rpmmdb _rpmmdbI;
+
+/*==============================================================*/
+const int initialBufferSize = 128;
+
+/* only need one of these */
+static const int zero = 0;
+static const int one = 1;
+
+/*==============================================================*/
+/* --- platform_hacks.h */
+/* Copyright 2009, 2010 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/* all platform-specific ifdefs should go here */
+
+#ifdef __GNUC__
+#define MONGO_INLINE static __inline__
+#else
+#define MONGO_INLINE static
+#endif
+
+#ifdef __cplusplus
+#define MONGO_EXTERN_C_START extern "C" {
+#define MONGO_EXTERN_C_END }
+#else
+#define MONGO_EXTERN_C_START
+#define MONGO_EXTERN_C_END
+#endif
+
+/* big endian is only used for OID generation. little is used everywhere else */
+#ifdef MONGO_BIG_ENDIAN
+#define bson_little_endian64(out, in) ( bson_swap_endian64(out, in) )
+#define bson_little_endian32(out, in) ( bson_swap_endian32(out, in) )
+#define bson_big_endian64(out, in) ( memcpy(out, in, 8) )
+#define bson_big_endian32(out, in) ( memcpy(out, in, 4) )
+#else
+#define bson_little_endian64(out, in) ( memcpy(out, in, 8) )
+#define bson_little_endian32(out, in) ( memcpy(out, in, 4) )
+#define bson_big_endian64(out, in) ( bson_swap_endian64(out, in) )
+#define bson_big_endian32(out, in) ( bson_swap_endian32(out, in) )
+#endif
+
+MONGO_EXTERN_C_START
+
+MONGO_INLINE void bson_swap_endian64(void* outp, const void* inp){
+ const char *in = (const char*)inp;
+ char *out = (char*)outp;
+
+ out[0] = in[7];
+ out[1] = in[6];
+ out[2] = in[5];
+ out[3] = in[4];
+ out[4] = in[3];
+ out[5] = in[2];
+ out[6] = in[1];
+ out[7] = in[0];
+
+}
+MONGO_INLINE void bson_swap_endian32(void* outp, const void* inp){
+ const char *in = (const char*)inp;
+ char *out = (char*)outp;
+
+ out[0] = in[3];
+ out[1] = in[2];
+ out[2] = in[1];
+ out[3] = in[0];
+}
+
+MONGO_EXTERN_C_END
+
+/*==============================================================*/
+/* --- numbers.c */
+
+/* all the numbers that fit in a 4 byte string */
+const char bson_numstrs[1000][4] = {
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+ "10", "11", "12", "13", "14", "15", "16", "17", "18", "19",
+ "20", "21", "22", "23", "24", "25", "26", "27", "28", "29",
+ "30", "31", "32", "33", "34", "35", "36", "37", "38", "39",
+ "40", "41", "42", "43", "44", "45", "46", "47", "48", "49",
+ "50", "51", "52", "53", "54", "55", "56", "57", "58", "59",
+ "60", "61", "62", "63", "64", "65", "66", "67", "68", "69",
+ "70", "71", "72", "73", "74", "75", "76", "77", "78", "79",
+ "80", "81", "82", "83", "84", "85", "86", "87", "88", "89",
+ "90", "91", "92", "93", "94", "95", "96", "97", "98", "99",
+
+ "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
+ "110", "111", "112", "113", "114", "115", "116", "117", "118", "119",
+ "120", "121", "122", "123", "124", "125", "126", "127", "128", "129",
+ "130", "131", "132", "133", "134", "135", "136", "137", "138", "139",
+ "140", "141", "142", "143", "144", "145", "146", "147", "148", "149",
+ "150", "151", "152", "153", "154", "155", "156", "157", "158", "159",
+ "160", "161", "162", "163", "164", "165", "166", "167", "168", "169",
+ "170", "171", "172", "173", "174", "175", "176", "177", "178", "179",
+ "180", "181", "182", "183", "184", "185", "186", "187", "188", "189",
+ "190", "191", "192", "193", "194", "195", "196", "197", "198", "199",
+
+ "200", "201", "202", "203", "204", "205", "206", "207", "208", "209",
+ "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
+ "220", "221", "222", "223", "224", "225", "226", "227", "228", "229",
+ "230", "231", "232", "233", "234", "235", "236", "237", "238", "239",
+ "240", "241", "242", "243", "244", "245", "246", "247", "248", "249",
+ "250", "251", "252", "253", "254", "255", "256", "257", "258", "259",
+ "260", "261", "262", "263", "264", "265", "266", "267", "268", "269",
+ "270", "271", "272", "273", "274", "275", "276", "277", "278", "279",
+ "280", "281", "282", "283", "284", "285", "286", "287", "288", "289",
+ "290", "291", "292", "293", "294", "295", "296", "297", "298", "299",
+
+ "300", "301", "302", "303", "304", "305", "306", "307", "308", "309",
+ "310", "311", "312", "313", "314", "315", "316", "317", "318", "319",
+ "320", "321", "322", "323", "324", "325", "326", "327", "328", "329",
+ "330", "331", "332", "333", "334", "335", "336", "337", "338", "339",
+ "340", "341", "342", "343", "344", "345", "346", "347", "348", "349",
+ "350", "351", "352", "353", "354", "355", "356", "357", "358", "359",
+ "360", "361", "362", "363", "364", "365", "366", "367", "368", "369",
+ "370", "371", "372", "373", "374", "375", "376", "377", "378", "379",
+ "380", "381", "382", "383", "384", "385", "386", "387", "388", "389",
+ "390", "391", "392", "393", "394", "395", "396", "397", "398", "399",
+
+ "400", "401", "402", "403", "404", "405", "406", "407", "408", "409",
+ "410", "411", "412", "413", "414", "415", "416", "417", "418", "419",
+ "420", "421", "422", "423", "424", "425", "426", "427", "428", "429",
+ "430", "431", "432", "433", "434", "435", "436", "437", "438", "439",
+ "440", "441", "442", "443", "444", "445", "446", "447", "448", "449",
+ "450", "451", "452", "453", "454", "455", "456", "457", "458", "459",
+ "460", "461", "462", "463", "464", "465", "466", "467", "468", "469",
+ "470", "471", "472", "473", "474", "475", "476", "477", "478", "479",
+ "480", "481", "482", "483", "484", "485", "486", "487", "488", "489",
+ "490", "491", "492", "493", "494", "495", "496", "497", "498", "499",
+
+ "500", "501", "502", "503", "504", "505", "506", "507", "508", "509",
+ "510", "511", "512", "513", "514", "515", "516", "517", "518", "519",
+ "520", "521", "522", "523", "524", "525", "526", "527", "528", "529",
+ "530", "531", "532", "533", "534", "535", "536", "537", "538", "539",
+ "540", "541", "542", "543", "544", "545", "546", "547", "548", "549",
+ "550", "551", "552", "553", "554", "555", "556", "557", "558", "559",
+ "560", "561", "562", "563", "564", "565", "566", "567", "568", "569",
+ "570", "571", "572", "573", "574", "575", "576", "577", "578", "579",
+ "580", "581", "582", "583", "584", "585", "586", "587", "588", "589",
+ "590", "591", "592", "593", "594", "595", "596", "597", "598", "599",
+
+ "600", "601", "602", "603", "604", "605", "606", "607", "608", "609",
+ "610", "611", "612", "613", "614", "615", "616", "617", "618", "619",
+ "620", "621", "622", "623", "624", "625", "626", "627", "628", "629",
+ "630", "631", "632", "633", "634", "635", "636", "637", "638", "639",
+ "640", "641", "642", "643", "644", "645", "646", "647", "648", "649",
+ "650", "651", "652", "653", "654", "655", "656", "657", "658", "659",
+ "660", "661", "662", "663", "664", "665", "666", "667", "668", "669",
+ "670", "671", "672", "673", "674", "675", "676", "677", "678", "679",
+ "680", "681", "682", "683", "684", "685", "686", "687", "688", "689",
+ "690", "691", "692", "693", "694", "695", "696", "697", "698", "699",
+
+ "700", "701", "702", "703", "704", "705", "706", "707", "708", "709",
+ "710", "711", "712", "713", "714", "715", "716", "717", "718", "719",
+ "720", "721", "722", "723", "724", "725", "726", "727", "728", "729",
+ "730", "731", "732", "733", "734", "735", "736", "737", "738", "739",
+ "740", "741", "742", "743", "744", "745", "746", "747", "748", "749",
+ "750", "751", "752", "753", "754", "755", "756", "757", "758", "759",
+ "760", "761", "762", "763", "764", "765", "766", "767", "768", "769",
+ "770", "771", "772", "773", "774", "775", "776", "777", "778", "779",
+ "780", "781", "782", "783", "784", "785", "786", "787", "788", "789",
+ "790", "791", "792", "793", "794", "795", "796", "797", "798", "799",
+
+ "800", "801", "802", "803", "804", "805", "806", "807", "808", "809",
+ "810", "811", "812", "813", "814", "815", "816", "817", "818", "819",
+ "820", "821", "822", "823", "824", "825", "826", "827", "828", "829",
+ "830", "831", "832", "833", "834", "835", "836", "837", "838", "839",
+ "840", "841", "842", "843", "844", "845", "846", "847", "848", "849",
+ "850", "851", "852", "853", "854", "855", "856", "857", "858", "859",
+ "860", "861", "862", "863", "864", "865", "866", "867", "868", "869",
+ "870", "871", "872", "873", "874", "875", "876", "877", "878", "879",
+ "880", "881", "882", "883", "884", "885", "886", "887", "888", "889",
+ "890", "891", "892", "893", "894", "895", "896", "897", "898", "899",
+
+ "900", "901", "902", "903", "904", "905", "906", "907", "908", "909",
+ "910", "911", "912", "913", "914", "915", "916", "917", "918", "919",
+ "920", "921", "922", "923", "924", "925", "926", "927", "928", "929",
+ "930", "931", "932", "933", "934", "935", "936", "937", "938", "939",
+ "940", "941", "942", "943", "944", "945", "946", "947", "948", "949",
+ "950", "951", "952", "953", "954", "955", "956", "957", "958", "959",
+ "960", "961", "962", "963", "964", "965", "966", "967", "968", "969",
+ "970", "971", "972", "973", "974", "975", "976", "977", "978", "979",
+ "980", "981", "982", "983", "984", "985", "986", "987", "988", "989",
+ "990", "991", "992", "993", "994", "995", "996", "997", "998", "999",
+};
+
+/*==============================================================*/
+/* --- bson.h */
+
+MONGO_EXTERN_C_START
+
+typedef enum {
+ bson_eoo=0 ,
+ bson_double=1,
+ bson_string=2,
+ bson_object=3,
+ bson_array=4,
+ bson_bindata=5,
+ bson_undefined=6,
+ bson_oid=7,
+ bson_bool=8,
+ bson_date=9,
+ bson_null=10,
+ bson_regex=11,
+ bson_dbref=12, /* deprecated */
+ bson_code=13,
+ bson_symbol=14,
+ bson_codewscope=15,
+ bson_int = 16,
+ bson_timestamp = 17,
+ bson_long = 18
+} bson_type;
+
+typedef int bson_bool_t;
+
+typedef struct {
+ char * data;
+ bson_bool_t owned;
+} bson;
+
+typedef struct {
+ const char * cur;
+ bson_bool_t first;
+} bson_iterator;
+
+typedef struct {
+ char * buf;
+ char * cur;
+ int bufSize;
+ bson_bool_t finished;
+ int stack[32];
+ int stackPos;
+} bson_buffer;
+
+#pragma pack(1)
+typedef union{
+ char bytes[12];
+ int ints[3];
+} bson_oid_t;
+#pragma pack()
+
+typedef int64_t bson_date_t; /* milliseconds since epoch UTC */
+
+/* ----------------------------
+ READING
+ ------------------------------ */
+
+
+bson * bson_empty(bson * obj); /* returns pointer to static empty bson object */
+void bson_copy(bson* out, const bson* in); /* puts data in new buffer. NOOP if out==NULL */
+bson * bson_from_buffer(bson * b, bson_buffer * buf);
+bson * bson_init( bson * b , char * data , bson_bool_t mine );
+int bson_size(const bson * b );
+void bson_destroy( bson * b );
+
+void bson_print( bson * b );
+void bson_print_raw( const char * bson , int depth );
+
+/* advances iterator to named field */
+/* returns bson_eoo (which is false) if field not found */
+bson_type bson_find(bson_iterator* it, const bson* obj, const char* name);
+
+void bson_iterator_init( bson_iterator * i , const char * bson );
+
+/* more returns true for eoo. best to loop with bson_iterator_next(&it) */
+bson_bool_t bson_iterator_more( const bson_iterator * i );
+bson_type bson_iterator_next( bson_iterator * i );
+
+bson_type bson_iterator_type( const bson_iterator * i );
+const char * bson_iterator_key( const bson_iterator * i );
+const char * bson_iterator_value( const bson_iterator * i );
+
+/* these convert to the right type (return 0 if non-numeric) */
+double bson_iterator_double( const bson_iterator * i );
+int bson_iterator_int( const bson_iterator * i );
+int64_t bson_iterator_long( const bson_iterator * i );
+
+/* false: boolean false, 0 in any type, or null */
+/* true: anything else (even empty strings and objects) */
+bson_bool_t bson_iterator_bool( const bson_iterator * i );
+
+/* these assume you are using the right type */
+double bson_iterator_double_raw( const bson_iterator * i );
+int bson_iterator_int_raw( const bson_iterator * i );
+int64_t bson_iterator_long_raw( const bson_iterator * i );
+bson_bool_t bson_iterator_bool_raw( const bson_iterator * i );
+bson_oid_t* bson_iterator_oid( const bson_iterator * i );
+
+/* these can also be used with bson_code and bson_symbol*/
+const char * bson_iterator_string( const bson_iterator * i );
+int bson_iterator_string_len( const bson_iterator * i );
+
+/* works with bson_code, bson_codewscope, and bson_string */
+/* returns NULL for everything else */
+const char * bson_iterator_code(const bson_iterator * i);
+
+/* calls bson_empty on scope if not a bson_codewscope */
+void bson_iterator_code_scope(const bson_iterator * i, bson * scope);
+
+/* both of these only work with bson_date */
+bson_date_t bson_iterator_date(const bson_iterator * i);
+time_t bson_iterator_time_t(const bson_iterator * i);
+
+int bson_iterator_bin_len( const bson_iterator * i );
+char bson_iterator_bin_type( const bson_iterator * i );
+const char * bson_iterator_bin_data( const bson_iterator * i );
+
+const char * bson_iterator_regex( const bson_iterator * i );
+const char * bson_iterator_regex_opts( const bson_iterator * i );
+
+/* these work with bson_object and bson_array */
+void bson_iterator_subobject(const bson_iterator * i, bson * sub);
+void bson_iterator_subiterator(const bson_iterator * i, bson_iterator * sub);
+
+/* str must be at least 24 hex chars + null byte */
+void bson_oid_from_string(bson_oid_t* oid, const char* str);
+void bson_oid_to_string(const bson_oid_t* oid, char* str);
+void bson_oid_gen(bson_oid_t* oid);
+
+time_t bson_oid_generated_time(bson_oid_t* oid); /* Gives the time the OID was created */
+
+/* ----------------------------
+ BUILDING
+ ------------------------------ */
+
+bson_buffer * bson_buffer_init( bson_buffer * b );
+bson_buffer * bson_ensure_space( bson_buffer * b , const int bytesNeeded );
+
+/**
+ * @return the raw data. you either should free this OR call bson_destroy not both
+ */
+char * bson_buffer_finish( bson_buffer * b );
+void bson_buffer_destroy( bson_buffer * b );
+
+bson_buffer * bson_append_oid( bson_buffer * b , const char * name , const bson_oid_t* oid );
+bson_buffer * bson_append_new_oid( bson_buffer * b , const char * name );
+bson_buffer * bson_append_int( bson_buffer * b , const char * name , const int i );
+bson_buffer * bson_append_long( bson_buffer * b , const char * name , const int64_t i );
+bson_buffer * bson_append_double( bson_buffer * b , const char * name , const double d );
+bson_buffer * bson_append_string( bson_buffer * b , const char * name , const char * str );
+bson_buffer * bson_append_symbol( bson_buffer * b , const char * name , const char * str );
+bson_buffer * bson_append_code( bson_buffer * b , const char * name , const char * str );
+bson_buffer * bson_append_code_w_scope( bson_buffer * b , const char * name , const char * code , const bson * scope);
+bson_buffer * bson_append_binary( bson_buffer * b, const char * name, char type, const char * str, int len );
+bson_buffer * bson_append_bool( bson_buffer * b , const char * name , const bson_bool_t v );
+bson_buffer * bson_append_null( bson_buffer * b , const char * name );
+bson_buffer * bson_append_undefined( bson_buffer * b , const char * name );
+bson_buffer * bson_append_regex( bson_buffer * b , const char * name , const char * pattern, const char * opts );
+bson_buffer * bson_append_bson( bson_buffer * b , const char * name , const bson* bson);
+bson_buffer * bson_append_element( bson_buffer * b, const char * name_or_null, const bson_iterator* elem);
+
+/* these both append a bson_date */
+bson_buffer * bson_append_date(bson_buffer * b, const char * name, bson_date_t millis);
+bson_buffer * bson_append_time_t(bson_buffer * b, const char * name, time_t secs);
+
+bson_buffer * bson_append_start_object( bson_buffer * b , const char * name );
+bson_buffer * bson_append_start_array( bson_buffer * b , const char * name );
+bson_buffer * bson_append_finish_object( bson_buffer * b );
+
+void bson_numstr(char* str, int i);
+void bson_incnumstr(char* str);
+
+
+/* ------------------------------
+ ERROR HANDLING - also used in mongo code
+ ------------------------------ */
+
+void * bson_malloc(int size); /* checks return value */
+
+/* bson_err_handlers shouldn't return!!! */
+typedef void(*bson_err_handler)(const char* errmsg);
+
+/* returns old handler or NULL */
+/* default handler prints error then exits with failure*/
+bson_err_handler set_bson_err_handler(bson_err_handler func);
+
+
+
+/* does nothing is ok != 0 */
+void bson_fatal( int ok );
+void bson_fatal_msg( int ok, const char* msg );
+
+MONGO_EXTERN_C_END
+
+/*==============================================================*/
+/* --- bson.c */
+
+/* ----------------------------
+ READING
+ ------------------------------ */
+
+bson * bson_empty(bson * obj){
+ static char * data = "\005\0\0\0\0";
+ return bson_init(obj, data, 0);
+}
+
+void bson_copy(bson* out, const bson* in){
+ if (!out) return;
+ out->data = bson_malloc(bson_size(in));
+ out->owned = 1;
+ memcpy(out->data, in->data, bson_size(in));
+}
+
+bson * bson_from_buffer(bson * b, bson_buffer * buf){
+ return bson_init(b, bson_buffer_finish(buf), 1);
+}
+
+bson * bson_init( bson * b , char * data , bson_bool_t mine ){
+ b->data = data;
+ b->owned = mine;
+ return b;
+}
+int bson_size(const bson * b ){
+ int i;
+ if ( ! b || ! b->data )
+ return 0;
+ bson_little_endian32(&i, b->data);
+ return i;
+}
+void bson_destroy( bson * b ){
+ if ( b->owned && b->data )
+ free( b->data );
+ b->data = 0;
+ b->owned = 0;
+}
+
+static char hexbyte(char hex){
+ switch (hex){
+ case '0': return 0x0;
+ case '1': return 0x1;
+ case '2': return 0x2;
+ case '3': return 0x3;
+ case '4': return 0x4;
+ case '5': return 0x5;
+ case '6': return 0x6;
+ case '7': return 0x7;
+ case '8': return 0x8;
+ case '9': return 0x9;
+ case 'a':
+ case 'A': return 0xa;
+ case 'b':
+ case 'B': return 0xb;
+ case 'c':
+ case 'C': return 0xc;
+ case 'd':
+ case 'D': return 0xd;
+ case 'e':
+ case 'E': return 0xe;
+ case 'f':
+ case 'F': return 0xf;
+ default: return 0x0; /* something smarter? */
+ }
+}
+
+void bson_oid_from_string(bson_oid_t* oid, const char* str){
+ int i;
+ for (i=0; i<12; i++){
+ oid->bytes[i] = (hexbyte(str[2*i]) << 4) | hexbyte(str[2*i + 1]);
+ }
+}
+void bson_oid_to_string(const bson_oid_t* oid, char* str){
+ static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ int i;
+ for (i=0; i<12; i++){
+ str[2*i] = hex[(oid->bytes[i] & 0xf0) >> 4];
+ str[2*i + 1] = hex[ oid->bytes[i] & 0x0f ];
+ }
+ str[24] = '\0';
+}
+void bson_oid_gen(bson_oid_t* oid){
+ static int incr = 0;
+ static int fuzz = 0;
+ int i = incr++; /*TODO make atomic*/
+ int t = time(NULL);
+
+ /* TODO rand sucks. find something better */
+ if (!fuzz){
+ srand(t);
+ fuzz = rand();
+ }
+
+ bson_big_endian32(&oid->ints[0], &t);
+ oid->ints[1] = fuzz;
+ bson_big_endian32(&oid->ints[2], &i);
+}
+
+time_t bson_oid_generated_time(bson_oid_t* oid){
+ time_t out;
+ bson_big_endian32(&out, &oid->ints[0]);
+ return out;
+}
+
+void bson_print( bson * b ){
+ bson_print_raw( b->data , 0 );
+}
+
+void bson_print_raw( const char * data , int depth ){
+ bson_iterator i;
+ const char * key;
+ int temp;
+ char oidhex[25];
+ bson_iterator_init( &i , data );
+
+ while ( bson_iterator_next( &i ) ){
+ bson_type t = bson_iterator_type( &i );
+ if ( t == 0 )
+ break;
+ key = bson_iterator_key( &i );
+
+ for ( temp=0; temp<=depth; temp++ )
+ printf( "\t" );
+ printf( "%s : %d \t " , key , t );
+ switch ( t ){
+ case bson_int: printf( "%d" , bson_iterator_int( &i ) ); break;
+ case bson_double: printf( "%f" , bson_iterator_double( &i ) ); break;
+ case bson_bool: printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" ); break;
+ case bson_string: printf( "%s" , bson_iterator_string( &i ) ); break;
+ case bson_null: printf( "null" ); break;
+ case bson_oid: bson_oid_to_string(bson_iterator_oid(&i), oidhex); printf( "%s" , oidhex ); break;
+ case bson_object:
+ case bson_array:
+ printf( "\n" );
+ bson_print_raw( bson_iterator_value( &i ) , depth + 1 );
+ break;
+ default:
+ fprintf( stderr , "can't print type : %d\n" , t );
+ }
+ printf( "\n" );
+ }
+}
+
+/* ----------------------------
+ ITERATOR
+ ------------------------------ */
+
+void bson_iterator_init( bson_iterator * i , const char * bson ){
+ i->cur = bson + 4;
+ i->first = 1;
+}
+
+bson_type bson_find(bson_iterator* it, const bson* obj, const char* name){
+ bson_iterator_init(it, obj->data);
+ while(bson_iterator_next(it)){
+ if (strcmp(name, bson_iterator_key(it)) == 0)
+ break;
+ }
+ return bson_iterator_type(it);
+}
+
+bson_bool_t bson_iterator_more( const bson_iterator * i ){
+ return *(i->cur);
+}
+
+bson_type bson_iterator_next( bson_iterator * i ){
+ int ds;
+
+ if ( i->first ){
+ i->first = 0;
+ return (bson_type)(*i->cur);
+ }
+
+ switch ( bson_iterator_type(i) ){
+ case bson_eoo: return bson_eoo; /* don't advance */
+ case bson_undefined:
+ case bson_null: ds = 0; break;
+ case bson_bool: ds = 1; break;
+ case bson_int: ds = 4; break;
+ case bson_long:
+ case bson_double:
+ case bson_timestamp:
+ case bson_date: ds = 8; break;
+ case bson_oid: ds = 12; break;
+ case bson_string:
+ case bson_symbol:
+ case bson_code: ds = 4 + bson_iterator_int_raw(i); break;
+ case bson_bindata: ds = 5 + bson_iterator_int_raw(i); break;
+ case bson_object:
+ case bson_array:
+ case bson_codewscope: ds = bson_iterator_int_raw(i); break;
+ case bson_dbref: ds = 4+12 + bson_iterator_int_raw(i); break;
+ case bson_regex:
+ {
+ const char * s = bson_iterator_value(i);
+ const char * p = s;
+ p += strlen(p)+1;
+ p += strlen(p)+1;
+ ds = p-s;
+ break;
+ }
+
+ default:
+ {
+ char msg[] = "unknown type: 000000000000";
+ bson_numstr(msg+14, (unsigned)(i->cur[0]));
+ bson_fatal_msg(0, msg);
+ return 0;
+ }
+ }
+
+ i->cur += 1 + strlen( i->cur + 1 ) + 1 + ds;
+
+ return (bson_type)(*i->cur);
+}
+
+bson_type bson_iterator_type( const bson_iterator * i ){
+ return (bson_type)i->cur[0];
+}
+const char * bson_iterator_key( const bson_iterator * i ){
+ return i->cur + 1;
+}
+const char * bson_iterator_value( const bson_iterator * i ){
+ const char * t = i->cur + 1;
+ t += strlen( t ) + 1;
+ return t;
+}
+
+/* types */
+
+int bson_iterator_int_raw( const bson_iterator * i ){
+ int out;
+ bson_little_endian32(&out, bson_iterator_value( i ));
+ return out;
+}
+double bson_iterator_double_raw( const bson_iterator * i ){
+ double out;
+ bson_little_endian64(&out, bson_iterator_value( i ));
+ return out;
+}
+int64_t bson_iterator_long_raw( const bson_iterator * i ){
+ int64_t out;
+ bson_little_endian64(&out, bson_iterator_value( i ));
+ return out;
+}
+
+bson_bool_t bson_iterator_bool_raw( const bson_iterator * i ){
+ return bson_iterator_value( i )[0];
+}
+
+bson_oid_t * bson_iterator_oid( const bson_iterator * i ){
+ return (bson_oid_t*)bson_iterator_value(i);
+}
+
+int bson_iterator_int( const bson_iterator * i ){
+ switch (bson_iterator_type(i)){
+ case bson_int: return bson_iterator_int_raw(i);
+ case bson_long: return bson_iterator_long_raw(i);
+ case bson_double: return bson_iterator_double_raw(i);
+ default: return 0;
+ }
+}
+double bson_iterator_double( const bson_iterator * i ){
+ switch (bson_iterator_type(i)){
+ case bson_int: return bson_iterator_int_raw(i);
+ case bson_long: return bson_iterator_long_raw(i);
+ case bson_double: return bson_iterator_double_raw(i);
+ default: return 0;
+ }
+}
+int64_t bson_iterator_long( const bson_iterator * i ){
+ switch (bson_iterator_type(i)){
+ case bson_int: return bson_iterator_int_raw(i);
+ case bson_long: return bson_iterator_long_raw(i);
+ case bson_double: return bson_iterator_double_raw(i);
+ default: return 0;
+ }
+}
+
+bson_bool_t bson_iterator_bool( const bson_iterator * i ){
+ switch (bson_iterator_type(i)){
+ case bson_bool: return bson_iterator_bool_raw(i);
+ case bson_int: return bson_iterator_int_raw(i) != 0;
+ case bson_long: return bson_iterator_long_raw(i) != 0;
+ case bson_double: return bson_iterator_double_raw(i) != 0;
+ case bson_eoo:
+ case bson_null: return 0;
+ default: return 1;
+ }
+}
+
+const char * bson_iterator_string( const bson_iterator * i ){
+ return bson_iterator_value( i ) + 4;
+}
+int bson_iterator_string_len( const bson_iterator * i ){
+ return bson_iterator_int_raw( i );
+}
+
+const char * bson_iterator_code( const bson_iterator * i ){
+ switch (bson_iterator_type(i)){
+ case bson_string:
+ case bson_code: return bson_iterator_value(i) + 4;
+ case bson_codewscope: return bson_iterator_value(i) + 8;
+ default: return NULL;
+ }
+}
+
+void bson_iterator_code_scope(const bson_iterator * i, bson * scope){
+ if (bson_iterator_type(i) == bson_codewscope){
+ int code_len;
+ bson_little_endian32(&code_len, bson_iterator_value(i)+4);
+ bson_init(scope, (void*)(bson_iterator_value(i)+8+code_len), 0);
+ }else{
+ bson_empty(scope);
+ }
+}
+
+bson_date_t bson_iterator_date(const bson_iterator * i){
+ return bson_iterator_long_raw(i);
+}
+
+time_t bson_iterator_time_t(const bson_iterator * i){
+ return bson_iterator_date(i) / 1000;
+}
+
+int bson_iterator_bin_len( const bson_iterator * i ){
+ return bson_iterator_int_raw( i );
+}
+
+char bson_iterator_bin_type( const bson_iterator * i ){
+ return bson_iterator_value(i)[4];
+}
+const char * bson_iterator_bin_data( const bson_iterator * i ){
+ return bson_iterator_value( i ) + 5;
+}
+
+const char * bson_iterator_regex( const bson_iterator * i ){
+ return bson_iterator_value( i );
+}
+const char * bson_iterator_regex_opts( const bson_iterator * i ){
+ const char* p = bson_iterator_value( i );
+ return p + strlen(p) + 1;
+
+}
+
+void bson_iterator_subobject(const bson_iterator * i, bson * sub){
+ bson_init(sub, (char*)bson_iterator_value(i), 0);
+}
+void bson_iterator_subiterator(const bson_iterator * i, bson_iterator * sub){
+ bson_iterator_init(sub, bson_iterator_value(i));
+}
+
+/* ----------------------------
+ BUILDING
+ ------------------------------ */
+
+bson_buffer * bson_buffer_init( bson_buffer * b ){
+ b->buf = (char*)bson_malloc( initialBufferSize );
+ b->bufSize = initialBufferSize;
+ b->cur = b->buf + 4;
+ b->finished = 0;
+ b->stackPos = 0;
+ return b;
+}
+
+void bson_append_byte( bson_buffer * b , char c ){
+ b->cur[0] = c;
+ b->cur++;
+}
+void bson_append( bson_buffer * b , const void * data , int len ){
+ memcpy( b->cur , data , len );
+ b->cur += len;
+}
+void bson_append32(bson_buffer * b, const void * data){
+ bson_little_endian32(b->cur, data);
+ b->cur += 4;
+}
+void bson_append64(bson_buffer * b, const void * data){
+ bson_little_endian64(b->cur, data);
+ b->cur += 8;
+}
+
+bson_buffer * bson_ensure_space( bson_buffer * b , const int bytesNeeded ){
+ int pos = b->cur - b->buf;
+ char * orig = b->buf;
+ int new_size;
+
+ if (b->finished)
+ bson_fatal_msg(!!b->buf, "trying to append to finished buffer");
+
+ if (pos + bytesNeeded <= b->bufSize)
+ return b;
+
+ new_size = 1.5 * (b->bufSize + bytesNeeded);
+ b->buf = realloc(b->buf, new_size);
+ if (!b->buf)
+ bson_fatal_msg(!!b->buf, "realloc() failed");
+
+ b->bufSize = new_size;
+ b->cur += b->buf - orig;
+
+ return b;
+}
+
+char * bson_buffer_finish( bson_buffer * b ){
+ int i;
+ if ( ! b->finished ){
+ if ( ! bson_ensure_space( b , 1 ) ) return 0;
+ bson_append_byte( b , 0 );
+ i = b->cur - b->buf;
+ bson_little_endian32(b->buf, &i);
+ b->finished = 1;
+ }
+ return b->buf;
+}
+
+void bson_buffer_destroy( bson_buffer * b ){
+ free( b->buf );
+ b->buf = 0;
+ b->cur = 0;
+ b->finished = 1;
+}
+
+static bson_buffer * bson_append_estart( bson_buffer * b , int type , const char * name , const int dataSize ){
+ const int sl = strlen(name) + 1;
+ if ( ! bson_ensure_space( b , 1 + sl + dataSize ) )
+ return 0;
+ bson_append_byte( b , (char)type );
+ bson_append( b , name , sl );
+ return b;
+}
+
+/* ----------------------------
+ BUILDING TYPES
+ ------------------------------ */
+
+bson_buffer * bson_append_int( bson_buffer * b , const char * name , const int i ){
+ if ( ! bson_append_estart( b , bson_int , name , 4 ) ) return 0;
+ bson_append32( b , &i );
+ return b;
+}
+bson_buffer * bson_append_long( bson_buffer * b , const char * name , const int64_t i ){
+ if ( ! bson_append_estart( b , bson_long , name , 8 ) ) return 0;
+ bson_append64( b , &i );
+ return b;
+}
+bson_buffer * bson_append_double( bson_buffer * b , const char * name , const double d ){
+ if ( ! bson_append_estart( b , bson_double , name , 8 ) ) return 0;
+ bson_append64( b , &d );
+ return b;
+}
+bson_buffer * bson_append_bool( bson_buffer * b , const char * name , const bson_bool_t i ){
+ if ( ! bson_append_estart( b , bson_bool , name , 1 ) ) return 0;
+ bson_append_byte( b , i != 0 );
+ return b;
+}
+bson_buffer * bson_append_null( bson_buffer * b , const char * name ){
+ if ( ! bson_append_estart( b , bson_null , name , 0 ) ) return 0;
+ return b;
+}
+bson_buffer * bson_append_undefined( bson_buffer * b , const char * name ){
+ if ( ! bson_append_estart( b , bson_undefined , name , 0 ) ) return 0;
+ return b;
+}
+bson_buffer * bson_append_string_base( bson_buffer * b , const char * name , const char * value , bson_type type){
+ int sl = strlen( value ) + 1;
+ if ( ! bson_append_estart( b , type , name , 4 + sl ) ) return 0;
+ bson_append32( b , &sl);
+ bson_append( b , value , sl );
+ return b;
+}
+bson_buffer * bson_append_string( bson_buffer * b , const char * name , const char * value ){
+ return bson_append_string_base(b, name, value, bson_string);
+}
+bson_buffer * bson_append_symbol( bson_buffer * b , const char * name , const char * value ){
+ return bson_append_string_base(b, name, value, bson_symbol);
+}
+bson_buffer * bson_append_code( bson_buffer * b , const char * name , const char * value ){
+ return bson_append_string_base(b, name, value, bson_code);
+}
+
+bson_buffer * bson_append_code_w_scope( bson_buffer * b , const char * name , const char * code , const bson * scope){
+ int sl = strlen(code) + 1;
+ int size = 4 + 4 + sl + bson_size(scope);
+ if (!bson_append_estart(b, bson_codewscope, name, size)) return 0;
+ bson_append32(b, &size);
+ bson_append32(b, &sl);
+ bson_append(b, code, sl);
+ bson_append(b, scope->data, bson_size(scope));
+ return b;
+}
+
+bson_buffer * bson_append_binary( bson_buffer * b, const char * name, char type, const char * str, int len ){
+ if ( ! bson_append_estart( b , bson_bindata , name , 4+1+len ) ) return 0;
+ bson_append32(b, &len);
+ bson_append_byte(b, type);
+ bson_append(b, str, len);
+ return b;
+}
+bson_buffer * bson_append_oid( bson_buffer * b , const char * name , const bson_oid_t * oid ){
+ if ( ! bson_append_estart( b , bson_oid , name , 12 ) ) return 0;
+ bson_append( b , oid , 12 );
+ return b;
+}
+bson_buffer * bson_append_new_oid( bson_buffer * b , const char * name ){
+ bson_oid_t oid;
+ bson_oid_gen(&oid);
+ return bson_append_oid(b, name, &oid);
+}
+
+bson_buffer * bson_append_regex( bson_buffer * b , const char * name , const char * pattern, const char * opts ){
+ const int plen = strlen(pattern)+1;
+ const int olen = strlen(opts)+1;
+ if ( ! bson_append_estart( b , bson_regex , name , plen + olen ) ) return 0;
+ bson_append( b , pattern , plen );
+ bson_append( b , opts , olen );
+ return b;
+}
+
+bson_buffer * bson_append_bson( bson_buffer * b , const char * name , const bson* bson){
+ if ( ! bson_append_estart( b , bson_object , name , bson_size(bson) ) ) return 0;
+ bson_append( b , bson->data , bson_size(bson) );
+ return b;
+}
+
+bson_buffer * bson_append_element( bson_buffer * b, const char * name_or_null, const bson_iterator* elem){
+ bson_iterator next = *elem;
+ int size;
+
+ bson_iterator_next(&next);
+ size = next.cur - elem->cur;
+
+ if (name_or_null == NULL){
+ bson_ensure_space(b, size);
+ bson_append(b, elem->cur, size);
+ }else{
+ int data_size = size - 1 - strlen(bson_iterator_key(elem));
+ bson_append_estart(b, elem->cur[0], name_or_null, data_size);
+ bson_append(b, name_or_null, strlen(name_or_null));
+ bson_append(b, bson_iterator_value(elem), data_size);
+ }
+
+ return b;
+}
+
+bson_buffer * bson_append_date( bson_buffer * b , const char * name , bson_date_t millis ){
+ if ( ! bson_append_estart( b , bson_date , name , 8 ) ) return 0;
+ bson_append64( b , &millis );
+ return b;
+}
+
+bson_buffer * bson_append_time_t( bson_buffer * b , const char * name , time_t secs){
+ return bson_append_date(b, name, (bson_date_t)secs * 1000);
+}
+
+bson_buffer * bson_append_start_object( bson_buffer * b , const char * name ){
+ if ( ! bson_append_estart( b , bson_object , name , 5 ) ) return 0;
+ b->stack[ b->stackPos++ ] = b->cur - b->buf;
+ bson_append32( b , &zero );
+ return b;
+}
+
+bson_buffer * bson_append_start_array( bson_buffer * b , const char * name ){
+ if ( ! bson_append_estart( b , bson_array , name , 5 ) ) return 0;
+ b->stack[ b->stackPos++ ] = b->cur - b->buf;
+ bson_append32( b , &zero );
+ return b;
+}
+
+bson_buffer * bson_append_finish_object( bson_buffer * b ){
+ char * start;
+ int i;
+ if ( ! bson_ensure_space( b , 1 ) ) return 0;
+ bson_append_byte( b , 0 );
+
+ start = b->buf + b->stack[ --b->stackPos ];
+ i = b->cur - start;
+ bson_little_endian32(start, &i);
+
+ return b;
+}
+
+void* bson_malloc(int size){
+ void* p = malloc(size);
+ bson_fatal_msg(!!p, "malloc() failed");
+ return p;
+}
+
+static bson_err_handler err_handler = NULL;
+
+bson_err_handler set_bson_err_handler(bson_err_handler func){
+ bson_err_handler old = err_handler;
+ err_handler = func;
+ return old;
+}
+
+void bson_fatal( int ok ){
+ bson_fatal_msg(ok, "");
+}
+
+void bson_fatal_msg( int ok , const char* msg){
+ if (ok)
+ return;
+
+ if (err_handler){
+ err_handler(msg);
+ }
+
+ fprintf( stderr , "error: %s\n" , msg );
+ exit(-5);
+}
+
+void bson_numstr(char* str, int i){
+ if(i < 1000)
+ memcpy(str, bson_numstrs[i], 4);
+ else
+ sprintf(str,"%d", i);
+}
+
+/*==============================================================*/
+/*
+ Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char mongo_md5_byte_t; /* 8-bit byte */
+typedef unsigned int mongo_md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct mongo_md5_state_s {
+ mongo_md5_word_t count[2]; /* message length in bits, lsw first */
+ mongo_md5_word_t abcd[4]; /* digest buffer */
+ mongo_md5_byte_t buf[64]; /* accumulate block */
+} mongo_md5_state_t;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ /* Initialize the algorithm. */
+ void mongo_md5_init(mongo_md5_state_t *pms);
+
+ /* Append a string to the message. */
+ void mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes);
+
+ /* Finish the message and return the digest. */
+ void mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+/*==============================================================*/
+/* --- md5.c */
+
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef MONGO_BIG_ENDIAN
+# define BYTE_ORDER 1
+#else
+# define BYTE_ORDER -1
+#endif
+
+#define T_MASK ((mongo_md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void
+mongo_md5_process(mongo_md5_state_t *pms, const mongo_md5_byte_t *data /*[64]*/)
+{
+ mongo_md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ mongo_md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ mongo_md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ mongo_md5_word_t xbuf[16];
+ const mongo_md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const mongo_md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const mongo_md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const mongo_md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const mongo_md5_byte_t *xp = data;
+ int i;
+
+# if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+# else
+# define xbuf X /* (static only) */
+# endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void
+mongo_md5_init(mongo_md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void
+mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes)
+{
+ const mongo_md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ mongo_md5_word_t nbits = (mongo_md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ mongo_md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ mongo_md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void
+mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16])
+{
+ static const mongo_md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ mongo_md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (mongo_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ mongo_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ mongo_md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (mongo_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+/*==============================================================*/
+/* --- mongo_except.h */
+
+/* This file is based loosely on cexcept (http://www.nicemice.net/cexcept/). I
+ * have modified it to work better with mongo's API.
+ *
+ * The MONGO_TRY, MONGO_CATCH, and MONGO_TROW macros assume that a pointer to
+ * the current connection is available as 'conn'. If you would like to use a
+ * different name, use the _GENERIC version of these macros.
+ *
+ * WARNING: do not return or otherwise jump (excluding MONGO_TRHOW()) out of a
+ * MONGO_TRY block as the nessesary clean-up code will not be called. Jumping
+ * out of the MONGO_CATCH block is OK.
+ */
+
+#ifdef MONGO_CODE_EXAMPLE
+ mongo_connection conn[1]; /* makes conn a ptr to the connection */
+
+ MONGO_TRY{
+ mongo_find_one(...);
+ MONGO_THROW(conn, MONGO_EXCEPT_NETWORK);
+ }MONGO_CATCH{
+ switch(conn->exception->type){
+ case MONGO_EXCEPT_NETWORK:
+ do_something();
+ case MONGO_EXCEPT_FIND_ERR:
+ do_something();
+ default:
+ MONGO_RETHROW();
+ }
+ }
+#endif
+
+ /* ORIGINAL CEXEPT COPYRIGHT:
+cexcept: README 2.0.1 (2008-Jul-23-Wed)
+http://www.nicemice.net/cexcept/
+Adam M. Costello
+http://www.nicemice.net/amc/
+
+The package is both free-as-in-speech and free-as-in-beer:
+
+ Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta.
+ This package may be modified only if its author and version
+ information is updated accurately, and may be redistributed
+ only if accompanied by this unaltered notice. Subject to those
+ restrictions, permission is granted to anyone to do anything with
+ this package. The copyright holders make no guarantees regarding
+ this package, and are not responsible for any damage resulting from
+ its use.
+ */
+
+/* always non-zero */
+typedef enum{
+ MONGO_EXCEPT_NETWORK=1,
+ MONGO_EXCEPT_FIND_ERR
+}mongo_exception_type;
+
+
+typedef struct {
+ jmp_buf base_handler;
+ jmp_buf *penv;
+ int caught;
+ volatile mongo_exception_type type;
+}mongo_exception_context;
+
+#define MONGO_TRY MONGO_TRY_GENERIC(conn)
+#define MONGO_CATCH MONGO_CATCH_GENERIC(conn)
+#define MONGO_THROW(e) MONGO_THROW_GENERIC(conn, e)
+#define MONGO_RETHROW() MONGO_RETHROW_GENERIC(conn)
+
+/* the rest of this file is implementation details */
+
+/* this is done in mongo_connect */
+#define MONGO_INIT_EXCEPTION(exception_ptr) \
+ do{ \
+ mongo_exception_type t; /* exception_ptr won't be available */\
+ (exception_ptr)->penv = &(exception_ptr)->base_handler; \
+ if ((t = setjmp((exception_ptr)->base_handler))) { /* yes, '=' is correct */ \
+ switch(t){ \
+ case MONGO_EXCEPT_NETWORK: bson_fatal_msg(0, "network error"); \
+ case MONGO_EXCEPT_FIND_ERR: bson_fatal_msg(0, "error in find"); \
+ default: bson_fatal_msg(0, "unknown exception"); \
+ } \
+ } \
+ }while(0)
+
+#define MONGO_TRY_GENERIC(connection) \
+ { \
+ jmp_buf *exception__prev, exception__env; \
+ exception__prev = (connection)->exception.penv; \
+ (connection)->exception.penv = &exception__env; \
+ if (setjmp(exception__env) == 0) { \
+ do
+
+#define MONGO_CATCH_GENERIC(connection) \
+ while ((connection)->exception.caught = 0, \
+ (connection)->exception.caught); \
+ } \
+ else { \
+ (connection)->exception.caught = 1; \
+ } \
+ (connection)->exception.penv = exception__prev; \
+ } \
+ if (!(connection)->exception.caught ) { } \
+ else
+
+/* Try ends with do, and Catch begins with while(0) and ends with */
+/* else, to ensure that Try/Catch syntax is similar to if/else */
+/* syntax. */
+/* */
+/* The 0 in while(0) is expressed as x=0,x in order to appease */
+/* compilers that warn about constant expressions inside while(). */
+/* Most compilers should still recognize that the condition is always */
+/* false and avoid generating code for it. */
+
+#define MONGO_THROW_GENERIC(connection, type_in) \
+ for (;; longjmp(*(connection)->exception.penv, type_in)) \
+ (connection)->exception.type = type_in
+
+#define MONGO_RETHROW_GENERIC(connection) \
+ MONGO_THROW_GENERIC(connection, (connection)->exception.type)
+
+/*==============================================================*/
+/* --- mongo.h */
+
+MONGO_EXTERN_C_START
+
+typedef struct mongo_connection_options {
+ char host[255];
+ int port;
+} mongo_connection_options;
+
+typedef struct {
+ mongo_connection_options* left_opts; /* always current server */
+ mongo_connection_options* right_opts; /* unused with single server */
+ struct sockaddr_in sa;
+ socklen_t addressSize;
+ int sock;
+ bson_bool_t connected;
+ mongo_exception_context exception;
+} mongo_connection;
+
+#pragma pack(1)
+typedef struct {
+ int len;
+ int id;
+ int responseTo;
+ int op;
+} mongo_header;
+
+typedef struct {
+ mongo_header head;
+ char data;
+} mongo_message;
+
+typedef struct {
+ int flag; /* non-zero on failure */
+ int64_t cursorID;
+ int start;
+ int num;
+} mongo_reply_fields;
+
+typedef struct {
+ mongo_header head;
+ mongo_reply_fields fields;
+ char objs;
+} mongo_reply;
+#pragma pack()
+
+typedef struct {
+ mongo_reply * mm; /* message is owned by cursor */
+ mongo_connection * conn; /* connection is *not* owned by cursor */
+ const char* ns; /* owned by cursor */
+ bson current;
+} mongo_cursor;
+
+enum mongo_operations {
+ mongo_op_msg = 1000, /* generic msg command followed by a string */
+ mongo_op_update = 2001, /* update object */
+ mongo_op_insert = 2002,
+ mongo_op_query = 2004,
+ mongo_op_get_more = 2005,
+ mongo_op_delete = 2006,
+ mongo_op_kill_cursors = 2007
+};
+
+/* ----------------------------
+ CONNECTION STUFF
+ ------------------------------ */
+
+typedef enum {
+ mongo_conn_success = 0,
+ mongo_conn_bad_arg,
+ mongo_conn_no_socket,
+ mongo_conn_fail,
+ mongo_conn_not_master /* leaves conn connected to slave */
+} mongo_conn_return;
+
+/**
+ * @param options can be null
+ */
+mongo_conn_return mongo_connect( mongo_connection * conn , mongo_connection_options * options );
+mongo_conn_return mongo_connect_pair( mongo_connection * conn , mongo_connection_options * left, mongo_connection_options * right );
+mongo_conn_return mongo_reconnect( mongo_connection * conn ); /* you will need to reauthenticate after calling */
+bson_bool_t mongo_disconnect( mongo_connection * conn ); /* use this if you want to be able to reconnect */
+bson_bool_t mongo_destroy( mongo_connection * conn ); /* you must call this even if connection failed */
+
+/* ----------------------------
+ CORE METHODS - insert update remove query getmore
+ ------------------------------ */
+
+void mongo_insert( mongo_connection * conn , const char * ns , bson * data );
+void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** data , int num );
+
+static const int MONGO_UPDATE_UPSERT = 0x1;
+static const int MONGO_UPDATE_MULTI = 0x2;
+void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, const bson* op, int flags);
+
+void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond);
+
+mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bson* fields ,int nToReturn ,int nToSkip, int options);
+bson_bool_t mongo_cursor_next(mongo_cursor* cursor);
+void mongo_cursor_destroy(mongo_cursor* cursor);
+
+/* out can be NULL if you don't care about results. useful for commands */
+bson_bool_t mongo_find_one(mongo_connection* conn, const char* ns, bson* query, bson* fields, bson* out);
+
+int64_t mongo_count(mongo_connection* conn, const char* db, const char* coll, bson* query);
+
+/* ----------------------------
+ HIGHER LEVEL - indexes - command helpers eval
+ ------------------------------ */
+
+/* Returns true on success */
+/* WARNING: Unlike other drivers these do not cache results */
+
+static const int MONGO_INDEX_UNIQUE = 0x1;
+static const int MONGO_INDEX_DROP_DUPS = 0x2;
+bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out);
+bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns, const char* field, int options, bson * out);
+
+/* ----------------------------
+ COMMANDS
+ ------------------------------ */
+
+bson_bool_t mongo_run_command(mongo_connection * conn, const char * db, bson * command, bson * out);
+
+/* for simple commands with a single k-v pair */
+bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, const char* cmd, int arg, bson * out);
+bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, const char* cmd, const char* arg, bson * out);
+
+bson_bool_t mongo_cmd_drop_db(mongo_connection * conn, const char * db);
+bson_bool_t mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out);
+
+void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass);
+bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const char* user, const char* pass);
+
+/* return value is master status */
+bson_bool_t mongo_cmd_ismaster(mongo_connection * conn, bson * out);
+
+/* true return indicates error */
+bson_bool_t mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out);
+bson_bool_t mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out);
+void mongo_cmd_reset_error(mongo_connection * conn, const char * db);
+
+/* ----------------------------
+ UTILS
+ ------------------------------ */
+
+MONGO_EXTERN_C_END
+
+/*==============================================================*/
+/* --- mongo.c */
+
+/* ----------------------------
+ message stuff
+ ------------------------------ */
+
+static void looping_write(mongo_connection * conn, const void* buf, int len){
+ const char* cbuf = buf;
+ while (len){
+ int sent = send(conn->sock, cbuf, len, 0);
+ if (sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
+ cbuf += sent;
+ len -= sent;
+ }
+}
+
+static void looping_read(mongo_connection * conn, void* buf, int len){
+ char* cbuf = buf;
+ while (len){
+ int sent = recv(conn->sock, cbuf, len, 0);
+ if (sent == 0 || sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
+ cbuf += sent;
+ len -= sent;
+ }
+}
+
+/* Always calls free(mm) */
+void mongo_message_send(mongo_connection * conn, mongo_message* mm){
+ mongo_header head; /* little endian */
+ bson_little_endian32(&head.len, &mm->head.len);
+ bson_little_endian32(&head.id, &mm->head.id);
+ bson_little_endian32(&head.responseTo, &mm->head.responseTo);
+ bson_little_endian32(&head.op, &mm->head.op);
+
+ MONGO_TRY{
+ looping_write(conn, &head, sizeof(head));
+ looping_write(conn, &mm->data, mm->head.len - sizeof(head));
+ }MONGO_CATCH{
+ free(mm);
+ MONGO_RETHROW();
+ }
+ free(mm);
+}
+
+char * mongo_data_append( char * start , const void * data , int len ){
+ memcpy( start , data , len );
+ return start + len;
+}
+
+char * mongo_data_append32( char * start , const void * data){
+ bson_little_endian32( start , data );
+ return start + 4;
+}
+
+char * mongo_data_append64( char * start , const void * data){
+ bson_little_endian64( start , data );
+ return start + 8;
+}
+
+mongo_message * mongo_message_create( int len , int id , int responseTo , int op ){
+ mongo_message * mm = (mongo_message*)bson_malloc( len );
+
+ if (!id)
+ id = rand();
+
+ /* native endian (converted on send) */
+ mm->head.len = len;
+ mm->head.id = id;
+ mm->head.responseTo = responseTo;
+ mm->head.op = op;
+
+ return mm;
+}
+
+/* ----------------------------
+ connection stuff
+ ------------------------------ */
+static int mongo_connect_helper( mongo_connection * conn ){
+ /* setup */
+ conn->sock = 0;
+ conn->connected = 0;
+
+ memset( conn->sa.sin_zero , 0 , sizeof(conn->sa.sin_zero) );
+ conn->sa.sin_family = AF_INET;
+ conn->sa.sin_port = htons(conn->left_opts->port);
+ conn->sa.sin_addr.s_addr = inet_addr( conn->left_opts->host );
+ conn->addressSize = sizeof(conn->sa);
+
+ /* connect */
+ conn->sock = socket( AF_INET, SOCK_STREAM, 0 );
+ if ( conn->sock <= 0 ){
+ return mongo_conn_no_socket;
+ }
+
+ if ( connect( conn->sock , (struct sockaddr*)&conn->sa , conn->addressSize ) ){
+ return mongo_conn_fail;
+ }
+
+ /* nagle */
+ setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) );
+
+ /* TODO signals */
+
+ conn->connected = 1;
+ return 0;
+}
+
+mongo_conn_return mongo_connect( mongo_connection * conn , mongo_connection_options * options ){
+ MONGO_INIT_EXCEPTION(&conn->exception);
+
+ conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
+ conn->right_opts = NULL;
+
+ if ( options ){
+ memcpy( conn->left_opts , options , sizeof( mongo_connection_options ) );
+ } else {
+ strcpy( conn->left_opts->host , "127.0.0.1" );
+ conn->left_opts->port = 27017;
+ }
+
+ return mongo_connect_helper(conn);
+}
+
+static void swap_repl_pair(mongo_connection * conn){
+ mongo_connection_options * tmp = conn->left_opts;
+ conn->left_opts = conn->right_opts;
+ conn->right_opts = tmp;
+}
+
+mongo_conn_return mongo_connect_pair( mongo_connection * conn , mongo_connection_options * left, mongo_connection_options * right ){
+ conn->connected = 0;
+ MONGO_INIT_EXCEPTION(&conn->exception);
+
+ conn->left_opts = NULL;
+ conn->right_opts = NULL;
+
+ if ( !left || !right )
+ return mongo_conn_bad_arg;
+
+ conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
+ conn->right_opts = bson_malloc(sizeof(mongo_connection_options));
+
+ memcpy( conn->left_opts, left, sizeof( mongo_connection_options ) );
+ memcpy( conn->right_opts, right, sizeof( mongo_connection_options ) );
+
+ return mongo_reconnect(conn);
+}
+
+mongo_conn_return mongo_reconnect( mongo_connection * conn ){
+ mongo_conn_return ret;
+ mongo_disconnect(conn);
+
+ /* single server */
+ if(conn->right_opts == NULL)
+ return mongo_connect_helper(conn);
+
+ /* repl pair */
+ ret = mongo_connect_helper(conn);
+ if (ret == mongo_conn_success && mongo_cmd_ismaster(conn, NULL)){
+ return mongo_conn_success;
+ }
+
+ swap_repl_pair(conn);
+
+ ret = mongo_connect_helper(conn);
+ if (ret == mongo_conn_success){
+ if(mongo_cmd_ismaster(conn, NULL))
+ return mongo_conn_success;
+ else
+ return mongo_conn_not_master;
+ }
+
+ /* failed to connect to both servers */
+ return ret;
+}
+
+void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** bsons, int count){
+ int size = 16 + 4 + strlen( ns ) + 1;
+ int i;
+ mongo_message * mm;
+ char* data;
+
+ for(i=0; i<count; i++){
+ size += bson_size(bsons[i]);
+ }
+
+ mm = mongo_message_create( size , 0 , 0 , mongo_op_insert );
+
+ data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, ns, strlen(ns) + 1);
+
+ for(i=0; i<count; i++){
+ data = mongo_data_append(data, bsons[i]->data, bson_size( bsons[i] ) );
+ }
+
+ mongo_message_send(conn, mm);
+}
+
+void mongo_insert( mongo_connection * conn , const char * ns , bson * bson ){
+ char * data;
+ mongo_message * mm = mongo_message_create( 16 /* header */
+ + 4 /* ZERO */
+ + strlen(ns)
+ + 1 + bson_size(bson)
+ , 0, 0, mongo_op_insert);
+
+ data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, ns, strlen(ns) + 1);
+ data = mongo_data_append(data, bson->data, bson_size(bson));
+
+ mongo_message_send(conn, mm);
+}
+
+void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, const bson* op, int flags){
+ char * data;
+ mongo_message * mm = mongo_message_create( 16 /* header */
+ + 4 /* ZERO */
+ + strlen(ns) + 1
+ + 4 /* flags */
+ + bson_size(cond)
+ + bson_size(op)
+ , 0 , 0 , mongo_op_update );
+
+ data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, ns, strlen(ns) + 1);
+ data = mongo_data_append32(data, &flags);
+ data = mongo_data_append(data, cond->data, bson_size(cond));
+ data = mongo_data_append(data, op->data, bson_size(op));
+
+ mongo_message_send(conn, mm);
+}
+
+void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond){
+ char * data;
+ mongo_message * mm = mongo_message_create( 16 /* header */
+ + 4 /* ZERO */
+ + strlen(ns) + 1
+ + 4 /* ZERO */
+ + bson_size(cond)
+ , 0 , 0 , mongo_op_delete );
+
+ data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, ns, strlen(ns) + 1);
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, cond->data, bson_size(cond));
+
+ mongo_message_send(conn, mm);
+}
+
+mongo_reply * mongo_read_response( mongo_connection * conn ){
+ mongo_header head; /* header from network */
+ mongo_reply_fields fields; /* header from network */
+ mongo_reply * out; /* native endian */
+ int len;
+
+ looping_read(conn, &head, sizeof(head));
+ looping_read(conn, &fields, sizeof(fields));
+
+ bson_little_endian32(&len, &head.len);
+ out = (mongo_reply*)bson_malloc(len);
+
+ out->head.len = len;
+ bson_little_endian32(&out->head.id, &head.id);
+ bson_little_endian32(&out->head.responseTo, &head.responseTo);
+ bson_little_endian32(&out->head.op, &head.op);
+
+ bson_little_endian32(&out->fields.flag, &fields.flag);
+ bson_little_endian64(&out->fields.cursorID, &fields.cursorID);
+ bson_little_endian32(&out->fields.start, &fields.start);
+ bson_little_endian32(&out->fields.num, &fields.num);
+
+ MONGO_TRY{
+ looping_read(conn, &out->objs, len-sizeof(head)-sizeof(fields));
+ }MONGO_CATCH{
+ free(out);
+ MONGO_RETHROW();
+ }
+
+ return out;
+}
+
+mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bson* fields, int nToReturn, int nToSkip, int options){
+ int sl;
+ mongo_cursor * cursor;
+ char * data;
+ mongo_message * mm = mongo_message_create( 16 + /* header */
+ 4 + /* options */
+ strlen( ns ) + 1 + /* ns */
+ 4 + 4 + /* skip,return */
+ bson_size( query ) +
+ bson_size( fields ) ,
+ 0 , 0 , mongo_op_query );
+
+
+ data = &mm->data;
+ data = mongo_data_append32( data , &options );
+ data = mongo_data_append( data , ns , strlen( ns ) + 1 );
+ data = mongo_data_append32( data , &nToSkip );
+ data = mongo_data_append32( data , &nToReturn );
+ data = mongo_data_append( data , query->data , bson_size( query ) );
+ if ( fields )
+ data = mongo_data_append( data , fields->data , bson_size( fields ) );
+
+ bson_fatal_msg( (data == ((char*)mm) + mm->head.len), "query building fail!" );
+
+ mongo_message_send( conn , mm );
+
+ cursor = (mongo_cursor*)bson_malloc(sizeof(mongo_cursor));
+
+ MONGO_TRY{
+ cursor->mm = mongo_read_response(conn);
+ }MONGO_CATCH{
+ free(cursor);
+ MONGO_RETHROW();
+ }
+
+ sl = strlen(ns)+1;
+ cursor->ns = bson_malloc(sl);
+ if (!cursor->ns){
+ free(cursor->mm);
+ free(cursor);
+ return 0;
+ }
+ memcpy((void*)cursor->ns, ns, sl); /* cast needed to silence GCC warning */
+ cursor->conn = conn;
+ cursor->current.data = NULL;
+ return cursor;
+}
+
+bson_bool_t mongo_find_one(mongo_connection* conn, const char* ns, bson* query, bson* fields, bson* out){
+ mongo_cursor* cursor = mongo_find(conn, ns, query, fields, 1, 0, 0);
+
+ if (cursor && mongo_cursor_next(cursor)){
+ bson_copy(out, &cursor->current);
+ mongo_cursor_destroy(cursor);
+ return 1;
+ }else{
+ mongo_cursor_destroy(cursor);
+ return 0;
+ }
+}
+
+int64_t mongo_count(mongo_connection* conn, const char* db, const char* ns, bson* query){
+ bson_buffer bb;
+ bson cmd;
+ bson out;
+ int64_t count = -1;
+
+ bson_buffer_init(&bb);
+ bson_append_string(&bb, "count", ns);
+ if (query && bson_size(query) > 5) /* not empty */
+ bson_append_bson(&bb, "query", query);
+ bson_from_buffer(&cmd, &bb);
+
+ MONGO_TRY{
+ if(mongo_run_command(conn, db, &cmd, &out)){
+ bson_iterator it;
+ if(bson_find(&it, &out, "n"))
+ count = bson_iterator_long(&it);
+ }
+ }MONGO_CATCH{
+ bson_destroy(&cmd);
+ MONGO_RETHROW();
+ }
+
+ bson_destroy(&cmd);
+ bson_destroy(&out);
+ return count;
+}
+
+bson_bool_t mongo_disconnect( mongo_connection * conn ){
+ if ( ! conn->connected )
+ return 1;
+
+#ifdef _WIN32
+ closesocket( conn->sock );
+#else
+ close( conn->sock );
+#endif
+
+ conn->sock = 0;
+ conn->connected = 0;
+
+ return 0;
+}
+
+bson_bool_t mongo_destroy( mongo_connection * conn ){
+ free(conn->left_opts);
+ free(conn->right_opts);
+ conn->left_opts = NULL;
+ conn->right_opts = NULL;
+
+ return mongo_disconnect( conn );
+}
+
+bson_bool_t mongo_cursor_get_more(mongo_cursor* cursor){
+ if (cursor->mm && cursor->mm->fields.cursorID){
+ mongo_connection* conn = cursor->conn;
+ char* data;
+ int sl = strlen(cursor->ns)+1;
+ mongo_message * mm = mongo_message_create(16 /*header*/
+ +4 /*ZERO*/
+ +sl
+ +4 /*numToReturn*/
+ +8 /*cursorID*/
+ , 0, 0, mongo_op_get_more);
+ data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append(data, cursor->ns, sl);
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append64(data, &cursor->mm->fields.cursorID);
+ mongo_message_send(conn, mm);
+
+ free(cursor->mm);
+
+ MONGO_TRY{
+ cursor->mm = mongo_read_response(cursor->conn);
+ }MONGO_CATCH{
+ cursor->mm = NULL;
+ mongo_cursor_destroy(cursor);
+ MONGO_RETHROW();
+ }
+
+ return cursor->mm && cursor->mm->fields.num;
+ } else{
+ return 0;
+ }
+}
+
+bson_bool_t mongo_cursor_next(mongo_cursor* cursor){
+ char* bson_addr;
+
+ /* no data */
+ if (!cursor->mm || cursor->mm->fields.num == 0)
+ return 0;
+
+ /* first */
+ if (cursor->current.data == NULL){
+ bson_init(&cursor->current, &cursor->mm->objs, 0);
+ return 1;
+ }
+
+ bson_addr = cursor->current.data + bson_size(&cursor->current);
+ if (bson_addr >= ((char*)cursor->mm + cursor->mm->head.len)){
+ if (!mongo_cursor_get_more(cursor))
+ return 0;
+ bson_init(&cursor->current, &cursor->mm->objs, 0);
+ } else {
+ bson_init(&cursor->current, bson_addr, 0);
+ }
+
+ return 1;
+}
+
+void mongo_cursor_destroy(mongo_cursor* cursor){
+ if (!cursor) return;
+
+ if (cursor->mm && cursor->mm->fields.cursorID){
+ mongo_connection* conn = cursor->conn;
+ mongo_message * mm = mongo_message_create(16 /*header*/
+ +4 /*ZERO*/
+ +4 /*numCursors*/
+ +8 /*cursorID*/
+ , 0, 0, mongo_op_kill_cursors);
+ char* data = &mm->data;
+ data = mongo_data_append32(data, &zero);
+ data = mongo_data_append32(data, &one);
+ data = mongo_data_append64(data, &cursor->mm->fields.cursorID);
+
+ MONGO_TRY{
+ mongo_message_send(conn, mm);
+ }MONGO_CATCH{
+ free(cursor->mm);
+ free((void*)cursor->ns);
+ free(cursor);
+ MONGO_RETHROW();
+ }
+ }
+
+ free(cursor->mm);
+ free((void*)cursor->ns);
+ free(cursor);
+}
+
+bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out){
+ bson_buffer bb;
+ bson b;
+ bson_iterator it;
+ char name[255] = {'_'};
+ int i = 1;
+ char idxns[1024];
+
+ bson_iterator_init(&it, key->data);
+ while(i < 255 && bson_iterator_next(&it)){
+ strncpy(name + i, bson_iterator_key(&it), 255 - i);
+ i += strlen(bson_iterator_key(&it));
+ }
+ name[254] = '\0';
+
+ bson_buffer_init(&bb);
+ bson_append_bson(&bb, "key", key);
+ bson_append_string(&bb, "ns", ns);
+ bson_append_string(&bb, "name", name);
+ if (options & MONGO_INDEX_UNIQUE)
+ bson_append_bool(&bb, "unique", 1);
+ if (options & MONGO_INDEX_DROP_DUPS)
+ bson_append_bool(&bb, "dropDups", 1);
+
+ bson_from_buffer(&b, &bb);
+
+ strncpy(idxns, ns, 1024-16);
+ strcpy(strchr(idxns, '.'), ".system.indexes");
+ mongo_insert(conn, idxns, &b);
+ bson_destroy(&b);
+
+ *strchr(idxns, '.') = '\0'; /* just db not ns */
+ return !mongo_cmd_get_last_error(conn, idxns, out);
+}
+bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns, const char* field, int options, bson * out){
+ bson_buffer bb;
+ bson b;
+ bson_bool_t success;
+
+ bson_buffer_init(&bb);
+ bson_append_int(&bb, field, 1);
+ bson_from_buffer(&b, &bb);
+
+ success = mongo_create_index(conn, ns, &b, options, out);
+ bson_destroy(&b);
+ return success;
+}
+
+bson_bool_t mongo_run_command(mongo_connection * conn, const char * db, bson * command, bson * out){
+ bson fields;
+ int sl = strlen(db);
+ char* ns = bson_malloc(sl + 5 + 1); /* ".$cmd" + nul */
+ bson_bool_t success;
+
+ strcpy(ns, db);
+ strcpy(ns+sl, ".$cmd");
+
+ success = mongo_find_one(conn, ns, command, bson_empty(&fields), out);
+ free(ns);
+ return success;
+}
+bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, const char* cmdstr, int arg, bson * realout){
+ bson out;
+ bson cmd;
+ bson_buffer bb;
+ bson_bool_t success = 0;
+
+ bson_buffer_init(&bb);
+ bson_append_int(&bb, cmdstr, arg);
+ bson_from_buffer(&cmd, &bb);
+
+ if(mongo_run_command(conn, db, &cmd, &out)){
+ bson_iterator it;
+ if(bson_find(&it, &out, "ok"))
+ success = bson_iterator_bool(&it);
+ }
+
+ bson_destroy(&cmd);
+
+ if (realout)
+ *realout = out;
+ else
+ bson_destroy(&out);
+
+ return success;
+}
+
+bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, const char* cmdstr, const char* arg, bson * realout){
+ bson out;
+ bson cmd;
+ bson_buffer bb;
+ bson_bool_t success = 0;
+
+ bson_buffer_init(&bb);
+ bson_append_string(&bb, cmdstr, arg);
+ bson_from_buffer(&cmd, &bb);
+
+ if(mongo_run_command(conn, db, &cmd, &out)){
+ bson_iterator it;
+ if(bson_find(&it, &out, "ok"))
+ success = bson_iterator_bool(&it);
+ }
+
+ bson_destroy(&cmd);
+
+ if (realout)
+ *realout = out;
+ else
+ bson_destroy(&out);
+
+ return success;
+}
+
+bson_bool_t mongo_cmd_drop_db(mongo_connection * conn, const char * db){
+ return mongo_simple_int_command(conn, db, "dropDatabase", 1, NULL);
+}
+
+bson_bool_t mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out){
+ return mongo_simple_str_command(conn, db, "drop", collection, out);
+}
+
+void mongo_cmd_reset_error(mongo_connection * conn, const char * db){
+ mongo_simple_int_command(conn, db, "reseterror", 1, NULL);
+}
+
+static bson_bool_t mongo_cmd_get_error_helper(mongo_connection * conn, const char * db, bson * realout, const char * cmdtype){
+ bson out = {NULL,0};
+ bson_bool_t haserror = 1;
+
+
+ if(mongo_simple_int_command(conn, db, cmdtype, 1, &out)){
+ bson_iterator it;
+ haserror = (bson_find(&it, &out, "err") != bson_null);
+ }
+
+ if(realout)
+ *realout = out; /* transfer of ownership */
+ else
+ bson_destroy(&out);
+
+ return haserror;
+}
+
+bson_bool_t mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out){
+ return mongo_cmd_get_error_helper(conn, db, out, "getpreverror");
+}
+bson_bool_t mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out){
+ return mongo_cmd_get_error_helper(conn, db, out, "getlasterror");
+}
+
+bson_bool_t mongo_cmd_ismaster(mongo_connection * conn, bson * realout){
+ bson out = {NULL,0};
+ bson_bool_t ismaster = 0;
+
+ if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out)){
+ bson_iterator it;
+ bson_find(&it, &out, "ismaster");
+ ismaster = bson_iterator_bool(&it);
+ }
+
+ if(realout)
+ *realout = out; /* transfer of ownership */
+ else
+ bson_destroy(&out);
+
+ return ismaster;
+}
+
+static void digest2hex(mongo_md5_byte_t digest[16], char hex_digest[33]){
+ static const char hex[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ int i;
+ for (i=0; i<16; i++){
+ hex_digest[2*i] = hex[(digest[i] & 0xf0) >> 4];
+ hex_digest[2*i + 1] = hex[ digest[i] & 0x0f ];
+ }
+ hex_digest[32] = '\0';
+}
+
+static void mongo_pass_digest(const char* user, const char* pass, char hex_digest[33]){
+ mongo_md5_state_t st;
+ mongo_md5_byte_t digest[16];
+
+ mongo_md5_init(&st);
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)user, strlen(user));
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)":mongo:", 7);
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)pass, strlen(pass));
+ mongo_md5_finish(&st, digest);
+ digest2hex(digest, hex_digest);
+}
+
+void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass){
+ bson_buffer bb;
+ bson user_obj;
+ bson pass_obj;
+ char hex_digest[33];
+ char* ns = malloc(strlen(db) + strlen(".system.users") + 1);
+
+ strcpy(ns, db);
+ strcpy(ns+strlen(db), ".system.users");
+
+ mongo_pass_digest(user, pass, hex_digest);
+
+ bson_buffer_init(&bb);
+ bson_append_string(&bb, "user", user);
+ bson_from_buffer(&user_obj, &bb);
+
+ bson_buffer_init(&bb);
+ bson_append_start_object(&bb, "$set");
+ bson_append_string(&bb, "pwd", hex_digest);
+ bson_append_finish_object(&bb);
+ bson_from_buffer(&pass_obj, &bb);
+
+
+ MONGO_TRY{
+ mongo_update(conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT);
+ }MONGO_CATCH{
+ free(ns);
+ bson_destroy(&user_obj);
+ bson_destroy(&pass_obj);
+ MONGO_RETHROW();
+ }
+
+ free(ns);
+ bson_destroy(&user_obj);
+ bson_destroy(&pass_obj);
+}
+
+bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const char* user, const char* pass){
+ bson_buffer bb;
+ bson from_db, auth_cmd;
+ const char* nonce;
+ bson_bool_t success = 0;
+
+ mongo_md5_state_t st;
+ mongo_md5_byte_t digest[16];
+ char hex_digest[33];
+
+ if (mongo_simple_int_command(conn, db, "getnonce", 1, &from_db)){
+ bson_iterator it;
+ bson_find(&it, &from_db, "nonce");
+ nonce = bson_iterator_string(&it);
+ }else{
+ return 0;
+ }
+
+ mongo_pass_digest(user, pass, hex_digest);
+
+ mongo_md5_init(&st);
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)nonce, strlen(nonce));
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)user, strlen(user));
+ mongo_md5_append(&st, (const mongo_md5_byte_t*)hex_digest, 32);
+ mongo_md5_finish(&st, digest);
+ digest2hex(digest, hex_digest);
+
+ bson_buffer_init(&bb);
+ bson_append_int(&bb, "authenticate", 1);
+ bson_append_string(&bb, "user", user);
+ bson_append_string(&bb, "nonce", nonce);
+ bson_append_string(&bb, "key", hex_digest);
+ bson_from_buffer(&auth_cmd, &bb);
+
+ bson_destroy(&from_db);
+
+ MONGO_TRY{
+ if(mongo_run_command(conn, db, &auth_cmd, &from_db)){
+ bson_iterator it;
+ if(bson_find(&it, &from_db, "ok"))
+ success = bson_iterator_bool(&it);
+ }
+ }MONGO_CATCH{
+ bson_destroy(&auth_cmd);
+ MONGO_RETHROW();
+ }
+
+ bson_destroy(&from_db);
+ bson_destroy(&auth_cmd);
+
+ return success;
+}
+
+/*==============================================================*/
+
static void rpmmdbFini(void * _mdb)
/*@globals fileSystem @*/
/*@modifies *_mdb, fileSystem @*/
@@ .
Received on Fri Sep 17 20:48:02 2010