void process_data (PacketProtoDecoder *enc) { int was_error = 0; do { uint8_t *data = enc->buf + enc->buf_start; int left = enc->buf_used; // check if header was received if (left < sizeof(struct packetproto_header)) { break; } struct packetproto_header header; memcpy(&header, data, sizeof(header)); data += sizeof(struct packetproto_header); left -= sizeof(struct packetproto_header); int data_len = ltoh16(header.len); // check data length if (data_len > enc->output_mtu) { BLog(BLOG_NOTICE, "error: packet too large"); was_error = 1; break; } // check if whole packet was received if (left < data_len) { break; } // update buffer enc->buf_start += sizeof(struct packetproto_header) + data_len; enc->buf_used -= sizeof(struct packetproto_header) + data_len; // submit packet PacketPassInterface_Sender_Send(enc->output, data, data_len); return; } while (0); if (was_error) { // reset buffer enc->buf_start = 0; enc->buf_used = 0; } else { // if we reached the end of the buffer, wrap around to allow more data to be received if (enc->buf_start + enc->buf_used == enc->buf_size) { memmove(enc->buf, enc->buf + enc->buf_start, enc->buf_used); enc->buf_start = 0; } } // receive data StreamRecvInterface_Receiver_Recv(enc->input, enc->buf + (enc->buf_start + enc->buf_used), enc->buf_size - (enc->buf_start + enc->buf_used)); // if we had error, report it if (was_error) { enc->handler_error(enc->user); return; } }
int main () { int ret = 1; BLog_InitStdout(); // init network if (!BNetwork_GlobalInit()) { fprintf(stderr, "BNetwork_GlobalInit failed\n"); goto fail1; } // init reactor (event loop) if (!BReactor_Init(&reactor)) { fprintf(stderr, "BReactor_Init failed\n"); goto fail1; } // init signal handling sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGTERM); if (!BUnixSignal_Init(&usignal, &reactor, set, signal_handler, NULL)) { fprintf(stderr, "BUnixSignal_Init failed\n"); goto fail2; } // init BConnection object backed by the stdin fd if (!BConnection_Init(&pipe_con, BCONNECTION_SOURCE_PIPE(0), &reactor, NULL, connection_handler)) { fprintf(stderr, "BConnection_Init failed\n"); goto fail3; } // init connection receive interface BConnection_RecvAsync_Init(&pipe_con); source_if = BConnection_RecvAsync_GetIf(&pipe_con); // init receive done callback StreamRecvInterface_Receiver_Init(source_if, input_handler_done, NULL); // receive first chunk StreamRecvInterface_Receiver_Recv(source_if, buf, BUF_SIZE); // run event loop ret = BReactor_Exec(&reactor); BConnection_RecvAsync_Free(&pipe_con); BConnection_Free(&pipe_con); fail3: BUnixSignal_Free(&usignal, 0); fail2: BReactor_Free(&reactor); fail1: BLog_Free(); DebugObjectGlobal_Finish(); return ret; }
static void input_handler_done (void *user, int data_len) { // receive next chunk StreamRecvInterface_Receiver_Recv(source_if, buf, BUF_SIZE); // print this chunk buf[data_len] = '\0'; printf("Received: '%s'\n", buf); }
static PRInt32 method_read (PRFileDesc *fd, void *buf, PRInt32 amount) { struct BSSLConnection_backend *b = (struct BSSLConnection_backend *)fd->secret; ASSERT(amount > 0) if (b->threadwork_state != THREADWORK_STATE_NONE) { BMutex_Lock(&b->recv_buf_mutex); } // if we are receiving into buffer or buffer has no data left, refuse recv if (b->recv_busy || b->recv_pos == b->recv_len) { if (b->threadwork_state != THREADWORK_STATE_NONE) { b->threadwork_want_recv = 1; BMutex_Unlock(&b->recv_buf_mutex); } else { // start receiving if not already if (!b->recv_busy) { // set recv busy b->recv_busy = 1; // receive into buffer StreamRecvInterface_Receiver_Recv(b->recv_if, b->recv_buf, BSSLCONNECTION_BUF_SIZE); } } PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return -1; } // limit amount to available data if (amount > b->recv_len - b->recv_pos) { amount = b->recv_len - b->recv_pos; } // copy data memcpy(buf, b->recv_buf + b->recv_pos, amount); // update buffer b->recv_pos += amount; if (b->threadwork_state != THREADWORK_STATE_NONE) { BMutex_Unlock(&b->recv_buf_mutex); } return amount; }
static void input_handler_done (SingleStreamReceiver *o, int data_len) { DebugObject_Access(&o->d_obj); ASSERT(data_len > 0) ASSERT(data_len <= o->packet_len - o->pos) // update position o->pos += data_len; // if everything was received, notify user if (o->pos == o->packet_len) { DEBUGERROR(&o->d_err, o->handler(o->user)); return; } // receive more StreamRecvInterface_Receiver_Recv(o->input, o->packet + o->pos, o->packet_len - o->pos); }
int PacketProtoDecoder_Init (PacketProtoDecoder *enc, StreamRecvInterface *input, PacketPassInterface *output, BPendingGroup *pg, void *user, PacketProtoDecoder_handler_error handler_error) { // init arguments enc->input = input; enc->output = output; enc->user = user; enc->handler_error = handler_error; // init input StreamRecvInterface_Receiver_Init(enc->input, (StreamRecvInterface_handler_done)input_handler_done, enc); // init output PacketPassInterface_Sender_Init(enc->output, (PacketPassInterface_handler_done)output_handler_done, enc); // set output MTU, limit by maximum payload size enc->output_mtu = bmin_int(PacketPassInterface_GetMTU(enc->output), PACKETPROTO_MAXPAYLOAD); // init buffer state enc->buf_size = PACKETPROTO_ENCLEN(enc->output_mtu); enc->buf_start = 0; enc->buf_used = 0; // allocate buffer if (!(enc->buf = (uint8_t *)malloc(enc->buf_size))) { goto fail0; } // start receiving StreamRecvInterface_Receiver_Recv(enc->input, enc->buf, enc->buf_size); DebugObject_Init(&enc->d_obj); return 1; fail0: return 0; }
void SingleStreamReceiver_Init (SingleStreamReceiver *o, uint8_t *packet, int packet_len, StreamRecvInterface *input, BPendingGroup *pg, void *user, SingleStreamReceiver_handler handler) { ASSERT(packet_len > 0) ASSERT(handler) // init arguments o->packet = packet; o->packet_len = packet_len; o->input = input; o->user = user; o->handler = handler; // set position zero o->pos = 0; // init output StreamRecvInterface_Receiver_Init(o->input, (StreamRecvInterface_handler_done)input_handler_done, o); // start receiving StreamRecvInterface_Receiver_Recv(o->input, o->packet + o->pos, o->packet_len - o->pos); DebugError_Init(&o->d_err, pg); DebugObject_Init(&o->d_obj); }
void do_receive (BSocksClient *o) { ASSERT(o->control.recv_len < o->control.recv_total) StreamRecvInterface_Receiver_Recv(o->control.recv_if, o->control.recv_dest + o->control.recv_len, o->control.recv_total - o->control.recv_len); }