about summary refs log tree commit diff stats
path: root/src/handlers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/handlers.c')
-rw-r--r--src/handlers.c122
1 files changed, 112 insertions, 10 deletions
diff --git a/src/handlers.c b/src/handlers.c
index fdd16f8..394ccb0 100644
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -24,8 +24,8 @@ nbd_opmode get_mode(char *mode) {
 	nbd_opmode opmode;
 	if (strncmp(mode, (char *)&"netascii", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
 		opmode = NETASCII;
-	} else if (strncmp(mode, (char *)&"octal", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
-		opmode = OCTAL;
+	} else if (strncmp(mode, (char *)&"octet", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
+		opmode = OCTET;
 	} else if (strncmp(mode, (char *)&"mail", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
 		opmode = MAIL;
 	} else {
@@ -35,9 +35,10 @@ nbd_opmode get_mode(char *mode) {
 }
 
 void *read_req_resp(void *args) {
-	char *fname = NULL, *wd = NULL, *buf = NULL;
+	char *fname = NULL, *wd = NULL, *buf = NULL, *rxb = NULL;
 	FILE *fp = NULL;
 	nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args;
+	syslog(LOG_DEBUG, "%s:%d is requesting file %s", inet_ntoa(argptr->client.sin_addr), ntohs(argptr->client.sin_port), argptr->path);
 	if (!is_netascii_str((char *)&argptr->path)) {
 		argptr->err = 1;
 		goto pre_socket;
@@ -71,21 +72,46 @@ void *read_req_resp(void *args) {
 		goto pre_socket;
 	}
 #endif
-	if (!strncmp(wd, fname, sizeof(wd) - 1)) {
+	syslog(LOG_DEBUG, "cwd: %s :: realpath: %s", wd, fname);
+	if (strncmp(wd, fname, strlen(wd))) {
+		syslog(
+			LOG_ERR,
+			"%s:%d requested invalid file %s",
+			inet_ntoa(argptr->client.sin_addr),
+			ntohs(argptr->client.sin_port),
+			fname
+		);
 		argptr->err = 2;
 		goto pre_socket;
 	}
-	if (!is_netascii_str((char *)&argptr->mode)) {
+	if (!is_netascii_str((char *)&(argptr->mode))) {
+		syslog(
+			LOG_ERR,
+			"%s:%d mode is invalid %s",
+			inet_ntoa(argptr->client.sin_addr),
+			ntohs(argptr->client.sin_port),
+			argptr->mode
+		);
 		argptr->err = 4;
 		goto pre_socket;
 	}
-	nbd_opmode opmode = get_mode((char *)&argptr->mode);
-	if ((opmode != NETASCII) && (opmode != OCTAL)) {
+	nbd_opmode opmode = get_mode((char *)&(argptr->mode));
+	if ((opmode != NETASCII) && (opmode != OCTET)) {
 		argptr->err = 4;
 		goto pre_socket;
 	}
 	fp = fopen(fname, "r");
+	if (fp == NULL) {
+		syslog(
+			LOG_ERR,
+			"failed to open file for reading: %s",
+			strerror(errno)
+		);
+		argptr->err = 2;
+		goto pre_socket;
+	}
 	buf = malloc(512);
+	rxb = malloc(256);
 	if (buf == NULL) {
 		syslog(
 			LOG_CRIT,
@@ -95,13 +121,17 @@ void *read_req_resp(void *args) {
 		argptr->err = 0;
 		goto pre_socket;
 	}
-	memset(buf, '\0', 512);
 	int s = socket(AF_INET, SOCK_DGRAM, 0);
 	if (s <= 0) {
 		syslog(LOG_ERR, "unable to define socket: %s", strerror(errno));
 		goto cleanup;
 	}
-	if (connect(s, (struct sockaddr *)&argptr->client, sizeof(struct sockaddr)) < 0) {
+	struct timeval timeout = { 30, 0 };
+	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
+		syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno));
+		goto socket_clean;
+	}
+	if (connect(s, (struct sockaddr *)&(argptr->client), sizeof(struct sockaddr)) < 0) {
 		syslog(
 			LOG_ERR,
 			"unable to connect to client %s: %s",
@@ -110,12 +140,82 @@ void *read_req_resp(void *args) {
 		);
 		goto socket_clean;
 	}
-
+	uint8_t rxon = 0, lon = 1;
+	uint16_t bnum = 0;
+	while (lon) {
+		memset(buf, '\0', 512);
+		uint8_t verif = 0;
+		uint8_t vcount = 0;
+		size_t num_read = fread(buf, 1, 512, fp);
+		if (((num_read < 512) && (!feof(fp))) || (vcount > 5)) {
+			//TODO: error response function!
+		}
+		char *packet = nbd_tftp_ser_data_from_parts(++bnum, buf, num_read);
+		while (!verif) {
+			syslog(LOG_DEBUG, "sending block number %d to %s:%d",
+				bnum,
+				inet_ntoa(argptr->client.sin_addr),
+				htons(argptr->client.sin_port)
+			);
+			if (send(s, packet, num_read + 4, 0) < 0) {
+				syslog(
+					LOG_ERR,
+					"unable to send data to %s: %s",
+					inet_ntoa(argptr->client.sin_addr),
+					strerror(errno)
+				);
+				continue;
+			}
+			rxon = 1;
+			uint8_t rxcount = 0;
+			while (rxon) {
+				syslog(LOG_DEBUG, "waiting for ack %d from %s:%d",
+					bnum,
+					inet_ntoa(argptr->client.sin_addr),
+					htons(argptr->client.sin_port)
+				);
+				memset(rxb, '\0', 256);
+				ssize_t rcv = recv(s, rxb, 256, 0);
+				syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d",
+					rcv,
+					inet_ntoa(argptr->client.sin_addr),
+					htons(argptr->client.sin_port)
+				);
+				if (rcv == 4) {
+					nbd_tftp_packet_ack ack = nbd_tftp_de_ack(rxb, rcv);
+					syslog(LOG_DEBUG, "%s:%d ack'd with block number: %d (expect %d)",
+						inet_ntoa(argptr->client.sin_addr),
+						htons(argptr->client.sin_port),
+						ack.block_num,
+						bnum
+					);
+					if (ack.block_num == bnum) {
+						rxon = 0;
+						verif = 1;
+						break;
+					}
+					if (ack.block_num == (bnum - 1)) {
+						rxon = 0;
+						vcount++;
+						break;
+					}
+				}
+				if (++rxcount > 30) {
+					//TODO: error response function!
+				}
+			}
+		}
+		free(packet);
+		if (num_read < 512) {
+			lon = 0;
+		}
+	}
 socket_clean:
 	close(s);
 cleanup:
 	fclose(fp);
 	free(buf);
+	free(rxb);
 	free(fname);
 	free(wd);
 	free(args);
@@ -125,6 +225,7 @@ pre_socket:
 		fclose(fp);
 	}
 	free(buf);
+	free(rxb);
 	free(fname);
 	free(wd);
 	return nbd_nbtpd_resp_error(args);
@@ -137,6 +238,7 @@ void *write_req_resp(void *args) {
 
 void *nbd_nbtpd_resp_error(void *args) {
 	//TODO: open socket and scream error, then cleanup.
+	//TODO: error response function!
 	free(args);
 	return (void *)NULL;
 }