send() and puts() are mixed together, (programming a FTP server in C)
Question
I'm making a FTP server in C. At the client side I'm using FileZilla. My code so far contains only the handshaking part.
The problem I've got is that the strings I print out for the terminal are sent to FileZilla. My question is how can I keep these two seperated, i've tried a couple of things, but none of them give the correct result.
This is only a part of my code, but for my question is this the useful part:
while (FOREVER){
addr_size = sizeof their_addr;
newfd = accept(listener, (struct sockaddr*) &their_addr, &addr_size);
if (newfd == -1){
perror("accept");
continue;
}
if ((send(newfd, "220 JEDI FTP is ready", 50, 0)) <= 0)
perror("error sending");
puts("connection established");
puts("waiting for user & connection");
while (!login){
// username
if (!user){
if ((recv(newfd, buffer, BUFFCON, 0)) <= 0){
puts("error receiving username");
}
else{
if (strstr(buffer, "USER") != NULL){
if (strstr(buffer, name) != NULL){
send(newfd, "331 password required", 50, 0);
puts("username correct");
user = 1;
}
else{
puts("username incorrect");
send(newfd, "430 username incorrect", 50, 0);
}//else
}//if
}//else
}//if user
And this is the output in FileZilla:
- Status: Adres bepalen van localhost
- Status: Verbinden met [::1]:21...
- Status: Verbinding aangemaakt, welkomstbericht afwachten...
- Antwoord: 220 JEDI FTP is ready
- Commando: USER yoda
- Antwoord: connection established
- Fout: Kan niet verbinden met server
So instead of sending "331 password required" it sends "connection established"
Hope you can help me with this, Thanks a lot.
Solution
The problem is that your len
parameter for send
is too large. send
has no concept of null-terminated strings; it only works with raw sequences of bytes. So the call send(newfd, "220 JEDI FTP is ready", 50, 0)
sends the string "220 JEDI FTP is ready"
, and then whatever happens to come in memory after it. Technically, this is undefined behavior, so literally anything could happen (usually a segfault). In your case, because constant literal strings are usually stored sequentially in memory, send
is reading the given string, and then reading a different string after it.
What you want to do is only send the exact string (which, by the way, needs the CR-LF sequence \r\n
after each command). No more, no less. You can implement a sends
function to send a string like so:
ssize_t sends(int fd, const char *str)
{
size_t len = strlen(str);
return send(fd, str, len, 0);
}
Also note that the data sent does not include the null-terminator, because the TCP packet specifies the size of the string.