MONGODB_DRIVER=./driver/src
LOCAL_CFLAGS=-I$(MONGODB_DRIVER)
-LOCAL_OBJS=$(MONGODB_DRIVER)/md5.o \
- $(MONGODB_DRIVER)/mongo.o $(MONGODB_DRIVER)/net.o \
- $(MONGODB_DRIVER)/bson.o $(MONGODB_DRIVER)/numbers.o $(MONGODB_DRIVER)/encoding.o \
+LOCAL_OBJS=$(MONGODB_DRIVER)/encoding.o $(MONGODB_DRIVER)/env_posix.o \
+ $(MONGODB_DRIVER)/bson.o $(MONGODB_DRIVER)/md5.o \
+ $(MONGODB_DRIVER)/mongo.o $(MONGODB_DRIVER)/numbers.o
local_depend: $(LOCAL_OBJS)
# MongoDB C Driver History
+## 0.5.2
+2012-5-4
+
+* Validate collection and database names on insert.
+* Validate insert limits using max BSON size.
+* Support getaddrinfo and SO_RCVTIMEO and SO_SNDTIMEO on Windows.
+* Store errno/WSAGetLastError() on errors.
+* Various bug fixes and refactorings.
+* Update error reporting docs.
+
+## 0.5.1
+
+* Env for POSIX, WIN32, and standard C.
+* Various bug fixes.
+
+## 0.5
+2012-3-31
+
+* Separate cursor-specific errors into their own enum: mongo_cursor_error_t.
+* Catch $err return on bad queries and store the result in conn->getlasterrorcode
+ and conn->getlasterrstr.
+* On queries that return $err, set cursor->err to MONGO_CURSOR_QUERY_FAIL.
+* When passing bad BSON to a cursor object, set cursor->err to MONGO_CURSOR_BSON_ERROR,
+ and store the specific BSON error on the conn->err field.
+* Remove bson_copy_basic().
+* bson_copy() will copy finished bson objects only.
+* bson_copy() returns BSON_OK on success and BSON_ERROR on failure.
+* Added a Makefile for easy compile and install on Linux and OS X.
+* Replica set connect fixes.
+
## 0.4
THIS RELEASE INCLUDES NUMEROUS BACKWARD-BREAKING CHANGES.
# Building
First check out the version you want to build. *Always build from a particular tag, since HEAD may be
-a work in progress.* For example, to build version 0.4, run:
+a work in progress.* For example, to build version 0.5.2, run:
- git checkout v0.4
+ git checkout v0.5.2
You can then build the driver with scons:
+++ /dev/null
-# -*- mode: python; -*-
-
-VERSION = "0.4"
-
-# --- options ----
-AddOption('--test-server',
- dest='test_server',
- default='127.0.0.1',
- type='string',
- nargs=1,
- action='store',
- help='IP address of server to use for testing')
-
-AddOption('--seed-start-port',
- dest='seed_start_port',
- default=30000,
- type='int',
- nargs=1,
- action='store',
- help='IP address of server to use for testing')
-
-AddOption('--c99',
- dest='use_c99',
- default=False,
- action='store_true',
- help='Compile with c99 (recommended for gcc)')
-
-AddOption('--d',
- dest='optimize',
- default=True,
- action='store_false',
- help='disable optimizations')
-
-AddOption('--use-platform',
- dest='compile_platform',
- default='GENERIC',
- type='string',
- nargs=1,
- action='store',
- help='Compile for a specific platform to take advantage '
- ' of particular system features. For the moment, this include timeouts only.'
- ' Current options include LINUX, '
- ' GENERIC, and CUSTOM. If you specific CUSTOM, you must place a'
- ' system-specific implementation of net.h and net.c in src/platform/custom/')
-
-import os, sys
-
-env = Environment( ENV=os.environ )
-
-# ---- Docs ----
-def build_docs(env, target, source):
- buildscript_path = os.path.join(os.path.abspath("docs"))
- sys.path.insert(0, buildscript_path)
- import buildscripts
- from buildscripts import docs
- docs.main()
-
-env.Alias("docs", [], [build_docs])
-env.AlwaysBuild("docs")
-
-# ---- Platforms ----
-PLATFORM_TEST_DIR = None
-if "LINUX" == GetOption('compile_platform'):
- env.Append( CPPFLAGS=" -D_MONGO_USE_LINUX_SYSTEM" )
- NET_LIB = "src/platform/linux/net.c"
- PLATFORM_TEST_DIR = "test/platform/linux/"
- PLATFORM_TESTS = [ "timeouts" ]
-elif "CUSTOM" == GetOption('compile_platform'):
- env.Append( CPPFLAGS=" -D_MONGO_USE_CUSTOM_SYSTEM" )
- NET_LIB = "src/platform/custom/net.c"
-else:
- NET_LIB = "src/net.c"
-
-# ---- Libraries ----
-if os.sys.platform in ["darwin", "linux2"]:
- env.Append( CPPFLAGS=" -pedantic -Wall -ggdb -DMONGO_HAVE_STDINT" )
- env.Append( CPPPATH=["/opt/local/include/"] )
- env.Append( LIBPATH=["/opt/local/lib/"] )
-
- if GetOption('use_c99'):
- env.Append( CFLAGS=" -std=c99 " )
- env.Append( CXXDEFINES="MONGO_HAVE_STDINT" )
- else:
- env.Append( CFLAGS=" -ansi " )
-
- if GetOption('optimize'):
- env.Append( CPPFLAGS=" -O3 " )
- # -O3 benchmarks *significantly* faster than -O2 when disabling networking
-elif 'win32' == os.sys.platform:
- env.Append( LIBS='ws2_32' )
-
-#we shouldn't need these options in c99 mode
-if not GetOption('use_c99'):
- conf = Configure(env)
-
- if not conf.CheckType('int64_t'):
- if conf.CheckType('int64_t', '#include <stdint.h>\n'):
- conf.env.Append( CPPDEFINES="MONGO_HAVE_STDINT" )
- elif conf.CheckType('int64_t', '#include <unistd.h>\n'):
- conf.env.Append( CPPDEFINES="MONGO_HAVE_UNISTD" )
- elif conf.CheckType('__int64'):
- conf.env.Append( CPPDEFINES="MONGO_USE__INT64" )
- elif conf.CheckType('long long int'):
- conf.env.Append( CPPDEFINES="MONGO_USE_LONG_LONG_INT" )
- else:
- print "*** what is your 64 bit int type? ****"
- Exit(1)
-
- env = conf.Finish()
-
-have_libjson = False
-conf = Configure(env)
-if conf.CheckLib('json'):
- have_libjson = True
-env = conf.Finish()
-
-if sys.byteorder == 'big':
- env.Append( CPPDEFINES="MONGO_BIG_ENDIAN" )
-
-env.Append( CPPPATH=["src/"] )
-
-coreFiles = ["src/md5.c" ]
-mFiles = [ "src/mongo.c", NET_LIB, "src/gridfs.c"]
-bFiles = [ "src/bson.c", "src/numbers.c", "src/encoding.c"]
-mLibFiles = coreFiles + mFiles + bFiles
-bLibFiles = coreFiles + bFiles
-m = env.Library( "mongoc" , mLibFiles )
-b = env.Library( "bson" , bLibFiles )
-env.Default( env.Alias( "lib" , [ m[0] , b[0] ] ) )
-
-if os.sys.platform == "linux2":
- env.Append( SHLINKFLAGS="-shared -Wl,-soname,libmongoc.so." + VERSION )
- env.Append( SHLINKFLAGS = "-shared -Wl,-soname,libbson.so." + VERSION )
-
-dynm = env.SharedLibrary( "mongoc" , mLibFiles )
-dynb = env.SharedLibrary( "bson" , bLibFiles )
-env.Default( env.Alias( "sharedlib" , [ dynm[0] , dynb[0] ] ) )
-
-
-
-# ---- Benchmarking ----
-benchmarkEnv = env.Clone()
-benchmarkEnv.Append( CPPDEFINES=[('TEST_SERVER', r'\"%s\"'%GetOption('test_server')),
-('SEED_START_PORT', r'%d'%GetOption('seed_start_port'))] )
-benchmarkEnv.Append( LIBS=[m, b] )
-benchmarkEnv.Prepend( LIBPATH=["."] )
-benchmarkEnv.Program( "benchmark" , [ "test/benchmark.c"] )
-
-# ---- Tests ----
-testEnv = benchmarkEnv.Clone()
-testCoreFiles = [ ]
-
-def run_tests( root, tests ):
- for name in tests:
- filename = "%s/%s.c" % (root, name)
- exe = "test_" + name
- test = testEnv.Program( exe , testCoreFiles + [filename] )
- test_alias = testEnv.Alias('test', [test], test[0].abspath + ' 2> ' + os.path.devnull)
- AlwaysBuild(test_alias)
-
-tests = Split("sizes resize endian_swap bson bson_subobject simple update errors "
-"count_delete auth gridfs validate examples helpers oid functions cursors replica_set")
-
-# Run standard tests
-run_tests("test", tests)
-
-# Run platform tests
-if not PLATFORM_TEST_DIR is None:
- run_tests( PLATFORM_TEST_DIR, PLATFORM_TESTS )
-
-if have_libjson:
- tests.append('json')
- testEnv.Append( LIBS=["json"] )
-
-# special case for cpptest
-test = testEnv.Program( 'test_cpp' , testCoreFiles + ['test/cpptest.cpp'] )
-test_alias = testEnv.Alias('test', [test], test[0].abspath + ' 2> '+ os.path.devnull)
-AlwaysBuild(test_alias)
void *( *bson_malloc_func )( size_t ) = malloc;
void *( *bson_realloc_func )( void *, size_t ) = realloc;
void ( *bson_free )( void * ) = free;
+#ifdef R_SAFETY_NET
+bson_printf_func bson_printf;
+#else
bson_printf_func bson_printf = printf;
+#endif
bson_fprintf_func bson_fprintf = fprintf;
bson_sprintf_func bson_sprintf = sprintf;
READING
------------------------------ */
-bson *bson_empty( bson *obj ) {
+MONGO_EXPORT bson* bson_create() {
+ return (bson*)bson_malloc(sizeof(bson));
+}
+
+MONGO_EXPORT void bson_dispose(bson* b) {
+ bson_free(b);
+}
+
+MONGO_EXPORT bson *bson_empty( bson *obj ) {
static char *data = "\005\0\0\0\0";
bson_init_data( obj, data );
obj->finished = 1;
obj->err = 0;
+ obj->errstr = NULL;
obj->stackPos = 0;
return obj;
}
-void bson_copy_basic( bson *out, const bson *in ) {
- if ( !out ) return;
+MONGO_EXPORT int bson_copy( bson *out, const bson *in ) {
+ if ( !out ) return BSON_ERROR;
+ if ( !in->finished ) return BSON_ERROR;
bson_init_size( out, bson_size( in ) );
memcpy( out->data, in->data, bson_size( in ) );
-}
-
-void bson_copy( bson *out, const bson *in ) {
- int i;
+ out->finished = 1;
- if ( !out ) return;
- bson_copy_basic( out, in );
- out->cur = out->data + ( in->cur - in->data );
- out->dataSize = in->dataSize;
- out->finished = in->finished;
- out->stackPos = in->stackPos;
- out->err = in->err;
- for( i=0; i<out->stackPos; i++ )
- out->stack[i] = in->stack[i];
+ return BSON_OK;
}
int bson_init_data( bson *b, char *data ) {
return BSON_OK;
}
+int bson_init_finished_data( bson *b, char *data ) {
+ bson_init_data( b, data );
+ b->finished = 1;
+ return BSON_OK;
+}
+
static void _bson_reset( bson *b ) {
b->finished = 0;
b->stackPos = 0;
b->errstr = NULL;
}
-int bson_size( const bson *b ) {
+MONGO_EXPORT int bson_size( const bson *b ) {
int i;
if ( ! b || ! b->data )
return 0;
return i;
}
-const char *bson_data( bson *b ) {
+MONGO_EXPORT int bson_buffer_size( const bson *b ) {
+ return (b->cur - b->data + 1);
+}
+
+
+MONGO_EXPORT const char *bson_data( const bson *b ) {
return (const char *)b->data;
}
}
}
-void bson_oid_from_string( bson_oid_t *oid, const char *str ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT 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[24] = '\0';
}
-void bson_set_oid_fuzz( int ( *func )( void ) ) {
+MONGO_EXPORT void bson_set_oid_fuzz( int ( *func )( void ) ) {
oid_fuzz_func = func;
}
-void bson_set_oid_inc( int ( *func )( void ) ) {
+MONGO_EXPORT void bson_set_oid_inc( int ( *func )( void ) ) {
oid_inc_func = func;
}
-void bson_oid_gen( bson_oid_t *oid ) {
+MONGO_EXPORT void bson_oid_gen( bson_oid_t *oid ) {
static int incr = 0;
static int fuzz = 0;
int i;
bson_big_endian32( &oid->ints[2], &i );
}
-time_t bson_oid_generated_time( bson_oid_t *oid ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT void bson_print( const bson *b ) {
bson_print_raw( b->data , 0 );
}
-void bson_print_raw( const char *data , int depth ) {
+MONGO_EXPORT void bson_print_raw( const char *data , int depth ) {
bson_iterator i;
const char *key;
int temp;
key = bson_iterator_key( &i );
for ( temp=0; temp<=depth; temp++ )
- printf( "\t" );
+ bson_printf( "\t" );
bson_printf( "%s : %d \t " , key , t );
switch ( t ) {
case BSON_DOUBLE:
- printf( "%f" , bson_iterator_double( &i ) );
+ bson_printf( "%f" , bson_iterator_double( &i ) );
break;
case BSON_STRING:
- printf( "%s" , bson_iterator_string( &i ) );
+ bson_printf( "%s" , bson_iterator_string( &i ) );
break;
case BSON_SYMBOL:
- printf( "SYMBOL: %s" , bson_iterator_string( &i ) );
+ bson_printf( "SYMBOL: %s" , bson_iterator_string( &i ) );
break;
case BSON_OID:
bson_oid_to_string( bson_iterator_oid( &i ), oidhex );
- printf( "%s" , oidhex );
+ bson_printf( "%s" , oidhex );
break;
case BSON_BOOL:
- printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" );
+ bson_printf( "%s" , bson_iterator_bool( &i ) ? "true" : "false" );
break;
case BSON_DATE:
- printf( "%ld" , ( long int )bson_iterator_date( &i ) );
+ bson_printf( "%ld" , ( long int )bson_iterator_date( &i ) );
break;
case BSON_BINDATA:
- printf( "BSON_BINDATA" );
+ bson_printf( "BSON_BINDATA" );
break;
case BSON_UNDEFINED:
- printf( "BSON_UNDEFINED" );
+ bson_printf( "BSON_UNDEFINED" );
break;
case BSON_NULL:
- printf( "BSON_NULL" );
+ bson_printf( "BSON_NULL" );
break;
case BSON_REGEX:
- printf( "BSON_REGEX: %s", bson_iterator_regex( &i ) );
+ bson_printf( "BSON_REGEX: %s", bson_iterator_regex( &i ) );
break;
case BSON_CODE:
- printf( "BSON_CODE: %s", bson_iterator_code( &i ) );
+ bson_printf( "BSON_CODE: %s", bson_iterator_code( &i ) );
break;
case BSON_CODEWSCOPE:
- printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) );
+ bson_printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) );
bson_init( &scope );
bson_iterator_code_scope( &i, &scope );
- printf( "\n\t SCOPE: " );
+ bson_printf( "\n\t SCOPE: " );
bson_print( &scope );
break;
case BSON_INT:
- printf( "%d" , bson_iterator_int( &i ) );
+ bson_printf( "%d" , bson_iterator_int( &i ) );
break;
case BSON_LONG:
- printf( "%lld" , ( long long int )bson_iterator_long( &i ) );
+ bson_printf( "%lld" , ( uint64_t )bson_iterator_long( &i ) );
break;
case BSON_TIMESTAMP:
ts = bson_iterator_timestamp( &i );
- printf( "i: %d, t: %d", ts.i, ts.t );
+ bson_printf( "i: %d, t: %d", ts.i, ts.t );
break;
case BSON_OBJECT:
case BSON_ARRAY:
- printf( "\n" );
+ bson_printf( "\n" );
bson_print_raw( bson_iterator_value( &i ) , depth + 1 );
break;
default:
bson_errprintf( "can't print type : %d\n" , t );
}
- printf( "\n" );
+ bson_printf( "\n" );
}
}
ITERATOR
------------------------------ */
-void bson_iterator_init( bson_iterator *i, const bson *b ) {
+MONGO_EXPORT bson_iterator* bson_iterator_create() {
+ return (bson_iterator*)malloc(sizeof(bson_iterator*));
+}
+
+MONGO_EXPORT void bson_iterator_dispose(bson_iterator* i) {
+ free(i);
+}
+
+MONGO_EXPORT void bson_iterator_init( bson_iterator *i, const bson *b ) {
i->cur = b->data + 4;
i->first = 1;
}
-void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ) {
+MONGO_EXPORT void bson_iterator_from_buffer( bson_iterator *i, const char *buffer ) {
i->cur = buffer + 4;
i->first = 1;
}
-bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ) {
+MONGO_EXPORT bson_type bson_find( bson_iterator *it, const bson *obj, const char *name ) {
bson_iterator_init( it, (bson *)obj );
while( bson_iterator_next( it ) ) {
if ( strcmp( name, bson_iterator_key( it ) ) == 0 )
return bson_iterator_type( it );
}
-bson_bool_t bson_iterator_more( const bson_iterator *i ) {
+MONGO_EXPORT bson_bool_t bson_iterator_more( const bson_iterator *i ) {
return *( i->cur );
}
-bson_type bson_iterator_next( bson_iterator *i ) {
+MONGO_EXPORT bson_type bson_iterator_next( bson_iterator *i ) {
int ds;
if ( i->first ) {
return ( bson_type )( *i->cur );
}
-bson_type bson_iterator_type( const bson_iterator *i ) {
+MONGO_EXPORT bson_type bson_iterator_type( const bson_iterator *i ) {
return ( bson_type )i->cur[0];
}
-const char *bson_iterator_key( const bson_iterator *i ) {
+MONGO_EXPORT const char *bson_iterator_key( const bson_iterator *i ) {
return i->cur + 1;
}
-const char *bson_iterator_value( const bson_iterator *i ) {
+MONGO_EXPORT const char *bson_iterator_value( const bson_iterator *i ) {
const char *t = i->cur + 1;
t += strlen( t ) + 1;
return t;
return bson_iterator_value( i )[0];
}
-bson_oid_t *bson_iterator_oid( const bson_iterator *i ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT int bson_iterator_int( const bson_iterator *i ) {
switch ( bson_iterator_type( i ) ) {
case BSON_INT:
return bson_iterator_int_raw( i );
}
}
-double bson_iterator_double( const bson_iterator *i ) {
+MONGO_EXPORT double bson_iterator_double( const bson_iterator *i ) {
switch ( bson_iterator_type( i ) ) {
case BSON_INT:
return bson_iterator_int_raw( i );
}
}
-int64_t bson_iterator_long( const bson_iterator *i ) {
+MONGO_EXPORT int64_t bson_iterator_long( const bson_iterator *i ) {
switch ( bson_iterator_type( i ) ) {
case BSON_INT:
return bson_iterator_int_raw( i );
}
}
-bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ) {
+MONGO_EXPORT bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i ) {
bson_timestamp_t ts;
bson_little_endian32( &( ts.i ), bson_iterator_value( i ) );
bson_little_endian32( &( ts.t ), bson_iterator_value( i ) + 4 );
return ts;
}
-bson_bool_t bson_iterator_bool( const bson_iterator *i ) {
+
+MONGO_EXPORT int bson_iterator_timestamp_time( const bson_iterator *i ) {
+ int time;
+ bson_little_endian32( &time, bson_iterator_value( i ) + 4 );
+ return time;
+}
+
+
+MONGO_EXPORT int bson_iterator_timestamp_increment( const bson_iterator *i ) {
+ int increment;
+ bson_little_endian32( &increment, bson_iterator_value( i ) );
+ return increment;
+}
+
+
+MONGO_EXPORT bson_bool_t bson_iterator_bool( const bson_iterator *i ) {
switch ( bson_iterator_type( i ) ) {
case BSON_BOOL:
return bson_iterator_bool_raw( i );
}
}
-const char *bson_iterator_string( const bson_iterator *i ) {
- return bson_iterator_value( i ) + 4;
+MONGO_EXPORT const char *bson_iterator_string( const bson_iterator *i ) {
+ switch ( bson_iterator_type( i ) ) {
+ case BSON_STRING:
+ case BSON_SYMBOL:
+ return bson_iterator_value( i ) + 4;
+ default:
+ return "";
+ }
}
int bson_iterator_string_len( const bson_iterator *i ) {
return bson_iterator_int_raw( i );
}
-const char *bson_iterator_code( const bson_iterator *i ) {
+MONGO_EXPORT const char *bson_iterator_code( const bson_iterator *i ) {
switch ( bson_iterator_type( i ) ) {
case BSON_STRING:
case BSON_CODE:
}
}
-void bson_iterator_code_scope( const bson_iterator *i, bson *scope ) {
+MONGO_EXPORT 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_data( scope, ( void * )( bson_iterator_value( i )+8+code_len ) );
+ _bson_reset( scope );
+ scope->finished = 1;
} else {
bson_empty( scope );
}
}
-bson_date_t bson_iterator_date( const bson_iterator *i ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT int bson_iterator_bin_len( const bson_iterator *i ) {
return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD )
? bson_iterator_int_raw( i ) - 4
: bson_iterator_int_raw( i );
}
-char bson_iterator_bin_type( const bson_iterator *i ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT const char *bson_iterator_bin_data( const bson_iterator *i ) {
return ( bson_iterator_bin_type( i ) == BSON_BIN_BINARY_OLD )
? bson_iterator_value( i ) + 9
: bson_iterator_value( i ) + 5;
}
-const char *bson_iterator_regex( const bson_iterator *i ) {
+MONGO_EXPORT const char *bson_iterator_regex( const bson_iterator *i ) {
return bson_iterator_value( i );
}
-const char *bson_iterator_regex_opts( const bson_iterator *i ) {
+MONGO_EXPORT 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 ) {
+MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub ) {
bson_init_data( sub, ( char * )bson_iterator_value( i ) );
_bson_reset( sub );
sub->finished = 1;
}
-void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ) {
+MONGO_EXPORT void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub ) {
bson_iterator_from_buffer( sub, bson_iterator_value( i ) );
}
_bson_reset( b );
}
-void bson_init( bson *b ) {
+MONGO_EXPORT void bson_init( bson *b ) {
_bson_init_size( b, initialBufferSize );
}
return BSON_OK;
}
-int bson_finish( bson *b ) {
+MONGO_EXPORT int bson_finish( bson *b ) {
int i;
if( b->err & BSON_NOT_UTF8 )
return BSON_OK;
}
-void bson_destroy( bson *b ) {
- bson_free( b->data );
- b->err = 0;
- b->data = 0;
- b->cur = 0;
- b->finished = 1;
+MONGO_EXPORT void bson_destroy( bson *b ) {
+ if (b) {
+ bson_free( b->data );
+ b->err = 0;
+ b->data = 0;
+ b->cur = 0;
+ b->finished = 1;
+ }
}
static int bson_append_estart( bson *b, int type, const char *name, const int dataSize ) {
BUILDING TYPES
------------------------------ */
-int bson_append_int( bson *b, const char *name, const int i ) {
+MONGO_EXPORT int bson_append_int( bson *b, const char *name, const int i ) {
if ( bson_append_estart( b, BSON_INT, name, 4 ) == BSON_ERROR )
return BSON_ERROR;
bson_append32( b , &i );
return BSON_OK;
}
-int bson_append_long( bson *b, const char *name, const int64_t i ) {
+MONGO_EXPORT int bson_append_long( bson *b, const char *name, const int64_t i ) {
if ( bson_append_estart( b , BSON_LONG, name, 8 ) == BSON_ERROR )
return BSON_ERROR;
bson_append64( b , &i );
return BSON_OK;
}
-int bson_append_double( bson *b, const char *name, const double d ) {
+MONGO_EXPORT int bson_append_double( bson *b, const char *name, const double d ) {
if ( bson_append_estart( b, BSON_DOUBLE, name, 8 ) == BSON_ERROR )
return BSON_ERROR;
bson_append64( b , &d );
return BSON_OK;
}
-int bson_append_bool( bson *b, const char *name, const bson_bool_t i ) {
+MONGO_EXPORT int bson_append_bool( bson *b, const char *name, const bson_bool_t i ) {
if ( bson_append_estart( b, BSON_BOOL, name, 1 ) == BSON_ERROR )
return BSON_ERROR;
bson_append_byte( b , i != 0 );
return BSON_OK;
}
-int bson_append_null( bson *b, const char *name ) {
+MONGO_EXPORT int bson_append_null( bson *b, const char *name ) {
if ( bson_append_estart( b , BSON_NULL, name, 0 ) == BSON_ERROR )
return BSON_ERROR;
return BSON_OK;
}
-int bson_append_undefined( bson *b, const char *name ) {
+MONGO_EXPORT int bson_append_undefined( bson *b, const char *name ) {
if ( bson_append_estart( b, BSON_UNDEFINED, name, 0 ) == BSON_ERROR )
return BSON_ERROR;
return BSON_OK;
return BSON_OK;
}
-int bson_append_string( bson *b, const char *name, const char *value ) {
+MONGO_EXPORT int bson_append_string( bson *b, const char *name, const char *value ) {
return bson_append_string_base( b, name, value, strlen ( value ), BSON_STRING );
}
-int bson_append_symbol( bson *b, const char *name, const char *value ) {
+MONGO_EXPORT int bson_append_symbol( bson *b, const char *name, const char *value ) {
return bson_append_string_base( b, name, value, strlen ( value ), BSON_SYMBOL );
}
-int bson_append_code( bson *b, const char *name, const char *value ) {
+MONGO_EXPORT int bson_append_code( bson *b, const char *name, const char *value ) {
return bson_append_string_base( b, name, value, strlen ( value ), BSON_CODE );
}
-int bson_append_string_n( bson *b, const char *name, const char *value, int len ) {
+MONGO_EXPORT int bson_append_string_n( bson *b, const char *name, const char *value, int len ) {
return bson_append_string_base( b, name, value, len, BSON_STRING );
}
-int bson_append_symbol_n( bson *b, const char *name, const char *value, int len ) {
+MONGO_EXPORT int bson_append_symbol_n( bson *b, const char *name, const char *value, int len ) {
return bson_append_string_base( b, name, value, len, BSON_SYMBOL );
}
-int bson_append_code_n( bson *b, const char *name, const char *value, int len ) {
+MONGO_EXPORT int bson_append_code_n( bson *b, const char *name, const char *value, int len ) {
return bson_append_string_base( b, name, value, len, BSON_CODE );
}
-int bson_append_code_w_scope_n( bson *b, const char *name,
+MONGO_EXPORT int bson_append_code_w_scope_n( bson *b, const char *name,
const char *code, int len, const bson *scope ) {
int sl = len + 1;
return BSON_OK;
}
-int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ) {
+MONGO_EXPORT int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope ) {
return bson_append_code_w_scope_n( b, name, code, strlen ( code ), scope );
}
-int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ) {
+MONGO_EXPORT int bson_append_binary( bson *b, const char *name, char type, const char *str, int len ) {
if ( type == BSON_BIN_BINARY_OLD ) {
int subtwolen = len + 4;
if ( bson_append_estart( b, BSON_BINDATA, name, 4+1+4+len ) == BSON_ERROR )
return BSON_OK;
}
-int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ) {
+MONGO_EXPORT int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid ) {
if ( bson_append_estart( b, BSON_OID, name, 12 ) == BSON_ERROR )
return BSON_ERROR;
bson_append( b , oid , 12 );
return BSON_OK;
}
-int bson_append_new_oid( bson *b, const char *name ) {
+MONGO_EXPORT int bson_append_new_oid( bson *b, const char *name ) {
bson_oid_t oid;
bson_oid_gen( &oid );
return bson_append_oid( b, name, &oid );
}
-int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts ) {
+MONGO_EXPORT int bson_append_regex( bson *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 ) == BSON_ERROR )
return BSON_OK;
}
-int bson_append_bson( bson *b, const char *name, const bson *bson ) {
+MONGO_EXPORT int bson_append_bson( bson *b, const char *name, const bson *bson ) {
if ( bson_append_estart( b, BSON_OBJECT, name, bson_size( bson ) ) == BSON_ERROR )
return BSON_ERROR;
bson_append( b , bson->data , bson_size( bson ) );
return BSON_OK;
}
-int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ) {
+MONGO_EXPORT int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem ) {
bson_iterator next = *elem;
int size;
return BSON_OK;
}
-int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ) {
+MONGO_EXPORT int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts ) {
if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR;
bson_append32( b , &( ts->i ) );
return BSON_OK;
}
-int bson_append_date( bson *b, const char *name, bson_date_t millis ) {
+MONGO_EXPORT int bson_append_timestamp2( bson *b, const char *name, int time, int increment ) {
+ if ( bson_append_estart( b, BSON_TIMESTAMP, name, 8 ) == BSON_ERROR ) return BSON_ERROR;
+
+ bson_append32( b , &increment );
+ bson_append32( b , &time );
+ return BSON_OK;
+}
+
+MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis ) {
if ( bson_append_estart( b, BSON_DATE, name, 8 ) == BSON_ERROR ) return BSON_ERROR;
bson_append64( b , &millis );
return BSON_OK;
}
-int bson_append_time_t( bson *b, const char *name, time_t secs ) {
+MONGO_EXPORT int bson_append_time_t( bson *b, const char *name, time_t secs ) {
return bson_append_date( b, name, ( bson_date_t )secs * 1000 );
}
-int bson_append_start_object( bson *b, const char *name ) {
+MONGO_EXPORT int bson_append_start_object( bson *b, const char *name ) {
if ( bson_append_estart( b, BSON_OBJECT, name, 5 ) == BSON_ERROR ) return BSON_ERROR;
b->stack[ b->stackPos++ ] = b->cur - b->data;
bson_append32( b , &zero );
return BSON_OK;
}
-int bson_append_start_array( bson *b, const char *name ) {
+MONGO_EXPORT int bson_append_start_array( bson *b, const char *name ) {
if ( bson_append_estart( b, BSON_ARRAY, name, 5 ) == BSON_ERROR ) return BSON_ERROR;
b->stack[ b->stackPos++ ] = b->cur - b->data;
bson_append32( b , &zero );
return BSON_OK;
}
-int bson_append_finish_object( bson *b ) {
+MONGO_EXPORT int bson_append_finish_object( bson *b ) {
char *start;
int i;
if ( bson_ensure_space( b, 1 ) == BSON_ERROR ) return BSON_ERROR;
return BSON_OK;
}
-int bson_append_finish_array( bson *b ) {
- return bson_append_finish_object( b );
+MONGO_EXPORT double bson_int64_to_double( int64_t i64 ) {
+ return (double)i64;
}
+MONGO_EXPORT int bson_append_finish_array( bson *b ) {
+ return bson_append_finish_object( b );
+}
/* Error handling and allocators. */
static bson_err_handler err_handler = NULL;
-bson_err_handler set_bson_err_handler( bson_err_handler func ) {
+MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func ) {
bson_err_handler old = err_handler;
err_handler = func;
return old;
}
-void *bson_malloc( int size ) {
+MONGO_EXPORT void *bson_malloc( int size ) {
void *p;
p = bson_malloc_func( size );
bson_fatal_msg( !!p, "malloc() failed" );
va_list ap;
int ret;
va_start( ap, format );
+#ifndef R_SAFETY_NET
ret = vfprintf( stderr, format, ap );
+#endif
va_end( ap );
return ret;
if ( err_handler ) {
err_handler( msg );
}
-
+#ifndef R_SAFETY_NET
bson_errprintf( "error: %s\n" , msg );
exit( -5 );
+#endif
}
else
bson_sprintf( str,"%d", i );
}
+
+MONGO_EXPORT 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_EXPORT 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];
+}
* @brief BSON Declarations
*/
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef _BSON_H_
-#define _BSON_H_
+#ifndef BSON_H_
+#define BSON_H_
-#include "platform.h"
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
+#ifdef __GNUC__
+ #define MONGO_INLINE static __inline__
+ #define MONGO_EXPORT
+#else
+ #define MONGO_INLINE static
+ #ifdef MONGO_STATIC_BUILD
+ #define MONGO_EXPORT
+ #elif defined(MONGO_DLL_BUILD)
+ #define MONGO_EXPORT __declspec(dllexport)
+ #else
+ #define MONGO_EXPORT __declspec(dllimport)
+ #endif
+#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
+
+#if defined(MONGO_HAVE_STDINT) || __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#elif defined(MONGO_HAVE_UNISTD)
+#include <unistd.h>
+#elif defined(MONGO_USE__INT64)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#elif defined(MONGO_USE_LONG_LONG_INT)
+typedef long long int int64_t;
+typedef unsigned long long int uint64_t;
+#else
+#error Must compile with c99 or define MONGO_HAVE_STDINT, MONGO_HAVE_UNISTD, MONGO_USE__INT64, or MONGO_USE_LONG_INT.
+#endif
+
+#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
#define BSON_OK 0
} bson_iterator;
typedef struct {
- char *data;
- char *cur;
- int dataSize;
- bson_bool_t finished;
- int stack[32];
- int stackPos;
+ char *data; /**< Pointer to a block of data in this BSON object. */
+ char *cur; /**< Pointer to the current position. */
+ int dataSize; /**< The number of bytes allocated to char *data. */
+ bson_bool_t finished; /**< When finished, the BSON object can no longer be modified. */
+ int stack[32]; /**< A stack used to keep track of nested BSON elements. */
+ int stackPos; /**< Index of current stack position. */
int err; /**< Bitfield representing errors or warnings on this buffer */
char *errstr; /**< A string representation of the most recent error or warning. */
} bson;
READING
------------------------------ */
+MONGO_EXPORT bson* bson_create();
+MONGO_EXPORT void bson_dispose(bson* b);
+
/**
* Size of a BSON object.
*
*
* @return the size.
*/
-int bson_size( const bson *b );
+MONGO_EXPORT int bson_size( const bson *b );
+MONGO_EXPORT int bson_buffer_size( const bson *b );
/**
* Print a string representation of a BSON object.
*
* @param b the BSON object to print.
*/
-void bson_print( bson *b );
+MONGO_EXPORT void bson_print( const bson *b );
/**
* Return a pointer to the raw buffer stored by this bson object.
*
* @param b a BSON object
*/
-const char *bson_data( bson *b );
+MONGO_EXPORT const char *bson_data( const bson *b );
/**
* Print a string representation of a BSON object.
* @param bson the raw data to print.
* @param depth the depth to recurse the object.x
*/
-void bson_print_raw( const char *bson , int depth );
+MONGO_EXPORT void bson_print_raw( const char *bson , int depth );
/**
* Advance a bson_iterator to the named field.
*
* @return the type of the found object or BSON_EOO if it is not found.
*/
-bson_type bson_find( bson_iterator *it, const bson *obj, const char *name );
+MONGO_EXPORT bson_type bson_find( bson_iterator *it, const bson *obj, const char *name );
+
+MONGO_EXPORT bson_iterator* bson_iterator_create();
+MONGO_EXPORT void bson_iterator_dispose(bson_iterator*);
/**
* Initialize a bson_iterator.
*
* @param i the bson_iterator to initialize.
* @param bson the BSON object to associate with the iterator.
*/
-void bson_iterator_init( bson_iterator *i , const bson *b );
+MONGO_EXPORT void bson_iterator_init( bson_iterator *i , const bson *b );
/**
* Initialize a bson iterator from a const char* buffer. Note
* @param i the bson_iterator to initialize.
* @param buffer the buffer to point to.
*/
-void bson_iterator_from_buffer( bson_iterator *i, const char *buffer );
+MONGO_EXPORT void bson_iterator_from_buffer( bson_iterator *i, const char *buffer );
/* more returns true for eoo. best to loop with bson_iterator_next(&it) */
/**
*
* @return returns true if there is more data.
*/
-bson_bool_t bson_iterator_more( const bson_iterator *i );
+MONGO_EXPORT bson_bool_t bson_iterator_more( const bson_iterator *i );
/**
* Point the iterator at the next BSON object.
*
* @return the type of the next BSON object.
*/
-bson_type bson_iterator_next( bson_iterator *i );
+MONGO_EXPORT bson_type bson_iterator_next( bson_iterator *i );
/**
* Get the type of the BSON object currently pointed to by the iterator.
*
* @return the type of the current BSON object.
*/
-bson_type bson_iterator_type( const bson_iterator *i );
+MONGO_EXPORT bson_type bson_iterator_type( const bson_iterator *i );
/**
* Get the key of the BSON object currently pointed to by the iterator.
*
* @return the key of the current BSON object.
*/
-const char *bson_iterator_key( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_key( const bson_iterator *i );
/**
* Get the value of the BSON object currently pointed to by the iterator.
*
* @return the value of the current BSON object.
*/
-const char *bson_iterator_value( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_value( const bson_iterator *i );
/* these convert to the right type (return 0 if non-numeric) */
/**
*
* @return the value of the current BSON object.
*/
-double bson_iterator_double( const bson_iterator *i );
+MONGO_EXPORT double bson_iterator_double( const bson_iterator *i );
/**
* Get the int value of the BSON object currently pointed to by the iterator.
*
* @return the value of the current BSON object.
*/
-int bson_iterator_int( const bson_iterator *i );
+MONGO_EXPORT int bson_iterator_int( const bson_iterator *i );
/**
* Get the long value of the BSON object currently pointed to by the iterator.
*
* @return the value of the current BSON object.
*/
-int64_t bson_iterator_long( const bson_iterator *i );
+MONGO_EXPORT int64_t bson_iterator_long( const bson_iterator *i );
/* return the bson timestamp as a whole or in parts */
/**
*
* @return the value of the current BSON object.
*/
-bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i );
+MONGO_EXPORT bson_timestamp_t bson_iterator_timestamp( const bson_iterator *i );
+MONGO_EXPORT int bson_iterator_timestamp_time( const bson_iterator *i );
+MONGO_EXPORT int bson_iterator_timestamp_increment( const bson_iterator *i );
/**
* Get the boolean value of the BSON object currently pointed to by
*/
/* 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 );
+MONGO_EXPORT bson_bool_t bson_iterator_bool( const bson_iterator *i );
/**
* Get the double value of the BSON object currently pointed to by the
*
* @return the value of the current BSON object.
*/
-bson_oid_t *bson_iterator_oid( const bson_iterator *i );
+MONGO_EXPORT bson_oid_t *bson_iterator_oid( const bson_iterator *i );
/**
* Get the string value of the BSON object currently pointed to by the
* @return the value of the current BSON object.
*/
/* these can also be used with bson_code and bson_symbol*/
-const char *bson_iterator_string( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_string( const bson_iterator *i );
/**
* Get the string length of the BSON object currently pointed to by the
*/
/* works with bson_code, bson_codewscope, and BSON_STRING */
/* returns NULL for everything else */
-const char *bson_iterator_code( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_code( const bson_iterator *i );
/**
* Calls bson_empty on scope if not a bson_codewscope
* @param scope the bson scope.
*/
/* calls bson_empty on scope if not a bson_codewscope */
-void bson_iterator_code_scope( const bson_iterator *i, bson *scope );
+MONGO_EXPORT void bson_iterator_code_scope( const bson_iterator *i, bson *scope );
/**
* Get the date value of the BSON object currently pointed to by the
* @return the date value of the current BSON object.
*/
/* both of these only work with bson_date */
-bson_date_t bson_iterator_date( const bson_iterator *i );
+MONGO_EXPORT bson_date_t bson_iterator_date( const bson_iterator *i );
/**
* Get the time value of the BSON object currently pointed to by the
*
* @return the time value of the current BSON object.
*/
-time_t bson_iterator_time_t( const bson_iterator *i );
+MONGO_EXPORT time_t bson_iterator_time_t( const bson_iterator *i );
/**
* Get the length of the BSON binary object currently pointed to by the
*
* @return the length of the current BSON binary object.
*/
-int bson_iterator_bin_len( const bson_iterator *i );
+MONGO_EXPORT int bson_iterator_bin_len( const bson_iterator *i );
/**
* Get the type of the BSON binary object currently pointed to by the
*
* @return the type of the current BSON binary object.
*/
-char bson_iterator_bin_type( const bson_iterator *i );
+MONGO_EXPORT char bson_iterator_bin_type( const bson_iterator *i );
/**
* Get the value of the BSON binary object currently pointed to by the
*
* @return the value of the current BSON binary object.
*/
-const char *bson_iterator_bin_data( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_bin_data( const bson_iterator *i );
/**
* Get the value of the BSON regex object currently pointed to by the
*
* @return the value of the current BSON regex object.
*/
-const char *bson_iterator_regex( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_regex( const bson_iterator *i );
/**
* Get the options of the BSON regex object currently pointed to by the
*
* @return the options of the current BSON regex object.
*/
-const char *bson_iterator_regex_opts( const bson_iterator *i );
+MONGO_EXPORT const char *bson_iterator_regex_opts( const bson_iterator *i );
/* these work with BSON_OBJECT and BSON_ARRAY */
/**
* @param i the bson_iterator.
* @param sub the BSON subobject destination.
*/
-void bson_iterator_subobject( const bson_iterator *i, bson *sub );
+MONGO_EXPORT void bson_iterator_subobject( const bson_iterator *i, bson *sub );
/**
* Get a bson_iterator that on the BSON subobject.
* @param i the bson_iterator.
* @param sub the iterator to point at the BSON subobject.
*/
-void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub );
+MONGO_EXPORT void bson_iterator_subiterator( const bson_iterator *i, bson_iterator *sub );
/* str must be at least 24 hex chars + null byte */
/**
* @param oid the bson_oid_t destination.
* @param str a null terminated string comprised of at least 24 hex chars.
*/
-void bson_oid_from_string( bson_oid_t *oid, const char *str );
+MONGO_EXPORT void bson_oid_from_string( bson_oid_t *oid, const char *str );
/**
* Create a string representation of the bson_oid_t.
* @param oid the bson_oid_t source.
* @param str the string representation destination.
*/
-void bson_oid_to_string( const bson_oid_t *oid, char *str );
+MONGO_EXPORT void bson_oid_to_string( const bson_oid_t *oid, char *str );
/**
* Create a bson_oid object.
*
* @param oid the destination for the newly created bson_oid_t.
*/
-void bson_oid_gen( bson_oid_t *oid );
+MONGO_EXPORT void bson_oid_gen( bson_oid_t *oid );
/**
* Set a function to be used to generate the second four bytes
*
* @param func a pointer to a function that returns an int.
*/
-void bson_set_oid_fuzz( int ( *func )( void ) );
+MONGO_EXPORT void bson_set_oid_fuzz( int ( *func )( void ) );
/**
* Set a function to be used to generate the incrementing part
*
* @param func a pointer to a function that returns an int.
*/
-void bson_set_oid_inc( int ( *func )( void ) );
+MONGO_EXPORT void bson_set_oid_inc( int ( *func )( void ) );
/**
* Get the time a bson_oid_t was created.
*
* @param oid the bson_oid_t.
*/
-time_t bson_oid_generated_time( bson_oid_t *oid ); /* Gives the time the OID was created */
+MONGO_EXPORT time_t bson_oid_generated_time( bson_oid_t *oid ); /* Gives the time the OID was created */
/* ----------------------------
BUILDING
* @note When finished, you must pass the bson object to
* bson_destroy( ).
*/
-void bson_init( bson *b );
+MONGO_EXPORT void bson_init( bson *b );
/**
* Initialize a BSON object, and point its data
* @return BSON_OK or BSON_ERROR.
*/
int bson_init_data( bson *b , char *data );
+int bson_init_finished_data( bson *b, char *data ) ;
/**
* Initialize a BSON object, and set its
* @return the standard error code. To deallocate memory,
* call bson_destroy on the bson object.
*/
-int bson_finish( bson *b );
+MONGO_EXPORT int bson_finish( bson *b );
/**
* Destroy a bson object.
* @param b the bson object to destroy.
*
*/
-void bson_destroy( bson *b );
+MONGO_EXPORT void bson_destroy( bson *b );
/**
* Returns a pointer to a static empty BSON object.
* @return the empty initialized BSON object.
*/
/* returns pointer to static empty bson object */
-bson *bson_empty( bson *obj );
-
-/**
- * Copy BSON data only from one object to another.
- *
- * @param out the copy destination BSON object.
- * @param in the copy source BSON object.
- */
-void bson_copy_basic( bson *out, const bson *in );
+MONGO_EXPORT bson *bson_empty( bson *obj );
/**
* Make a complete copy of the a BSON object.
+ * The source bson object must be in a finished
+ * state; otherwise, the copy will fail.
*
* @param out the copy destination BSON object.
* @param in the copy source BSON object.
*/
-void bson_copy( bson *out, const bson *in ); /* puts data in new buffer. NOOP if out==NULL */
+MONGO_EXPORT int bson_copy( bson *out, const bson *in ); /* puts data in new buffer. NOOP if out==NULL */
/**
* Append a previously created bson_oid_t to a bson object.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid );
+MONGO_EXPORT int bson_append_oid( bson *b, const char *name, const bson_oid_t *oid );
/**
* Append a bson_oid_t to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_new_oid( bson *b, const char *name );
+MONGO_EXPORT int bson_append_new_oid( bson *b, const char *name );
/**
* Append an int to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_int( bson *b, const char *name, const int i );
+MONGO_EXPORT int bson_append_int( bson *b, const char *name, const int i );
/**
* Append an long to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_long( bson *b, const char *name, const int64_t i );
+MONGO_EXPORT int bson_append_long( bson *b, const char *name, const int64_t i );
/**
* Append an double to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_double( bson *b, const char *name, const double d );
+MONGO_EXPORT int bson_append_double( bson *b, const char *name, const double d );
/**
* Append a string to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_string( bson *b, const char *name, const char *str );
+MONGO_EXPORT int bson_append_string( bson *b, const char *name, const char *str );
/**
* Append len bytes of a string to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_string_n( bson *b, const char *name, const char *str, int len );
+MONGO_EXPORT int bson_append_string_n( bson *b, const char *name, const char *str, int len );
/**
* Append a symbol to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_symbol( bson *b, const char *name, const char *str );
+MONGO_EXPORT int bson_append_symbol( bson *b, const char *name, const char *str );
/**
* Append len bytes of a symbol to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_symbol_n( bson *b, const char *name, const char *str, int len );
+MONGO_EXPORT int bson_append_symbol_n( bson *b, const char *name, const char *str, int len );
/**
* Append code to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_code( bson *b, const char *name, const char *str );
+MONGO_EXPORT int bson_append_code( bson *b, const char *name, const char *str );
/**
* Append len bytes of code to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_code_n( bson *b, const char *name, const char *str, int len );
+MONGO_EXPORT int bson_append_code_n( bson *b, const char *name, const char *str, int len );
/**
* Append code to a bson with scope.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope );
+MONGO_EXPORT int bson_append_code_w_scope( bson *b, const char *name, const char *code, const bson *scope );
/**
* Append len bytes of code to a bson with scope.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_code_w_scope_n( bson *b, const char *name, const char *code, int size, const bson *scope );
+MONGO_EXPORT int bson_append_code_w_scope_n( bson *b, const char *name, const char *code, int size, const bson *scope );
/**
* Append binary data to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_binary( bson *b, const char *name, char type, const char *str, int len );
+MONGO_EXPORT int bson_append_binary( bson *b, const char *name, char type, const char *str, int len );
/**
* Append a bson_bool_t to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_bool( bson *b, const char *name, const bson_bool_t v );
+MONGO_EXPORT int bson_append_bool( bson *b, const char *name, const bson_bool_t v );
/**
* Append a null value to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_null( bson *b, const char *name );
+MONGO_EXPORT int bson_append_null( bson *b, const char *name );
/**
* Append an undefined value to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_undefined( bson *b, const char *name );
+MONGO_EXPORT int bson_append_undefined( bson *b, const char *name );
/**
* Append a regex value to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts );
+MONGO_EXPORT int bson_append_regex( bson *b, const char *name, const char *pattern, const char *opts );
/**
* Append bson data to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_bson( bson *b, const char *name, const bson *bson );
+MONGO_EXPORT int bson_append_bson( bson *b, const char *name, const bson *bson );
/**
* Append a BSON element to a bson from the current point of an iterator.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem );
+MONGO_EXPORT int bson_append_element( bson *b, const char *name_or_null, const bson_iterator *elem );
/**
* Append a bson_timestamp_t value to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts );
+MONGO_EXPORT int bson_append_timestamp( bson *b, const char *name, bson_timestamp_t *ts );
+MONGO_EXPORT int bson_append_timestamp2( bson *b, const char *name, int time, int increment );
/* these both append a bson_date */
/**
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_date( bson *b, const char *name, bson_date_t millis );
+MONGO_EXPORT int bson_append_date( bson *b, const char *name, bson_date_t millis );
/**
* Append a time_t value to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_time_t( bson *b, const char *name, time_t secs );
+MONGO_EXPORT int bson_append_time_t( bson *b, const char *name, time_t secs );
/**
* Start appending a new object to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_start_object( bson *b, const char *name );
+MONGO_EXPORT int bson_append_start_object( bson *b, const char *name );
/**
* Start appending a new array to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_start_array( bson *b, const char *name );
+MONGO_EXPORT int bson_append_start_array( bson *b, const char *name );
/**
* Finish appending a new object or array to a bson.
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_finish_object( bson *b );
+MONGO_EXPORT int bson_append_finish_object( bson *b );
/**
* Finish appending a new object or array to a bson. This
*
* @return BSON_OK or BSON_ERROR.
*/
-int bson_append_finish_array( bson *b );
+MONGO_EXPORT int bson_append_finish_array( bson *b );
void bson_numstr( char *str, int i );
void bson_incnumstr( char *str );
-/* Error handling and stadard library function over-riding. */
+/* Error handling and standard library function over-riding. */
/* -------------------------------------------------------- */
/* bson_err_handlers shouldn't return!!! */
extern bson_printf_func bson_printf;
extern bson_fprintf_func bson_fprintf;
extern bson_sprintf_func bson_sprintf;
-
extern bson_printf_func bson_errprintf;
/**
*
* @sa malloc(3)
*/
-void *bson_malloc( int size );
+MONGO_EXPORT void *bson_malloc( int size );
/**
* Changes the size of allocated memory and checks return value,
*
* @return the old error handling function, or NULL.
*/
-bson_err_handler set_bson_err_handler( bson_err_handler func );
+MONGO_EXPORT bson_err_handler set_bson_err_handler( bson_err_handler func );
/* does nothing if ok != 0 */
/**
*/
void bson_builder_error( bson *b );
+/**
+ * Cast an int64_t to double. This is necessary for embedding in
+ * certain environments.
+ *
+ */
+MONGO_EXPORT double bson_int64_to_double( int64_t i64 );
+
+MONGO_EXPORT void bson_swap_endian32( void *outp, const void *inp );
+MONGO_EXPORT void bson_swap_endian64( void *outp, const void *inp );
+
MONGO_EXTERN_C_END
#endif
/*
- * Copyright 2009-2011 10gen, Inc.
+ * Copyright 2009-2012 10gen, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/*
- * Copyright 2009-2011 10gen, Inc.
+ * Copyright 2009-2012 10gen, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef _BSON_ENCODING_H_
-#define _BSON_ENCODING_H_
+#ifndef BSON_ENCODING_H_
+#define BSON_ENCODING_H_
MONGO_EXTERN_C_START
--- /dev/null
+/** @file env.h */
+
+/* Copyright 2009-2012 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.
+ */
+
+/* Header for generic net.h */
+#ifndef MONGO_ENV_H_
+#define MONGO_ENV_H_
+
+#include "mongo.h"
+
+MONGO_EXTERN_C_START
+
+/* This is a no-op in the generic implementation. */
+int mongo_env_set_socket_op_timeout( mongo *conn, int millis );
+int mongo_env_read_socket( mongo *conn, void *buf, int len );
+int mongo_env_write_socket( mongo *conn, const void *buf, int len );
+int mongo_env_socket_connect( mongo *conn, const char *host, int port );
+
+/* Initialize socket services */
+MONGO_EXPORT int mongo_env_sock_init( void );
+
+/* Close a socket */
+MONGO_EXPORT int mongo_env_close_socket( int socket );
+
+MONGO_EXTERN_C_END
+#endif
--- /dev/null
+/* env_posix.c */
+
+/* Copyright 2009-2012 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.
+ */
+
+/* Networking and other niceties for POSIX systems. */
+#include "env.h"
+#include "mongo.h"
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+int mongo_env_close_socket( int socket ) {
+ return close( socket );
+}
+
+int mongo_env_sock_init( void ) {
+ return 0;
+}
+
+int mongo_env_write_socket( mongo *conn, const void *buf, int len ) {
+ const char *cbuf = buf;
+#ifdef __APPLE__
+ int flags = 0;
+#else
+ int flags = MSG_NOSIGNAL;
+#endif
+
+ while ( len ) {
+ int sent = send( conn->sock, cbuf, len, flags );
+ if ( sent == -1 ) {
+ if (errno == EPIPE)
+ conn->connected = 0;
+ __mongo_set_error( conn, MONGO_IO_ERROR, strerror( errno ), errno );
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_read_socket( mongo *conn, void *buf, int len ) {
+ char *cbuf = buf;
+ while ( len ) {
+ int sent = recv( conn->sock, cbuf, len, 0 );
+ if ( sent == 0 || sent == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, strerror( errno ), errno );
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_set_socket_op_timeout( mongo *conn, int millis ) {
+ struct timeval tv;
+ tv.tv_sec = millis / 1000;
+ tv.tv_usec = ( millis % 1000 ) * 1000;
+
+ if ( setsockopt( conn->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof( tv ) ) == -1 ) {
+ conn->err = MONGO_IO_ERROR;
+ __mongo_set_error( conn, MONGO_IO_ERROR, "setsockopt SO_RCVTIMEO failed.", errno );
+ return MONGO_ERROR;
+ }
+
+ if ( setsockopt( conn->sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof( tv ) ) == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, "setsockopt SO_SNDTIMEO failed.", errno );
+ return MONGO_ERROR;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_socket_connect( mongo *conn, const char *host, int port ) {
+ char port_str[NI_MAXSERV];
+ int status;
+
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list = NULL;
+ struct addrinfo *ai_ptr = NULL;
+
+ conn->sock = 0;
+ conn->connected = 0;
+ sprintf(port_str,"%d",port);
+
+ bson_sprintf( port_str, "%d", port );
+
+ memset( &ai_hints, 0, sizeof( ai_hints ) );
+#ifdef AI_ADDRCONFIG
+ ai_hints.ai_flags = AI_ADDRCONFIG;
+#endif
+ ai_hints.ai_family = AF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+
+ status = getaddrinfo( host, port_str, &ai_hints, &ai_list );
+ if ( status != 0 ) {
+ bson_errprintf( "getaddrinfo failed: %s", gai_strerror( status ) );
+ conn->err = MONGO_CONN_ADDR_FAIL;
+ return MONGO_ERROR;
+ }
+
+ for ( ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) {
+ conn->sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol );
+ if ( conn->sock < 0 ) {
+ conn->sock = 0;
+ continue;
+ }
+
+ status = connect( conn->sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen );
+ if ( status != 0 ) {
+ mongo_env_close_socket( conn->sock );
+ conn->sock = 0;
+ continue;
+ }
+
+ if ( ai_ptr->ai_protocol == IPPROTO_TCP ) {
+ int flag = 1;
+
+ setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY,
+ ( void * ) &flag, sizeof( flag ) );
+ if ( conn->op_timeout_ms > 0 )
+ mongo_env_set_socket_op_timeout( conn, conn->op_timeout_ms );
+ }
+
+ conn->connected = 1;
+ break;
+ }
+
+ freeaddrinfo( ai_list );
+
+ if ( ! conn->connected ) {
+ conn->err = MONGO_CONN_FAIL;
+ return MONGO_ERROR;
+ }
+
+ return MONGO_OK;
+}
--- /dev/null
+/* env_standard.c */
+
+/* Copyright 2009-2012 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.
+ */
+
+/* Vanilla networking designed to work on all systems. */
+#include "env.h"
+#include <errno.h>
+#include <string.h>
+
+#ifdef _WIN32
+ #ifdef _MSC_VER
+ #include <ws2tcpip.h> // send,recv,socklen_t etc
+ #include <wspiapi.h> // addrinfo
+ #else
+ #include <windows.h>
+ #include <winsock.h>
+ typedef int socklen_t;
+ #endif
+#else
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+int mongo_env_close_socket( int socket ) {
+#ifdef _WIN32
+ return closesocket( socket );
+#else
+ return close( socket );
+#endif
+}
+
+int mongo_env_write_socket( mongo *conn, const void *buf, int len ) {
+ const char *cbuf = buf;
+#ifdef _WIN32
+ int flags = 0;
+#else
+#ifdef __APPLE__
+ int flags = 0;
+#else
+ int flags = MSG_NOSIGNAL;
+#endif
+#endif
+
+ while ( len ) {
+ int sent = send( conn->sock, cbuf, len, flags );
+ if ( sent == -1 ) {
+ if (errno == EPIPE)
+ conn->connected = 0;
+ conn->err = MONGO_IO_ERROR;
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_read_socket( mongo *conn, void *buf, int len ) {
+ char *cbuf = buf;
+ while ( len ) {
+ int sent = recv( conn->sock, cbuf, len, 0 );
+ if ( sent == 0 || sent == -1 ) {
+ conn->err = MONGO_IO_ERROR;
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+/* This is a no-op in the generic implementation. */
+int mongo_env_set_socket_op_timeout( mongo *conn, int millis ) {
+ return MONGO_OK;
+}
+
+int mongo_env_socket_connect( mongo *conn, const char *host, int port ) {
+ struct sockaddr_in sa;
+ socklen_t addressSize;
+ int flag = 1;
+
+ if ( ( conn->sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) {
+ conn->sock = 0;
+ conn->err = MONGO_CONN_NO_SOCKET;
+ return MONGO_ERROR;
+ }
+
+ memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) );
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons( port );
+ sa.sin_addr.s_addr = inet_addr( host );
+ addressSize = sizeof( sa );
+
+ if ( connect( conn->sock, ( struct sockaddr * )&sa, addressSize ) == -1 ) {
+ mongo_env_close_socket( conn->sock );
+ conn->connected = 0;
+ conn->sock = 0;
+ conn->err = MONGO_CONN_FAIL;
+ return MONGO_ERROR;
+ }
+
+ setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * ) &flag, sizeof( flag ) );
+
+ if( conn->op_timeout_ms > 0 )
+ mongo_env_set_socket_op_timeout( conn, conn->op_timeout_ms );
+
+ conn->connected = 1;
+
+ return MONGO_OK;
+}
+
+MONGO_EXPORT int mongo_env_sock_init( void ) {
+
+#if defined(_WIN32)
+ WSADATA wsaData;
+ WORD wVers;
+#elif defined(SIGPIPE)
+ struct sigaction act;
+#endif
+
+ static int called_once;
+ static int retval;
+ if (called_once) return retval;
+ called_once = 1;
+
+#if defined(_WIN32)
+ wVers = MAKEWORD(1, 1);
+ retval = (WSAStartup(wVers, &wsaData) == 0);
+#elif defined(MACINTOSH)
+ GUSISetup(GUSIwithInternetSockets);
+ retval = 1;
+#elif defined(SIGPIPE)
+ retval = 1;
+ if (sigaction(SIGPIPE, (struct sigaction *)NULL, &act) < 0)
+ retval = 0;
+ else if (act.sa_handler == SIG_DFL) {
+ act.sa_handler = SIG_IGN;
+ if (sigaction(SIGPIPE, &act, (struct sigaction *)NULL) < 0)
+ retval = 0;
+ }
+#endif
+ return retval;
+}
--- /dev/null
+/* env_win32.c */
+
+/* Copyright 2009-2012 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.
+ */
+
+/* Networking and other niceties for WIN32. */
+#include "env.h"
+#include "mongo.h"
+#include <string.h>
+
+#ifdef _MSC_VER
+#include <ws2tcpip.h> // send,recv,socklen_t etc
+#include <wspiapi.h> // addrinfo
+#else
+#include <windows.h>
+#include <winsock.h>
+typedef int socklen_t;
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+static void mongo_clear_errors( mongo *conn ) {
+ conn->err = 0;
+ memset( conn->errstr, 0, MONGO_ERR_LEN );
+}
+
+int mongo_env_close_socket( int socket ) {
+ return closesocket( socket );
+}
+
+int mongo_env_write_socket( mongo *conn, const void *buf, int len ) {
+ const char *cbuf = buf;
+ int flags = 0;
+
+ while ( len ) {
+ int sent = send( conn->sock, cbuf, len, flags );
+ if ( sent == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, NULL, WSAGetLastError() );
+ conn->connected = 0;
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_read_socket( mongo *conn, void *buf, int len ) {
+ char *cbuf = buf;
+
+ while ( len ) {
+ int sent = recv( conn->sock, cbuf, len, 0 );
+ if ( sent == 0 || sent == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, NULL, WSAGetLastError() );
+ return MONGO_ERROR;
+ }
+ cbuf += sent;
+ len -= sent;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_set_socket_op_timeout( mongo *conn, int millis ) {
+ if ( setsockopt( conn->sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&millis,
+ sizeof( millis ) ) == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, "setsockopt SO_RCVTIMEO failed.",
+ WSAGetLastError() );
+ return MONGO_ERROR;
+ }
+
+ if ( setsockopt( conn->sock, SOL_SOCKET, SO_SNDTIMEO, (const char *)&millis,
+ sizeof( millis ) ) == -1 ) {
+ __mongo_set_error( conn, MONGO_IO_ERROR, "setsockopt SO_SNDTIMEO failed.",
+ WSAGetLastError() );
+ return MONGO_ERROR;
+ }
+
+ return MONGO_OK;
+}
+
+int mongo_env_socket_connect( mongo *conn, const char *host, int port ) {
+ char port_str[NI_MAXSERV];
+ char errstr[MONGO_ERR_LEN];
+ int status;
+
+ struct addrinfo ai_hints;
+ struct addrinfo *ai_list = NULL;
+ struct addrinfo *ai_ptr = NULL;
+
+ conn->sock = 0;
+ conn->connected = 0;
+
+ bson_sprintf( port_str, "%d", port );
+
+ memset( &ai_hints, 0, sizeof( ai_hints ) );
+ ai_hints.ai_family = AF_UNSPEC;
+ ai_hints.ai_socktype = SOCK_STREAM;
+ ai_hints.ai_protocol = IPPROTO_TCP;
+
+ status = getaddrinfo( host, port_str, &ai_hints, &ai_list );
+ if ( status != 0 ) {
+ bson_sprintf( errstr, "getaddrinfo failed with error %d", status );
+ __mongo_set_error( conn, MONGO_CONN_ADDR_FAIL, errstr, WSAGetLastError() );
+ return MONGO_ERROR;
+ }
+
+ for ( ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next ) {
+ conn->sock = socket( ai_ptr->ai_family, ai_ptr->ai_socktype,
+ ai_ptr->ai_protocol );
+
+ if ( conn->sock < 0 ) {
+ __mongo_set_error( conn, MONGO_SOCKET_ERROR, "socket() failed",
+ WSAGetLastError() );
+ conn->sock = 0;
+ continue;
+ }
+
+ status = connect( conn->sock, ai_ptr->ai_addr, ai_ptr->ai_addrlen );
+ if ( status != 0 ) {
+ __mongo_set_error( conn, MONGO_SOCKET_ERROR, "connect() failed",
+ WSAGetLastError() );
+ mongo_env_close_socket( conn->sock );
+ conn->sock = 0;
+ continue;
+ }
+
+ if ( ai_ptr->ai_protocol == IPPROTO_TCP ) {
+ int flag = 1;
+
+ setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY,
+ ( void * ) &flag, sizeof( flag ) );
+
+ if ( conn->op_timeout_ms > 0 )
+ mongo_env_set_socket_op_timeout( conn, conn->op_timeout_ms );
+ }
+
+ conn->connected = 1;
+ break;
+ }
+
+ freeaddrinfo( ai_list );
+
+ if ( ! conn->connected ) {
+ conn->err = MONGO_CONN_FAIL;
+ return MONGO_ERROR;
+ }
+ else {
+ mongo_clear_errors( conn );
+ return MONGO_OK;
+ }
+}
+
+MONGO_EXPORT int mongo_env_sock_init( void ) {
+
+ WSADATA wsaData;
+ WORD wVers;
+ static int called_once;
+ static int retval;
+
+ if (called_once) return retval;
+
+ called_once = 1;
+ wVers = MAKEWORD(1, 1);
+ retval = (WSAStartup(wVers, &wsaData) == 0);
+
+ return retval;
+}
/* gridfs.c */
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <string.h>
#include <assert.h>
+MONGO_EXPORT gridfs* gridfs_create() {
+ return (gridfs*)bson_malloc(sizeof(gridfs));
+}
+
+MONGO_EXPORT void gridfs_dispose(gridfs* gfs) {
+ free(gfs);
+}
+
+MONGO_EXPORT gridfile* gridfile_create() {
+ return (gridfile*)bson_malloc(sizeof(gridfile));
+}
+
+MONGO_EXPORT void gridfile_dispose(gridfile* gf) {
+ free(gf);
+}
+
+MONGO_EXPORT void gridfile_get_descriptor(gridfile* gf, bson* out) {
+ *out = *gf->meta;
+}
+
+
static bson *chunk_new( bson_oid_t id, int chunkNumber,
const char *data, int len ) {
bson *b = bson_malloc( sizeof( bson ) );
return MONGO_OK;
}
-void gridfs_destroy( gridfs *gfs ) {
+MONGO_EXPORT void gridfs_destroy( gridfs *gfs ) {
if ( gfs == NULL ) return;
if ( gfs->dbname ) bson_free( ( char * )gfs->dbname );
if ( gfs->prefix ) bson_free( ( char * )gfs->prefix );
bson res;
bson_iterator it;
int result;
+ int64_t d;
/* Check run md5 */
bson_init( &command );
bson_append_oid( &command, "filemd5", &id );
bson_append_string( &command, "root", gfs->prefix );
bson_finish( &command );
- assert( mongo_run_command( gfs->client, gfs->dbname, &command, &res ) == MONGO_OK );
+ result = mongo_run_command( gfs->client, gfs->dbname, &command, &res );
bson_destroy( &command );
+ if (result != MONGO_OK)
+ return result;
/* Create and insert BSON for file metadata */
bson_init( &ret );
}
bson_append_long( &ret, "length", length );
bson_append_int( &ret, "chunkSize", DEFAULT_CHUNK_SIZE );
- bson_append_date( &ret, "uploadDate", ( bson_date_t )1000*time( NULL ) );
+ d = ( bson_date_t )1000*time( NULL );
+ bson_append_date( &ret, "uploadDate", d);
bson_find( &it, &res, "md5" );
bson_append_string( &ret, "md5", bson_iterator_string( &it ) );
bson_destroy( &res );
return result;
}
-int gridfs_store_buffer( gridfs *gfs, const char *data,
+MONGO_EXPORT int gridfs_store_buffer( gridfs *gfs, const char *data,
gridfs_offset length, const char *remotename,
const char *contenttype ) {
bson *oChunk;
/* Large files Assertion */
- assert( length <= 0xffffffff );
+ /* assert( length <= 0xffffffff ); */
/* Generate and append an oid*/
bson_oid_gen( &id );
return gridfs_insert_file( gfs, remotename, id, length, contenttype );
}
-void gridfile_writer_init( gridfile *gfile, gridfs *gfs,
+MONGO_EXPORT void gridfile_writer_init( gridfile *gfile, gridfs *gfs,
const char *remote_name, const char *content_type ) {
gfile->gfs = gfs;
strcpy( ( char * )gfile->content_type, content_type );
}
-void gridfile_write_buffer( gridfile *gfile, const char *data,
+MONGO_EXPORT void gridfile_write_buffer( gridfile *gfile, const char *data,
gridfs_offset length ) {
int bytes_left = 0;
gfile->pending_len += length;
} else { /* At least one chunk of data to write */
+ chunks_to_write = to_write / DEFAULT_CHUNK_SIZE;
+ bytes_left = to_write % DEFAULT_CHUNK_SIZE;
/* If there's a pending chunk to be written, we need to combine
* the buffer provided up to DEFAULT_CHUNK_SIZE.
*/
if ( gfile->pending_len > 0 ) {
- chunks_to_write = to_write / DEFAULT_CHUNK_SIZE;
- bytes_left = to_write % DEFAULT_CHUNK_SIZE;
-
data_partial_len = DEFAULT_CHUNK_SIZE - gfile->pending_len;
buffer = ( char * )bson_malloc( DEFAULT_CHUNK_SIZE );
memcpy( buffer, gfile->pending_data, gfile->pending_len );
}
}
-int gridfile_writer_done( gridfile *gfile ) {
+MONGO_EXPORT int gridfile_writer_done( gridfile *gfile ) {
/* write any remaining pending chunk data.
* pending data will always take up less than one chunk */
/* Open the file and the correct stream */
if ( strcmp( filename, "-" ) == 0 ) fd = stdin;
- else fd = fopen( filename, "rb" );
- assert( fd != NULL ); /* No such file */
+ else {
+ fd = fopen( filename, "rb" );
+ if (fd == NULL)
+ return MONGO_ERROR;
+ }
/* Generate and append an oid*/
bson_oid_gen( &id );
return gridfs_insert_file( gfs, remotename, id, length, contenttype );
}
-void gridfs_remove_filename( gridfs *gfs, const char *filename ) {
+MONGO_EXPORT void gridfs_remove_filename( gridfs *gfs, const char *filename ) {
bson query;
mongo_cursor *files;
bson file;
return MONGO_OK;
}
-void gridfile_destroy( gridfile *gfile )
+MONGO_EXPORT void gridfile_destroy( gridfile *gfile )
{
bson_destroy( gfile->meta );
return ( bson_bool_t )( gfile != NULL || gfile->meta == NULL );
}
-const char *gridfile_get_filename( gridfile *gfile ) {
+MONGO_EXPORT const char *gridfile_get_filename( gridfile *gfile ) {
bson_iterator it;
bson_find( &it, gfile->meta, "filename" );
return bson_iterator_string( &it );
}
-int gridfile_get_chunksize( gridfile *gfile ) {
+MONGO_EXPORT int gridfile_get_chunksize( gridfile *gfile ) {
bson_iterator it;
bson_find( &it, gfile->meta, "chunkSize" );
return bson_iterator_int( &it );
}
-gridfs_offset gridfile_get_contentlength( gridfile *gfile ) {
+MONGO_EXPORT gridfs_offset gridfile_get_contentlength( gridfile *gfile ) {
bson_iterator it;
bson_find( &it, gfile->meta, "length" );
return ( gridfs_offset )bson_iterator_long( &it );
}
-const char *gridfile_get_contenttype( gridfile *gfile ) {
+MONGO_EXPORT const char *gridfile_get_contenttype( gridfile *gfile ) {
bson_iterator it;
if ( bson_find( &it, gfile->meta, "contentType" ) )
else return NULL;
}
-bson_date_t gridfile_get_uploaddate( gridfile *gfile ) {
+MONGO_EXPORT bson_date_t gridfile_get_uploaddate( gridfile *gfile ) {
bson_iterator it;
bson_find( &it, gfile->meta, "uploadDate" );
return bson_iterator_date( &it );
}
-const char *gridfile_get_md5( gridfile *gfile ) {
+MONGO_EXPORT const char *gridfile_get_md5( gridfile *gfile ) {
bson_iterator it;
bson_find( &it, gfile->meta, "md5" );
return bson_iterator_bool( &it );
}
-bson gridfile_get_metadata( gridfile *gfile ) {
- bson sub;
+MONGO_EXPORT void gridfile_get_metadata( gridfile *gfile, bson* out ) {
bson_iterator it;
- if ( bson_find( &it, gfile->meta, "metadata" ) ) {
- bson_iterator_subobject( &it, &sub );
- return sub;
- } else {
- bson_empty( &sub );
- return sub;
- }
+ if ( bson_find( &it, gfile->meta, "metadata" ) )
+ bson_iterator_subobject( &it, out );
+ else
+ bson_empty( out );
}
-int gridfile_get_numchunks( gridfile *gfile ) {
+MONGO_EXPORT int gridfile_get_numchunks( gridfile *gfile ) {
bson_iterator it;
gridfs_offset length;
gridfs_offset chunkSize;
: ( int )( numchunks );
}
-bson gridfile_get_chunk( gridfile *gfile, int n ) {
+MONGO_EXPORT void gridfile_get_chunk( gridfile *gfile, int n, bson* out ) {
bson query;
- bson out;
+
bson_iterator it;
bson_oid_t id;
+ int result;
bson_init( &query );
bson_find( &it, gfile->meta, "_id" );
bson_append_int( &query, "n", n );
bson_finish( &query );
- assert( mongo_find_one( gfile->gfs->client,
- gfile->gfs->chunks_ns,
- &query, NULL, &out ) == MONGO_OK );
-
+ result = (mongo_find_one(gfile->gfs->client,
+ gfile->gfs->chunks_ns,
+ &query, NULL, out ) == MONGO_OK );
bson_destroy( &query );
- return out;
+ if (!result) {
+ bson empty;
+ bson_empty(&empty);
+ bson_copy(out, &empty);
+ }
}
-mongo_cursor *gridfile_get_chunks( gridfile *gfile, int start, int size ) {
+MONGO_EXPORT mongo_cursor *gridfile_get_chunks( gridfile *gfile, int start, int size ) {
bson_iterator it;
bson_oid_t id;
bson gte;
const int num = gridfile_get_numchunks( gfile );
for ( i=0; i<num; i++ ) {
- chunk = gridfile_get_chunk( gfile, i );
+ gridfile_get_chunk( gfile, i, &chunk );
bson_find( &it, &chunk, "data" );
len = bson_iterator_bin_len( &it );
data = bson_iterator_bin_data( &it );
- fwrite( data , sizeof( char ), len, stream );
+ fwrite( data, sizeof( char ), len, stream );
bson_destroy( &chunk );
}
return gridfile_get_contentlength( gfile );
}
-gridfs_offset gridfile_read( gridfile *gfile, gridfs_offset size, char *buf ) {
+MONGO_EXPORT gridfs_offset gridfile_read( gridfile *gfile, gridfs_offset size, char *buf ) {
mongo_cursor *chunks;
bson chunk;
return size;
}
-gridfs_offset gridfile_seek( gridfile *gfile, gridfs_offset offset ) {
+MONGO_EXPORT gridfs_offset gridfile_seek( gridfile *gfile, gridfs_offset offset ) {
gridfs_offset length;
length = gridfile_get_contentlength( gfile );
*
* */
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "mongo.h"
-#ifndef GRIDFS_INCLUDED
-#define GRIDFS_INCLUDED
+#ifndef MONGO_GRIDFS_H_
+#define MONGO_GRIDFS_H_
enum {DEFAULT_CHUNK_SIZE = 256 * 1024};
int pending_len; /**> Length of pending_data buffer */
} gridfile;
+MONGO_EXPORT gridfs* gridfs_create();
+MONGO_EXPORT void gridfs_dispose(gridfs* gfs);
+MONGO_EXPORT gridfile* gridfile_create();
+MONGO_EXPORT void gridfile_dispose(gridfile* gf);
+MONGO_EXPORT void gridfile_get_descriptor(gridfile* gf, bson* out);
+
/**
* Initializes a GridFS object
* @param client - db connection
*
* @return - MONGO_OK or MONGO_ERROR.
*/
-int gridfs_init( mongo *client, const char *dbname,
+MONGO_EXPORT int gridfs_init( mongo *client, const char *dbname,
const char *prefix, gridfs *gfs );
/**
*
* @param gfs a grid
*/
-void gridfs_destroy( gridfs *gfs );
+MONGO_EXPORT void gridfs_destroy( gridfs *gfs );
/**
* Initializes a gridfile for writing incrementally with gridfs_write_buffer.
* When done, you must call gridfs_writer_done to save the file metadata.
*
*/
-void gridfile_writer_init( gridfile *gfile, gridfs *gfs, const char *remote_name,
+MONGO_EXPORT void gridfile_writer_init( gridfile *gfile, gridfs *gfs, const char *remote_name,
const char *content_type );
/**
* stream to a GridFS file. When finished, be sure to call gridfs_writer_done.
*
*/
-void gridfile_write_buffer( gridfile *gfile, const char *data,
+MONGO_EXPORT void gridfile_write_buffer( gridfile *gfile, const char *data,
gridfs_offset length );
/**
*
* @return - MONGO_OK or MONGO_ERROR.
*/
-int gridfile_writer_done( gridfile *gfile );
+MONGO_EXPORT int gridfile_writer_done( gridfile *gfile );
/**
* Store a buffer as a GridFS file.
*
* @return - MONGO_OK or MONGO_ERROR.
*/
-int gridfs_store_buffer( gridfs *gfs, const char *data, gridfs_offset length,
+MONGO_EXPORT int gridfs_store_buffer( gridfs *gfs, const char *data, gridfs_offset length,
const char *remotename,
const char *contenttype );
*
* @return - MONGO_OK or MONGO_ERROR.
*/
-int gridfs_store_file( gridfs *gfs, const char *filename,
+MONGO_EXPORT int gridfs_store_file( gridfs *gfs, const char *filename,
const char *remotename, const char *contenttype );
/**
* @param gfs - the working GridFS
* @param filename - the filename of the file/s to be removed
*/
-void gridfs_remove_filename( gridfs *gfs, const char *filename );
+MONGO_EXPORT void gridfs_remove_filename( gridfs *gfs, const char *filename );
/**
* Find the first file matching the provided query within the
*
* @return MONGO_OK if successful, MONGO_ERROR otherwise
*/
-int gridfs_find_query( gridfs *gfs, bson *query, gridfile *gfile );
+MONGO_EXPORT int gridfs_find_query( gridfs *gfs, bson *query, gridfile *gfile );
/**
* Find the first file referenced by filename within the GridFS
*
* @return MONGO_OK or MONGO_ERROR.
*/
-int gridfs_find_filename( gridfs *gfs, const char *filename, gridfile *gfile );
+MONGO_EXPORT int gridfs_find_filename( gridfs *gfs, const char *filename, gridfile *gfile );
/**
* Initializes a GridFile containing the GridFS and file bson
*
* @return - MONGO_OK or MONGO_ERROR.
*/
-int gridfile_init( gridfs *gfs, bson *meta, gridfile *gfile );
+MONGO_EXPORT int gridfile_init( gridfs *gfs, bson *meta, gridfile *gfile );
/**
* Destroys the GridFile
*
* @param oGridFIle - the GridFile being destroyed
*/
-void gridfile_destroy( gridfile *gfile );
+MONGO_EXPORT void gridfile_destroy( gridfile *gfile );
/**
* Returns whether or not the GridFile exists
* @param gfile - the GridFile being examined
*/
-bson_bool_t gridfile_exists( gridfile *gfile );
+MONGO_EXPORT bson_bool_t gridfile_exists( gridfile *gfile );
/**
* Returns the filename of GridFile
*
* @return - the filename of the Gridfile
*/
-const char *gridfile_get_filename( gridfile *gfile );
+MONGO_EXPORT const char *gridfile_get_filename( gridfile *gfile );
/**
* Returns the size of the chunks of the GridFile
*
* @return - the size of the chunks of the Gridfile
*/
-int gridfile_get_chunksize( gridfile *gfile );
+MONGO_EXPORT int gridfile_get_chunksize( gridfile *gfile );
/**
* Returns the length of GridFile's data
*
* @return - the length of the Gridfile's data
*/
-gridfs_offset gridfile_get_contentlength( gridfile *gfile );
+MONGO_EXPORT gridfs_offset gridfile_get_contentlength( gridfile *gfile );
/**
* Returns the MIME type of the GridFile
* @return - the MIME type of the Gridfile
* (NULL if no type specified)
*/
-const char *gridfile_get_contenttype( gridfile *gfile );
+MONGO_EXPORT const char *gridfile_get_contenttype( gridfile *gfile );
/**
* Returns the upload date of GridFile
*
* @return - the upload date of the Gridfile
*/
-bson_date_t gridfile_get_uploaddate( gridfile *gfile );
+MONGO_EXPORT bson_date_t gridfile_get_uploaddate( gridfile *gfile );
/**
* Returns the MD5 of GridFile
*
* @return - the MD5 of the Gridfile
*/
-const char *gridfile_get_md5( gridfile *gfile );
+MONGO_EXPORT const char *gridfile_get_md5( gridfile *gfile );
/**
* Returns the field in GridFile specified by name
* @return - the metadata of the Gridfile in a bson object
* (an empty bson is returned if none exists)
*/
-bson gridfile_get_metadata( gridfile *gfile );
+MONGO_EXPORT void gridfile_get_metadata( gridfile *gfile, bson* out );
/**
* Returns the number of chunks in the GridFile
*
* @return - the number of chunks in the Gridfile
*/
-int gridfile_get_numchunks( gridfile *gfile );
+MONGO_EXPORT int gridfile_get_numchunks( gridfile *gfile );
/**
* Returns chunk n of GridFile
*
* @return - the nth chunk of the Gridfile
*/
-bson gridfile_get_chunk( gridfile *gfile, int n );
+MONGO_EXPORT void gridfile_get_chunk( gridfile *gfile, int n, bson* out );
/**
* Returns a mongo_cursor of *size* chunks starting with chunk *start*
*
* @return - mongo_cursor of the chunks (must be destroyed after use)
*/
-mongo_cursor *gridfile_get_chunks( gridfile *gfile, int start, int size );
+MONGO_EXPORT mongo_cursor *gridfile_get_chunks( gridfile *gfile, int start, int size );
/**
* Writes the GridFile to a stream
* @param gfile - the working GridFile
* @param stream - the file stream to write to
*/
-gridfs_offset gridfile_write_file( gridfile *gfile, FILE *stream );
+MONGO_EXPORT gridfs_offset gridfile_write_file( gridfile *gfile, FILE *stream );
/**
* Reads length bytes from the GridFile to a buffer
*
* @return - the number of bytes read
*/
-gridfs_offset gridfile_read( gridfile *gfile, gridfs_offset size, char *buf );
+MONGO_EXPORT gridfs_offset gridfile_read( gridfile *gfile, gridfs_offset size, char *buf );
/**
* Updates the position in the file
*
* @return - resulting offset location
*/
-gridfs_offset gridfile_seek( gridfile *gfile, gridfs_offset offset );
+MONGO_EXPORT gridfs_offset gridfile_seek( gridfile *gfile, gridfs_offset offset );
#endif
pms->abcd[3] += d;
}
-void
+MONGO_EXPORT void
mongo_md5_init(mongo_md5_state_t *pms)
{
pms->count[0] = pms->count[1] = 0;
pms->abcd[3] = 0x10325476;
}
-void
+MONGO_EXPORT void
mongo_md5_append(mongo_md5_state_t *pms, const mongo_md5_byte_t *data, int nbytes)
{
const mongo_md5_byte_t *p = data;
memcpy(pms->buf, p, left);
}
-void
+MONGO_EXPORT void
mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16])
{
static const mongo_md5_byte_t pad[64] = {
1999-05-03 lpd Original version.
*/
-#ifndef md5_INCLUDED
-# define md5_INCLUDED
+#ifndef MONGO_MD5_H_
+#define MONGO_MD5_H_
/*
* This package supports both compile-time and run-time determination of CPU
* 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.
*/
+#include "bson.h"
typedef unsigned char mongo_md5_byte_t; /* 8-bit byte */
typedef unsigned int mongo_md5_word_t; /* 32-bit word */
{
#endif
- /* Initialize the algorithm. */
- void mongo_md5_init(mongo_md5_state_t *pms);
+/* Initialize the algorithm. */
+MONGO_EXPORT 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);
+/* Append a string to the message. */
+MONGO_EXPORT 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]);
+/* Finish the message and return the digest. */
+MONGO_EXPORT void mongo_md5_finish(mongo_md5_state_t *pms, mongo_md5_byte_t digest[16]);
#ifdef __cplusplus
} /* end extern "C" */
#endif
-#endif /* md5_INCLUDED */
+#endif /* MONGO_MD5_H_ */
/* mongo.c */
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "mongo.h"
#include "md5.h"
+#include "env.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#ifdef _USE_LINUX_SYSTEM
-#include "platform/linux/net.h"
-#elif defined _USE_CUSTOM_SYSTEM
-#include "platform/custom/net.h"
-#else
-#include "net.h"
-#endif
+MONGO_EXPORT mongo* mongo_create() {
+ return (mongo*)bson_malloc(sizeof(mongo));
+}
+
+
+MONGO_EXPORT void mongo_dispose(mongo* conn) {
+ free(conn);
+}
+
+MONGO_EXPORT int mongo_get_err(mongo* conn) {
+ return conn->err;
+}
+
+
+MONGO_EXPORT int mongo_is_connected(mongo* conn) {
+ return conn->connected != 0;
+}
+
+
+MONGO_EXPORT int mongo_get_op_timeout(mongo* conn) {
+ return conn->op_timeout_ms;
+}
+
+
+const char* _get_host_port(mongo_host_port* hp) {
+ static char _hp[sizeof(hp->host)+12];
+ bson_sprintf(_hp, "%s:%d", hp->host, hp->port);
+ return _hp;
+}
+
+
+MONGO_EXPORT const char* mongo_get_primary(mongo* conn) {
+ mongo* conn_ = (mongo*)conn;
+ return _get_host_port(conn_->primary);
+}
+
+
+MONGO_EXPORT int mongo_get_socket(mongo* conn) {
+ mongo* conn_ = (mongo*)conn;
+ return conn_->sock;
+}
+
+
+MONGO_EXPORT int mongo_get_host_count(mongo* conn) {
+ mongo_replset* r = conn->replset;
+ mongo_host_port* hp;
+ int count = 0;
+ if (!r) return 0;
+ for (hp = r->hosts; hp; hp = hp->next)
+ ++count;
+ return count;
+}
+
+
+MONGO_EXPORT const char* mongo_get_host(mongo* conn, int i) {
+ mongo_replset* r = conn->replset;
+ mongo_host_port* hp;
+ int count = 0;
+ if (!r) return 0;
+ for (hp = r->hosts; hp; hp = hp->next) {
+ if (count == i)
+ return _get_host_port(hp);
+ ++count;
+ }
+ return 0;
+}
+
+
+MONGO_EXPORT mongo_cursor* mongo_cursor_create() {
+ return (mongo_cursor*)bson_malloc(sizeof(mongo_cursor));
+}
+
+
+MONGO_EXPORT void mongo_cursor_dispose(mongo_cursor* cursor) {
+ free(cursor);
+}
+
+
+MONGO_EXPORT int mongo_get_server_err(mongo* conn) {
+ return conn->lasterrcode;
+}
+
+
+MONGO_EXPORT const char* mongo_get_server_err_string(mongo* conn) {
+ return conn->lasterrstr;
+}
+
+MONGO_EXPORT void __mongo_set_error( mongo *conn, mongo_error_t err, const char *str,
+ int errcode ) {
+ int errstr_size, str_size;
+
+ conn->err = err;
+ conn->errcode = errcode;
+
+ if( str ) {
+ str_size = strlen( str ) + 1;
+ errstr_size = str_size > MONGO_ERR_LEN ? MONGO_ERR_LEN : str_size;
+ memcpy( conn->errstr, str, errstr_size );
+ conn->errstr[errstr_size] = '\0';
+ }
+}
+
+MONGO_EXPORT void mongo_clear_errors( mongo *conn ) {
+ conn->err = 0;
+ conn->errcode = 0;
+ conn->lasterrcode = 0;
+ memset( conn->errstr, 0, MONGO_ERR_LEN );
+ memset( conn->lasterrstr, 0, MONGO_ERR_LEN );
+}
+
+MONGO_EXPORT int mongo_validate_ns( mongo *conn, const char *ns ) {
+ char *last = NULL;
+ char *current = NULL;
+ const char *db_name = ns;
+ char *collection_name = NULL;
+ char errmsg[64];
+ int ns_len = 0;
+
+ /* If the first character is a '.', fail. */
+ if( *ns == '.' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID, "ns cannot start with a '.'.", 0 );
+ return MONGO_ERROR;
+ }
+
+ /* Find the division between database and collection names. */
+ for( current = (char *)ns; *current != '\0'; current++ ) {
+ if( *current == '.' ) {
+ current++;
+ break;
+ }
+ }
+
+ /* Fail because the ns doesn't contain a '.'
+ * or the collection part starts with a dot. */
+ if( *current == '\0' || *current == '.' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID, "ns cannot start with a '.'.", 0 );
+ return MONGO_ERROR;
+ }
+
+ /* Fail if collection length is 0. */
+ if( *(current + 1) == '\0' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID, "Collection name missing.", 0 );
+ return MONGO_ERROR;
+ }
+
+
+ /* Point to the beginning of the collection name. */
+ collection_name = current;
+
+ /* Ensure that the database name is greater than one char.*/
+ if( collection_name - 1 == db_name ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID, "Database name missing.", 0 );
+ return MONGO_ERROR;
+ }
+
+ /* Go back and validate the database name. */
+ for( current = (char *)db_name; *current != '.'; current++ ) {
+ switch( *current ) {
+ case ' ':
+ case '$':
+ case '/':
+ case '\\':
+ __mongo_set_error( conn, MONGO_NS_INVALID,
+ "Database name may not contain ' ', '$', '/', or '\\'", 0 );
+ return MONGO_ERROR;
+ default:
+ break;
+ }
+
+ ns_len++;
+ }
+
+ /* Add one to the length for the '.' character. */
+ ns_len++;
+
+ /* Now validate the collection name. */
+ for( current = collection_name; *current != '\0'; current++ ) {
+
+ /* Cannot have two consecutive dots. */
+ if( last && *last == '.' && *current == '.' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID,
+ "Collection may not contain two consecutive '.'", 0 );
+ return MONGO_ERROR;
+ }
+
+ /* Cannot contain a '$' */
+ if( *current == '$' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID,
+ "Collection may not contain '$'", 0 );
+ return MONGO_ERROR;
+ }
+
+ last = current;
+ ns_len++;
+ }
+
+ if( ns_len > 128 ) {
+ bson_sprintf( errmsg, "Namespace too long; has %d but must <= 128.",
+ ns_len );
+ __mongo_set_error( conn, MONGO_NS_INVALID, errmsg, 0 );
+ return MONGO_ERROR;
+ }
+
+ /* Cannot end with a '.' */
+ if( *(current - 1) == '.' ) {
+ __mongo_set_error( conn, MONGO_NS_INVALID,
+ "Collection may not end with '.'", 0 );
+ return MONGO_ERROR;
+ }
+
+ return MONGO_OK;
+}
+
+static void mongo_set_last_error( mongo *conn, bson_iterator *it, bson *obj ) {
+ int result_len = bson_iterator_string_len( it );
+ const char *result_string = bson_iterator_string( it );
+ int len = result_len < MONGO_ERR_LEN ? result_len : MONGO_ERR_LEN;
+ memcpy( conn->lasterrstr, result_string, len );
+
+ if( bson_find( it, obj, "code" ) != BSON_NULL )
+ conn->lasterrcode = bson_iterator_int( it );
+}
static const int ZERO = 0;
static const int ONE = 1;
bson_little_endian32( &head.responseTo, &mm->head.responseTo );
bson_little_endian32( &head.op, &mm->head.op );
- res = mongo_write_socket( conn, &head, sizeof( head ) );
+ res = mongo_env_write_socket( conn, &head, sizeof( head ) );
if( res != MONGO_OK ) {
bson_free( mm );
return res;
}
- res = mongo_write_socket( conn, &mm->data, mm->head.len - sizeof( head ) );
+ res = mongo_env_write_socket( conn, &mm->data, mm->head.len - sizeof( head ) );
if( res != MONGO_OK ) {
bson_free( mm );
return res;
unsigned int len;
int res;
- mongo_read_socket( conn, &head, sizeof( head ) );
- mongo_read_socket( conn, &fields, sizeof( fields ) );
+ mongo_env_read_socket( conn, &head, sizeof( head ) );
+ mongo_env_read_socket( conn, &fields, sizeof( fields ) );
bson_little_endian32( &len, &head.len );
bson_little_endian32( &out->fields.start, &fields.start );
bson_little_endian32( &out->fields.num, &fields.num );
- res = mongo_read_socket( conn, &out->objs, len-sizeof( head )-sizeof( fields ) );
+ res = mongo_env_read_socket( conn, &out->objs, len-sizeof( head )-sizeof( fields ) );
if( res != MONGO_OK ) {
bson_free( out );
return res;
bson out;
bson_iterator it;
bson_bool_t ismaster = 0;
+ int max_bson_size = MONGO_DEFAULT_MAX_BSON_SIZE;
out.data = NULL;
if ( mongo_simple_int_command( conn, "admin", "ismaster", 1, &out ) == MONGO_OK ) {
if( bson_find( &it, &out, "ismaster" ) )
ismaster = bson_iterator_bool( &it );
+ if( bson_find( &it, &out, "maxBsonObjectSize" ) ) {
+ max_bson_size = bson_iterator_int( &it );
+ }
+ conn->max_bson_size = max_bson_size;
} else {
return MONGO_ERROR;
}
}
}
-void mongo_init( mongo *conn ) {
- conn->replset = NULL;
- conn->err = 0;
- conn->errstr = NULL;
- conn->lasterrcode = 0;
- conn->lasterrstr = NULL;
+MONGO_EXPORT void mongo_init_sockets( void ) {
+ mongo_env_sock_init();
+}
+
- conn->conn_timeout_ms = 0;
- conn->op_timeout_ms = 0;
+MONGO_EXPORT void mongo_init( mongo *conn ) {
+ memset( conn, 0, sizeof( mongo ) );
+ conn->max_bson_size = MONGO_DEFAULT_MAX_BSON_SIZE;
}
-int mongo_connect( mongo *conn , const char *host, int port ) {
+MONGO_EXPORT int mongo_connect( mongo *conn , const char *host, int port ) {
+ mongo_init( conn );
+
conn->primary = bson_malloc( sizeof( mongo_host_port ) );
strncpy( conn->primary->host, host, strlen( host ) + 1 );
conn->primary->port = port;
conn->primary->next = NULL;
- mongo_init( conn );
- if( mongo_socket_connect( conn, host, port ) != MONGO_OK )
+ if( mongo_env_socket_connect( conn, host, port ) != MONGO_OK )
return MONGO_ERROR;
if( mongo_check_is_master( conn ) != MONGO_OK )
return MONGO_OK;
}
-void mongo_replset_init( mongo *conn, const char *name ) {
+MONGO_EXPORT void mongo_replset_init( mongo *conn, const char *name ) {
mongo_init( conn );
conn->replset = bson_malloc( sizeof( mongo_replset ) );
*list = NULL;
}
-void mongo_replset_add_seed( mongo *conn, const char *host, int port ) {
+MONGO_EXPORT void mongo_replset_add_seed( mongo *conn, const char *host, int port ) {
mongo_replset_add_node( &conn->replset->seeds, host, port );
}
bson_destroy( &out );
bson_destroy( &hosts );
- mongo_close_socket( conn->sock );
+ mongo_env_close_socket( conn->sock );
conn->sock = 0;
conn->connected = 0;
bson_iterator it;
bson_bool_t ismaster = 0;
const char *set_name;
+ int max_bson_size = MONGO_DEFAULT_MAX_BSON_SIZE;
out.data = NULL;
if( bson_find( &it, &out, "ismaster" ) )
ismaster = bson_iterator_bool( &it );
+ if( bson_find( &it, &out, "maxBsonObjectSize" ) )
+ max_bson_size = bson_iterator_int( &it );
+ conn->max_bson_size = max_bson_size;
+
if( bson_find( &it, &out, "setName" ) ) {
set_name = bson_iterator_string( &it );
if( strcmp( set_name, conn->replset->name ) != 0 ) {
if( ismaster ) {
conn->replset->primary_connected = 1;
} else {
- mongo_close_socket( conn->sock );
+ mongo_env_close_socket( conn->sock );
}
return MONGO_OK;
}
-int mongo_replset_connect( mongo *conn ) {
+MONGO_EXPORT int mongo_replset_connect( mongo *conn ) {
int res = 0;
mongo_host_port *node;
*/
node = conn->replset->seeds;
while( node != NULL ) {
- res = mongo_socket_connect( conn, ( const char * )&node->host, node->port );
- if( res != MONGO_OK )
- return MONGO_ERROR;
-
- mongo_replset_check_seed( conn );
-
- if( conn->replset->hosts )
- break;
-
+ res = mongo_env_socket_connect( conn, ( const char * )&node->host, node->port );
+ if( res == MONGO_OK ) {
+ mongo_replset_check_seed( conn );
+ if( conn->replset->hosts )
+ break;
+ }
node = node->next;
}
node = conn->replset->hosts;
while( node != NULL ) {
- res = mongo_socket_connect( conn, ( const char * )&node->host, node->port );
+ res = mongo_env_socket_connect( conn, ( const char * )&node->host, node->port );
if( res == MONGO_OK ) {
if( mongo_replset_check_host( conn ) != MONGO_OK )
return MONGO_ERROR;
/* Primary found, so return. */
- else if( conn->replset->primary_connected )
+ else if( conn->replset->primary_connected ) {
+ strncpy( conn->primary->host, node->host, strlen( node->host ) + 1 );
+ conn->primary->port = node->port;
return MONGO_OK;
+ }
/* No primary, so close the connection. */
else {
- mongo_close_socket( conn->sock );
+ mongo_env_close_socket( conn->sock );
conn->sock = 0;
conn->connected = 0;
}
return MONGO_ERROR;
}
-int mongo_set_op_timeout( mongo *conn, int millis ) {
+MONGO_EXPORT int mongo_set_op_timeout( mongo *conn, int millis ) {
conn->op_timeout_ms = millis;
if( conn->sock && conn->connected )
- mongo_set_socket_op_timeout( conn, millis );
+ mongo_env_set_socket_op_timeout( conn, millis );
return MONGO_OK;
}
-int mongo_reconnect( mongo *conn ) {
+MONGO_EXPORT int mongo_reconnect( mongo *conn ) {
int res;
mongo_disconnect( conn );
res = mongo_replset_connect( conn );
return res;
} else
- return mongo_socket_connect( conn, conn->primary->host, conn->primary->port );
+ return mongo_env_socket_connect( conn, conn->primary->host, conn->primary->port );
}
-int mongo_check_connection( mongo *conn ) {
+MONGO_EXPORT int mongo_check_connection( mongo *conn ) {
if( ! conn->connected )
return MONGO_ERROR;
return MONGO_ERROR;
}
-void mongo_disconnect( mongo *conn ) {
+MONGO_EXPORT void mongo_disconnect( mongo *conn ) {
if( ! conn->connected )
return;
conn->replset->hosts = NULL;
}
- mongo_close_socket( conn->sock );
+ mongo_env_close_socket( conn->sock );
conn->sock = 0;
conn->connected = 0;
}
-void mongo_destroy( mongo *conn ) {
+MONGO_EXPORT void mongo_destroy( mongo *conn ) {
mongo_disconnect( conn );
if( conn->replset ) {
}
bson_free( conn->primary );
- bson_free( conn->errstr );
- bson_free( conn->lasterrstr );
- conn->err = 0;
- conn->errstr = NULL;
- conn->lasterrcode = 0;
- conn->lasterrstr = NULL;
+ mongo_clear_errors( conn );
}
/* Determine whether this BSON object is valid for the given operation. */
-static int mongo_bson_valid( mongo *conn, bson *bson, int write ) {
+static int mongo_bson_valid( mongo *conn, const bson *bson, int write ) {
+ int size;
+
+ size = bson_size( bson );
+ if( size > conn->max_bson_size ) {
+ conn->err = MONGO_BSON_TOO_LARGE;
+ return MONGO_ERROR;
+ }
+
if( ! bson->finished ) {
conn->err = MONGO_BSON_NOT_FINISHED;
return MONGO_ERROR;
}
conn->err = 0;
- conn->errstr = NULL;
return MONGO_OK;
}
/* Determine whether this BSON object is valid for the given operation. */
-static int mongo_cursor_bson_valid( mongo_cursor *cursor, bson *bson ) {
+static int mongo_cursor_bson_valid( mongo_cursor *cursor, const bson *bson ) {
if( ! bson->finished ) {
- cursor->err = MONGO_BSON_NOT_FINISHED;
+ cursor->err = MONGO_CURSOR_BSON_ERROR;
+ cursor->conn->err = MONGO_BSON_NOT_FINISHED;
return MONGO_ERROR;
}
if( bson->err & BSON_NOT_UTF8 ) {
- cursor->err = MONGO_BSON_INVALID;
+ cursor->err = MONGO_CURSOR_BSON_ERROR;
+ cursor->conn->err = MONGO_BSON_INVALID;
return MONGO_ERROR;
}
/* MongoDB CRUD API */
-int mongo_insert_batch( mongo *conn, const char *ns,
- bson **bsons, int count ) {
+MONGO_EXPORT int mongo_insert_batch( mongo *conn, const char *ns,
+ const bson **bsons, int count ) {
- int size = 16 + 4 + strlen( ns ) + 1;
- int i;
mongo_message *mm;
+ int i;
char *data;
+ int overhead = 16 + 4 + strlen( ns ) + 1;
+ int size = overhead;
+
+ if( mongo_validate_ns( conn, ns ) != MONGO_OK )
+ return MONGO_ERROR;
for( i=0; i<count; i++ ) {
size += bson_size( bsons[i] );
return MONGO_ERROR;
}
+ if( ( size - overhead ) > conn->max_bson_size ) {
+ conn->err = MONGO_BSON_TOO_LARGE;
+ return MONGO_ERROR;
+ }
+
mm = mongo_message_create( size , 0 , 0 , MONGO_OP_INSERT );
data = &mm->data;
return mongo_message_send( conn, mm );
}
-int mongo_insert( mongo *conn , const char *ns , bson *bson ) {
+MONGO_EXPORT int mongo_insert( mongo *conn , const char *ns , const bson *bson ) {
char *data;
mongo_message *mm;
+ if( mongo_validate_ns( conn, ns ) != MONGO_OK )
+ return MONGO_ERROR;
+
/* Make sure that BSON is valid for insert. */
if( mongo_bson_valid( conn, bson, 1 ) != MONGO_OK ) {
return MONGO_ERROR;
return mongo_message_send( conn, mm );
}
-int mongo_update( mongo *conn, const char *ns, const bson *cond,
+MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
const bson *op, int flags ) {
char *data;
return mongo_message_send( conn, mm );
}
-int mongo_remove( mongo *conn, const char *ns, const bson *cond ) {
+MONGO_EXPORT int mongo_remove( mongo *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 );
+ mongo_message *mm;
/* Make sure that the BSON is valid UTF-8.
* TODO: decide whether to check cond as well.
return MONGO_ERROR;
}
+ 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 );
bson empty;
char *data;
mongo_message *mm;
+ bson temp;
+ bson_iterator it;
+
+ /* Clear any errors. */
+ mongo_clear_errors( cursor->conn );
/* Set up default values for query and fields, if necessary. */
if( ! cursor->query )
return MONGO_ERROR;
}
+ if( cursor->reply->fields.num == 1 ) {
+ bson_init_data( &temp, &cursor->reply->objs );
+ if( bson_find( &it, &temp, "$err" ) ) {
+ mongo_set_last_error( cursor->conn, &it, &temp );
+ cursor->err = MONGO_CURSOR_QUERY_FAIL;
+ return MONGO_ERROR;
+ }
+ }
+
cursor->seen += cursor->reply->fields.num;
cursor->flags |= MONGO_CURSOR_QUERY_SENT;
return MONGO_OK;
}
}
-mongo_cursor *mongo_find( mongo *conn, const char *ns, bson *query,
- bson *fields, int limit, int skip, int options ) {
+MONGO_EXPORT mongo_cursor *mongo_find( mongo *conn, const char *ns, const bson *query,
+ const bson *fields, int limit, int skip, int options ) {
mongo_cursor *cursor = ( mongo_cursor * )bson_malloc( sizeof( mongo_cursor ) );
mongo_cursor_init( cursor, conn, ns );
}
}
-int mongo_find_one( mongo *conn, const char *ns, bson *query,
- bson *fields, bson *out ) {
+MONGO_EXPORT int mongo_find_one( mongo *conn, const char *ns, const bson *query,
+ const bson *fields, bson *out ) {
- mongo_cursor *cursor = mongo_find( conn, ns, query, fields, 1, 0, 0 );
+ mongo_cursor cursor[1];
+ mongo_cursor_init( cursor, conn, ns );
+ mongo_cursor_set_query( cursor, query );
+ mongo_cursor_set_fields( cursor, fields );
+ mongo_cursor_set_limit( cursor, 1 );
- if ( cursor && mongo_cursor_next( cursor ) == MONGO_OK ) {
- bson_copy_basic( out, &cursor->current );
+ if ( mongo_cursor_next( cursor ) == MONGO_OK ) {
+ bson_init_size( out, bson_size( (bson *)&cursor->current ) );
+ memcpy( out->data, cursor->current.data,
+ bson_size( (bson *)&cursor->current ) );
+ out->finished = 1;
mongo_cursor_destroy( cursor );
return MONGO_OK;
} else {
}
}
-void mongo_cursor_init( mongo_cursor *cursor, mongo *conn, const char *ns ) {
+MONGO_EXPORT void mongo_cursor_init( mongo_cursor *cursor, mongo *conn, const char *ns ) {
+ memset( cursor, 0, sizeof( mongo_cursor ) );
cursor->conn = conn;
cursor->ns = ( const char * )bson_malloc( strlen( ns ) + 1 );
strncpy( ( char * )cursor->ns, ns, strlen( ns ) + 1 );
cursor->current.data = NULL;
- cursor->reply = NULL;
- cursor->flags = 0;
- cursor->seen = 0;
- cursor->err = 0;
- cursor->options = 0;
- cursor->query = NULL;
- cursor->fields = NULL;
- cursor->skip = 0;
- cursor->limit = 0;
-}
-
-void mongo_cursor_set_query( mongo_cursor *cursor, bson *query ) {
+}
+
+MONGO_EXPORT void mongo_cursor_set_query( mongo_cursor *cursor, const bson *query ) {
cursor->query = query;
}
-void mongo_cursor_set_fields( mongo_cursor *cursor, bson *fields ) {
+MONGO_EXPORT void mongo_cursor_set_fields( mongo_cursor *cursor, const bson *fields ) {
cursor->fields = fields;
}
-void mongo_cursor_set_skip( mongo_cursor *cursor, int skip ) {
+MONGO_EXPORT void mongo_cursor_set_skip( mongo_cursor *cursor, int skip ) {
cursor->skip = skip;
}
-void mongo_cursor_set_limit( mongo_cursor *cursor, int limit ) {
+MONGO_EXPORT void mongo_cursor_set_limit( mongo_cursor *cursor, int limit ) {
cursor->limit = limit;
}
-void mongo_cursor_set_options( mongo_cursor *cursor, int options ) {
+MONGO_EXPORT void mongo_cursor_set_options( mongo_cursor *cursor, int options ) {
cursor->options = options;
}
-const char *mongo_cursor_data( mongo_cursor *cursor ) {
+MONGO_EXPORT const char *mongo_cursor_data( mongo_cursor *cursor ) {
return cursor->current.data;
}
-const bson *mongo_cursor_bson( mongo_cursor *cursor ) {
+MONGO_EXPORT const bson *mongo_cursor_bson( mongo_cursor *cursor ) {
return (const bson *)&(cursor->current);
}
-int mongo_cursor_next( mongo_cursor *cursor ) {
+MONGO_EXPORT int mongo_cursor_next( mongo_cursor *cursor ) {
char *next_object;
char *message_end;
if( ! ( cursor->flags & MONGO_CURSOR_QUERY_SENT ) )
- mongo_cursor_op_query( cursor );
+ if( mongo_cursor_op_query( cursor ) != MONGO_OK )
+ return MONGO_ERROR;
if( !cursor->reply )
return MONGO_ERROR;
/* first */
if ( cursor->current.data == NULL ) {
- bson_init_data( &cursor->current, &cursor->reply->objs );
+ bson_init_finished_data( &cursor->current, &cursor->reply->objs );
return MONGO_OK;
}
return MONGO_ERROR;
}
- bson_init_data( &cursor->current, &cursor->reply->objs );
+ bson_init_finished_data( &cursor->current, &cursor->reply->objs );
} else {
- bson_init_data( &cursor->current, next_object );
+ bson_init_finished_data( &cursor->current, next_object );
}
return MONGO_OK;
}
-int mongo_cursor_destroy( mongo_cursor *cursor ) {
+MONGO_EXPORT int mongo_cursor_destroy( mongo_cursor *cursor ) {
int result = MONGO_OK;
if ( !cursor ) return result;
/* MongoDB Helper Functions */
-int mongo_create_index( mongo *conn, const char *ns, bson *key, int options, bson *out ) {
+MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns, const bson *key, int options, bson *out ) {
bson b;
bson_iterator it;
char name[255] = {'_'};
return success;
}
-int64_t mongo_count( mongo *conn, const char *db, const char *ns, bson *query ) {
+MONGO_EXPORT double mongo_count( mongo *conn, const char *db, const char *ns, const bson *query ) {
bson cmd;
bson out = {NULL, 0};
- int64_t count = -1;
+ double count = -1;
bson_init( &cmd );
bson_append_string( &cmd, "count", ns );
if( mongo_run_command( conn, db, &cmd, &out ) == MONGO_OK ) {
bson_iterator it;
if( bson_find( &it, &out, "n" ) )
- count = bson_iterator_long( &it );
+ count = bson_iterator_double( &it );
bson_destroy( &cmd );
bson_destroy( &out );
return count;
}
}
-int mongo_run_command( mongo *conn, const char *db, bson *command,
+MONGO_EXPORT int mongo_run_command( mongo *conn, const char *db, const bson *command,
bson *out ) {
+ bson response = {NULL, 0};
bson fields;
int sl = strlen( db );
char *ns = bson_malloc( sl + 5 + 1 ); /* ".$cmd" + nul */
- int res;
+ int res, success = 0;
strcpy( ns, db );
strcpy( ns+sl, ".$cmd" );
- res = mongo_find_one( conn, ns, command, bson_empty( &fields ), out );
+ res = mongo_find_one( conn, ns, command, bson_empty( &fields ), &response );
bson_free( ns );
- return res;
+
+ if( res != MONGO_OK )
+ return MONGO_ERROR;
+ else {
+ bson_iterator it;
+ if( bson_find( &it, &response, "ok" ) )
+ success = bson_iterator_bool( &it );
+
+ if( !success ) {
+ conn->err = MONGO_COMMAND_FAILED;
+ return MONGO_ERROR;
+ } else {
+ if( out )
+ *out = response;
+ return MONGO_OK;
+ }
+ }
}
-int mongo_simple_int_command( mongo *conn, const char *db,
+MONGO_EXPORT int mongo_simple_int_command( mongo *conn, const char *db,
const char *cmdstr, int arg, bson *realout ) {
bson out = {NULL, 0};
bson cmd;
- bson_bool_t success = 0;
+ int result;
bson_init( &cmd );
bson_append_int( &cmd, cmdstr, arg );
bson_finish( &cmd );
- if( mongo_run_command( conn, db, &cmd, &out ) == MONGO_OK ) {
- bson_iterator it;
- if( bson_find( &it, &out, "ok" ) )
- success = bson_iterator_bool( &it );
- }
+ result = mongo_run_command( conn, db, &cmd, &out );
bson_destroy( &cmd );
else
bson_destroy( &out );
- if( success )
- return MONGO_OK;
- else {
- conn->err = MONGO_COMMAND_FAILED;
- return MONGO_ERROR;
- }
+ return result;
}
-int mongo_simple_str_command( mongo *conn, const char *db,
+MONGO_EXPORT int mongo_simple_str_command( mongo *conn, const char *db,
const char *cmdstr, const char *arg, bson *realout ) {
bson out = {NULL, 0};
- int success = 0;
+ int result;
bson cmd;
bson_init( &cmd );
bson_append_string( &cmd, cmdstr, arg );
bson_finish( &cmd );
- if( mongo_run_command( conn, db, &cmd, &out ) == MONGO_OK ) {
- bson_iterator it;
- if( bson_find( &it, &out, "ok" ) )
- success = bson_iterator_bool( &it );
- }
+ result = mongo_run_command( conn, db, &cmd, &out );
bson_destroy( &cmd );
else
bson_destroy( &out );
- if( success )
- return MONGO_OK;
- else
- return MONGO_ERROR;
+ return result;
}
-int mongo_cmd_drop_db( mongo *conn, const char *db ) {
+MONGO_EXPORT int mongo_cmd_drop_db( mongo *conn, const char *db ) {
return mongo_simple_int_command( conn, db, "dropDatabase", 1, NULL );
}
-int mongo_cmd_drop_collection( mongo *conn, const char *db, const char *collection, bson *out ) {
+MONGO_EXPORT int mongo_cmd_drop_collection( mongo *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 *conn, const char *db ) {
+MONGO_EXPORT void mongo_cmd_reset_error( mongo *conn, const char *db ) {
mongo_simple_int_command( conn, db, "reseterror", 1, NULL );
}
bson_bool_t haserror = 0;
/* Reset last error codes. */
- conn->lasterrcode = 0;
- bson_free( conn->lasterrstr );
- conn->lasterrstr = NULL;
+ mongo_clear_errors( conn );
/* If there's an error, store its code and string in the connection object. */
if( mongo_simple_int_command( conn, db, cmdtype, 1, &out ) == MONGO_OK ) {
bson_iterator it;
haserror = ( bson_find( &it, &out, "err" ) != BSON_NULL );
- if( haserror ) {
- conn->lasterrstr = ( char * )bson_malloc( bson_iterator_string_len( &it ) );
- if( conn->lasterrstr ) {
- strcpy( conn->lasterrstr, bson_iterator_string( &it ) );
- }
-
- if( bson_find( &it, &out, "code" ) != BSON_NULL )
- conn->lasterrcode = bson_iterator_int( &it );
- }
+ if( haserror ) mongo_set_last_error( conn, &it, &out );
}
if( realout )
return MONGO_OK;
}
-int mongo_cmd_get_prev_error( mongo *conn, const char *db, bson *out ) {
+MONGO_EXPORT int mongo_cmd_get_prev_error( mongo *conn, const char *db, bson *out ) {
return mongo_cmd_get_error_helper( conn, db, out, "getpreverror" );
}
-int mongo_cmd_get_last_error( mongo *conn, const char *db, bson *out ) {
+MONGO_EXPORT int mongo_cmd_get_last_error( mongo *conn, const char *db, bson *out ) {
return mongo_cmd_get_error_helper( conn, db, out, "getlasterror" );
}
-bson_bool_t mongo_cmd_ismaster( mongo *conn, bson *realout ) {
+MONGO_EXPORT bson_bool_t mongo_cmd_ismaster( mongo *conn, bson *realout ) {
bson out = {NULL,0};
bson_bool_t ismaster = 0;
digest2hex( digest, hex_digest );
}
-int mongo_cmd_add_user( mongo *conn, const char *db, const char *user, const char *pass ) {
+MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db, const char *user, const char *pass ) {
bson user_obj;
bson pass_obj;
char hex_digest[33];
return res;
}
-bson_bool_t mongo_cmd_authenticate( mongo *conn, const char *db, const char *user, const char *pass ) {
+MONGO_EXPORT bson_bool_t mongo_cmd_authenticate( mongo *conn, const char *db, const char *user, const char *pass ) {
bson from_db;
bson cmd;
bson out;
const char *nonce;
- bson_bool_t success = 0;
+ int result;
mongo_md5_state_t st;
mongo_md5_byte_t digest[16];
bson_finish( &cmd );
bson_destroy( &from_db );
- /*bson_init( &from_db ); */
- if( mongo_run_command( conn, db, &cmd, &out ) == MONGO_OK ) {
- bson_iterator it;
- if( bson_find( &it, &out, "ok" ) )
- success = bson_iterator_bool( &it );
- }
+
+ result = mongo_run_command( conn, db, &cmd, &out );
bson_destroy( &from_db );
bson_destroy( &cmd );
- if( success )
- return MONGO_OK;
- else
- return MONGO_ERROR;
+ return result;
}
* @brief Main MongoDB Declarations
*/
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* limitations under the License.
*/
-#ifndef _MONGO_H_
-#define _MONGO_H_
+#ifndef MONGO_H_
+#define MONGO_H_
#include "bson.h"
MONGO_EXTERN_C_START
#define MONGO_MAJOR 0
-#define MONGO_MINOR 4
-#define MONGO_PATCH 0
+#define MONGO_MINOR 5
+#define MONGO_PATCH 2
#define MONGO_OK 0
#define MONGO_ERROR -1
#define MONGO_DEFAULT_PORT 27017
+#define MONGO_DEFAULT_MAX_BSON_SIZE 4 * 1024 * 1024
+
+#define MONGO_ERR_LEN 128
+
typedef enum mongo_error_t {
MONGO_CONN_SUCCESS = 0, /**< Connection success! */
MONGO_CONN_NO_SOCKET, /**< Could not create a socket. */
MONGO_CONN_BAD_SET_NAME, /**< Given rs name doesn't match this replica set. */
MONGO_CONN_NO_PRIMARY, /**< Can't find primary in replica set. Connection closed. */
- MONGO_IO_ERROR, /**< An error occurred while reading or writing on socket. */
+ MONGO_IO_ERROR, /**< An error occurred while reading or writing on the socket. */
+ MONGO_SOCKET_ERROR, /**< Other socket error. */
MONGO_READ_SIZE_ERROR, /**< The response is not the expected length. */
MONGO_COMMAND_FAILED, /**< The command returned with 'ok' value of 0. */
+ MONGO_NS_INVALID, /**< The name for the ns (database or collection) is invalid. */
+ MONGO_BSON_INVALID, /**< BSON not valid for the specified op. */
+ MONGO_BSON_NOT_FINISHED, /**< BSON object has not been finished. */
+ MONGO_BSON_TOO_LARGE /**< BSON object exceeds max BSON size. */
+} mongo_error_t;
+
+typedef enum mongo_cursor_error_t {
MONGO_CURSOR_EXHAUSTED, /**< The cursor has no more results. */
MONGO_CURSOR_INVALID, /**< The cursor has timed out or is not recognized. */
MONGO_CURSOR_PENDING, /**< Tailable cursor still alive but no data. */
- MONGO_BSON_INVALID, /**< BSON not valid for the specified op. */
- MONGO_BSON_NOT_FINISHED /**< BSON object has not been finished. */
-} mongo_error_t;
+ MONGO_CURSOR_QUERY_FAIL, /**< The server returned an '$err' object, indicating query failure.
+ See conn->lasterrcode and conn->lasterrstr for details. */
+ MONGO_CURSOR_BSON_ERROR /**< Something is wrong with the BSON provided. See conn->err
+ for details. */
+} mongo_cursor_error_t;
enum mongo_cursor_flags {
MONGO_CURSOR_MUST_FREE = 1, /**< mongo_cursor_destroy should free cursor. */
int flags; /**< Flags on this connection object. */
int conn_timeout_ms; /**< Connection timeout in milliseconds. */
int op_timeout_ms; /**< Read and write timeout in milliseconds. */
+ int max_bson_size; /**< Largest BSON object allowed on this connection. */
bson_bool_t connected; /**< Connection status. */
- mongo_error_t err; /**< Most recent driver error code. */
- char *errstr; /**< String version of most recent driver error code. */
- int lasterrcode; /**< getlasterror given by the server on calls. */
- char *lasterrstr; /**< getlasterror string generated by server. */
+ mongo_error_t err; /**< Most recent driver error code. */
+ int errcode; /**< Most recent errno or WSAGetLastError(). */
+ char errstr[MONGO_ERR_LEN]; /**< String version of error. */
+ int lasterrcode; /**< getlasterror code from the server. */
+ char lasterrstr[MONGO_ERR_LEN]; /**< getlasterror string from the server. */
} mongo;
typedef struct {
int flags; /**< Flags used internally by this drivers. */
int seen; /**< Number returned so far. */
bson current; /**< This cursor's current bson object. */
- mongo_error_t err; /**< Errors on this cursor. */
- bson *query; /**< Bitfield containing cursor options. */
- bson *fields; /**< Bitfield containing cursor options. */
+ mongo_cursor_error_t err; /**< Errors on this cursor. */
+ const bson *query; /**< Bitfield containing cursor options. */
+ const bson *fields;/**< Bitfield containing cursor options. */
int options; /**< Bitfield containing cursor options. */
int limit; /**< Bitfield containing cursor options. */
int skip; /**< Bitfield containing cursor options. */
/* Connection API */
-/** Initialize a new mongo connection object. If not created
- * with mongo_new, you must initialize each mongo
- * object using this function.
+MONGO_EXPORT mongo* mongo_create();
+MONGO_EXPORT void mongo_dispose(mongo* conn);
+MONGO_EXPORT int mongo_get_err(mongo* conn);
+MONGO_EXPORT int mongo_is_connected(mongo* conn);
+MONGO_EXPORT int mongo_get_op_timeout(mongo* conn);
+MONGO_EXPORT const char* mongo_get_primary(mongo* conn);
+MONGO_EXPORT int mongo_get_socket(mongo* conn) ;
+MONGO_EXPORT int mongo_get_host_count(mongo* conn);
+MONGO_EXPORT const char* mongo_get_host(mongo* conn, int i);
+MONGO_EXPORT mongo_cursor* mongo_cursor_create();
+MONGO_EXPORT void mongo_cursor_dispose(mongo_cursor* cursor);
+MONGO_EXPORT int mongo_get_server_err(mongo* conn);
+MONGO_EXPORT const char* mongo_get_server_err_string(mongo* conn);
+
+/**
+ * Set an error this mongo connection object. Mostly for internal use.
+ *
+ * @param conn a mongo connection object.
+ * @param err a driver error code of mongo_error_t.
+ * @param errstr a string version of the error.
+ * @param errorcode Currently errno or WSAGetLastError().
+ */
+MONGO_EXPORT void __mongo_set_error( mongo *conn, mongo_error_t err,
+ const char *errstr, int errorcode );
+/**
+ * Clear all errors stored on this mongo connection object.
+ *
+ * @param conn a mongo connection object.
+ */
+MONGO_EXPORT void mongo_clear_errors( mongo *conn );
+
+/** Initialize sockets for Windows.
+ */
+MONGO_EXPORT void mongo_init_sockets();
+
+/**
+ * Initialize a new mongo connection object. You must initialize each mongo
+ * object using this function.
*
* @note When finished, you must pass this object to
* mongo_destroy( ).
* @param conn a mongo connection object allocated on the stack
* or heap.
*/
-void mongo_init( mongo *conn );
+MONGO_EXPORT void mongo_init( mongo *conn );
/**
* Connect to a single MongoDB server.
* @param port the port to connect to.
*
* @return MONGO_OK or MONGO_ERROR on failure. On failure, a constant of type
- * mongo_conn_return_t will be set on the conn->err field.
+ * mongo_error_t will be set on the conn->err field.
*/
-int mongo_connect( mongo *conn , const char *host, int port );
+MONGO_EXPORT int mongo_connect( mongo *conn , const char *host, int port );
/**
* Set up this connection object for connecting to a replica set.
* @param conn a mongo object.
* @param name the name of the replica set to connect to.
* */
-void mongo_replset_init( mongo *conn, const char *name );
+MONGO_EXPORT void mongo_replset_init( mongo *conn, const char *name );
/**
* Add a seed node to the replica set connection object.
* @param host a numerical network address or a network hostname.
* @param port the port to connect to.
*/
-void mongo_replset_add_seed( mongo *conn, const char *host, int port );
+MONGO_EXPORT void mongo_replset_add_seed( mongo *conn, const char *host, int port );
/**
* Utility function for converting a host-port string to a mongo_host_port.
*/
void mongo_parse_host( const char *host_string, mongo_host_port *host_port );
+/**
+ * Utility function for validation database and collection names.
+ *
+ * @param conn a mongo object.
+ *
+ * @return MONGO_OK or MONGO_ERROR on failure. On failure, a constant of type
+ * mongo_conn_return_t will be set on the conn->err field.
+ *
+ */
+MONGO_EXPORT int mongo_validate_ns( mongo *conn, const char *ns );
+
/**
* Connect to a replica set.
*
* @return MONGO_OK or MONGO_ERROR on failure. On failure, a constant of type
* mongo_conn_return_t will be set on the conn->err field.
*/
-int mongo_replset_connect( mongo *conn );
+MONGO_EXPORT int mongo_replset_connect( mongo *conn );
/** Set a timeout for operations on this connection. This
* is a platform-specific feature, and only work on *nix
* @return MONGO_OK. On error, return MONGO_ERROR and
* set the conn->err field.
*/
-int mongo_set_op_timeout( mongo *conn, int millis );
+MONGO_EXPORT int mongo_set_op_timeout( mongo *conn, int millis );
/**
* Ensure that this connection is healthy by performing
*
* @return MONGO_OK if connected; otherwise, MONGO_ERROR.
*/
-int mongo_check_connection( mongo *conn );
+MONGO_EXPORT int mongo_check_connection( mongo *conn );
/**
* Try reconnecting to the server using the existing connection settings.
* @return MONGO_OK or MONGO_ERROR and
* set the conn->err field.
*/
-int mongo_reconnect( mongo *conn );
+MONGO_EXPORT int mongo_reconnect( mongo *conn );
/**
* Close the current connection to the server. After calling
*
* @param conn a mongo object.
*/
-void mongo_disconnect( mongo *conn );
+MONGO_EXPORT void mongo_disconnect( mongo *conn );
/**
* Close any existing connection to the server and free all allocated
*
* @param conn a mongo object.
*/
-void mongo_destroy( mongo *conn );
+MONGO_EXPORT void mongo_destroy( mongo *conn );
/**
* Insert a BSON document into a MongoDB server. This function
* field is MONGO_BSON_INVALID, check the err field
* on the bson struct for the reason.
*/
-int mongo_insert( mongo *conn, const char *ns, bson *data );
+MONGO_EXPORT int mongo_insert( mongo *conn, const char *ns, const bson *data );
/**
* Insert a batch of BSON documents into a MongoDB server. This function
* @return MONGO_OK or MONGO_ERROR.
*
*/
-int mongo_insert_batch( mongo *conn , const char *ns ,
- bson **data , int num );
+MONGO_EXPORT int mongo_insert_batch( mongo *conn , const char *ns ,
+ const bson **data , int num );
/**
* Update a document in a MongoDB server.
* @return MONGO_OK or MONGO_ERROR with error stored in conn object.
*
*/
-int mongo_update( mongo *conn, const char *ns, const bson *cond,
+MONGO_EXPORT int mongo_update( mongo *conn, const char *ns, const bson *cond,
const bson *op, int flags );
/**
*
* @return MONGO_OK or MONGO_ERROR with error stored in conn object.
*/
-int mongo_remove( mongo *conn, const char *ns, const bson *cond );
+MONGO_EXPORT int mongo_remove( mongo *conn, const char *ns, const bson *cond );
/**
* Find documents in a MongoDB server.
* an error has occurred. For finer-grained error checking,
* use the cursor builder API instead.
*/
-mongo_cursor *mongo_find( mongo *conn, const char *ns, bson *query,
- bson *fields, int limit, int skip, int options );
+MONGO_EXPORT mongo_cursor *mongo_find( mongo *conn, const char *ns, const bson *query,
+ const bson *fields, int limit, int skip, int options );
/**
* Initalize a new cursor object.
* @param ns the namespace, represented as the the database
* name and collection name separated by a dot. e.g., "test.users"
*/
-void mongo_cursor_init( mongo_cursor *cursor, mongo *conn, const char *ns );
+MONGO_EXPORT void mongo_cursor_init( mongo_cursor *cursor, mongo *conn, const char *ns );
/**
* Set the bson object specifying this cursor's query spec. If
* $query, $orderby, $hint, and/or $explain. See
* http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol for details.
*/
-void mongo_cursor_set_query( mongo_cursor *cursor, bson *query );
+MONGO_EXPORT void mongo_cursor_set_query( mongo_cursor *cursor, const bson *query );
/**
* Set the fields to return for this cursor. If you want to return
* @param fields a bson object representing the fields to return.
* See http://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields.
*/
-void mongo_cursor_set_fields( mongo_cursor *cursor, bson *fields );
+MONGO_EXPORT void mongo_cursor_set_fields( mongo_cursor *cursor, const bson *fields );
/**
* Set the number of documents to skip.
* @param cursor
* @param skip
*/
-void mongo_cursor_set_skip( mongo_cursor *cursor, int skip );
+MONGO_EXPORT void mongo_cursor_set_skip( mongo_cursor *cursor, int skip );
/**
* Set the number of documents to return.
* @param cursor
* @param limit
*/
-void mongo_cursor_set_limit( mongo_cursor *cursor, int limit );
+MONGO_EXPORT void mongo_cursor_set_limit( mongo_cursor *cursor, int limit );
/**
* Set any of the available query options (e.g., MONGO_TAILABLE).
* @param options a bitfield storing query options. See
* mongo_cursor_bitfield_t for available constants.
*/
-void mongo_cursor_set_options( mongo_cursor *cursor, int options );
+MONGO_EXPORT void mongo_cursor_set_options( mongo_cursor *cursor, int options );
/**
* Return the current BSON object data as a const char*. This is useful
*
* @param cursor
*/
-const char *mongo_cursor_data( mongo_cursor *cursor );
+MONGO_EXPORT const char *mongo_cursor_data( mongo_cursor *cursor );
/**
* Return the current BSON object data as a const char*. This is useful
*
* @param cursor
*/
-const bson *mongo_cursor_bson( mongo_cursor *cursor );
+MONGO_EXPORT const bson *mongo_cursor_bson( mongo_cursor *cursor );
/**
* Iterate the cursor, returning the next item. When successful,
* @return MONGO_OK. On error, returns MONGO_ERROR and sets
* cursor->err with a value of mongo_error_t.
*/
-int mongo_cursor_next( mongo_cursor *cursor );
+MONGO_EXPORT int mongo_cursor_next( mongo_cursor *cursor );
/**
* Destroy a cursor object. When finished with a cursor, you
* @return MONGO_OK or an error code. On error, check cursor->conn->err
* for errors.
*/
-int mongo_cursor_destroy( mongo_cursor *cursor );
+MONGO_EXPORT int mongo_cursor_destroy( mongo_cursor *cursor );
/**
* Find a single document in a MongoDB server.
*
*/
/* out can be NULL if you don't care about results. useful for commands */
-bson_bool_t mongo_find_one( mongo *conn, const char *ns, bson *query,
- bson *fields, bson *out );
+MONGO_EXPORT int mongo_find_one( mongo *conn, const char *ns, const bson *query,
+ const bson *fields, bson *out );
/* MongoDB Helper Functions */
* @return the number of matching documents. If the command fails,
* MONGO_ERROR is returned.
*/
-int64_t mongo_count( mongo *conn, const char *db, const char *coll,
- bson *query );
+MONGO_EXPORT double mongo_count( mongo *conn, const char *db, const char *coll,
+ const bson *query );
/**
* Create a compouned index.
*
* @return MONGO_OK if index is created successfully; otherwise, MONGO_ERROR.
*/
-int mongo_create_index( mongo *conn, const char *ns, bson *key, int options, bson *out );
+MONGO_EXPORT int mongo_create_index( mongo *conn, const char *ns, const bson *key, int options, bson *out );
/**
* Create an index with a single key.
* @param command the BSON command to run.
* @param out the BSON result of the command.
*
- * @return true if the command ran without error.
+ * @return MONGO_OK if the command ran without error.
*/
-bson_bool_t mongo_run_command( mongo *conn, const char *db, bson *command, bson *out );
+MONGO_EXPORT int mongo_run_command( mongo *conn, const char *db, const bson *command, bson *out );
/**
* Run a command that accepts a simple string key and integer value.
* @return MONGO_OK or an error code.
*
*/
-int mongo_simple_int_command( mongo *conn, const char *db,
+MONGO_EXPORT int mongo_simple_int_command( mongo *conn, const char *db,
const char *cmd, int arg, bson *out );
/**
* @return true if the command ran without error.
*
*/
-bson_bool_t mongo_simple_str_command( mongo *conn, const char *db, const char *cmd, const char *arg, bson *out );
+MONGO_EXPORT int mongo_simple_str_command( mongo *conn, const char *db, const char *cmd, const char *arg, bson *out );
/**
* Drop a database.
*
* @return MONGO_OK or an error code.
*/
-int mongo_cmd_drop_db( mongo *conn, const char *db );
+MONGO_EXPORT int mongo_cmd_drop_db( mongo *conn, const char *db );
/**
* Drop a collection.
*
* @return true if the collection drop was successful.
*/
-bson_bool_t mongo_cmd_drop_collection( mongo *conn, const char *db, const char *collection, bson *out );
+MONGO_EXPORT int mongo_cmd_drop_collection( mongo *conn, const char *db, const char *collection, bson *out );
/**
* Add a database user.
*
* @return MONGO_OK or MONGO_ERROR.
*/
-int mongo_cmd_add_user( mongo *conn, const char *db, const char *user, const char *pass );
+MONGO_EXPORT int mongo_cmd_add_user( mongo *conn, const char *db, const char *user, const char *pass );
/**
* Authenticate a user.
*
* @return MONGO_OK on sucess and MONGO_ERROR on failure.
*/
-int mongo_cmd_authenticate( mongo *conn, const char *db, const char *user, const char *pass );
+MONGO_EXPORT int mongo_cmd_authenticate( mongo *conn, const char *db, const char *user, const char *pass );
/**
* Check if the current server is a master.
* @return true if the server is a master.
*/
/* return value is master status */
-bson_bool_t mongo_cmd_ismaster( mongo *conn, bson *out );
+MONGO_EXPORT bson_bool_t mongo_cmd_ismaster( mongo *conn, bson *out );
/**
* Get the error for the last command with the current connection.
* @return MONGO_OK if no error and MONGO_ERROR on error. On error, check the values
* of conn->lasterrcode and conn->lasterrstr for the error status.
*/
-int mongo_cmd_get_last_error( mongo *conn, const char *db, bson *out );
+MONGO_EXPORT int mongo_cmd_get_last_error( mongo *conn, const char *db, bson *out );
/**
* Get the most recent error with the current connection.
* @return MONGO_OK if no error and MONGO_ERROR on error. On error, check the values
* of conn->lasterrcode and conn->lasterrstr for the error status.
*/
-int mongo_cmd_get_prev_error( mongo *conn, const char *db, bson *out );
+MONGO_EXPORT int mongo_cmd_get_prev_error( mongo *conn, const char *db, bson *out );
/**
* Reset the error state for the connection.
* @param conn a mongo object.
* @param db the name of the database.
*/
-void mongo_cmd_reset_error( mongo *conn, const char *db );
+MONGO_EXPORT void mongo_cmd_reset_error( mongo *conn, const char *db );
+
MONGO_EXTERN_C_END
+++ /dev/null
-/* net.c */
-
-/* Copyright 2009-2011 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.
- */
-
-/* Implementation for generic version of net.h */
-#include "net.h"
-#include <string.h>
-
-int mongo_write_socket( mongo *conn, const void *buf, int len ) {
- const char *cbuf = buf;
- while ( len ) {
- int sent = send( conn->sock, cbuf, len, 0 );
- if ( sent == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
- cbuf += sent;
- len -= sent;
- }
-
- return MONGO_OK;
-}
-
-int mongo_read_socket( mongo *conn, void *buf, int len ) {
- char *cbuf = buf;
- while ( len ) {
- int sent = recv( conn->sock, cbuf, len, 0 );
- if ( sent == 0 || sent == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
- cbuf += sent;
- len -= sent;
- }
-
- return MONGO_OK;
-}
-
-/* This is a no-op in the generic implementation. */
-int mongo_set_socket_op_timeout( mongo *conn, int millis ) {
- return MONGO_OK;
-}
-
-static int mongo_create_socket( mongo *conn ) {
- int fd;
-
- if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) {
- conn->err = MONGO_CONN_NO_SOCKET;
- return MONGO_ERROR;
- }
- conn->sock = fd;
-
- return MONGO_OK;
-}
-
-int mongo_socket_connect( mongo *conn, const char *host, int port ) {
- struct sockaddr_in sa;
- socklen_t addressSize;
- int flag = 1;
-
- if( mongo_create_socket( conn ) != MONGO_OK )
- return MONGO_ERROR;
-
- memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) );
- sa.sin_family = AF_INET;
- sa.sin_port = htons( port );
- sa.sin_addr.s_addr = inet_addr( host );
- addressSize = sizeof( sa );
-
- if ( connect( conn->sock, ( struct sockaddr * )&sa, addressSize ) == -1 ) {
- mongo_close_socket( conn->sock );
- conn->connected = 0;
- conn->sock = 0;
- conn->err = MONGO_CONN_FAIL;
- return MONGO_ERROR;
- }
-
- setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * ) &flag, sizeof( flag ) );
- if( conn->op_timeout_ms > 0 )
- mongo_set_socket_op_timeout( conn, conn->op_timeout_ms );
-
- conn->connected = 1;
-
- return MONGO_OK;
-}
+++ /dev/null
-/** @file net.h */
-
-/* Copyright 2009-2011 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.
- */
-
-/* Header for generic net.h */
-#ifndef _MONGO_NET_H_
-#define _MONGO_NET_H_
-
-#include "mongo.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#include <winsock.h>
-#define mongo_close_socket(sock) ( closesocket(sock) )
-typedef int socklen_t;
-#else
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <fcntl.h>
-#define mongo_close_socket(sock) ( close(sock) )
-#endif
-
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-
-#if defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || _POSIX_C_SOURCE >= 1
-#define _MONGO_USE_GETADDRINFO
-#endif
-
-MONGO_EXTERN_C_START
-
-/* This is a no-op in the generic implementation. */
-int mongo_set_socket_op_timeout( mongo *conn, int millis );
-int mongo_read_socket( mongo *conn, void *buf, int len );
-int mongo_write_socket( mongo *conn, const void *buf, int len );
-int mongo_socket_connect( mongo *conn, const char *host, int port );
-
-MONGO_EXTERN_C_END
-#endif
-/* Copyright 2009-2011 10gen Inc.
+/* Copyright 2009-2012 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+++ /dev/null
-/** @file platform.h */
-
-/** Copyright 2009-2011 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 */
-
-#ifndef _PLATFORM_HACKS_H_
-#define _PLATFORM_HACKS_H_
-
-#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
-
-
-#if defined(MONGO_HAVE_STDINT) || __STDC_VERSION__ >= 199901L
-#include <stdint.h>
-#elif defined(MONGO_HAVE_UNISTD)
-#include <unistd.h>
-#elif defined(MONGO_USE__INT64)
-typedef __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#elif defined(MONGO_USE_LONG_LONG_INT)
-typedef long long int int64_t;
-typedef unsigned long long int uint64_t;
-#else
-#error must have a 64bit int type
-#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
-
-#endif
+++ /dev/null
-/* net.c */
-
-/* Copyright 2009-2011 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.
- */
-
-/* Implementation for Linux version of net.h */
-#include "net.h"
-#include <string.h>
-
-int mongo_write_socket( mongo *conn, const void *buf, int len ) {
- const char *cbuf = buf;
- while ( len ) {
- int sent = send( conn->sock, cbuf, len, 0 );
- if ( sent == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
- cbuf += sent;
- len -= sent;
- }
-
- return MONGO_OK;
-}
-
-int mongo_read_socket( mongo *conn, void *buf, int len ) {
- char *cbuf = buf;
- while ( len ) {
- int sent = recv( conn->sock, cbuf, len, 0 );
- if ( sent == 0 || sent == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
- cbuf += sent;
- len -= sent;
- }
-
- return MONGO_OK;
-}
-
-static int mongo_create_socket( mongo *conn ) {
- int fd;
-
- if( ( fd = socket( AF_INET, SOCK_STREAM, 0 ) ) == -1 ) {
- conn->err = MONGO_CONN_NO_SOCKET;
- return MONGO_ERROR;
- }
- conn->sock = fd;
-
- return MONGO_OK;
-}
-
-static int mongo_set_blocking_status( mongo *conn ) {
- int flags;
- int blocking;
-
- blocking = ( conn->conn_timeout_ms == 0 );
- if( blocking )
- return MONGO_OK;
- else {
- if( ( flags = fcntl( conn->sock, F_GETFL ) ) == -1 ) {
- conn->err = MONGO_IO_ERROR;
- mongo_close_socket( conn->sock );
- return MONGO_ERROR;
- }
-
- flags |= O_NONBLOCK;
-
- if( ( flags = fcntl( conn->sock, F_SETFL, flags ) ) == -1 ) {
- conn->err = MONGO_IO_ERROR;
- mongo_close_socket( conn->sock );
- return MONGO_ERROR;
- }
- }
-
- return MONGO_OK;
-}
-
-int mongo_set_socket_op_timeout( mongo *conn, int millis ) {
- struct timeval tv;
- tv.tv_sec = millis / 1000;
- tv.tv_usec = ( millis % 1000 ) * 1000;
-
- if ( setsockopt( conn->sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof( tv ) ) == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
-
- if ( setsockopt( conn->sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof( tv ) ) == -1 ) {
- conn->err = MONGO_IO_ERROR;
- return MONGO_ERROR;
- }
-
- return MONGO_OK;
-}
-
-#ifdef _MONGO_USE_GETADDRINFO
-int mongo_socket_connect( mongo *conn, const char *host, int port ) {
-
- struct addrinfo *addrs = NULL;
- struct addrinfo hints;
- int flag = 1;
- char port_str[12];
- int ret;
-
- conn->sock = 0;
- conn->connected = 0;
-
- memset( &hints, 0, sizeof( hints ) );
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
-
- sprintf( port_str, "%d", port );
-
- if( mongo_create_socket( conn ) != MONGO_OK )
- return MONGO_ERROR;
-
- if( getaddrinfo( host, port_str, &hints, &addrs ) != 0 ) {
- bson_errprintf( "getaddrinfo failed: %s", gai_strerror( ret ) );
- conn->err = MONGO_CONN_ADDR_FAIL;
- return MONGO_ERROR;
- }
-
- if ( connect( conn->sock, addrs->ai_addr, addrs->ai_addrlen ) == -1 ) {
- mongo_close_socket( conn->sock );
- freeaddrinfo( addrs );
- conn->err = MONGO_CONN_FAIL;
- return MONGO_ERROR;
- }
-
- setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * )&flag, sizeof( flag ) );
- if( conn->op_timeout_ms > 0 )
- mongo_set_socket_op_timeout( conn, conn->op_timeout_ms );
-
- conn->connected = 1;
- freeaddrinfo( addrs );
-
- return MONGO_OK;
-}
-#else
-int mongo_socket_connect( mongo *conn, const char *host, int port ) {
- struct sockaddr_in sa;
- socklen_t addressSize;
- int flag = 1;
-
- if( mongo_create_socket( conn ) != MONGO_OK )
- return MONGO_ERROR;
-
- memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) );
- sa.sin_family = AF_INET;
- sa.sin_port = htons( port );
- sa.sin_addr.s_addr = inet_addr( host );
- addressSize = sizeof( sa );
-
- if ( connect( conn->sock, ( struct sockaddr * )&sa, addressSize ) == -1 ) {
- mongo_close_socket( conn->sock );
- conn->connected = 0;
- conn->sock = 0;
- conn->err = MONGO_CONN_FAIL;
- return MONGO_ERROR;
- }
-
- setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, ( char * ) &flag, sizeof( flag ) );
-
- if( conn->op_timeout_ms > 0 )
- mongo_set_socket_op_timeout( conn, conn->op_timeout_ms );
-
- conn->connected = 1;
-
- return MONGO_OK;
-}
-#endif
+++ /dev/null
-/**
- * @file net.h
- * @brief Networking.
- */
-
-/* Copyright 2009-2011 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.
- */
-
-/* Header for Linux net.h */
-#ifndef _MONGO_NET_H_
-#define _MONGO_NET_H_
-
-#include "mongo.h"
-
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#define mongo_close_socket(sock) ( close(sock) )
-
-#if defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) || _POSIX_C_SOURCE >= 1
-#define _MONGO_USE_GETADDRINFO
-#endif
-
-MONGO_EXTERN_C_START
-
-int mongo_set_socket_op_timeout( mongo *conn, int millis );
-int mongo_read_socket( mongo *conn, void *buf, int len );
-int mongo_write_socket( mongo *conn, const void *buf, int len );
-int mongo_socket_connect( mongo *conn, const char *host, int port );
-
-MONGO_EXTERN_C_END
-#endif