static int get_header(int sock, SV *cursor_sv, SV *link_sv) { mongo_cursor *cursor; mongo_link *link; int size; cursor = (mongo_cursor*)perl_mongo_get_ptr_from_instance(cursor_sv, &cursor_vtbl); link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv, &connection_vtbl); size = 0; size = link->receiver(link, (char*)&cursor->header.length, INT_32); if(size != INT_32){ set_disconnected(link_sv); return 0; } cursor->header.length = MONGO_32(cursor->header.length); // make sure we're not getting crazy data if (cursor->header.length > MAX_RESPONSE_LEN || cursor->header.length < REPLY_HEADER_SIZE) { set_disconnected(link_sv); return 0; } if (link->receiver(link, (char*)&cursor->header.request_id, INT_32) != INT_32 || link->receiver(link, (char*)&cursor->header.response_to, INT_32) != INT_32 || link->receiver(link, (char*)&cursor->header.op, INT_32) != INT_32) { return 0; } cursor->header.request_id = MONGO_32(cursor->header.request_id); cursor->header.response_to = MONGO_32(cursor->header.response_to); cursor->header.op = MONGO_32(cursor->header.op); return 1; }
/* * Gets a reply from the MongoDB server and * creates a cursor for it */ int mongo_link_hear(SV *cursor_sv) { int sock; int num_returned = 0; mongo_cursor *cursor = (mongo_cursor*)perl_mongo_get_ptr_from_instance(cursor_sv); SV *link_sv = perl_mongo_call_reader(cursor_sv, "_connection"); mongo_link *link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv); if (!check_connection(link)) { croak("can't get db response, not connected"); return 0; } sock = perl_mongo_link_master(link_sv); // if this fails, we might be disconnected... but we're probably // just out of results if (recv(sock, (char*)&cursor->header.length, INT_32, 0) == -1) { return 0; } // make sure we're not getting crazy data if (cursor->header.length > MAX_RESPONSE_LEN || cursor->header.length < REPLY_HEADER_SIZE) { set_disconnected(link); if (!check_connection(link)) { croak("bad response length: %d, max: %d, did the db assert?\n", cursor->header.length, MAX_RESPONSE_LEN); return 0; } } if (recv(sock, (char*)&cursor->header.request_id, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.response_to, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.op, INT_32, 0) == -1 || recv(sock, (char*)&cursor->flag, INT_32, 0) == -1 || recv(sock, (char*)&cursor->cursor_id, INT_64, 0) == -1 || recv(sock, (char*)&cursor->start, INT_32, 0) == -1 || recv(sock, (char*)&num_returned, INT_32, 0) == -1) { return 0; } // create buf cursor->header.length -= INT_32*9; // point buf.start at buf's first char if (!cursor->buf.start) { Newx(cursor->buf.start, cursor->header.length, char); cursor->buf.end = cursor->buf.start + cursor->header.length; }
static int get_header(int sock, SV *cursor_sv, SV *link_sv) { mongo_cursor *cursor; cursor = (mongo_cursor*)perl_mongo_get_ptr_from_instance(cursor_sv); if (recv(sock, (char*)&cursor->header.length, INT_32, 0) == -1) { SvREFCNT_dec(link_sv); return 0; } cursor->header.length = MONGO_32(cursor->header.length); // make sure we're not getting crazy data if (cursor->header.length > MAX_RESPONSE_LEN || cursor->header.length < REPLY_HEADER_SIZE) { set_disconnected(link_sv); return 0; } if (recv(sock, (char*)&cursor->header.request_id, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.response_to, INT_32, 0) == -1 || recv(sock, (char*)&cursor->header.op, INT_32, 0) == -1) { return 0; } cursor->header.request_id = MONGO_32(cursor->header.request_id); cursor->header.response_to = MONGO_32(cursor->header.response_to); cursor->header.op = MONGO_32(cursor->header.op); return 1; }
/* * Sends a message to the MongoDB server */ int mongo_link_say(SV *link_sv, buffer *buf) { int sock, sent; mongo_link *link; link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv, &connection_vtbl); if ((sock = perl_mongo_master(link_sv, 1)) == -1) { return -1; } sent = link->sender(link, (const char*)buf->start, buf->pos-buf->start); if (sent == -1) { set_disconnected(link_sv); } return sent; }
/* * Sends a message to the MongoDB server */ int mongo_link_say(SV *link_sv, buffer *buf) { int sock, sent; mongo_link *link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv); if (!check_connection(link)) { croak("can't get db response, not connected"); return -1; } sock = perl_mongo_link_master(link_sv); sent = send(sock, (const char*)buf->start, buf->pos-buf->start, 0); if (sent == -1) { if (check_connection(link)) { sock = perl_mongo_link_master(link_sv); sent = send(sock, (const char*)buf->start, buf->pos-buf->start, 0); } else { return -1; } } return sent; }
/* * Gets a reply from the MongoDB server and * creates a cursor for it */ int mongo_link_hear(SV *cursor_sv) { int sock; int num_returned = 0, timeout = -1; mongo_cursor *cursor; mongo_link *link; SV *link_sv, *request_id_sv, *timeout_sv; cursor = (mongo_cursor*)perl_mongo_get_ptr_from_instance(cursor_sv); link_sv = perl_mongo_call_reader(cursor_sv, "_connection"); link = (mongo_link*)perl_mongo_get_ptr_from_instance(link_sv); timeout_sv = perl_mongo_call_reader(link_sv, "query_timeout"); if ((sock = perl_mongo_master(link_sv)) == -1) { set_disconnected(link_sv); SvREFCNT_dec(link_sv); croak("can't get db response, not connected"); } timeout = SvIV(timeout_sv); SvREFCNT_dec(timeout_sv); // set a timeout if (timeout >= 0) { struct timeval t; fd_set readfds; t.tv_sec = timeout / 1000 ; t.tv_usec = (timeout % 1000) * 1000; FD_ZERO(&readfds); FD_SET(sock, &readfds); select(sock+1, &readfds, NULL, NULL, &t); if (!FD_ISSET(sock, &readfds)) { SvREFCNT_dec(link_sv); croak("recv timed out (%d ms)", timeout); return 0; } } if (get_header(sock, cursor_sv, link_sv) == 0) { SvREFCNT_dec(link_sv); return 0; } request_id_sv = perl_mongo_call_reader(cursor_sv, "_request_id"); while (SvIV(request_id_sv) != cursor->header.response_to) { char temp[4096]; int len = cursor->header.length - 36; if (SvIV(request_id_sv) < cursor->header.response_to) { SvREFCNT_dec(link_sv); SvREFCNT_dec(request_id_sv); croak("missed the response we wanted, please try again"); return 0; } if (recv(sock, (char*)temp, 20, 0) == -1) { SvREFCNT_dec(link_sv); SvREFCNT_dec(request_id_sv); croak("couldn't get header response to throw out"); return 0; } do { int temp_len = len > 4096 ? 4096 : len; len -= temp_len; if (mongo_link_reader(sock, (void*)temp, temp_len) == -1) { SvREFCNT_dec(link_sv); SvREFCNT_dec(request_id_sv); croak("couldn't get response to throw out"); return 0; } } while (len > 0); if (get_header(sock, cursor_sv, link_sv) == 0) { SvREFCNT_dec(link_sv); SvREFCNT_dec(request_id_sv); return 0; } } SvREFCNT_dec(request_id_sv); if (recv(sock, (char*)&cursor->flag, INT_32, 0) == -1 || recv(sock, (char*)&cursor->cursor_id, INT_64, 0) == -1 || recv(sock, (char*)&cursor->start, INT_32, 0) == -1 || recv(sock, (char*)&num_returned, INT_32, 0) == -1) { SvREFCNT_dec(link_sv); croak("%s", strerror(errno)); return 0; } SvREFCNT_dec(link_sv); cursor->flag = MONGO_32(cursor->flag); // if zero-th bit is set, cursor is invalid if (cursor->flag & 1) { cursor->num = 0; croak("cursor not found"); } cursor->cursor_id = MONGO_64(cursor->cursor_id); cursor->start = MONGO_32(cursor->start); num_returned = MONGO_32(num_returned); // create buf cursor->header.length -= INT_32*9; // point buf.start at buf's first char if (!cursor->buf.start) { New(0, cursor->buf.start, cursor->header.length, char); cursor->buf.end = cursor->buf.start + cursor->header.length; }