Files
my-os-project2/kernel/picotcp/test/test_tftp_app_client.c
2025-10-29 14:29:06 +01:00

245 lines
6.4 KiB
C

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <inttypes.h>
#include "pico_stack.h"
#include "pico_config.h"
#include "pico_ipv4.h"
#include "pico_icmp4.h"
#include "pico_socket.h"
#include "pico_stack.h"
#include "pico_device.h"
#include "pico_dev_vde.h"
#include "pico_tftp.h"
static struct pico_device *pico_dev;
int32_t get_filesize(const char *filename)
{
int ret;
struct stat buf;
ret = stat(filename, &buf);
if (ret)
return -1;
return buf.st_size;
}
void start_rx(struct pico_tftp_session *session, int *synchro, const char *filename, int options)
{
int ret;
int fd;
int32_t len;
uint8_t buf[PICO_TFTP_PAYLOAD_SIZE];
int left = 1000;
int countdown = 0;
printf("Start receiving file %s with options set to %d\n", filename, options);
if (options) {
ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, 0);
if (ret) {
fprintf(stderr, "Error in pico_tftp_set_option\n");
exit(1);
}
}
ret = pico_tftp_app_start_rx(session, filename);
if (ret) {
fprintf(stderr, "Error in pico_tftp_app_start_rx\n");
exit(1);
}
fd = open(filename, O_WRONLY | O_EXCL | O_CREAT, 0664);
if (!fd) {
fprintf(stderr, "Error in open\n");
countdown = 1;
}
for(; left; left -= countdown) {
usleep(2000); /* PICO_IDLE(); */
pico_stack_tick();
if (countdown)
continue;
if (*synchro) {
len = pico_tftp_get(session, buf, PICO_TFTP_PAYLOAD_SIZE);
if (len < 0) {
fprintf(stderr, "Failure in pico_tftp_get\n");
close(fd);
countdown = 1;
continue;
}
ret = write(fd, buf, len);
if (ret < 0) {
fprintf(stderr, "Error in write\n");
pico_tftp_abort(session, TFTP_ERR_EXCEEDED, "File write error");
close(fd);
countdown = 1;
continue;
}
printf("Written %" PRId32 " bytes to file (synchro=%d)\n", len, *synchro);
if (len != PICO_TFTP_PAYLOAD_SIZE) {
close(fd);
printf("Transfer complete!\n");
countdown = 1;
}
}
}
}
void start_tx(struct pico_tftp_session *session, int *synchro, const char *filename, int options)
{
int ret;
int fd;
int32_t len;
uint8_t buf[PICO_TFTP_PAYLOAD_SIZE];
int left = 1000;
int countdown = 0;
printf("Start sending file %s with options set to %d\n", filename, options);
if (options) {
ret = get_filesize(filename);
if (ret < 0) {
fprintf(stderr, "Error in get_filesize\n");
exit(1);
}
ret = pico_tftp_set_option(session, PICO_TFTP_OPTION_FILE, ret);
if (ret) {
fprintf(stderr, "Error in pico_tftp_set_option\n");
exit(1);
}
}
ret = pico_tftp_app_start_tx(session, filename);
if (ret) {
fprintf(stderr, "Error in pico_tftp_app_start_rx\n");
exit(1);
}
fd = open(filename, O_RDONLY, 0444);
if (!fd) {
fprintf(stderr, "Error in open\n");
pico_tftp_abort(session, TFTP_ERR_EACC, "Error opening file");
countdown = 1;
}
for(; left; left -= countdown) {
usleep(2000); /* PICO_IDLE(); */
pico_stack_tick();
if (countdown)
continue;
if (*synchro) {
ret = read(fd, buf, PICO_TFTP_PAYLOAD_SIZE);
if (ret < 0) {
fprintf(stderr, "Error in read\n");
pico_tftp_abort(session, TFTP_ERR_EACC, "File read error");
close(fd);
countdown = 1;
continue;
}
printf("Read %" PRId32 " bytes from file (synchro=%d)\n", len, *synchro);
len = pico_tftp_put(session, buf, ret);
if (len < 0) {
fprintf(stderr, "Failure in pico_tftp_put\n");
close(fd);
countdown = 1;
continue;
}
if (len != PICO_TFTP_PAYLOAD_SIZE) {
close(fd);
printf("Transfer complete!\n");
countdown = 1;
}
}
}
}
void usage(const char *text)
{
fprintf(stderr, "%s\nArguments must be <filename> <mode>\n"
"<mode> can be:\n"
"\tg => GET request without options\n"
"\tG => GET request WITH options\n"
"\tp => PUT request without options\n"
"\tP => PUT request WITH options\n\n",
text);
exit(1);
}
int main(int argc, char**argv)
{
struct pico_ip4 my_ip;
union pico_address server_address;
struct pico_ip4 netmask;
struct pico_tftp_session *session;
int synchro;
int options = 0;
void (*operation)(struct pico_tftp_session *session, int *synchro, const char *filename, int options);
unsigned char macaddr[6] = {
0, 0, 0, 0xa, 0xb, 0x0
};
uint16_t *macaddr_low = (uint16_t *) (macaddr + 2);
*macaddr_low = *macaddr_low ^ (uint16_t)((uint16_t)getpid() & (uint16_t)0xFFFFU);
macaddr[4] ^= (uint8_t)(getpid() >> 8);
macaddr[5] ^= (uint8_t) (getpid() & 0xFF);
pico_string_to_ipv4("10.40.0.10", &my_ip.addr);
pico_string_to_ipv4("255.255.255.0", &netmask.addr);
pico_string_to_ipv4("10.40.0.2", &server_address.ip4.addr);
if (argc != 3) {
usage("Invalid number or arguments");
}
switch (argv[2][0]) {
case 'G':
options = 1;
case 'g':
operation = start_rx;
break;
case 'P':
options = 1;
case 'p':
operation = start_tx;
break;
default:
usage("Invalid mode");
}
printf("%s start!\n", argv[0]);
pico_stack_init();
pico_dev = (struct pico_device *) pico_vde_create("/tmp/vde_switch", "tap0", macaddr);
if(!pico_dev) {
fprintf(stderr, "Error creating pico device, got enough privileges? Exiting...\n");
exit(1);
}
pico_ipv4_link_add(pico_dev, my_ip, netmask);
printf("Starting picoTCP loop\n");
session = pico_tftp_app_setup(&server_address, short_be(PICO_TFTP_PORT), PICO_PROTO_IPV4, &synchro);
if (!session) {
fprintf(stderr, "Error in pico_tftp_app_setup\n");
exit(1);
}
printf("synchro %d\n", synchro);
operation(session, &synchro, argv[1], options);
}