#include "packet.h" size_t get_full_size(struct buffer_packet* bp) { union abstract_packet* ap = &bp->ip.ap; for (int i = 0; i < bp->ap_count; i++) { ap = (union abstract_packet*)(&ap->raw + ap->fmt.headers.size); } return &ap->raw - &bp->ip.ap.raw; } enum FD_STATE read_packet_from_tcp(int fd, struct buffer_packet* bp) { ssize_t nread; size_t pkt_size_size = sizeof(bp->ip.ap.fmt.headers.size); if (bp->mode != BP_READING) return FDS_ERR; while (bp->aread < pkt_size_size) { nread = read(fd, &(bp->ip.ap.raw) + bp->aread, pkt_size_size - bp->aread); if (nread == 0) return FDS_AGAIN; if (nread == -1 && errno == EAGAIN) return FDS_AGAIN; if (nread == -1) return FDS_ERR; bp->aread += nread; } while (bp->aread < bp->ip.ap.fmt.headers.size) { nread = read(fd, &(bp->ip.ap.raw) + bp->aread, bp->ip.ap.fmt.headers.size - bp->aread); if (nread == 0) return FDS_AGAIN; if (nread == -1 && errno == EAGAIN) return FDS_AGAIN; if (nread == -1) return FDS_ERR; bp->aread += nread; } bp->mode = BP_WRITING; bp->awrite = 0; bp->ap_count = 1; return FDS_READY; } enum FD_STATE write_packet_to_tcp(int fd, struct buffer_packet* bp) { ssize_t nwrite; //dump_buffer_packet (bp); if (bp->mode != BP_WRITING) return FDS_ERR; while (bp->awrite < get_full_size(bp)) { nwrite = send(fd, &(bp->ip.ap.raw) + bp->awrite, get_full_size(bp) - bp->awrite, 0); if (nwrite == -1 && errno == EAGAIN) return FDS_AGAIN; if (nwrite == -1) return FDS_ERR; bp->awrite += nwrite; } bp->mode = BP_READING; bp->aread = 0; bp->ap_count = 0; return FDS_READY; } enum FD_STATE write_packet_to_udp(int fd, struct buffer_packet* bp, struct udp_target* udp_t) { ssize_t nwrite; size_t bytes_to_send; assert(bp->ip.ap.fmt.headers.cmd == CMD_CLEAR); size_t pkt_header_size = sizeof(bp->ip.ap.fmt.headers) + sizeof(bp->ip.ap.fmt.content.clear) - sizeof(char); struct sockaddr* addr = NULL; socklen_t addrlen = 0; if (udp_t->set) { addr = (struct sockaddr*) &udp_t->addr; addrlen = sizeof(struct sockaddr_in); } if (bp->mode != BP_WRITING) return FDS_ERR; bytes_to_send = bp->ip.ap.fmt.headers.size - pkt_header_size; nwrite = sendto(fd, &(bp->ip.ap.fmt.content.clear.payload), bytes_to_send, 0, addr, addrlen); if (nwrite == -1 && errno == EAGAIN) return FDS_AGAIN; if (nwrite != bytes_to_send) return FDS_ERR; bp->mode = BP_READING; bp->aread = 0; bp->ap_count = 0; return FDS_READY; } enum FD_STATE read_packet_from_udp (int fd, struct buffer_packet* bp, struct udp_target* udp_t) { ssize_t nread; if (bp->mode != BP_READING) { fprintf(stderr, "Buffer packet is not in reading mode (mode: %d)\n", bp->mode); return FDS_ERR; } size_t pkt_header_size = sizeof(bp->ip.ap.fmt.headers) + sizeof(bp->ip.ap.fmt.content.clear) - sizeof(char); // We remove the payload size_t udp_packet_size = sizeof(struct internet_packet) - pkt_header_size; socklen_t addrlen = sizeof(struct sockaddr_in); nread = recvfrom(fd, &(bp->ip.ap.fmt.content.clear.payload), udp_packet_size, MSG_TRUNC, (struct sockaddr*)&udp_t->addr, &addrlen); if ((int)nread > (int)udp_packet_size) { fprintf(stderr, "Packet has been truncated (%ld instead of %d)\n", nread, (int)udp_packet_size); return FDS_ERR; } if (nread == -1 && errno == EAGAIN) return FDS_AGAIN; if (nread == 0) return FDS_AGAIN; if (nread == -1) { fprintf(stderr, "A system error occurred\n"); return FDS_ERR; } udp_t->set = 1; udp_t->addrlen = addrlen; bp->ip.ap.fmt.headers.size = nread + pkt_header_size; bp->ip.ap.fmt.headers.cmd = CMD_CLEAR; bp->mode = BP_WRITING; bp->awrite = 0; bp->ap_count = 1; return FDS_READY; } void dump_buffer_packet(struct buffer_packet* bp) { printf("\n"); printf(" mode=%d, aread=%d, awrite=%d, ap_count=%d, usage=%ld/%ld\n", bp->mode, bp->aread, bp->awrite, bp->ap_count, get_full_size (bp), sizeof(struct internet_packet)); union abstract_packet* ap = &bp->ip.ap; for (int i = 0; i < bp->ap_count; i++) { dump_abstract_packet(ap); ap = (union abstract_packet*)(&ap->raw + ap->fmt.headers.size); } printf("\n"); } void dump_abstract_packet(union abstract_packet* ap) { printf(" \n"); printf(" size=%d, cmd=%d\n", ap->fmt.headers.size, ap->fmt.headers.cmd); switch (ap->fmt.headers.cmd) { case CMD_HEALTH: printf(" id=%d, deltat=%d, prevlink=%d, min_blocked_pkt=%d, bitfield=%02x\n", ap->fmt.content.health.id, ap->fmt.content.health.deltat, ap->fmt.content.health.prevlink, ap->fmt.content.health.min_blocked_pkt, ap->fmt.content.health.bitfield); break; case CMD_CLEAR: printf(" id=%d, port=%d\n", ap->fmt.content.clear.id, ap->fmt.content.clear.port); break; case CMD_XOR: printf(" Unimplemented\n"); break; default: printf(" \n"); break; } printf(" \n"); }