faststep 0.0.8.1 → 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/faststep/mongo.c CHANGED
@@ -23,6 +23,7 @@
23
23
  #include <errno.h>
24
24
  #include <string.h>
25
25
  #include <stdlib.h>
26
+ #include <errno.h>
26
27
 
27
28
  #ifndef _WIN32
28
29
  #include <unistd.h>
@@ -36,42 +37,55 @@ static const int one = 1;
36
37
  message stuff
37
38
  ------------------------------ */
38
39
 
39
- static void looping_write(mongo_connection * conn, const void* buf, int len){
40
+ static int looping_write(mongo_connection * conn, const void* buf, int len){
40
41
  const char* cbuf = buf;
41
42
  while (len){
42
43
  int sent = send(conn->sock, cbuf, len, 0);
43
- if (sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
44
+ if (sent == -1)
45
+ return MONGO_IO_ERROR;
44
46
  cbuf += sent;
45
47
  len -= sent;
46
48
  }
49
+
50
+ return MONGO_OK;
47
51
  }
48
52
 
49
- static void looping_read(mongo_connection * conn, void* buf, int len){
53
+ static int looping_read(mongo_connection * conn, void* buf, int len){
50
54
  char* cbuf = buf;
51
55
  while (len){
52
56
  int sent = recv(conn->sock, cbuf, len, 0);
53
- if (sent == 0 || sent == -1) MONGO_THROW(MONGO_EXCEPT_NETWORK);
57
+ if (sent == 0 || sent == -1)
58
+ return MONGO_IO_ERROR;
54
59
  cbuf += sent;
55
60
  len -= sent;
56
61
  }
62
+
63
+ return MONGO_OK;
57
64
  }
58
65
 
59
66
  /* Always calls free(mm) */
60
- void mongo_message_send(mongo_connection * conn, mongo_message* mm){
67
+ int mongo_message_send(mongo_connection * conn, mongo_message* mm){
61
68
  mongo_header head; /* little endian */
69
+ int res;
62
70
  bson_little_endian32(&head.len, &mm->head.len);
63
71
  bson_little_endian32(&head.id, &mm->head.id);
64
72
  bson_little_endian32(&head.responseTo, &mm->head.responseTo);
65
73
  bson_little_endian32(&head.op, &mm->head.op);
66
74
 
67
- MONGO_TRY{
68
- looping_write(conn, &head, sizeof(head));
69
- looping_write(conn, &mm->data, mm->head.len - sizeof(head));
70
- }MONGO_CATCH{
71
- free(mm);
72
- MONGO_RETHROW();
75
+ res = looping_write(conn, &head, sizeof(head));
76
+ if( res != MONGO_OK ) {
77
+ free( mm );
78
+ return res;
73
79
  }
74
- free(mm);
80
+
81
+ res = looping_write(conn, &mm->data, mm->head.len - sizeof(head));
82
+ if( res != MONGO_OK ) {
83
+ free( mm );
84
+ return res;
85
+ }
86
+
87
+ free( mm );
88
+ return MONGO_OK;
75
89
  }
76
90
 
77
91
  char * mongo_data_append( char * start , const void * data , int len ){
@@ -107,108 +121,391 @@ mongo_message * mongo_message_create( int len , int id , int responseTo , int op
107
121
  /* ----------------------------
108
122
  connection stuff
109
123
  ------------------------------ */
110
- static int mongo_connect_helper( mongo_connection * conn ){
111
- /* setup */
124
+ #ifdef _MONGO_USE_GETADDRINFO
125
+ static int mongo_socket_connect( mongo_connection * conn, const char * host, int port ){
126
+
127
+ struct addrinfo* addrs = NULL;
128
+ struct addrinfo hints;
129
+ char port_str[12];
130
+ int ret;
131
+
112
132
  conn->sock = 0;
113
133
  conn->connected = 0;
114
134
 
115
- memset( conn->sa.sin_zero , 0 , sizeof(conn->sa.sin_zero) );
116
- conn->sa.sin_family = AF_INET;
117
- conn->sa.sin_port = htons(conn->left_opts->port);
118
- conn->sa.sin_addr.s_addr = inet_addr( conn->left_opts->host );
119
- conn->addressSize = sizeof(conn->sa);
135
+ memset( &hints, 0, sizeof( hints ) );
136
+ hints.ai_family = AF_INET;
137
+
138
+ sprintf( port_str, "%d", port );
120
139
 
121
- /* connect */
122
140
  conn->sock = socket( AF_INET, SOCK_STREAM, 0 );
123
- if ( conn->sock <= 0 ){
141
+ if ( conn->sock < 0 ){
142
+ printf("Socket: %d", conn->sock);
124
143
  mongo_close_socket( conn->sock );
125
144
  return mongo_conn_no_socket;
126
145
  }
127
146
 
128
- if ( connect( conn->sock , (struct sockaddr*)&conn->sa , conn->addressSize ) ){
147
+ ret = getaddrinfo( host, port_str, &hints, &addrs );
148
+ if(ret) {
149
+ fprintf( stderr, "getaddrinfo failed: %s", gai_strerror( ret ) );
150
+ return mongo_conn_fail;
151
+ }
152
+
153
+ if ( connect( conn->sock, addrs->ai_addr, addrs->ai_addrlen ) ){
129
154
  mongo_close_socket( conn->sock );
155
+ freeaddrinfo( addrs );
130
156
  return mongo_conn_fail;
131
157
  }
132
158
 
133
- /* nagle */
134
159
  setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) );
135
160
 
136
- /* TODO signals */
161
+ conn->connected = 1;
162
+ freeaddrinfo( addrs );
163
+ return MONGO_OK;
164
+ }
165
+ #else
166
+ static int mongo_socket_connect( mongo_connection * conn, const char * host, int port ){
167
+ struct sockaddr_in sa;
168
+ socklen_t addressSize;
169
+
170
+ memset( sa.sin_zero , 0 , sizeof( sa.sin_zero ) );
171
+ sa.sin_family = AF_INET;
172
+ sa.sin_port = htons( port );
173
+ sa.sin_addr.s_addr = inet_addr( host );
174
+ addressSize = sizeof( sa );
175
+
176
+ conn->sock = socket( AF_INET, SOCK_STREAM, 0 );
177
+ if ( conn->sock < 0 ){
178
+ mongo_close_socket( conn->sock );
179
+ return mongo_conn_no_socket;
180
+ }
181
+
182
+ if ( connect( conn->sock, (struct sockaddr *)&sa, addressSize ) ){
183
+ return mongo_conn_fail;
184
+ }
185
+
186
+ setsockopt( conn->sock, IPPROTO_TCP, TCP_NODELAY, (char *) &one, sizeof(one) );
137
187
 
138
188
  conn->connected = 1;
139
- return 0;
189
+ return MONGO_OK;
140
190
  }
191
+ #endif
141
192
 
142
- mongo_conn_return mongo_connect( mongo_connection * conn , mongo_connection_options * options ){
143
- MONGO_INIT_EXCEPTION(&conn->exception);
193
+ mongo_conn_return mongo_connect( mongo_connection * conn , const char * host, int port ){
194
+ conn->replset = NULL;
144
195
 
145
- conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
146
- conn->right_opts = NULL;
196
+ conn->primary = bson_malloc( sizeof( mongo_host_port ) );
147
197
 
148
- if ( options ){
149
- memcpy( conn->left_opts , options , sizeof( mongo_connection_options ) );
150
- } else {
151
- strcpy( conn->left_opts->host , "127.0.0.1" );
152
- conn->left_opts->port = 27017;
198
+ strncpy( conn->primary->host, host, strlen( host ) + 1 );
199
+ conn->primary->port = port;
200
+ conn->primary->next = NULL;
201
+
202
+ conn->err = 0;
203
+ conn->errstr = NULL;
204
+ conn->lasterrcode = 0;
205
+ conn->lasterrstr = NULL;
206
+
207
+ return mongo_socket_connect(conn, host, port);
208
+ }
209
+
210
+ void mongo_replset_init_conn( mongo_connection* conn, const char* name ) {
211
+ conn->replset = bson_malloc( sizeof( mongo_replset ) );
212
+ conn->replset->primary_connected = 0;
213
+ conn->replset->seeds = NULL;
214
+ conn->replset->hosts = NULL;
215
+ conn->replset->name = (char *)bson_malloc( sizeof( name ) + 1 );
216
+ memcpy( conn->replset->name, name, sizeof( name ) + 1 );
217
+
218
+ conn->primary = bson_malloc( sizeof( mongo_host_port ) );
219
+ conn->primary = NULL;
220
+
221
+ conn->err = 0;
222
+ conn->errstr = NULL;
223
+ conn->lasterrcode = 0;
224
+ conn->lasterrstr = NULL;
225
+ }
226
+
227
+ static int mongo_replset_add_node( mongo_host_port** list, const char* host, int port ) {
228
+ mongo_host_port* host_port = bson_malloc( sizeof( mongo_host_port ) );
229
+ host_port->port = port;
230
+ host_port->next = NULL;
231
+ strncpy( host_port->host, host, strlen(host) + 1 );
232
+
233
+ if( *list == NULL )
234
+ *list = host_port;
235
+ else {
236
+ mongo_host_port* p = *list;
237
+ while( p->next != NULL )
238
+ p = p->next;
239
+ p->next = host_port;
240
+ }
241
+
242
+ return MONGO_OK;
243
+ }
244
+
245
+ static int mongo_replset_free_list( mongo_host_port** list ) {
246
+ mongo_host_port* node = *list;
247
+ mongo_host_port* prev;
248
+
249
+ while( node != NULL ) {
250
+ prev = node;
251
+ node = node->next;
252
+ free(prev);
153
253
  }
154
254
 
155
- return mongo_connect_helper(conn);
255
+ *list = NULL;
256
+ return MONGO_OK;
156
257
  }
157
258
 
158
- static void swap_repl_pair(mongo_connection * conn){
159
- mongo_connection_options * tmp = conn->left_opts;
160
- conn->left_opts = conn->right_opts;
161
- conn->right_opts = tmp;
259
+ int mongo_replset_add_seed(mongo_connection* conn, const char* host, int port) {
260
+ return mongo_replset_add_node( &conn->replset->seeds, host, port );
162
261
  }
163
262
 
164
- mongo_conn_return mongo_connect_pair( mongo_connection * conn , mongo_connection_options * left, mongo_connection_options * right ){
263
+ static int mongo_replset_check_seed( mongo_connection* conn ) {
264
+ bson out;
265
+ bson hosts;
266
+ const char* data;
267
+ bson_iterator it;
268
+ bson_iterator it_sub;
269
+ const char* host_string;
270
+ char* host;
271
+ int len, idx, port, split;
272
+
273
+ out.data = NULL;
274
+ out.owned = 1;
275
+
276
+ hosts.data = NULL;
277
+ hosts.owned = 1;
278
+
279
+ if( mongo_simple_int_command(conn, "admin", "ismaster", 1, &out) == MONGO_OK ) {
280
+
281
+ if( bson_find( &it, &out, "hosts" ) ) {
282
+ data = bson_iterator_value( &it );
283
+ bson_iterator_init( &it_sub, data );
284
+
285
+ /* Iterate over host list, adding each host to the
286
+ * connection's host list.
287
+ */
288
+ while( bson_iterator_next( &it_sub ) ) {
289
+ host_string = bson_iterator_string( &it_sub );
290
+ len = split = idx = 0;
291
+
292
+ /* Split the host_port string at the ':' */
293
+ while(1) {
294
+ if( *(host_string + len) == 0)
295
+ break;
296
+ if( *(host_string + len) == ':' )
297
+ split = len;
298
+ len++;
299
+ }
300
+
301
+ /* If 'split' is set, we know the that port exists;
302
+ * Otherwise, we set the default port.
303
+ */
304
+ if( len > 0 ) {
305
+ idx = split ? split : len;
306
+ host = (char *)bson_malloc( idx + 1 );
307
+ memcpy( host, host_string, idx );
308
+ memcpy( host + idx, "\0", 1 );
309
+ if( split )
310
+ port = atoi( host_string + idx + 1 );
311
+ else
312
+ port = 27017;
313
+
314
+ mongo_replset_add_node( &conn->replset->hosts, host, port );
315
+ }
316
+ }
317
+ }
318
+ }
319
+
320
+ bson_destroy( &out );
321
+ bson_destroy( &hosts );
322
+ mongo_close_socket( conn->sock );
323
+ conn->sock = 0;
165
324
  conn->connected = 0;
166
- MONGO_INIT_EXCEPTION(&conn->exception);
167
325
 
168
- conn->left_opts = NULL;
169
- conn->right_opts = NULL;
326
+ return 0;
327
+ }
170
328
 
171
- if ( !left || !right )
172
- return mongo_conn_bad_arg;
329
+ /* Find out whether the current connected node is master, and
330
+ * verify that the node's replica set name matched the provided name
331
+ */
332
+ static int mongo_replset_check_host( mongo_connection* conn ) {
333
+
334
+ bson out;
335
+ bson_iterator it;
336
+ bson_bool_t ismaster = 0;
337
+ const char* set_name;
338
+
339
+ out.data = NULL;
340
+ out.owned = 1;
173
341
 
174
- conn->left_opts = bson_malloc(sizeof(mongo_connection_options));
175
- conn->right_opts = bson_malloc(sizeof(mongo_connection_options));
342
+ if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out) == MONGO_OK) {
343
+ if( bson_find(&it, &out, "ismaster") )
344
+ ismaster = bson_iterator_bool( &it );
176
345
 
177
- memcpy( conn->left_opts, left, sizeof( mongo_connection_options ) );
178
- memcpy( conn->right_opts, right, sizeof( mongo_connection_options ) );
346
+ if( bson_find( &it, &out, "setName" ) ) {
347
+ set_name = bson_iterator_string( &it );
348
+ if( strcmp( set_name, conn->replset->name ) != 0 ) {
349
+ return mongo_conn_bad_set_name;
350
+ }
351
+ }
352
+ }
353
+
354
+ bson_destroy( &out );
355
+
356
+ if(ismaster) {
357
+ conn->replset->primary_connected = 1;
358
+ }
359
+ else {
360
+ mongo_close_socket( conn->sock );
361
+ }
179
362
 
180
- return mongo_reconnect(conn);
363
+ return 0;
364
+ }
365
+
366
+ mongo_conn_return mongo_replset_connect(mongo_connection* conn) {
367
+
368
+ int connect_error = 0;
369
+ mongo_host_port* node;
370
+
371
+ conn->sock = 0;
372
+ conn->connected = 0;
373
+
374
+ /* First iterate over the seed nodes to get the canonical list of hosts
375
+ * from the replica set. Break out once we have a host list.
376
+ */
377
+ node = conn->replset->seeds;
378
+ while( node != NULL ) {
379
+ connect_error = mongo_socket_connect( conn, (const char*)&node->host, node->port );
380
+
381
+ if( connect_error == 0 ) {
382
+ if ( (connect_error = mongo_replset_check_seed( conn )) )
383
+ return connect_error;
384
+ }
385
+
386
+ if( conn->replset->hosts )
387
+ break;
388
+
389
+ node = node->next;
390
+ }
391
+
392
+ /* Iterate over the host list, checking for the primary node. */
393
+ if( !conn->replset->hosts ) {
394
+ return mongo_conn_cannot_find_primary;
395
+ }
396
+ else {
397
+ node = conn->replset->hosts;
398
+
399
+ while( node != NULL ) {
400
+ connect_error = mongo_socket_connect( conn, (const char*)&node->host, node->port );
401
+
402
+ if( connect_error == 0 ) {
403
+ if ( (connect_error = mongo_replset_check_host( conn )) )
404
+ return connect_error;
405
+
406
+ /* Primary found, so return. */
407
+ else if( conn->replset->primary_connected )
408
+ return 0;
409
+
410
+ /* No primary, so close the connection. */
411
+ else {
412
+ mongo_close_socket( conn->sock );
413
+ conn->sock = 0;
414
+ conn->connected = 0;
415
+ }
416
+ }
417
+
418
+ node = node->next;
419
+ }
420
+ }
421
+
422
+ return mongo_conn_cannot_find_primary;
181
423
  }
182
424
 
183
425
  mongo_conn_return mongo_reconnect( mongo_connection * conn ){
184
- mongo_conn_return ret;
426
+ int res;
185
427
  mongo_disconnect(conn);
186
428
 
187
- /* single server */
188
- if(conn->right_opts == NULL)
189
- return mongo_connect_helper(conn);
429
+ if( conn->replset ) {
430
+ conn->replset->primary_connected = 0;
431
+ mongo_replset_free_list( &conn->replset->hosts );
432
+ conn->replset->hosts = NULL;
433
+ res = mongo_replset_connect( conn );
434
+ return res;
435
+ }
436
+ else
437
+ return mongo_socket_connect( conn, conn->primary->host, conn->primary->port );
438
+ }
439
+
440
+ bson_bool_t mongo_disconnect( mongo_connection * conn ){
441
+ if( ! conn->connected )
442
+ return 1;
443
+
444
+ if( conn->replset ) {
445
+ conn->replset->primary_connected = 0;
446
+ mongo_replset_free_list( &conn->replset->hosts );
447
+ conn->replset->hosts = NULL;
448
+ return mongo_replset_connect( conn );
449
+ }
450
+
451
+ mongo_close_socket( conn->sock );
452
+
453
+ conn->sock = 0;
454
+ conn->connected = 0;
455
+
456
+ return 0;
457
+ }
458
+
459
+ bson_bool_t mongo_destroy( mongo_connection * conn ){
460
+ if( conn->replset ) {
461
+ mongo_replset_free_list( &conn->replset->seeds );
462
+ mongo_replset_free_list( &conn->replset->hosts );
463
+ free( conn->replset->name );
464
+ free( conn->replset );
465
+ conn->replset = NULL;
466
+ }
467
+
468
+ free( conn->primary );
469
+ free( conn->errstr );
470
+ free( conn->lasterrstr );
471
+
472
+ conn->err = 0;
473
+ conn->errstr = NULL;
474
+ conn->lasterrcode = 0;
475
+ conn->lasterrstr = NULL;
476
+
477
+ return mongo_disconnect( conn );
478
+ }
190
479
 
191
- /* repl pair */
192
- ret = mongo_connect_helper(conn);
193
- if (ret == mongo_conn_success && mongo_cmd_ismaster(conn, NULL)){
194
- return mongo_conn_success;
480
+ /*
481
+ * Determine whether this BSON object is valid for the
482
+ * given operation.
483
+ */
484
+ static int mongo_bson_valid( mongo_connection * conn, bson* bson, int write ) {
485
+ if( bson->err & BSON_NOT_UTF8 ) {
486
+ conn->err = MONGO_INVALID_BSON;
487
+ return MONGO_ERROR;
195
488
  }
196
489
 
197
- swap_repl_pair(conn);
490
+ if( write ) {
491
+ if( (bson->err & BSON_FIELD_HAS_DOT) ||
492
+ (bson->err & BSON_FIELD_INIT_DOLLAR) ) {
493
+
494
+ conn->err = MONGO_INVALID_BSON;
495
+ return MONGO_ERROR;
198
496
 
199
- ret = mongo_connect_helper(conn);
200
- if (ret == mongo_conn_success){
201
- if(mongo_cmd_ismaster(conn, NULL))
202
- return mongo_conn_success;
203
- else
204
- return mongo_conn_not_master;
497
+ }
205
498
  }
206
499
 
207
- /* failed to connect to both servers */
208
- return ret;
500
+ conn->err = 0;
501
+ conn->errstr = NULL;
502
+
503
+ return MONGO_OK;
209
504
  }
210
505
 
211
- void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** bsons, int count){
506
+ int mongo_insert_batch( mongo_connection * conn, const char * ns,
507
+ bson ** bsons, int count ) {
508
+
212
509
  int size = 16 + 4 + strlen( ns ) + 1;
213
510
  int i;
214
511
  mongo_message * mm;
@@ -216,6 +513,8 @@ void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** bso
216
513
 
217
514
  for(i=0; i<count; i++){
218
515
  size += bson_size(bsons[i]);
516
+ if( mongo_bson_valid( conn, bsons[i], 1 ) != MONGO_OK )
517
+ return MONGO_ERROR;
219
518
  }
220
519
 
221
520
  mm = mongo_message_create( size , 0 , 0 , mongo_op_insert );
@@ -228,34 +527,53 @@ void mongo_insert_batch( mongo_connection * conn , const char * ns , bson ** bso
228
527
  data = mongo_data_append(data, bsons[i]->data, bson_size( bsons[i] ) );
229
528
  }
230
529
 
231
- mongo_message_send(conn, mm);
530
+ return mongo_message_send(conn, mm);
232
531
  }
233
532
 
234
- void mongo_insert( mongo_connection * conn , const char * ns , bson * bson ){
235
- char * data;
236
- mongo_message * mm = mongo_message_create( 16 /* header */
237
- + 4 /* ZERO */
238
- + strlen(ns)
239
- + 1 + bson_size(bson)
240
- , 0, 0, mongo_op_insert);
533
+ int mongo_insert( mongo_connection * conn , const char * ns , bson * bson ) {
534
+
535
+ char* data;
536
+ mongo_message* mm;
537
+
538
+ /* Make sure that BSON is valid for insert. */
539
+ if( mongo_bson_valid( conn, bson, 1 ) != MONGO_OK ) {
540
+ return MONGO_ERROR;
541
+ }
542
+
543
+ mm = mongo_message_create( 16 /* header */
544
+ + 4 /* ZERO */
545
+ + strlen(ns)
546
+ + 1 + bson_size(bson)
547
+ , 0, 0, mongo_op_insert);
241
548
 
242
549
  data = &mm->data;
243
550
  data = mongo_data_append32(data, &zero);
244
551
  data = mongo_data_append(data, ns, strlen(ns) + 1);
245
552
  data = mongo_data_append(data, bson->data, bson_size(bson));
246
553
 
247
- mongo_message_send(conn, mm);
554
+ return mongo_message_send(conn, mm);
248
555
  }
249
556
 
250
- void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, const bson* op, int flags){
251
- char * data;
252
- mongo_message * mm = mongo_message_create( 16 /* header */
253
- + 4 /* ZERO */
254
- + strlen(ns) + 1
255
- + 4 /* flags */
256
- + bson_size(cond)
257
- + bson_size(op)
258
- , 0 , 0 , mongo_op_update );
557
+ int mongo_update(mongo_connection* conn, const char* ns, const bson* cond,
558
+ const bson* op, int flags) {
559
+
560
+ char* data;
561
+ mongo_message* mm;
562
+
563
+ /* Make sure that the op BSON is valid UTF-8.
564
+ * TODO: decide whether to check cond as well.
565
+ * */
566
+ if( mongo_bson_valid( conn, op, 0 ) != MONGO_OK ) {
567
+ return MONGO_ERROR;
568
+ }
569
+
570
+ mm = mongo_message_create( 16 /* header */
571
+ + 4 /* ZERO */
572
+ + strlen(ns) + 1
573
+ + 4 /* flags */
574
+ + bson_size(cond)
575
+ + bson_size(op)
576
+ , 0 , 0 , mongo_op_update );
259
577
 
260
578
  data = &mm->data;
261
579
  data = mongo_data_append32(data, &zero);
@@ -264,7 +582,7 @@ void mongo_update(mongo_connection* conn, const char* ns, const bson* cond, cons
264
582
  data = mongo_data_append(data, cond->data, bson_size(cond));
265
583
  data = mongo_data_append(data, op->data, bson_size(op));
266
584
 
267
- mongo_message_send(conn, mm);
585
+ return mongo_message_send(conn, mm);
268
586
  }
269
587
 
270
588
  void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond){
@@ -285,11 +603,12 @@ void mongo_remove(mongo_connection* conn, const char* ns, const bson* cond){
285
603
  mongo_message_send(conn, mm);
286
604
  }
287
605
 
288
- mongo_reply * mongo_read_response( mongo_connection * conn ){
606
+ int mongo_read_response( mongo_connection * conn, mongo_reply** mm ){
289
607
  mongo_header head; /* header from network */
290
608
  mongo_reply_fields fields; /* header from network */
291
609
  mongo_reply * out; /* native endian */
292
- int len;
610
+ unsigned int len;
611
+ int res;
293
612
 
294
613
  looping_read(conn, &head, sizeof(head));
295
614
  looping_read(conn, &fields, sizeof(fields));
@@ -297,7 +616,7 @@ mongo_reply * mongo_read_response( mongo_connection * conn ){
297
616
  bson_little_endian32(&len, &head.len);
298
617
 
299
618
  if (len < sizeof(head)+sizeof(fields) || len > 64*1024*1024)
300
- MONGO_THROW(MONGO_EXCEPT_NETWORK); /* most likely corruption */
619
+ return MONGO_READ_SIZE_ERROR; /* most likely corruption */
301
620
 
302
621
  out = (mongo_reply*)bson_malloc(len);
303
622
 
@@ -311,18 +630,22 @@ mongo_reply * mongo_read_response( mongo_connection * conn ){
311
630
  bson_little_endian32(&out->fields.start, &fields.start);
312
631
  bson_little_endian32(&out->fields.num, &fields.num);
313
632
 
314
- MONGO_TRY{
315
- looping_read(conn, &out->objs, len-sizeof(head)-sizeof(fields));
316
- }MONGO_CATCH{
633
+ res = looping_read(conn, &out->objs, len-sizeof(head)-sizeof(fields));
634
+ if( res != MONGO_OK ) {
317
635
  free(out);
318
- MONGO_RETHROW();
636
+ return res;
319
637
  }
320
638
 
321
- return out;
639
+ *mm = out;
640
+
641
+ return MONGO_OK;
322
642
  }
323
643
 
324
- mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bson* fields, int nToReturn, int nToSkip, int options){
644
+ mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query,
645
+ bson* fields, int nToReturn, int nToSkip, int options) {
646
+
325
647
  int sl;
648
+ int res;
326
649
  volatile mongo_cursor * cursor; /* volatile due to longjmp in mongo exception handler */
327
650
  char * data;
328
651
  mongo_message * mm = mongo_message_create( 16 + /* header */
@@ -349,11 +672,11 @@ mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bs
349
672
 
350
673
  cursor = (mongo_cursor*)bson_malloc(sizeof(mongo_cursor));
351
674
 
352
- MONGO_TRY{
353
- cursor->mm = mongo_read_response(conn);
354
- }MONGO_CATCH{
675
+ res = mongo_read_response( conn, &(cursor->mm) );
676
+ if( res != MONGO_OK ) {
677
+ conn->err = res;
355
678
  free((mongo_cursor*)cursor); /* cast away volatile, not changing type */
356
- MONGO_RETHROW();
679
+ return NULL;
357
680
  }
358
681
 
359
682
  sl = strlen(ns)+1;
@@ -361,24 +684,27 @@ mongo_cursor* mongo_find(mongo_connection* conn, const char* ns, bson* query, bs
361
684
  if (!cursor->ns){
362
685
  free(cursor->mm);
363
686
  free((mongo_cursor*)cursor); /* cast away volatile, not changing type */
364
- return 0;
687
+ return NULL;
365
688
  }
366
689
  memcpy((void*)cursor->ns, ns, sl); /* cast needed to silence GCC warning */
367
690
  cursor->conn = conn;
368
691
  cursor->current.data = NULL;
692
+
369
693
  return (mongo_cursor*)cursor;
370
694
  }
371
695
 
372
- bson_bool_t mongo_find_one(mongo_connection* conn, const char* ns, bson* query, bson* fields, bson* out){
696
+ int mongo_find_one(mongo_connection* conn, const char* ns, bson* query,
697
+ bson* fields, bson* out) {
698
+
373
699
  mongo_cursor* cursor = mongo_find(conn, ns, query, fields, 1, 0, 0);
374
700
 
375
- if (cursor && mongo_cursor_next(cursor)){
701
+ if (cursor && mongo_cursor_next(cursor) == MONGO_OK){
376
702
  bson_copy(out, &cursor->current);
377
703
  mongo_cursor_destroy(cursor);
378
- return 1;
379
- }else{
704
+ return MONGO_OK;
705
+ } else{
380
706
  mongo_cursor_destroy(cursor);
381
- return 0;
707
+ return MONGO_ERROR;
382
708
  }
383
709
  }
384
710
 
@@ -394,45 +720,30 @@ int64_t mongo_count(mongo_connection* conn, const char* db, const char* ns, bson
394
720
  bson_append_bson(&bb, "query", query);
395
721
  bson_from_buffer(&cmd, &bb);
396
722
 
397
- MONGO_TRY{
398
- if(mongo_run_command(conn, db, &cmd, &out)){
399
- bson_iterator it;
400
- if(bson_find(&it, &out, "n"))
401
- count = bson_iterator_long(&it);
402
- }
403
- }MONGO_CATCH{
723
+ if( mongo_run_command(conn, db, &cmd, &out) == MONGO_OK ) {
724
+ bson_iterator it;
725
+ if(bson_find(&it, &out, "n"))
726
+ count = bson_iterator_long(&it);
404
727
  bson_destroy(&cmd);
405
- MONGO_RETHROW();
728
+ bson_destroy(&out);
729
+ return count;
730
+ }
731
+ else {
732
+ bson_destroy(&cmd);
733
+ return MONGO_ERROR;
406
734
  }
407
-
408
- bson_destroy(&cmd);
409
- bson_destroy(&out);
410
- return count;
411
735
  }
412
736
 
413
- bson_bool_t mongo_disconnect( mongo_connection * conn ){
414
- if ( ! conn->connected )
415
- return 1;
416
-
417
- mongo_close_socket( conn->sock );
418
-
419
- conn->sock = 0;
420
- conn->connected = 0;
421
-
422
- return 0;
423
- }
424
737
 
425
- bson_bool_t mongo_destroy( mongo_connection * conn ){
426
- free(conn->left_opts);
427
- free(conn->right_opts);
428
- conn->left_opts = NULL;
429
- conn->right_opts = NULL;
430
738
 
431
- return mongo_disconnect( conn );
432
- }
739
+ int mongo_cursor_get_more(mongo_cursor* cursor){
740
+ int res;
433
741
 
434
- bson_bool_t mongo_cursor_get_more(mongo_cursor* cursor){
435
- if (cursor->mm && cursor->mm->fields.cursorID){
742
+ if( ! cursor->mm->fields.cursorID)
743
+ return MONGO_CURSOR_EXHAUSTED;
744
+ else if( ! cursor->mm )
745
+ return MONGO_CURSOR_INVALID;
746
+ else {
436
747
  mongo_connection* conn = cursor->conn;
437
748
  char* data;
438
749
  int sl = strlen(cursor->ns)+1;
@@ -451,47 +762,47 @@ bson_bool_t mongo_cursor_get_more(mongo_cursor* cursor){
451
762
 
452
763
  free(cursor->mm);
453
764
 
454
- MONGO_TRY{
455
- cursor->mm = mongo_read_response(cursor->conn);
456
- }MONGO_CATCH{
765
+ res = mongo_read_response( cursor->conn, &(cursor->mm) );
766
+ if( res != MONGO_OK ) {
457
767
  cursor->mm = NULL;
458
768
  mongo_cursor_destroy(cursor);
459
- MONGO_RETHROW();
769
+ return res;
460
770
  }
461
771
 
462
- return cursor->mm && cursor->mm->fields.num;
463
- } else{
464
- return 0;
772
+ return MONGO_OK;
465
773
  }
466
774
  }
467
775
 
468
- bson_bool_t mongo_cursor_next(mongo_cursor* cursor){
776
+ int mongo_cursor_next(mongo_cursor* cursor){
469
777
  char* bson_addr;
470
778
 
471
779
  /* no data */
472
- if (!cursor->mm || cursor->mm->fields.num == 0)
473
- return 0;
780
+ if (!cursor->mm || cursor->mm->fields.num == 0) {
781
+ return MONGO_ERROR;
782
+ }
474
783
 
475
784
  /* first */
476
785
  if (cursor->current.data == NULL){
477
786
  bson_init(&cursor->current, &cursor->mm->objs, 0);
478
- return 1;
787
+ return MONGO_OK;
479
788
  }
480
789
 
481
790
  bson_addr = cursor->current.data + bson_size(&cursor->current);
482
791
  if (bson_addr >= ((char*)cursor->mm + cursor->mm->head.len)){
483
- if (!mongo_cursor_get_more(cursor))
484
- return 0;
792
+ if( mongo_cursor_get_more(cursor) != MONGO_OK )
793
+ return MONGO_ERROR;
485
794
  bson_init(&cursor->current, &cursor->mm->objs, 0);
486
795
  } else {
487
796
  bson_init(&cursor->current, bson_addr, 0);
488
797
  }
489
798
 
490
- return 1;
799
+ return MONGO_OK;
491
800
  }
492
801
 
493
- void mongo_cursor_destroy(mongo_cursor* cursor){
494
- if (!cursor) return;
802
+ int mongo_cursor_destroy(mongo_cursor* cursor){
803
+ int result = MONGO_OK;
804
+
805
+ if (!cursor) return result;
495
806
 
496
807
  if (cursor->mm && cursor->mm->fields.cursorID){
497
808
  mongo_connection* conn = cursor->conn;
@@ -505,22 +816,17 @@ void mongo_cursor_destroy(mongo_cursor* cursor){
505
816
  data = mongo_data_append32(data, &one);
506
817
  data = mongo_data_append64(data, &cursor->mm->fields.cursorID);
507
818
 
508
- MONGO_TRY{
509
- mongo_message_send(conn, mm);
510
- }MONGO_CATCH{
511
- free(cursor->mm);
512
- free((void*)cursor->ns);
513
- free(cursor);
514
- MONGO_RETHROW();
515
- }
819
+ result = mongo_message_send(conn, mm);
820
+
821
+ free(cursor->mm);
822
+ free((void*)cursor->ns);
823
+ free(cursor);
516
824
  }
517
825
 
518
- free(cursor->mm);
519
- free((void*)cursor->ns);
520
- free(cursor);
826
+ return result;
521
827
  }
522
828
 
523
- bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out){
829
+ int mongo_create_index(mongo_connection * conn, const char * ns, bson * key, int options, bson * out){
524
830
  bson_buffer bb;
525
831
  bson b;
526
832
  bson_iterator it;
@@ -552,7 +858,7 @@ bson_bool_t mongo_create_index(mongo_connection * conn, const char * ns, bson *
552
858
  bson_destroy(&b);
553
859
 
554
860
  *strchr(idxns, '.') = '\0'; /* just db not ns */
555
- return !mongo_cmd_get_last_error(conn, idxns, out);
861
+ return mongo_cmd_get_last_error(conn, idxns, out);
556
862
  }
557
863
  bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns, const char* field, int options, bson * out){
558
864
  bson_buffer bb;
@@ -568,20 +874,25 @@ bson_bool_t mongo_create_simple_index(mongo_connection * conn, const char * ns,
568
874
  return success;
569
875
  }
570
876
 
571
- bson_bool_t mongo_run_command(mongo_connection * conn, const char * db, bson * command, bson * out){
877
+ int mongo_run_command(mongo_connection* conn, const char* db, bson* command,
878
+ bson* out) {
879
+
572
880
  bson fields;
573
881
  int sl = strlen(db);
574
882
  char* ns = bson_malloc(sl + 5 + 1); /* ".$cmd" + nul */
575
- bson_bool_t success;
883
+ int res;
576
884
 
577
885
  strcpy(ns, db);
578
886
  strcpy(ns+sl, ".$cmd");
579
887
 
580
- success = mongo_find_one(conn, ns, command, bson_empty(&fields), out);
888
+ res = mongo_find_one(conn, ns, command, bson_empty(&fields), out);
581
889
  free(ns);
582
- return success;
890
+ return res;
583
891
  }
584
- bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, const char* cmdstr, int arg, bson * realout){
892
+
893
+ int mongo_simple_int_command(mongo_connection * conn, const char * db,
894
+ const char* cmdstr, int arg, bson * realout) {
895
+
585
896
  bson out;
586
897
  bson cmd;
587
898
  bson_buffer bb;
@@ -591,7 +902,7 @@ bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, c
591
902
  bson_append_int(&bb, cmdstr, arg);
592
903
  bson_from_buffer(&cmd, &bb);
593
904
 
594
- if(mongo_run_command(conn, db, &cmd, &out)){
905
+ if( mongo_run_command(conn, db, &cmd, &out) == MONGO_OK ){
595
906
  bson_iterator it;
596
907
  if(bson_find(&it, &out, "ok"))
597
908
  success = bson_iterator_bool(&it);
@@ -604,20 +915,27 @@ bson_bool_t mongo_simple_int_command(mongo_connection * conn, const char * db, c
604
915
  else
605
916
  bson_destroy(&out);
606
917
 
607
- return success;
918
+ if( success )
919
+ return MONGO_OK;
920
+ else {
921
+ conn->err = MONGO_COMMAND_FAILED;
922
+ return MONGO_ERROR;
923
+ }
608
924
  }
609
925
 
610
- bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, const char* cmdstr, const char* arg, bson * realout){
926
+ int mongo_simple_str_command(mongo_connection * conn, const char * db,
927
+ const char* cmdstr, const char* arg, bson * realout) {
928
+
611
929
  bson out;
612
930
  bson cmd;
613
931
  bson_buffer bb;
614
- bson_bool_t success = 0;
932
+ int success = 0;
615
933
 
616
934
  bson_buffer_init(&bb);
617
935
  bson_append_string(&bb, cmdstr, arg);
618
936
  bson_from_buffer(&cmd, &bb);
619
937
 
620
- if(mongo_run_command(conn, db, &cmd, &out)){
938
+ if( mongo_run_command(conn, db, &cmd, &out) == MONGO_OK ) {
621
939
  bson_iterator it;
622
940
  if(bson_find(&it, &out, "ok"))
623
941
  success = bson_iterator_bool(&it);
@@ -630,14 +948,17 @@ bson_bool_t mongo_simple_str_command(mongo_connection * conn, const char * db, c
630
948
  else
631
949
  bson_destroy(&out);
632
950
 
633
- return success;
951
+ if(success)
952
+ return MONGO_OK;
953
+ else
954
+ return MONGO_ERROR;
634
955
  }
635
956
 
636
- bson_bool_t mongo_cmd_drop_db(mongo_connection * conn, const char * db){
957
+ int mongo_cmd_drop_db(mongo_connection * conn, const char * db){
637
958
  return mongo_simple_int_command(conn, db, "dropDatabase", 1, NULL);
638
959
  }
639
960
 
640
- bson_bool_t mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out){
961
+ int mongo_cmd_drop_collection(mongo_connection * conn, const char * db, const char * collection, bson * out){
641
962
  return mongo_simple_str_command(conn, db, "drop", collection, out);
642
963
  }
643
964
 
@@ -645,14 +966,30 @@ void mongo_cmd_reset_error(mongo_connection * conn, const char * db){
645
966
  mongo_simple_int_command(conn, db, "reseterror", 1, NULL);
646
967
  }
647
968
 
648
- static bson_bool_t mongo_cmd_get_error_helper(mongo_connection * conn, const char * db, bson * realout, const char * cmdtype){
969
+ static int mongo_cmd_get_error_helper(mongo_connection * conn, const char * db,
970
+ bson * realout, const char * cmdtype) {
971
+
649
972
  bson out = {NULL,0};
650
- bson_bool_t haserror = 1;
973
+ bson_bool_t haserror = 0;
651
974
 
975
+ /* Reset last error codes. */
976
+ conn->lasterrcode = 0;
977
+ free(conn->lasterrstr);
978
+ conn->lasterrstr = NULL;
652
979
 
653
- if(mongo_simple_int_command(conn, db, cmdtype, 1, &out)){
980
+ /* If there's an error, store its code and string in the connection object. */
981
+ if( mongo_simple_int_command(conn, db, cmdtype, 1, &out) == MONGO_OK ) {
654
982
  bson_iterator it;
655
983
  haserror = (bson_find(&it, &out, "err") != bson_null);
984
+ if( haserror ) {
985
+ conn->lasterrstr = (char *)bson_malloc( bson_iterator_string_len( &it ) );
986
+ if( conn->lasterrstr ) {
987
+ strcpy( conn->lasterrstr, bson_iterator_string( &it ) );
988
+ }
989
+
990
+ if( bson_find( &it, &out, "code" ) != bson_null )
991
+ conn->lasterrcode = bson_iterator_int( &it );
992
+ }
656
993
  }
657
994
 
658
995
  if(realout)
@@ -660,13 +997,17 @@ static bson_bool_t mongo_cmd_get_error_helper(mongo_connection * conn, const cha
660
997
  else
661
998
  bson_destroy(&out);
662
999
 
663
- return haserror;
1000
+ if( haserror )
1001
+ return MONGO_ERROR;
1002
+ else
1003
+ return MONGO_OK;
664
1004
  }
665
1005
 
666
- bson_bool_t mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out){
1006
+ int mongo_cmd_get_prev_error(mongo_connection * conn, const char * db, bson * out) {
667
1007
  return mongo_cmd_get_error_helper(conn, db, out, "getpreverror");
668
1008
  }
669
- bson_bool_t mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out){
1009
+
1010
+ int mongo_cmd_get_last_error(mongo_connection * conn, const char * db, bson * out) {
670
1011
  return mongo_cmd_get_error_helper(conn, db, out, "getlasterror");
671
1012
  }
672
1013
 
@@ -674,7 +1015,7 @@ bson_bool_t mongo_cmd_ismaster(mongo_connection * conn, bson * realout){
674
1015
  bson out = {NULL,0};
675
1016
  bson_bool_t ismaster = 0;
676
1017
 
677
- if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out)){
1018
+ if (mongo_simple_int_command(conn, "admin", "ismaster", 1, &out) == MONGO_OK){
678
1019
  bson_iterator it;
679
1020
  bson_find(&it, &out, "ismaster");
680
1021
  ismaster = bson_iterator_bool(&it);
@@ -710,12 +1051,13 @@ static void mongo_pass_digest(const char* user, const char* pass, char hex_diges
710
1051
  digest2hex(digest, hex_digest);
711
1052
  }
712
1053
 
713
- void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass){
1054
+ int mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user, const char* pass){
714
1055
  bson_buffer bb;
715
1056
  bson user_obj;
716
1057
  bson pass_obj;
717
1058
  char hex_digest[33];
718
1059
  char* ns = bson_malloc(strlen(db) + strlen(".system.users") + 1);
1060
+ int res;
719
1061
 
720
1062
  strcpy(ns, db);
721
1063
  strcpy(ns+strlen(db), ".system.users");
@@ -733,18 +1075,13 @@ void mongo_cmd_add_user(mongo_connection* conn, const char* db, const char* user
733
1075
  bson_from_buffer(&pass_obj, &bb);
734
1076
 
735
1077
 
736
- MONGO_TRY{
737
- mongo_update(conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT);
738
- }MONGO_CATCH{
739
- free(ns);
740
- bson_destroy(&user_obj);
741
- bson_destroy(&pass_obj);
742
- MONGO_RETHROW();
743
- }
1078
+ res = mongo_update(conn, ns, &user_obj, &pass_obj, MONGO_UPDATE_UPSERT);
744
1079
 
745
1080
  free(ns);
746
1081
  bson_destroy(&user_obj);
747
1082
  bson_destroy(&pass_obj);
1083
+
1084
+ return res;
748
1085
  }
749
1086
 
750
1087
  bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const char* user, const char* pass){
@@ -757,12 +1094,13 @@ bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const
757
1094
  mongo_md5_byte_t digest[16];
758
1095
  char hex_digest[33];
759
1096
 
760
- if (mongo_simple_int_command(conn, db, "getnonce", 1, &from_db)){
1097
+ if( mongo_simple_int_command(conn, db, "getnonce", 1, &from_db) == MONGO_OK ) {
761
1098
  bson_iterator it;
762
1099
  bson_find(&it, &from_db, "nonce");
763
1100
  nonce = bson_iterator_string(&it);
764
- }else{
765
- return 0;
1101
+ }
1102
+ else {
1103
+ return MONGO_ERROR;
766
1104
  }
767
1105
 
768
1106
  mongo_pass_digest(user, pass, hex_digest);
@@ -783,19 +1121,17 @@ bson_bool_t mongo_cmd_authenticate(mongo_connection* conn, const char* db, const
783
1121
 
784
1122
  bson_destroy(&from_db);
785
1123
 
786
- MONGO_TRY{
787
- if(mongo_run_command(conn, db, &auth_cmd, &from_db)){
788
- bson_iterator it;
789
- if(bson_find(&it, &from_db, "ok"))
790
- success = bson_iterator_bool(&it);
791
- }
792
- }MONGO_CATCH{
793
- bson_destroy(&auth_cmd);
794
- MONGO_RETHROW();
1124
+ if( mongo_run_command(conn, db, &auth_cmd, &from_db) == MONGO_OK ) {
1125
+ bson_iterator it;
1126
+ if(bson_find(&it, &from_db, "ok"))
1127
+ success = bson_iterator_bool(&it);
795
1128
  }
796
1129
 
797
1130
  bson_destroy(&from_db);
798
1131
  bson_destroy(&auth_cmd);
799
1132
 
800
- return success;
1133
+ if( success )
1134
+ return MONGO_OK;
1135
+ else
1136
+ return MONGO_ERROR;
801
1137
  }