static gpointer pull_buffer_impl( XferElement *elt, size_t *size) { XferFilterCrc *self = (XferFilterCrc *)elt; char *buf; XMsg *msg; if (elt->cancelled) { /* drain our upstream only if we're expecting an EOF */ if (elt->expect_eof) { xfer_element_drain_buffers(XFER_ELEMENT(self)->upstream); } /* return an EOF */ *size = 0; return NULL; } /* get a buffer from upstream, crc it, and hand it back */ buf = xfer_element_pull_buffer(XFER_ELEMENT(self)->upstream, size); if (buf) { crc32_add((uint8_t *)buf, *size, &elt->crc); } else { g_debug("sending XMSG_CRC message"); g_debug("crc pull_buffer CRC: %08x", crc32_finish(&elt->crc)); msg = xmsg_new(elt, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); } return buf; }
static void push_buffer_impl( XferElement *elt, gpointer buf, size_t len) { XferFilterCrc *self = (XferFilterCrc *)elt; XMsg *msg; /* drop the buffer if we've been cancelled */ if (elt->cancelled) { amfree(buf); return; } /* crc the given buffer and pass it downstream */ if (buf) { crc32_add((uint8_t *)buf, len, &elt->crc); } else { g_debug("sending XMSG_CRC message to %p", elt); g_debug("crc push_buffer CRC: %08x", crc32_finish(&elt->crc)); msg = xmsg_new(elt, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); } xfer_element_push_buffer(XFER_ELEMENT(self)->downstream, buf, len); }
static void pull_and_write(XferElementGlue *self) { XferElement *elt = XFER_ELEMENT(self); int fd = get_write_fd(self); XMsg *msg; size_t written; self->write_fdp = NULL; while (!elt->cancelled) { size_t len; char *buf; /* get a buffer from upstream */ buf = xfer_element_pull_buffer(elt->upstream, &len); if (!buf) break; /* write it */ if (!elt->downstream->drain_mode) { written = full_write(fd, buf, len); if (written < len) { if (elt->downstream->must_drain) { g_debug("Error writing to fd %d: %s", fd, strerror(errno)); } else if (elt->downstream->ignore_broken_pipe && errno == EPIPE) { } else { if (!elt->cancelled) { xfer_cancel_with_error(elt, _("Error writing to fd %d: %s"), fd, strerror(errno)); xfer_cancel(elt->xfer); wait_until_xfer_cancelled(elt->xfer); } amfree(buf); break; } elt->downstream->drain_mode = TRUE; } } crc32_add((uint8_t *)buf, len, &elt->crc); amfree(buf); } if (elt->cancelled && elt->expect_eof) xfer_element_drain_buffers(elt->upstream); g_debug("sending XMSG_CRC message %p", elt->downstream); g_debug("pull_and_write CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(elt->downstream, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); /* close the fd we've been writing, as an EOF signal to downstream, and * set it to -1 to avoid accidental re-use */ close_write_fd(self); }
static void read_and_push( XferElementGlue *self) { XferElement *elt = XFER_ELEMENT(self); int fd = get_read_fd(self); XMsg *msg; crc32_init(&elt->crc); while (!elt->cancelled) { char *buf = g_malloc(GLUE_BUFFER_SIZE); gsize len; int read_error; /* read a buffer from upstream */ len = read_fully(fd, buf, GLUE_BUFFER_SIZE, &read_error); if (len < GLUE_BUFFER_SIZE) { if (read_error) { if (!elt->cancelled) { xfer_cancel_with_error(elt, _("Error reading from fd %d: %s"), fd, strerror(read_error)); g_debug("element-glue: error reading from fd %d: %s", fd, strerror(read_error)); wait_until_xfer_cancelled(elt->xfer); } amfree(buf); break; } else if (len == 0) { /* we only count a zero-length read as EOF */ amfree(buf); break; } } crc32_add((uint8_t *)buf, len, &elt->crc); xfer_element_push_buffer(elt->downstream, buf, len); } if (elt->cancelled && elt->expect_eof) xfer_element_drain_fd(fd); /* send an EOF indication downstream */ xfer_element_push_buffer(elt->downstream, NULL, 0); /* close the read fd, since it's at EOF */ close_read_fd(self); g_debug("sending XMSG_CRC message"); g_debug("read_and_push CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(elt->upstream, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); }
static int test_size( size_t size) { crc_t crc1; crc_t crc16; #if defined __GNUC__ && GCC_VERSION > 40300 && (defined __x86_64__ || defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__) crc_t crchw; #endif crc32_init(&crc1); crc32_init(&crc16); #if defined __GNUC__ && GCC_VERSION > 40300 && (defined __x86_64__ || defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__) crc32_init(&crchw); #endif crc32_add_1byte(test_buf, size, &crc1); crc32_add_16bytes(test_buf, size, &crc16); #if defined __GNUC__ && GCC_VERSION > 40300 && (defined __x86_64__ || defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__) if (have_sse42) { crc32c_add_hw(test_buf, size, &crchw); } #endif #if defined __GNUC__ && GCC_VERSION > 40300 && (defined __x86_64__ || defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__) g_fprintf(stderr, " %08x:%lld %08x:%lld %08x:%lld\n", crc32_finish(&crc1), (long long)crc1.size, crc32_finish(&crc16), (long long)crc16.size, crc32_finish(&crchw), (long long)crchw.size); #else g_fprintf(stderr, " %08x:%lld %08x:%lld\n", crc32_finish(&crc1), (long long)crc1.size, crc32_finish(&crc16), (long long)crc16.size); #endif if (crc1.crc != crc16.crc || crc1.size != crc16.size) { g_fprintf(stderr, " CRC16 %zu %08x:%lld != %08x:%lld\n", size, crc32_finish(&crc1), (long long)crc1.size, crc32_finish(&crc16), (long long)crc16.size); return FALSE; } #if defined __GNUC__ && GCC_VERSION > 40300 && (defined __x86_64__ || defined __i386__ || defined __i486__ || defined __i586__ || defined __i686__) if (have_sse42) { if (crc1.crc != crchw.crc || crc1.size != crchw.size) { g_fprintf(stderr, " CRChw %zu %08x:%lld != %08x:%lld\n", size, crc32_finish(&crc1), (long long)crc1.size, crc32_finish(&crchw), (long long)crchw.size); return FALSE; } } #endif return TRUE; }
static int send_error_msg(port_addr fd, int error_code) { // Send a fail response - <magic><resp_length = 8><error_code><crc> uint32_t resp_length = 8; uint32_t crc = crc32_start(); crc = crc32_append(crc, &magic, 4); crc = crc32_append(crc, &resp_length, 4); crc = crc32_append(crc, &error_code, 4); crc = crc32_finish(crc); serial_write(fd, &magic, 4); serial_write(fd, &resp_length, 4); serial_write(fd, &error_code, 4); serial_write(fd, &crc, 4); fprintf(stderr, "Sent ERROR %i response\n", error_code); return 0; }
static void push_buffer_impl( XferElement *elt, gpointer buf, size_t len) { XferDestNull *self = (XferDestNull *)elt; if (buf) { crc32_add(buf, len, &elt->crc); } else { XMsg *msg = xmsg_new((XferElement *)self, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(XFER_ELEMENT(self)->xfer, msg); return; } if (self->do_verify && !elt->cancelled) { if (!simpleprng_verify_buffer(&self->prng, buf, len)) { xfer_cancel_with_error(elt, "verification of incoming bytestream failed; see stderr for details"), wait_until_xfer_cancelled(elt->xfer); amfree(buf); return; } } self->byte_position += len; if (!self->sent_info) { /* send a superfluous message (this is a testing XferElement, * after all) */ XMsg *msg = xmsg_new((XferElement *)self, XMSG_INFO, 0); msg->message = g_strdup("Is this thing on?"); xfer_queue_message(XFER_ELEMENT(self)->xfer, msg); self->sent_info = TRUE; } amfree(buf); }
int crc32_test(void) { #ifndef LTC_TEST return CRYPT_NOP; #else const void* in = "libtomcrypt"; const unsigned char crc32[] = { 0xef, 0x76, 0x73, 0xb3 }; unsigned char out[4]; crc32_state ctx; crc32_init(&ctx); crc32_update(&ctx, in, strlen(in)); crc32_finish(&ctx, out, 4); if (XMEMCMP(crc32, out, 4)) { #ifdef LTC_TEST_DBG ulong32 _out, _crc32; LOAD32H(_out, out); LOAD32H(_crc32, crc32); printf("crc32 fail! Is: 0x%x Should: 0x%x\n", _out, _crc32); #endif return CRYPT_FAIL_TESTVECTOR; } return CRYPT_OK; #endif }
static int do_cmd(int cmd, port_addr fd) { switch(cmd) { case 0: { // Identify command // Read the command crc uint32_t ccrc; serial_read(fd, &ccrc, 4); uint32_t eccrc = crc32((void *)0, 0); if(ccrc != eccrc) return send_error_msg(fd, CRC_ERROR); // Set the response length and error code uint32_t resp_length = 12; uint32_t error_code = SUCCESS; // Build the response crc uint32_t crc = crc32_start(); crc = crc32_append(crc, &magic, 4); crc = crc32_append(crc, &resp_length, 4); crc = crc32_append(crc, &error_code, 4); crc = crc32_append(crc, &server_caps, 4); crc = crc32_finish(crc); // Send the response serial_write(fd, &magic, 4); serial_write(fd, &resp_length, 4); serial_write(fd, &error_code, 4); serial_write(fd, &server_caps, 4); serial_write(fd, &crc, 4); fprintf(stderr, "Sent CMD0 response\n"); return 0; } case 1: { // Read directory uint32_t eccrc = crc32_start(); // Read the directory name uint16_t dir_name_len; serial_read(fd, &dir_name_len, 2); eccrc = crc32_append(eccrc, &dir_name_len, 2); char *dir_name = (char *)malloc((int)dir_name_len + 1); memset(dir_name, 0, dir_name_len + 1); serial_read(fd, dir_name, (size_t)dir_name_len); eccrc = crc32_append(eccrc, dir_name, (size_t)dir_name_len); eccrc = crc32_finish(eccrc); // Read the command crc uint32_t ccrc; serial_read(fd, &ccrc, 4); if(ccrc != eccrc) return send_error_msg(fd, CRC_ERROR); // Append the requested dir to the base dir int full_dir_len = strlen(base_dir) + 1 + dir_name_len + 1; char *full_dir = (char *)malloc(full_dir_len); memset(full_dir, 0, full_dir_len); strcat(full_dir, base_dir); strcat(full_dir, "/"); strcat(full_dir, dir_name); // Try and read the requested directory DIR *dirp = opendir(full_dir); if(dirp == NULL) { free(dir_name); free(full_dir); if((errno == ENOENT) || (errno == ENOTDIR)) return send_error_msg(fd, PATH_NOT_FOUND); else return send_error_msg(fd, UNKNOWN_ERROR); } // Count the directory entries int byte_count = 0; uint32_t entry_count = 0; struct dirent *de; while((de = readdir(dirp)) != NULL) { // Add space for byte_size, user_id, group_id // and props fields byte_count += 16; // Add space for name string byte_count += 2; byte_count += strlen(de->d_name); entry_count++; } rewinddir(dirp); // Allocate the buffer to send uint8_t *buf = (uint8_t *)malloc(byte_count); int bptr = 0; // Fill in the buffer uint32_t entries_filled = 0; while((de = readdir(dirp)) != NULL) { // Build a string of the whole filename int fname_len = strlen(de->d_name); int path_len = full_dir_len + 1 + fname_len + 1; char *path = (char *)malloc(path_len); memset(path, 0, path_len); strcat(path, full_dir); strcat(path, "/"); strcat(path, de->d_name); // Get the file stats struct stat stat_buf; if(stat(path, &stat_buf) != 0) { fprintf(stderr, "Error running fstat on %s, errno = %i\n", path, errno); free(path); free(buf); free(full_dir); free(dir_name); return send_error_msg(fd, UNKNOWN_ERROR); } // Fill in the buffer write_word((uint32_t)stat_buf.st_size, buf, bptr); write_word((uint32_t)stat_buf.st_uid, buf, bptr + 4); write_word((uint32_t)stat_buf.st_gid, buf, bptr + 8); write_word((uint32_t)stat_buf.st_mode, buf, bptr + 12); bptr += 16; // Fill in the name write_halfword((uint16_t)dir_name_len, buf, bptr); bptr += 2; memcpy(&buf[bptr], de->d_name, dir_name_len); bptr += dir_name_len; free(path); entries_filled++; } if(entries_filled != entry_count) { // An error has occurred re-parsing the directory fprintf(stderr, "entries_filled (%i) != entry_count (%i)\n", entries_filled, entry_count); free(buf); free(dir_name); free(full_dir); send_error_msg(fd, UNKNOWN_ERROR); } fprintf(stderr, "SERVER: %i directory entries, byte_count %i\n", entry_count, byte_count); // Set the response length and error code uint32_t resp_length = 16 + byte_count; uint32_t error_code = SUCCESS; uint32_t dir_entry_version = 0; // Build the response crc uint32_t crc = crc32_start(); crc = crc32_append(crc, &magic, 4); crc = crc32_append(crc, &resp_length, 4); crc = crc32_append(crc, &error_code, 4); crc = crc32_append(crc, &entry_count, 4); crc = crc32_append(crc, &dir_entry_version, 4); crc = crc32_append(crc, buf, byte_count); crc = crc32_finish(crc); // Send the response serial_write(fd, &magic, 4); serial_write(fd, &resp_length, 4); serial_write(fd, &error_code, 4); serial_write(fd, &entry_count, 4); serial_write(fd, &dir_entry_version, 4); serial_write(fd, buf, byte_count); serial_write(fd, &crc, 4); fprintf(stderr, "Sent CMD1 response\n"); free(buf); free(dir_name); free(full_dir); return 0; } } (void)fd; return 0; }
static void read_and_write(XferElementGlue *self) { XferElement *elt = XFER_ELEMENT(self); /* dynamically allocate a buffer, in case this thread has * a limited amount of stack allocated */ char *buf = g_malloc(GLUE_BUFFER_SIZE); int rfd = get_read_fd(self); int wfd = get_write_fd(self); XMsg *msg; crc32_init(&elt->crc); g_debug("read_and_write: read from %d, write to %d", rfd, wfd); while (!elt->cancelled) { size_t len; /* read from upstream */ len = read_fully(rfd, buf, GLUE_BUFFER_SIZE, NULL); if (len < GLUE_BUFFER_SIZE) { if (errno) { if (!elt->cancelled) { xfer_cancel_with_error(elt, _("Error reading from fd %d: %s"), rfd, strerror(errno)); wait_until_xfer_cancelled(elt->xfer); } break; } else if (len == 0) { /* we only count a zero-length read as EOF */ break; } } /* write the buffer fully */ if (!elt->downstream->drain_mode && full_write(wfd, buf, len) < len) { if (elt->downstream->must_drain) { g_debug("Could not write to fd %d: %s", wfd, strerror(errno)); } else if (elt->downstream->ignore_broken_pipe && errno == EPIPE) { } else { if (!elt->cancelled) { xfer_cancel_with_error(elt, _("Could not write to fd %d: %s"), wfd, strerror(errno)); wait_until_xfer_cancelled(elt->xfer); } break; } } crc32_add((uint8_t *)buf, len, &elt->crc); } if (elt->cancelled && elt->expect_eof) xfer_element_drain_fd(rfd); /* close the read fd. If it's not at EOF, then upstream will get EPIPE, which will hopefully * kill it and complete the cancellation */ close_read_fd(self); /* close the fd we've been writing, as an EOF signal to downstream */ close_write_fd(self); g_debug("read_and_write upstream CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); g_debug("sending XMSG_CRC message"); msg = xmsg_new(elt->upstream, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); g_debug("read_and_write downstream CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); g_debug("sending XMSG_CRC message"); msg = xmsg_new(elt->downstream, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); amfree(buf); }
static void push_buffer_impl( XferElement *elt, gpointer buf, size_t len) { XferElementGlue *self = (XferElementGlue *)elt; XMsg *msg; /* accept first, if required */ if (self->on_push & PUSH_ACCEPT_FIRST) { /* don't accept the next time around */ self->on_push &= ~PUSH_ACCEPT_FIRST; if (elt->cancelled) { return; } if ((self->output_data_socket = do_directtcp_accept(self, &self->output_listen_socket)) == -1) { /* do_directtcp_accept already signalled an error; xfer * is cancelled */ return; } /* write to this new socket */ self->write_fdp = &self->output_data_socket; } /* or connect first, if required */ if (self->on_push & PUSH_CONNECT_FIRST) { /* don't accept the next time around */ self->on_push &= ~PUSH_CONNECT_FIRST; if (elt->cancelled) { return; } if ((self->output_data_socket = do_directtcp_connect(self, elt->downstream->input_listen_addrs)) == -1) { /* do_directtcp_connect already signalled an error; xfer * is cancelled */ return; } /* read from this new socket */ self->write_fdp = &self->output_data_socket; } switch (self->on_push) { case PUSH_TO_RING_BUFFER: /* just drop packets if the transfer has been cancelled */ if (elt->cancelled) { amfree(buf); return; } /* make sure there's at least one element free */ amsemaphore_down(self->ring_free_sem); /* set it */ self->ring[self->ring_head].buf = buf; self->ring[self->ring_head].size = len; self->ring_head = (self->ring_head + 1) % GLUE_RING_BUFFER_SIZE; /* and mark this element as available for reading */ amsemaphore_up(self->ring_used_sem); return; case PUSH_TO_FD: { int fd = get_write_fd(self); /* if the fd is already closed, it's possible upstream bailed out * so quickly that we didn't even get a look at the fd. In this * case we can assume the xfer has been cancelled and just discard * the data. */ if (fd == -1) return; if (elt->cancelled) { if (!elt->expect_eof || !buf) { close_write_fd(self); /* hack to ensure we won't close the fd again, if we get another push */ elt->expect_eof = TRUE; } amfree(buf); return; } /* write the full buffer to the fd, or close on EOF */ if (buf) { if (!elt->downstream->drain_mode && full_write(fd, buf, len) < len) { if (elt->downstream->must_drain) { g_debug("Error writing to fd %d: %s", fd, strerror(errno)); } else if (elt->downstream->ignore_broken_pipe && errno == EPIPE) { } else { if (!elt->cancelled) { xfer_cancel_with_error(elt, _("Error writing to fd %d: %s"), fd, strerror(errno)); wait_until_xfer_cancelled(elt->xfer); } /* nothing special to do to handle a cancellation */ } elt->downstream->drain_mode = TRUE; } crc32_add((uint8_t *)buf, len, &elt->crc); amfree(buf); } else { g_debug("sending XMSG_CRC message"); g_debug("push_to_fd CRC: %08x", crc32_finish(&elt->crc)); msg = xmsg_new(elt->downstream, XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); close_write_fd(self); } return; } default: case PUSH_INVALID: g_assert_not_reached(); break; } }
/* loads the next level from open file fd. returns 0 on success, 1 on success with end of file reached, or -1 on error. */ static int loadlevelfromfile(struct sokgame *game, unsigned char **memptr, char *comment, int maxcommentlen) { int leveldatastarted = 0, endoffile = 0; int x, y, bytebuff; int commentfound = 0; char *origcomment = comment; game->positionx = -1; game->positiony = -1; game->field_width = 0; game->field_height = 0; game->solution = NULL; if ((comment != NULL) && (maxcommentlen > 0)) *comment = 0; /* Fill the area with floor */ for (y = 0; y < 64; y++) { for (x = 0; x < 64; x++) { game->field[x][y] = field_floor; } } x = 0; y = 0; for (;;) { int rleprefix; rleprefix = readRLEbyte(memptr, &bytebuff); if (rleprefix < 0) endoffile = 1; if (endoffile != 0) break; for (; rleprefix > 0; rleprefix--) { switch (bytebuff) { case ' ': /* empty space */ case '-': /* dash (-) and underscore (_) are sometimes used to denote empty spaces */ case '_': game->field[x + 1][y + 1] |= field_floor; x += 1; break; case '#': /* wall */ game->field[x + 1][y + 1] |= field_wall; x += 1; break; case '@': /* player */ game->field[x + 1][y + 1] |= field_floor; game->positionx = x; game->positiony = y; x += 1; break; case '*': /* atom on goal */ game->field[x + 1][y + 1] |= field_goal; case '$': /* atom */ game->field[x + 1][y + 1] |= field_atom; x += 1; break; case '+': /* player on goal */ game->positionx = x; game->positiony = y; case '.': /* goal */ game->field[x + 1][y + 1] |= field_goal; x += 1; break; case '\n': /* next row */ case '|': /* some variants of the xsb format use | as the 'new row' separator (mostly when used with RLE) */ if (leveldatastarted != 0) y += 1; x = 0; break; case '\r': /* CR - ignore those */ break; default: /* anything else is a comment -> skip until end of line or end of file */ if (leveldatastarted != 0) leveldatastarted = -1; if ((commentfound == 0) && (comment != NULL)) commentfound = -1; for (;;) { bytebuff = readbytefrommem(memptr); if (bytebuff == '\r') continue; if (bytebuff == '\n') break; if (bytebuff < 0) { endoffile = 1; break; } if (commentfound == -1) { if (maxcommentlen > 1) { maxcommentlen--; *comment = bytebuff; comment += 1; } else { commentfound = -2; } } } if (commentfound < 0) { commentfound = 1; *comment = 0; trim(origcomment); } break; } if ((leveldatastarted < 0) || (endoffile != 0)) break; if (x > 0) leveldatastarted = 1; if (x >= 62) return(ERR_LEVEL_TOO_LARGE); if (y >= 62) return(ERR_LEVEL_TOO_HIGH); if (x > game->field_width) game->field_width = x; if ((y >= game->field_height) && (x > 0)) game->field_height = y + 1; } if ((leveldatastarted < 0) || (endoffile != 0)) break; } /* check if the loaded game looks sane */ if (game->positionx < 0) return(ERR_PLAYER_POS_UNDEFINED); if (game->field_height < 1) return(ERR_LEVEL_TOO_SMALL); if (game->field_width < 1) return(ERR_LEVEL_TOO_SMALL); if (leveldatastarted == 0) return(ERR_NO_LEVEL_DATA_FOUND); /* remove floors around the level */ floodFillField(game, 63, 63); /* move the field by -1 vertically and horizontally to remove the additional row and column added for the fill function to be able to get around the field. */ for (y = 0; y < 63; y++) { for (x = 0; x < 63; x++) { game->field[x][y] = game->field[x + 1][y + 1]; } } /* compute the CRC32 of the field */ game->crc32 = crc32_init(); for (y = 0; y < game->field_width; y++) { for (x = 0; x < game->field_height; x++) { crc32_feed(&(game->crc32), &(game->field[x][y]), 1); } } crc32_finish(&(game->crc32)); if (endoffile != 0) return(1); return(0); }
static int send_message_int(int cmd_id, void *send_buf, size_t send_buf_len, void *recv_buf, size_t recv_buf_len) { // Send a message (v2 messages only) #ifdef RASPBOOTIN_DEBUG printf("RASPBOOTIN: sending cmd %i\n"); int fail_loc = 0; #endif // Check capabilities if((cmd_id < 0) || (cmd_id > 31)) { printf("RASPBOOTIN: invalid cmd number %i\n"); return INVALID_CMD; } if(cmd_id == 3) { printf("RASPBOOTIN: cannot use send_message_int to send cmd 3\n"); return INVALID_CMD; } uint32_t msg_capabilities = (1 << cmd_id); if(!(client_capabilities & msg_capabilities)) { printf("RASPBOOTIN: client does not support cmd %i\n"); return UNSUPPORTED_CMD; } if(!(server_capabilities & msg_capabilities)) { printf("RASPBOOTIN: server does not support cmd %i\n"); return UNSUPPORTED_CMD; } // The crc of the request is calculated from 'options' uint32_t crc = crc32(send_buf, send_buf_len); // Disable debug output on the uart rpi_boot_output_state ostate = output_get_state(); output_disable_uart(); // Clear the receive buffer while(uart_getc_timeout(1000) != -1); // Send the message uart_putc('\003'); uart_putc('\003'); uart_putc(cmd_id); uint8_t *send_p = (uint8_t *)send_buf; while(send_buf_len--) uart_putc(*send_p++); uart_putc(BYTE(crc, 0)); uart_putc(BYTE(crc, 1)); uart_putc(BYTE(crc, 2)); uart_putc(BYTE(crc, 3)); // Wait for the response usleep(2000); // Begin reading response int r_buf = 0; int ret = 0; // Read magic number uint32_t magic = 0; CHECK(read_lsb32(&magic, UART_TIMEOUT), 0); if(magic != MAGIC) { #ifdef RASPBOOTIN_DEBUG printf("RASPBOOTIN: invalid magic received: %08x (expecting %08x)\n", magic, MAGIC); #endif ret = INVALID_MAGIC; goto cleanup; } // Read response length uint32_t resp_length = 0; CHECK(read_lsb32(&resp_length, UART_TIMEOUT), 1); // Read error_code uint32_t error_code = 0; CHECK(read_lsb32(&error_code, UART_TIMEOUT), 2); if(error_code != SUCCESS) { ret = error_code; #ifdef RASPBOOTIN_DEBUG fail_loc = 3; #endif goto cleanup; } // Read the data (maximum is whatever is greater - recv_buf_len // or resp_length) // Resp_length is length of the message minus magic and crc // therefore it includes the length of resp_length and error_code // which have already been read, therefore subtract 8 size_t data_to_read_to_buffer = (size_t)(resp_length - 8); size_t data_to_discard = 0; size_t data_to_pad = 0; if(data_to_read_to_buffer > recv_buf_len) { data_to_read_to_buffer = recv_buf_len; data_to_discard = data_to_read_to_buffer - recv_buf_len; } else if(recv_buf_len > data_to_read_to_buffer) data_to_pad = recv_buf_len - data_to_read_to_buffer; crc = crc32_start(); crc = crc32_append(crc, &magic, 4); crc = crc32_append(crc, &resp_length, 4); crc = crc32_append(crc, &error_code, 4); int data_read = 0; uint8_t *rptr = (uint8_t *)recv_buf; while(data_to_read_to_buffer--) { r_buf = uart_getc_timeout(UART_TIMEOUT); CHECK(r_buf, 4); crc = crc32_append(crc, &r_buf, 1); *rptr++ = r_buf; data_read++; } while(data_to_discard--) { r_buf = uart_getc_timeout(UART_TIMEOUT); CHECK(r_buf, 5); crc = crc32_append(crc, &r_buf, 1); } while(data_to_pad--) *rptr++ = 0; crc = crc32_finish(crc); // Read the response CRC uint32_t resp_crc = 0; CHECK(read_lsb32(&resp_crc, UART_TIMEOUT), 6); if(resp_crc != crc) { ret = CRC_ERROR; #ifdef RASPBOOTIN_DEBUG fail_loc = 7; #endif goto cleanup; } cleanup: if(ret == 0) ret = data_read; // Clear the uart buffer while(uart_getc_timeout(1000) != -1); // Re-enable uart debug output output_restore_state(ostate); #ifdef RASPBOOTIN_DEBUG printf("RASPBOOTIN: send_message_int, returning %i (fail_loc %i)\n", ret, fail_loc); if(ret == CRC_ERROR) { printf("RASPBOOTIN: CRC error: read CRC %08x, expected %08x, magic %08x, resp_length %08x, error_code %08x\n", resp_crc, crc, magic, resp_length, error_code); } #endif return ret; }
static gpointer holding_thread( gpointer data) { XferDestHolding *self = XFER_DEST_HOLDING(data); XferElement *elt = XFER_ELEMENT(self); XMsg *msg; gchar *mesg = NULL; GTimer *timer = g_timer_new(); DBG(1, "(this is the holding thread)"); /* This is the outer loop, that loops once for each holding file or * CONTINUE command */ g_mutex_lock(self->state_mutex); while (1) { gboolean done; /* wait until the main thread un-pauses us, and check that we have * the relevant holding info available */ while (self->paused && !elt->cancelled) { DBG(9, "waiting to be unpaused"); g_cond_wait(self->state_cond, self->state_mutex); } DBG(9, "holding_thread done waiting"); if (elt->cancelled) break; self->data_bytes_written = 0; self->header_bytes_written = 0; /* new holding file */ if (self->filename == NULL || strcmp(self->filename, self->new_filename) != 0) { char *tmp_filename; char *pc; int fd; ssize_t write_header_size; if (self->use_bytes < HEADER_BLOCK_BYTES) { self->chunk_status = CHUNK_NO_ROOM; goto no_room; } tmp_filename = g_strjoin(NULL, self->new_filename, ".tmp", NULL); pc = strrchr(tmp_filename, '/'); g_assert(pc != NULL); *pc = '\0'; mkholdingdir(tmp_filename); *pc = '/'; fd = open(tmp_filename, O_RDWR|O_CREAT|O_TRUNC, 0600); if (fd < 0) { self->chunk_status = CHUNK_NO_ROOM; g_free(mesg); mesg = g_strdup_printf("Failed to open '%s': %s", tmp_filename, strerror(errno)); g_free(tmp_filename); goto no_room; } if (self->filename == NULL) { self->chunk_header->type = F_DUMPFILE; } else { self->chunk_header->type = F_CONT_DUMPFILE; } self->chunk_header->cont_filename[0] = '\0'; write_header_size = write_header(self, fd); if (write_header_size != HEADER_BLOCK_BYTES) { self->chunk_status = CHUNK_NO_ROOM; mesg = g_strdup_printf("Failed to write header to '%s': %s", tmp_filename, strerror(errno)); close(fd); unlink(tmp_filename); g_free(tmp_filename); goto no_room; } g_free(tmp_filename); self->use_bytes -= HEADER_BLOCK_BYTES; /* rewrite old_header */ if (self->filename && strcmp(self->filename, self->new_filename) != 0) { close_chunk(self, self->new_filename); } self->filename = self->new_filename; self->new_filename = NULL; self->fd = fd; self->header_bytes_written = HEADER_BLOCK_BYTES; self->chunk_offset = HEADER_BLOCK_BYTES; } DBG(2, "beginning to write chunk"); done = holding_thread_write_chunk(self); DBG(2, "done writing chunk"); if (!done) /* cancelled */ break; no_room: msg = xmsg_new(XFER_ELEMENT(self), XMSG_CHUNK_DONE, 0); msg->header_size = self->header_bytes_written; msg->data_size = self->data_bytes_written; msg->no_room = (self->chunk_status == CHUNK_NO_ROOM); if (mesg) { msg->message = mesg; mesg = NULL; } xfer_queue_message(elt->xfer, msg); /* pause ourselves and await instructions from the main thread */ self->paused = TRUE; /* if this is the last part, we're done with the chunk loop */ if (self->chunk_status == CHUNK_EOF) { break; } } g_mutex_unlock(self->state_mutex); g_debug("sending XMSG_CRC message"); g_debug("xfer-dest-holding CRC: %08x size: %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(XFER_ELEMENT(self), XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); msg = xmsg_new(XFER_ELEMENT(self), XMSG_DONE, 0); msg->duration = g_timer_elapsed(timer, NULL); g_timer_destroy(timer); /* tell the main thread we're done */ xfer_queue_message(elt->xfer, msg); return NULL; }
static gpointer pull_buffer_impl( XferElement *elt, size_t *size) { XferSourceRecovery *self = XFER_SOURCE_RECOVERY(elt); gpointer buf = NULL; int result; int devsize; XMsg *msg; g_assert(elt->output_mech == XFER_MECH_PULL_BUFFER); g_mutex_lock(self->start_part_mutex); if (elt->size == 0) { if (elt->offset == 0 && elt->orig_size == 0) { self->paused = TRUE; } else { DBG(2, "xfer-source-recovery sending XMSG_CRC message"); DBG(2, "xfer-source-recovery CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(XFER_ELEMENT(self), XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); /* the device has signalled EOF (really end-of-part), so clean up instance * variables and report the EOP to the caller in the form of an xmsg */ DBG(2, "pull_buffer hit EOF; sending XMSG_SEGMENT_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_SEGMENT_DONE, 0); msg->size = self->part_size; if (self->part_timer) { msg->duration = g_timer_elapsed(self->part_timer, NULL); g_timer_destroy(self->part_timer); self->part_timer = NULL; } msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; self->paused = TRUE; device_clear_bytes_read(self->device); self->bytes_read += self->part_size; self->part_size = 0; self->block_size = 0; /* don't queue the XMSG_PART_DONE until we've adjusted all of our * instance variables appropriately */ xfer_queue_message(elt->xfer, msg); if (self->device->is_eof) { DBG(2, "pull_buffer hit EOF; sending XMSG_PART_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_PART_DONE, 0); msg->size = self->part_size; if (self->part_timer) { msg->duration = g_timer_elapsed(self->part_timer, NULL); g_timer_destroy(self->part_timer); self->part_timer = NULL; } msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; xfer_queue_message(elt->xfer, msg); } } } while (1) { /* make sure we have a device */ while (self->paused && !elt->cancelled) g_cond_wait(self->start_part_cond, self->start_part_mutex); /* indicate EOF on an cancel or when there are no more parts */ if (elt->cancelled) { goto error; } if (self->done) goto error; /* start the timer if this is the first pull_buffer of this part */ if (!self->part_timer) { DBG(2, "first pull_buffer of new part"); self->part_timer = g_timer_new(); } if (elt->size == 0) { result = -1; } else { /* loop until we read a full block, in case the blocks are larger * than expected */ if (self->block_size == 0) self->block_size = (size_t)self->device->block_size; do { int max_block; buf = g_malloc(self->block_size); if (buf == NULL) { xfer_cancel_with_error(elt, _("%s: cannot allocate memory"), self->device->device_name); g_mutex_unlock(self->start_part_mutex); wait_until_xfer_cancelled(elt->xfer); goto error_unlocked; } devsize = (int)self->block_size; if (elt->size < 0) max_block = -1; else max_block = (elt->size+self->block_size-1)/self->block_size; result = device_read_block(self->device, buf, &devsize, max_block); *size = devsize; if (result == 0) { g_assert(*size > self->block_size); self->block_size = devsize; amfree(buf); } } while (result == 0); if (result > 0 && (elt->offset || (elt->size > 0 && (long long unsigned)elt->size < *size))) { gpointer buf1 = g_malloc(self->block_size); if ((long long unsigned)elt->offset > *size) { g_debug("offset > *size"); } else if ((long long unsigned)elt->offset == *size) { g_debug("offset == *size"); } *size -= elt->offset; if (elt->size > 0 && (size_t)elt->size < *size) *size = elt->size; memmove(buf1, buf + elt->offset, *size); elt->offset = 0; g_free(buf); buf = buf1; } if (result > 0) elt->size -= *size; } /* if this block was successful, return it */ if (result > 0) { self->part_size += *size; break; } if (result < 0) { amfree(buf); /* if we're not at EOF, it's an error */ if (!self->device->is_eof && elt->size != 0) { xfer_cancel_with_error(elt, _("error reading from %s: %s"), self->device->device_name, device_error_or_status(self->device)); g_mutex_unlock(self->start_part_mutex); wait_until_xfer_cancelled(elt->xfer); goto error_unlocked; } DBG(2, "xfer-source-recovery sending XMSG_CRC message"); DBG(2, "xfer-source-recovery CRC: %08x size %lld", crc32_finish(&elt->crc), (long long)elt->crc.size); msg = xmsg_new(XFER_ELEMENT(self), XMSG_CRC, 0); msg->crc = crc32_finish(&elt->crc); msg->size = elt->crc.size; xfer_queue_message(elt->xfer, msg); /* the device has signalled EOF (really end-of-part), so clean up instance * variables and report the EOP to the caller in the form of an xmsg */ DBG(2, "pull_buffer hit EOF; sending XMSG_PART_DONE"); msg = xmsg_new(XFER_ELEMENT(self), XMSG_PART_DONE, 0); msg->size = self->part_size; msg->duration = g_timer_elapsed(self->part_timer, NULL); msg->partnum = 0; msg->fileno = self->device->file; msg->successful = TRUE; msg->eof = FALSE; self->paused = TRUE; self->bytes_read += self->part_size; device_clear_bytes_read(self->device); self->part_size = 0; self->block_size = 0; if (self->part_timer) { g_timer_destroy(self->part_timer); self->part_timer = NULL; } /* don't queue the XMSG_PART_DONE until we've adjusted all of our * instance variables appropriately */ xfer_queue_message(elt->xfer, msg); if (elt->size == 0) { g_mutex_unlock(self->start_part_mutex); return NULL; } } } g_mutex_unlock(self->start_part_mutex); if (buf) { crc32_add(buf, *size, &elt->crc); } return buf; error: g_mutex_unlock(self->start_part_mutex); error_unlocked: *size = 0; return NULL; }