Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 065df329cf5372e90ce7af0da06733aebda8ab5a 0 parents
@timburks authored
202 APACHE-2.0.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
34 Nukefile
@@ -0,0 +1,34 @@
+;; source files
+(set @m_files (filelist "^objc/.*.m$"))
+(set @c_files (filelist "^src/.*.c$"))
+(set @nu_files (filelist "^nu/.*nu$"))
+
+(set SYSTEM ((NSString stringWithShellCommand:"uname") chomp))
+(case SYSTEM
+ ("Darwin"
+ (set @arch (list "x86_64"))
+ (set @cflags "-g -std=gnu99 -fobjc-gc -DDARWIN")
+ (set @ldflags "-framework Foundation -framework Nu"))
+ ("Linux"
+ (set @arch (list "i386"))
+ (set gnustep_flags ((NSString stringWithShellCommand:"gnustep-config --objc-flags") chomp))
+ (set gnustep_libs ((NSString stringWithShellCommand:"gnustep-config --base-libs") chomp))
+ (set @cflags "-g -std=gnu99 -DLINUX -I/usr/local/include #{gnustep_flags}")
+ (set @ldflags "#{gnustep_libs} -lNu"))
+ (else nil))
+
+;; framework description
+(set @framework "NuMongoDB")
+(set @framework_identifier "nu.programming.numongodb")
+(set @framework_creator_code "????")
+
+(compilation-tasks)
+(framework-tasks)
+
+(task "clobber" => "clean" is
+ (SH "rm -rf #{@framework_dir}"))
+
+(task "default" => "framework")
+
+(task "doc" is (SH "nudoc"))
+
65 README
@@ -0,0 +1,65 @@
+
+This is an Objective-C wrapper around the MongoDB C driver.
+
+It is intended for use with Nu but may be useful in other Objective-C programming applications.
+
+Tim Burks
+
+
+
+
+
+
+=== original README =============
+This is a very basic MongoDB c driver. This is an alpha release, please email mathias@10gen.com if you run into issues or have API suggestions.
+
+The goal is to be super strict for ultimate portability, no dependencies, and very embeddable anywhere.
+
+You will need JSON-C (http://oss.metaparadigm.com/json-c/) to compile the unit tests, but it is not required for the main libraries.
+
+Building with scons:
+scons # this will produce libbson.a and libmongoc.a
+scons --c99 # this will use c99 mode in gcc (recommended)
+scons test # this will compile and run the unit tests (optional)
+scons test --test-server=123.4.5.67 # use remote server for tests
+
+Building with gcc:
+gcc --std=c99 -Isrc src/*.c YOUR_APP.c # No -Ddefines are needed in c99 mode on little endien
+
+Building with MSVC:
+TODO
+
+#define options (you must use the same flags to compile all apps and libs):
+MONGO_BIG_ENDIAN This must be defined if on a big endian architecture
+
+one of these (defaults to unsigned char if neither is defined)
+MONGO_HAVE_BOOL Define this if your compiler has a plain 'bool' type
+MONGO_HAVE_STDBOOL Define this if you must include <stdbool.h> to get 'bool'
+
+one of these (required if not using c99):
+MONGO_HAVE_STDINT Define this if you have <stdint.h> for int64_t
+MONGO_HAVE_UNISTD Define this if you have <unistd.h> for int64_t
+MONGO_USE__INT64 Define this if '__int64' is your compiler's 64bit type (MSVC)
+MONGO_USE_LONG_LONG_INT Define this if 'long long int' is your compiler's 64bit type
+
+
+Error Handling:
+I'm using an exception system based on cexcept. If you would like to gracefully
+handle errors, take a look at src/mongo_except.h. It is currently only used for
+network failures, but more errors will be used in the future.
+
+TODO:
+building on windows
+more documentation
+checking for $err in query results
+query helper for sort and hint
+explain and profiler helpers
+GridFS
+safe-mode modifications (maybe)
+cached ensure_index (maybe)
+
+LICENSE
+
+Unless otherwise specified in a source file, sources in this
+repository are published under the terms of the Apache License version
+2.0, a copy of which is in this repository as APACHE-2.0.txt.
19 SETUP
@@ -0,0 +1,19 @@
+
+Information and utilities for running MongoDB with Nu.
+
+BUILDING MongoDB o
+
+Debian Linux
+1. git clone
+2. sudo apt-get install scons
+3. sudo apt-get install libboost-dev
+4. sudo apt-get
+
+For Debian 5:
+1. edit /etc/apt/sources.list, adding:
+deb http://downloads.mongodb.org/distros/debian 5.0 10gen
+2. sudo aptitude update
+3. sudo apt-get install mongodb-stable
+
+
+
134 objc/NuMongoDB.m
@@ -0,0 +1,134 @@
+#include <stdlib.h>
+
+#define ASSERT(x) \
+ do{ \
+ if(!(x)){ \
+ printf("failed assert (%d): %s\n", __LINE__, #x); \
+ exit(1); \
+ }\
+ }while(0)
+
+#ifdef _WIN32
+#define INIT_SOCKETS_FOR_WINDOWS \
+ do{ \
+ WSADATA out; \
+ WSAStartup(MAKEWORD(2,2), &out); \
+ } while(0)
+#else
+#define INIT_SOCKETS_FOR_WINDOWS do {} while(0)
+#endif
+
+#define TEST_SERVER "127.0.0.1"
+
+#include "mongo.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#import <Foundation/Foundation.h>
+
+@interface NuMongoDB : NSObject {
+
+}
+@end
+
+@implementation NuMongoDB
+
+
++ (int) main {
+ mongo_connection conn[1];
+ mongo_connection_options opts;
+ bson_buffer bb;
+ bson b;
+ mongo_cursor * cursor;
+ int i;
+ char hex_oid[25];
+
+ const char * col = "c.simple";
+ const char * ns = "test.c.simple";
+
+ INIT_SOCKETS_FOR_WINDOWS;
+
+ strncpy(opts.host, TEST_SERVER, 255);
+ opts.host[254] = '\0';
+ opts.port = 27017;
+
+ if (mongo_connect( conn , &opts )){
+ printf("failed to connect\n");
+ exit(1);
+ }
+
+ /* if the collection doesn't exist dropping it will fail */
+ if (!mongo_cmd_drop_collection(conn, "test", col, NULL)
+ && mongo_find_one(conn, ns, bson_empty(&b), bson_empty(&b), NULL)){
+ printf("failed to drop collection\n");
+ exit(1);
+ }
+
+ for(i=0; i< 5; i++){
+ bson_buffer_init( & bb );
+
+ bson_append_new_oid( &bb, "_id" );
+ bson_append_double( &bb , "a" , 17 );
+ bson_append_int( &bb , "b" , 17 );
+ bson_append_string( &bb , "c" , "17" );
+
+ {
+ bson_buffer * sub = bson_append_start_object( &bb , "d" );
+ bson_append_int( sub, "i", 71 );
+ bson_append_finish_object(sub);
+ }
+ {
+ bson_buffer * arr = bson_append_start_array( &bb , "e" );
+ bson_append_int( arr, "0", 71 );
+ bson_append_string( arr, "1", "71" );
+ bson_append_finish_object(arr);
+ }
+
+ bson_from_buffer(&b, &bb);
+ mongo_insert( conn , ns , &b );
+ bson_destroy(&b);
+ }
+
+ cursor = mongo_find( conn , ns , bson_empty(&b) , 0 , 0 , 0 , 0 );
+
+ while (mongo_cursor_next(cursor)){
+ bson_iterator it;
+ bson_iterator_init(&it, cursor->current.data);
+ while(bson_iterator_next(&it)){
+ fprintf(stderr, " %s: ", bson_iterator_key(&it));
+
+ switch(bson_iterator_type(&it)){
+ case bson_double:
+ fprintf(stderr, "(double) %e\n", bson_iterator_double(&it));
+ break;
+ case bson_int:
+ fprintf(stderr, "(int) %d\n", bson_iterator_int(&it));
+ break;
+ case bson_string:
+ fprintf(stderr, "(string) \"%s\"\n", bson_iterator_string(&it));
+ break;
+ case bson_oid:
+ bson_oid_to_string(bson_iterator_oid(&it), hex_oid);
+ fprintf(stderr, "(oid) \"%s\"\n", hex_oid);
+ break;
+ case bson_object:
+ fprintf(stderr, "(subobject) {...}\n");
+ break;
+ case bson_array:
+ fprintf(stderr, "(array) [...]\n");
+ break;
+ default:
+ fprintf(stderr, "(type %d)\n", bson_iterator_type(&it));
+ break;
+ }
+ }
+ fprintf(stderr, "\n");
+ }
+
+ mongo_cursor_destroy(cursor);
+ mongo_destroy( conn );
+ return 0;
+}
+
+@end
648 src/bson.c
@@ -0,0 +1,648 @@
+/* bson.c */
+
+/* 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.
+ */
+
+#include "bson.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+const int initialBufferSize = 128;
+
+/* only need one of these */
+static const int zero = 0;
+
+/* ----------------------------
+ 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);
+}
+
+extern const char bson_numstrs[1000][4];
+void bson_numstr(char* str, int i){
+ if(i < 1000)
+ memcpy(str, bson_numstrs[i], 4);
+ else
+ sprintf(str,"%d", i);
+}
218 src/bson.h
@@ -0,0 +1,218 @@
+/* bson.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.
+ */
+
+#ifndef _BSON_H_
+#define _BSON_H_
+
+#include "platform_hacks.h"
+#include <time.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
+#endif
381 src/md5.c
@@ -0,0 +1,381 @@
+/*
+ Copyright (C) 1999, 2000, 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
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ 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.
+ */
+
+#include "md5.h"
+#include <string.h>
+
+#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));
+}
91 src/md5.h
@@ -0,0 +1,91 @@
+/*
+ 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
+
+ */
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ 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.
+ */
+
+#ifndef md5_INCLUDED
+# define md5_INCLUDED
+
+/*
+ * 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
+
+#endif /* md5_INCLUDED */
799 src/mongo.c
@@ -0,0 +1,799 @@
+/* mongo.c */
+
+/* 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.
+ */
+
+#include "mongo.h"
+#include "md5.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+/* only need one of these */
+static const int zero = 0;
+static const int one = 1;
+
+/* ----------------------------
+ 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;
+}
186 src/mongo.h
@@ -0,0 +1,186 @@
+/* mongo.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.
+ */
+
+#ifndef _MONGO_H_
+#define _MONGO_H_
+
+#include "mongo_except.h"
+#include "bson.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <winsock.h>
+typedef int socklen_t;
+#else
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#endif
+
+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;
+