Untitled
unknown
plain_text
2 years ago
11 kB
6
Indexable
#include "backend.h"
#include <time.h>
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "cmu_packet.h"
#include "cmu_tcp.h"
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
int syn_check = 0;
/**
* Tells if a given sequence number has been acknowledged by the socket.
*
* @param sock The socket to check for acknowledgements.
* @param seq Sequence number to check.
*
* @return 1 if the sequence number has been acknowledged, 0 otherwise.
*/
int has_been_acked(cmu_socket_t *sock, uint32_t seq) {
int result;
while (pthread_mutex_lock(&(sock->window.ack_lock)) != 0) {
}
result = after(sock->window.last_ack_received, seq);
pthread_mutex_unlock(&(sock->window.ack_lock));
return result;
}
/**
* Updates the socket information to represent the newly received packet.
*
* In the current stop-and-wait implementation, this function also sends an
* acknowledgement for the packet.
*
* @param sock The socket used for handling packets received.
* @param pkt The packet data received by the socket.
*/
void handle_message(cmu_socket_t *sock, uint8_t *pkt) {
cmu_tcp_header_t *hdr = (cmu_tcp_header_t *)pkt;
uint8_t flags = get_flags(hdr);
switch (flags) {
case ACK_FLAG_MASK: {
uint32_t ack = get_ack(hdr);
if (after(ack, sock->window.last_ack_received)) {
sock->window.last_ack_received = ack;
}
break;
}
case SYN_FLAG_MASK: {
if (get_ack(hdr) != 0)
{
break;
}
srand(time(0));
socklen_t conn_len = sizeof(sock->conn);
uint32_t seq = rand();
// No payload.
uint8_t *payload = NULL;
uint16_t payload_len = 0;
// No extension.
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t ack = get_seq(hdr) + get_payload_len(pkt);
if (get_payload_len(pkt) == 0)
{
ack = get_seq(hdr) + 1;
}
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = SYN_FLAG_MASK + ACK_FLAG_MASK;
uint16_t adv_window = 1;
uint8_t *response_packet =
create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
printf(" :Sending SYN_ACK response\n" );//debug
sendto(sock->socket, response_packet, plen, flags,
(struct sockaddr *)&(sock->conn), conn_len);
free(response_packet);
seq = get_seq(hdr);
if (seq == sock->window.next_seq_expected) {
sock->window.next_seq_expected = seq + get_payload_len(pkt);
payload_len = get_payload_len(pkt);
payload = get_payload(pkt);
// Make sure there is enough space in the buffer to store the payload.
sock->received_buf =
realloc(sock->received_buf, sock->received_len + payload_len);
memcpy(sock->received_buf + sock->received_len, payload, payload_len);
sock->received_len += payload_len;
}
break;
}
case 0: {
socklen_t conn_len = sizeof(sock->conn);
uint32_t seq = sock->window.last_ack_received;
// No payload.
uint8_t *payload = NULL;
uint16_t payload_len = 0;
// No extension.
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t ack = get_seq(hdr) + get_payload_len(pkt);
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = ACK_FLAG_MASK;
uint16_t adv_window = 1;
uint8_t *response_packet =
create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
printf(" :Sending from case 0\n"); //debug
sendto(sock->socket, response_packet, plen, 0,
(struct sockaddr *)&(sock->conn), conn_len);
free(response_packet);
seq = get_seq(hdr);
if (seq == sock->window.next_seq_expected) {
sock->window.next_seq_expected = seq + get_payload_len(pkt);
payload_len = get_payload_len(pkt);
payload = get_payload(pkt);
// Make sure there is enough space in the buffer to store the payload.
sock->received_buf =
realloc(sock->received_buf, sock->received_len + payload_len);
memcpy(sock->received_buf + sock->received_len, payload, payload_len);
sock->received_len += payload_len;
}
}
}
}
/**
* Checks if the socket received any data.
*
* It first peeks at the header to figure out the length of the packet and then
* reads the entire packet.
*
* @param sock The socket used for receiving data on the connection.
* @param flags Flags that determine how the socket should wait for data. Check
* `cmu_read_mode_t` for more information.
*/
void check_for_data(cmu_socket_t *sock, cmu_read_mode_t flags) {
cmu_tcp_header_t hdr;
uint8_t *pkt;
socklen_t conn_len = sizeof(sock->conn);
ssize_t len = 0;
uint32_t plen = 0, buf_size = 0, n = 0;
while (pthread_mutex_lock(&(sock->recv_lock)) != 0) {
}
switch (flags) {
case NO_FLAG:
len = recvfrom(sock->socket, &hdr, sizeof(cmu_tcp_header_t), MSG_PEEK,
(struct sockaddr *)&(sock->conn), &conn_len);
break;
case TIMEOUT: {
// Using `poll` here so that we can specify a timeout.
struct pollfd ack_fd;
ack_fd.fd = sock->socket;
ack_fd.events = POLLIN;
// Timeout after 3 seconds.
if (poll(&ack_fd, 1, 3000) <= 0) {
break;
}
}
// Fallthrough.
case NO_WAIT:
len = recvfrom(sock->socket, &hdr, sizeof(cmu_tcp_header_t),
MSG_DONTWAIT | MSG_PEEK, (struct sockaddr *)&(sock->conn),
&conn_len);
break;
default:
perror("ERROR unknown flag");
}
if (len >= (ssize_t)sizeof(cmu_tcp_header_t)) {
plen = get_plen(&hdr);
pkt = malloc(plen);
while (buf_size < plen) {
n = recvfrom(sock->socket, pkt + buf_size, plen - buf_size, 0,
(struct sockaddr *)&(sock->conn), &conn_len);
buf_size = buf_size + n;
}
handle_message(sock, pkt);
free(pkt);
}
pthread_mutex_unlock(&(sock->recv_lock));
}
/**
* Breaks up the data into packets and sends a single packet at a time.
*
* You should most certainly update this function in your implementation.
*
* @param sock The socket to use for sending data.
* @param data The data to be sent.
* @param buf_len The length of the data being sent.
*/
void single_send(cmu_socket_t *sock, uint8_t *data, int buf_len) {
uint8_t *msg;
uint8_t *data_offset = data;
size_t conn_len = sizeof(sock->conn);
int sockfd = sock->socket;
if (buf_len > 0) {
while (buf_len != 0) {
uint16_t payload_len = MIN((uint16_t)buf_len, (uint16_t)MSS);
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t seq = sock->window.last_ack_received;
uint32_t ack = sock->window.next_seq_expected + get_payload_len(pkt);
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = 0;
uint16_t adv_window = 1;
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint8_t *payload = data_offset;
msg = create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
buf_len -= payload_len;
while (1) {
// FIXME: This is using stop and wait, can we do better?
printf(" :send from signle_send\n");
sendto(sockfd, msg, plen, 0, (struct sockaddr *)&(sock->conn),
conn_len);
check_for_data(sock, TIMEOUT);
if (has_been_acked(sock, seq)) {
break;
}
}
data_offset += payload_len;
}
}
}
//Send the first syn
void send_syn(cmu_socket_t *sock) {
uint8_t *syn_msg;
size_t conn_len = sizeof(sock->conn);
srand(time(NULL));
int sockfd = sock->socket;
uint16_t payload_len = 0;
uint16_t src = sock->my_port;
uint16_t dst = ntohs(sock->conn.sin_port);
uint32_t seq = rand();
uint32_t ack = 0;
uint16_t hlen = sizeof(cmu_tcp_header_t);
uint16_t plen = hlen + payload_len;
uint8_t flags = SYN_FLAG_MASK;
uint16_t adv_window = 1;
uint16_t ext_len = 0;
uint8_t *ext_data = NULL;
uint8_t *payload = NULL;
syn_msg = create_packet(src, dst, seq, ack, hlen, plen, flags, adv_window,
ext_len, ext_data, payload, payload_len);
printf("\nsending syn packet, ack: %d ,seq: %d\n",ack,seq);//debug
sendto(sockfd, syn_msg, plen, 0, (struct sockaddr *)&(sock->conn),
conn_len);
}
void *begin_backend(void *in) {
cmu_socket_t *sock = (cmu_socket_t *)in;
int death, buf_len, send_signal;
uint8_t *data;
//Code to modify
send_syn(sock);
while (1) {
while (pthread_mutex_lock(&(sock->death_lock)) != 0) {
}
death = sock->dying;
pthread_mutex_unlock(&(sock->death_lock));
while (pthread_mutex_lock(&(sock->send_lock)) != 0) {
}
buf_len = sock->sending_len;
if (death && buf_len == 0) {
break;
}
if (syn_check)
{
if (buf_len > 0) {
data = malloc(buf_len);
memcpy(data, sock->sending_buf, buf_len);
sock->sending_len = 0;
free(sock->sending_buf);
sock->sending_buf = NULL;
pthread_mutex_unlock(&(sock->send_lock));
single_send(sock, data, buf_len);
free(data);
} else {
pthread_mutex_unlock(&(sock->send_lock));
}
}
check_for_data(sock, NO_WAIT);
while (pthread_mutex_lock(&(sock->recv_lock)) != 0) {
}
send_signal = sock->received_len > 0;
pthread_mutex_unlock(&(sock->recv_lock));
if (send_signal) {
pthread_cond_signal(&(sock->wait_cond));
}
}
pthread_exit(NULL);
return NULL;
}
Editor is loading...