Permalink
Browse files

Support TFTP options sent with read requests, write requests are not …

…finished yet and most of this code is not ready.

- Support "blksize" and "tsize" TFTP options as per RFC 2347, RFC 2348, and RFC 2349, "timeout" is still missing
- Once again rewrote the way packets are parsed in ProcessPacket, this is MUCH simpler to understand now.
- Modified much of the core to use a dynamic block size instead of 512 bytes as to support "blksize"
- Remove OACK packet handling from ProcessPacket, a client will never send that packet and we would ignore it anyway.
  • Loading branch information...
Justasic committed Jan 9, 2015
1 parent 05761d6 commit 6e74dcd9e9518fa3f50f15c994ab1c3be1706c87
View
@@ -54,6 +54,11 @@ typedef struct client_s
// The client's Transfer ID, just the udp port
tid_t tid;
// The block transfer size.
uint32_t blksize;
// An actual data block.
void *blk;
} client_t;
typedef vec_t(client_t*) client_vec_t;
View
@@ -40,5 +40,4 @@ extern int SwitchUserAndGroup(const char *user, const char *group);
extern void Daemonize(void);
extern int vasprintf(char **str, const char *fmt, va_list args);
extern char *SizeReduce(size_t size);
extern char *GetBlockSize(size_t blocks);
extern char *stringify(const char *str, ...);
View
@@ -89,3 +89,4 @@ __attribute__((format(printf, 3, 4)))
extern void Error(client_t *client, const uint16_t errnum, const char *str, ...);
extern void Acknowledge(client_t *client, uint16_t blockno);
extern void SendData(client_t *client, void *data, size_t len);
extern void OptionAcknowledge(client_t *c, const char *option, const char *param);
View
@@ -41,6 +41,7 @@ void AddClient(client_t *c)
// The transfer ID is given as the port.
c->tid = -GetPort(c->s);
c->blksize = 512;
}
client_t *FindOrAllocateClient(socket_t cs)
@@ -96,6 +97,12 @@ void RemoveClient(client_t *c)
if (c->lastpacket.allocated)
free(c->lastpacket.p);
// Remove the client's block buffer.
if (c->blk)
free(c->blk);
printf("Removing client\n");
// Delete the client
free(c);
}
View
@@ -161,7 +161,7 @@ int SwitchUserAndGroup(const char *user, const char *group)
return 1;
}
}
// Check our directory permissions
int r = access(config->directory, R_OK) + 1, w = access(config->directory, W_OK) + 1;
if (!r && !w)
@@ -235,11 +235,6 @@ char *SizeReduce(size_t size)
return str;
}
char *GetBlockSize(size_t blocks)
{
return SizeReduce(blocks * 512);
}
char *stringify(const char *str, ...)
{
char *ret = NULL;
@@ -248,4 +243,4 @@ char *stringify(const char *str, ...)
vasprintf(&ret, str, ap);
va_end(ap);
return ret;
}
}
@@ -166,17 +166,17 @@ void ProcessSockets(void)
continue;
}
// process socket read events.
if (ev->events & EPOLLIN && ReceivePackets(s) == -1)
// Process socket write events
if (ev->events & EPOLLOUT && SendPackets(s) == -1)
{
bprintf("Destorying socket due to receive failure!\n");
bprintf("Destorying socket due to send failure!\n");
DestroySocket(s, 1);
}
// Process socket write events
if (ev->events & EPOLLOUT && SendPackets(s) == -1)
// process socket read events.
if (ev->events & EPOLLIN && ReceivePackets(s) == -1)
{
bprintf("Destorying socket due to send failure!\n");
bprintf("Destorying socket due to receive failure!\n");
DestroySocket(s, 1);
}
}
@@ -188,17 +188,17 @@ void ProcessSockets(void)
continue;
}
// process socket read events.
if (ev->filter & EVFILT_READ && ReceivePackets(s) == -1)
// Process socket write events
if (ev->filter & EVFILT_WRITE && SendPackets(s) == -1)
{
bprintf("Destorying socket due to receive failure!\n");
bprintf("Destorying socket due to send failure!\n");
DestroySocket(s, 1);
}
// Process socket write events
if (ev->filter & EVFILT_WRITE && SendPackets(s) == -1)
// process socket read events.
if (ev->filter & EVFILT_READ && ReceivePackets(s) == -1)
{
bprintf("Destorying socket due to send failure!\n");
bprintf("Destorying socket due to receive failure!\n");
DestroySocket(s, 1);
}
}
@@ -150,15 +150,15 @@ void ProcessSockets(void)
continue;
}
if (ev->revents & POLLIN && ReceivePackets(s) == -1)
if (ev->revents & POLLOUT && SendPackets(s) == -1)
{
bprintf("Destorying socket due to receive failure!\n");
bprintf("Destorying socket due to send failure!\n");
DestroySocket(s, 1);
}
if (ev->revents & POLLOUT && SendPackets(s) == -1)
if (ev->revents & POLLIN && ReceivePackets(s) == -1)
{
bprintf("Destorying socket due to send failure!\n");
bprintf("Destorying socket due to receive failure!\n");
DestroySocket(s, 1);
}
}
@@ -126,15 +126,15 @@ void ProcessSockets(void)
continue;
}
if (has_read && ReceivePackets(s) == -1)
if (has_write && SendPackets(s) == -1)
{
bprintf("Destorying socket due to receive failure!\n");
bprintf("Destorying socket due to send failure!\n");
DestroySocket(s, 1);
}
if (has_write && SendPackets(s) == -1)
if (has_read && ReceivePackets(s) == -1)
{
bprintf("Destorying socket due to send failure!\n");
bprintf("Destorying socket due to receive failure!\n");
DestroySocket(s, 1);
}
}
View
@@ -32,15 +32,17 @@
void SendData(client_t *c, void *data, size_t len)
{
// Make sure the packet size does not exceed the max packet length.
assert((len + sizeof(packet_t) <= MAX_PACKET_SIZE));
assert(c && data);
// Previously we would make sure the data packets do not exceed a certain length
// but that would violate the blksize extension and therefore we trust that
// we are given the proper size.
// assert((len + sizeof(packet_t) <= MAX_PACKET_SIZE));
assert(c && data);
// Allocate a packet that is as big as the data + len
packet_t *p = nmalloc(len + sizeof(packet_t));
p->opcode = htons(PACKET_DATA);
p->blockno = htons(c->currentblockno);
// Cast the pointer, move to the end of the struct,
// then copy our data, this will mean we have a full
// packet struct.
@@ -52,7 +54,7 @@ void SendData(client_t *c, void *data, size_t len)
//
uint8_t *pptr = ((uint8_t*)p) + sizeof(packet_t);
memcpy(pptr, data, len);
// Queue our packet for sending when EPoll comes around to send.
QueuePacket(c, p, len + sizeof(packet_t), 1);
}
@@ -69,7 +71,7 @@ void Acknowledge(client_t *c, uint16_t blockno)
packet_t *p = nmalloc(sizeof(packet_t));
p->opcode = htons(PACKET_ACK);
p->blockno = htons(blockno);
QueuePacket(c, p, sizeof(packet_t), 1);
}
@@ -90,13 +92,15 @@ void Error(client_t *c, const uint16_t errnum, const char *str, ...)
va_start(ap, str);
size_t len = vasprintf(&buf, str, ap);
va_end(ap);
if (len == -1)
{
fprintf(stderr, "ERROR: cannot format error string: %s\n", strerror(errno));
return;
}
bprintf("Error Packet: %s\n", buf);
// If your message is seriously bigger than 512 characters
// then you need to rethink what is going on.
// The end user doesn't need a god damn book because a file
@@ -106,17 +110,40 @@ void Error(client_t *c, const uint16_t errnum, const char *str, ...)
packet_t *p = nmalloc(len + sizeof(packet_t) + 1);
p->opcode = htons(PACKET_ERROR);
p->blockno = htons(errnum);
// Fancy casting magic!
uint8_t *pptr = ((uint8_t*)p) + sizeof(packet_t);
strncpy((char*)pptr, buf, len);
// guaranteed null-termination.
pptr[len] = 0;
QueuePacket(c, p, len + sizeof(packet_t) + 1, 1);
// We don't care what they say now, destroy the client.
c->destroy = 1;
free(buf);
free(buf);
}
void OptionAcknowledge(client_t *c, const char *option, const char *param)
{
//
// 2 bytes string 1 byte string 1 byte string 1 byte string 1 byte
// +----------+---~~---+---------+---~~---+---------+---~~---+-----------+---~~---+---+
// | Opcode | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
// +----------+---~~---+---------+---~~---+---------+---~~---+-----------+---~~---+---+
//
assert(c && option && param);
packet_t *p = nmalloc(sizeof(packet_t) + strlen(option) + strlen(param) + 2);
p->opcode = htons(PACKET_OACK);
uint8_t *pptr = ((uint8_t*)p) + sizeof(uint16_t);
strcpy((char*)pptr, option);
pptr += strlen(option);
*pptr++ = '\0';
strcpy((char*)pptr, param);
*pptr = '\0';
QueuePacket(c, p, sizeof(packet_t) + strlen(option) + strlen(param) + 2, 1);
}
Oops, something went wrong.

0 comments on commit 6e74dcd

Please sign in to comment.