int send_nack(rms_meta_channel *channel, rms_meta_peer *peer, rms_meta_msg* msg) { unsigned long *seq; void *data; int count; int itr; unsigned long seq2 = peer->sequence_sent-1; msg->hdr->type = RMS_NACK; msg->hdr->sequence = htonl(peer->sequence_rcvd); msg->hdr->id = htonl(peer->id); count = 1; seq = (unsigned long*)msg->data; for(itr = peer->sequence_rcvd + 1; itr!=seq2; itr++) { if(!htbl_get(peer->ht_unseq_msgs, itr, &data)) { seq[count] = htonl(itr); count++; peer->lost++; rmsb->self->lost++; } } seq[0] = htonl(count); count = count*sizeof(unsigned long); msg->hdr->length = htons(count); rmsb->ucast_addr.sin_addr.s_addr = htonl(peer->id); return sendto(rmsb->mcast_sock, msg->buf, sizeof(rms_msg_hdr) + count, 0, (struct sockaddr*) &rmsb->ucast_addr, sizeof(rmsb->mcast_addr)); }
void * http_option_get_val(struct http_ctx *c, http_opt_t o) { char *opt_id = NULL; void *opt = NULL; if(c == NULL) { libnet_error_set(LIBNET_E_INV_ARG); return NULL; } opt_id = http_option_get_id(o); opt = htbl_get(&c->options, opt_id); return opt; }
void* rms_manager(void* arg) { //init int nfound; int ret; int err; int itr; int ipc_read; int count; int gottime; char *data; float t1; float t2; fd_set readset; struct timeval timeout; struct timeval ratechk; unsigned long *keys; unsigned long *seq; rms_meta_msg *msg; rms_meta_peer *peer; int addr_len; rms_msg_hbeat *hbeat; rmscb *rmsb = (rmscb*)arg; gottime = 0; while(rmsb->active) { FD_ZERO(&readset); FD_SET(rmsb->ipc_sock, &readset); FD_SET(rmsb->mcast_sock, &readset); timeout.tv_sec = 1; timeout.tv_usec = 0; nfound= select(rmsb->maxsock, &readset, (fd_set*)0, (fd_set*)0, &timeout); if(nfound > 0) { //available to read on mcast port if((nfound = FD_ISSET(rmsb->mcast_sock, &readset)) > 0) { msg = alloc_meta_msg(); ret = recvfrom(rmsb->mcast_sock, &msg->buf, msg->size, 0, (struct sockaddr*)&rmsb->recv_addr, &addr_len); printf("\n\tRMC: recvd %d bytes from %ld", ret, rmsb->recv_addr.sin_addr.s_addr); if(ret < sizeof(rms_msg_hdr)) { //not enough data continue; } msg->hdr->length = ntohs(msg->hdr->length); msg->hdr->sequence = ntohl(msg->hdr->sequence); msg->hdr->id = ntohl(msg->hdr->id); if(ret < msg->hdr->length + sizeof(rms_msg_hdr)) { //not enough data continue; } switch(msg->hdr->type) { case RMS_DATA: if(!htbl_get(rmsb->ht_peers, msg->hdr->id, (void*)&peer)) { //peer not registered, drop packet release_meta_msg(msg); } else { peer->sequence_sent = msg->hdr->sequence; if(peer->sequence_rcvd + 1 != msg->hdr->sequence) { //gap in sequence num if(peer->sequence_rcvd < msg->hdr->sequence) { //cache msg htbl_put(peer->ht_unseq_msgs, msg->hdr->sequence, msg); //send NACK msg = alloc_meta_msg(); send_nack(rmsb, peer, msg); } //else retransmitted data, drop packet release_meta_msg(msg); } else { //in sequence //syncqueue_signal_data(rmsb->inmsgq, msg); nfound = msg->hdr->length; ret = send(rmsb->ipc_sock, &nfound, sizeof(int),0); ret = 0; while(ret < nfound) { ret+=send(rmsb->ipc_sock, msg->data+ret, nfound-ret, 0); } peer->sequence_rcvd++; //release out of sequence data if any while(htbl_remove(peer->ht_unseq_msgs, peer->sequence_sent, (void*)&msg)) { //syncqueue_signal_data(rmsb->inmsgq, msg); nfound = msg->hdr->length; ret = send(rmsb->ipc_sock, &nfound, sizeof(int),0); ret = 0; while(ret < nfound) { ret+=send(rmsb->ipc_sock, msg->data+ret, nfound-ret, 0); } peer->sequence_rcvd++; } }} break; case RMS_HEARTBEAT: hbeat = (rms_msg_hbeat*) msg->data; data = msg->data + sizeof(rms_msg_hbeat); if(!htbl_get(rmsb->ht_peers, msg->hdr->id, (void*)&peer)) { //peer not registered, register it if(hbeat->namelen) { rms_meta_peer_init(&peer, msg->data, msg->hdr->id); } else { rms_meta_peer_init(&peer, "noname", msg->hdr->id); } htbl_put(rmsb->ht_peers, peer->id, peer); mqueue_add(rmsb->mq_peers, peer); } peer->lost = ntohs(hbeat->lost); //check for namelen if(hbeat->namelen) { hbeat->namelen = htonl(hbeat->namelen); data+=hbeat->namelen; } //check for acks if(hbeat->acks) { seq = (unsigned long*)data; hbeat->acks = ntohs(hbeat->acks); for(itr=0;itr < hbeat->acks; itr++) { if(ntohl(seq[itr*2])== rmsb->self->id) { peer->sequence_sync = ntohl(seq[itr*2 + 1]); break; } } data+=hbeat->acks*2*sizeof(long); } //check for piggybacked data if(hbeat->pgback) { hbeat->pgback = ntohs(hbeat->pgback); } gettimeofday(&timeout, NULL); gottime=1; peer->last_hbeat.tv_sec = timeout.tv_sec; peer->last_hbeat.tv_usec = timeout.tv_usec; if(peer->sequence_sent + 1 != msg->hdr->sequence) { //gap in sequence num if(peer->sequence_sent < msg->hdr->sequence) { //send NACK send_nack(rmsb, peer, msg); } } release_meta_msg(msg); break; case RMS_NACK: seq = (unsigned long*)msg->data; count = seq[0]; rmsb->ucast_addr.sin_addr.s_addr = htonl(msg->hdr->id); for(itr=1; itr <= count; itr++) { seq[itr]=ntohl(seq[itr]); if(htbl_get(rmsb->outmsgbuf, seq[itr], (void*)&msg)) { ret = sendto(rmsb->mcast_sock, msg->buf, msg->length + sizeof(rms_msg_hdr), 0, (struct sockaddr*) &rmsb->ucast_addr, sizeof(rmsb->ucast_addr)); } } break; case RMS_LEAVE: if(htbl_remove(rmsb->ht_peers, msg->hdr->id, (void*)&peer)) { //clean up unseq msgs buffer count = htbl_count(peer->ht_unseq_msgs); keys = (unsigned long*)malloc(count*sizeof(unsigned long)); memset(keys,0,count*sizeof(unsigned long)); count = htbl_enum_keys(peer->ht_unseq_msgs, (void*)keys, count); for(itr = 0; itr < count; itr++) { if(htbl_remove(peer->ht_unseq_msgs, keys[itr], (void*)&msg)) { release_meta_msg(msg); } } free(keys); mqueue_remove_item(rmsb->mq_peers, peer); rms_meta_peer_free(peer); } break; case RMS_ACK: case RMS_JOIN: case RMS_CERT: default: //unimplemented options, drop packet release_meta_msg(msg); break; } } //available to read on ipc port if((nfound = FD_ISSET(rmsb->ipc_sock, &readset)) > 0) { err = 1; ret = recv(rmsb->ipc_sock, &ipc_read, sizeof(int), 0); if(ret > 0) { //alloc buffer msg = alloc_meta_msg(); if(ipc_read > rmsb->bufsize) { rmsb->bufsize = ipc_read * 1.5; msg->size = rmsb->bufsize; msg->buf = realloc(msg->buf,msg->size); msg->hdr = (rms_msg_hdr*)msg->buf; msg->data = msg->buf + sizeof(rms_msg_hdr); } ret = recv(rmsb->ipc_sock, &msg->data, ipc_read, 0); if(ret == ipc_read) { msg->length = ipc_read; msg->hdr->type = RMS_DATA; msg->hdr->length = htons(msg->length); msg->hdr->sequence = htonl(rmsb->self->sequence_sent); msg->hdr->id = htonl(rmsb->self->id); ret = sendto(rmsb->mcast_sock, msg->buf, ret + sizeof(rms_msg_hdr), 0, (struct sockaddr*) &rmsb->mcast_addr, sizeof(rmsb->mcast_addr)); if (ret > 0) { htbl_put(rmsb->outmsgbuf, rmsb->self->sequence_sent, msg); rmsb->self->sequence_sent++; rmsb->msg_this_sec++; err = 0; } } } if(err) { release_meta_msg(msg); } } } //do periodic things if(!gottime) gettimeofday(&timeout, NULL); gottime=0; //heartbeat if(timeout.tv_sec - rmsb->self->last_hbeat.tv_sec >= rmsb->hbeat_rate) { //time for hbeat send_hbeat(rmsb, NULL,0); //check msg send rate t1 = (float)timeout.tv_sec + ((float)timeout.tv_usec)/1000000; t2 = (float)rmsb->self->last_hbeat.tv_sec + ((float)rmsb->self->last_hbeat.tv_usec)/1000000; rmsb->msg_per_sec = rmsb->msg_this_sec/(t1-t2); //calculate heartbeat rate rmsb->hbeat_rate = RMS_RATE_FACTOR / rmsb->msg_per_sec; //clamp if(rmsb->hbeat_rate > 5) rmsb->hbeat_rate = 5; else if(rmsb->hbeat_rate < 1) rmsb->hbeat_rate = 1; rmsb->msg_this_sec = 0; rmsb->self->last_hbeat.tv_sec = timeout.tv_sec; rmsb->self->last_hbeat.tv_usec = timeout.tv_usec; } //if acks are used if(rmsb->hb_ack) { //clear buffers count = mqueue_size(rmsb->mq_peers); for(itr=0; itr < count; itr++) { peer = (rms_meta_peer*) mqueue_peek_at_index(rmsb->mq_peers, itr); if(peer->sequence_sync < rmsb->self->sequence_sync); rmsb->self->sequence_sync = peer->sequence_sync; } while(rmsb->oldest_seq < rmsb->self->sequence_sync){ if(htbl_remove(rmsb->outmsgbuf, rmsb->oldest_seq, (void*)&msg)) { release_meta_msg(msg); } rmsb->oldest_seq++; } } } //send leave message msg = alloc_meta_msg(); msg->hdr->type = RMS_LEAVE; msg->hdr->length = 0; msg->hdr->sequence = htonl(rmsb->self->sequence_sent); msg->hdr->id = htonl(rmsb->self->id); ret = sendto(rmsb->mcast_sock, msg->buf, sizeof(rms_msg_hdr), 0, (struct sockaddr*) &rmsb->mcast_addr, sizeof(rmsb->mcast_addr)); release_meta_msg(msg); return 0; }
void http_response_parse/*_and_read*/(struct http_ctx *c, http_response_t *r, buffer_t *d) { char buf[LIBNET_HTTP_SIZE_CHUNK] = {0}, *tok; uint32_t len, i = 0, chunk_size = 0; bool chunked = false; http_header_field_t *hf_e; if(c == NULL || r == NULL || d == NULL) { libnet_error_set(LIBNET_E_INV_ARG); return; } htbl_create(&r->header, 0); buffer_create(&r->body, LIBNET_BM_FILE); len = buffer_size(d); buffer_seek(d, 0); /* read status line */ while(len > 0) { buffer_read(d, buf + i, 1); if(strstr(buf, LIBNET_HTTP_DEL)) { break; } ++i; --len; } //printf("status line: %s", buf); /* do something with the http version */ /* get status code */ tok = strstr(buf, " ") + 1; sprintf(buf, "%s", tok); sscanf(buf, "%3d", &r->code); /* get reason */ i = strcspn(buf+4, LIBNET_HTTP_DEL) + 1; if(i > LIBNET_HTTP_SIZE_REASON) { i -= LIBNET_HTTP_SIZE_REASON; // LIBNET_HTTP_DEL; } snprintf(r->reason, i, "%s", buf+4); /* now parse header */ http_header_parse(&r->header, d); /* chunked? */ hf_e = (http_header_field_t *)htbl_get(&r->header, "transfer-encoding"); chunked = (!strcmp(hf_e->value, "chunked") ? true : false); uint32_t get_chunk_size(socket_t *s) { uint32_t i = 0, size; char buf[LIBNET_HTTP_SIZE_CHUNK] = {0}; while(!strstr(buf, LIBNET_HTTP_DEL)) { if(0 == socket_read(s, buf+i++, 1)) { return 0; } } if(i >= 3) { buf[i-2] = 0; } else { return 0; } sscanf(buf, "%x", &size); return size; }