Лучший способ создать данные протокола - это иметь где-то буфер uint8_t
и заполнять его, как указано в протоколе.
Для собственно FTP это довольно просто, поскольку существуют только ASCIIСтроки в контрольном соединении.Примерно так может работать:
bool append_literal(uint8_t **cursor, uint8_t *end, uint8_t const *data, size_t size) {
assert(cursor);
assert(*cursor);
assert(end);
assert(*cursor < end);
assert(data);
if((end - *cursor) < size) // Check buffer limit
return false;
memcpy(*cursor, data, size); // Copy
*cursor += size; // Increment cursor
return true;
}
bool append_number(uint8_t **cursor, uint8_t *end, uint64_t number) {
assert(cursor);
assert(*cursor);
assert(end);
assert(*cursor < end);
if((end - *cursor) < 17) // Max number of base 10 digits in uint64_t
return false;
*cursor += sprintf(*cursor, "%" PRIu64, number);
return true;
}
bool append_uint32_binary(uint8_t **cursor, uint8_t *end, uint32_t value) {
assert(cursor);
assert(*cursor);
assert(end);
assert(*cursor < end);
if((end - *cursor) < 4) // Bytes needed for uint32 value
return false;
*(*cursor)++ = (value >> 24) & 0xff;
*(*cursor)++ = (value >> 16) & 0xff;
*(*cursor)++ = (value >> 8) & 0xff;
*(*cursor)++ = value & 0xff;
return true;
}
// Specific FTP commands
bool append_size_command(uint8_t **cursor, uint8_t *end, uint64_t size) {
return append_literal(cursor, end, "SIZE ", 5) &&
append_number(cursor, end, size) &&
append_literal(cursor, end, "\r\n", 2);
}
// [...]
bool send_size_command(int fd, uint64_t size) {
uint8_t buffer[32];
uint8_t *cursor = buffer;
uint8_t *const end = buffer + sizeof buffer;
if(!append_size_command(&cursor, end, size))
return false;
size_t length = cursor - buffer;
ssize_t sent = send(fd, buffer, length, 0);
return (sent == length);
}
Операторы "assert" проверяют вещи, которые всегда будут верными, если ваша программа написана правильно, то есть указатели действительны.Любая функция возвращает true
в случае успеха и false
в случае неудачи.
Я использовал стандартные функции POSIX для сокетов, потому что WinSock их реализует, и они довольно переносимы.
Ваша домашняя работа - найти заголовки, которые вам нужно включить для PRIu64
:)