faststep 0.0.8.1 → 0.1.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
  }