Network Interface Object
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
6
down vote
favorite
I wrote a Network... thing (not really telnet); and it's pretty simple. No options, just straight I/O. It seems programs get so bloated easily.
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
sig_atomic_t run = 1;
sig_atomic_t sd = 1;
char e_socket_msg = "socket creation failedn";
char e_sockopt_msg = "set socket non-block failedn";
char e_parse_msg = "address parsing failedn";
char e_timeout_msg = "connection attempt timed outn";
char e_io_msg = "i/o errorn";
char e_generic_msg = "unknown or unexpected errorn";
char e_resolve_msg = "unable to resolve addressn";
typedef enum
e_resolve = -1,
e_socket = -2,
e_sockopt = -3,
e_parse = -4,
e_timeout = -5,
e_io = -6
Error;
void input(char *input, char *output, int len);
int resolve(char *host);
void sig_handler(int sig);
int connect_to(char *host, int port);
int transfer(int fd_in, char *buf, int buf_len, int fd_out);
int print_error(Error e);
int main(void)
fd_set fds;
struct timeval tv;
int rv;
char buffer[BUFLEN];
char host[64], port[16];
char host_msg = "host:t";
char port_msg = "port:t";
input(host_msg, host, 64);
input(port_msg, port, 16);
sd = connect_to(host, atoi(port));
if (sd < 0)
rv = resolve(host);
if (rv < 0) return print_error(rv);
sd = connect_to(host, atoi(port));
if (sd < 0) return print_error(sd);
signal(SIGINT, sig_handler);
signal(SIGPIPE, sig_handler);
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 300000;
while (run)
FD_SET(sd, &fds);
FD_SET(STDIN_FILENO, &fds);
rv = select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);
else if (FD_ISSET(sd, &fds))
rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO);
if (rv != 0)
run = 0;
if (rv > 0) print_error(e_io);
close(sd);
return 0;
void input(char *input, char *output, int len)
int rv;
(void) write(STDOUT_FILENO, input, strlen(input));
rv = read(STDIN_FILENO, output, len - 1);
output[rv - 1] = '';
void sig_handler(int sig)
run = 0;
close(sd);
int resolve(char *host)
struct addrinfo hints, *servinfo;
struct in_addr addr;
char *addr_tmp;
int rv = 0;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
rv = getaddrinfo(host, NULL, &hints, &servinfo);
if (rv) return print_error(e_resolve);
addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr;
addr_tmp = inet_ntoa(addr);
memset(host, 0, 64);
memcpy(host, addr_tmp, strlen(addr_tmp));
freeaddrinfo(servinfo);
return rv;
int connect_to(char *host, int port)
int sd;
struct sockaddr_in addr;
fd_set sfds;
struct timeval tv;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) return e_socket;
if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return e_sockopt;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1)
return e_parse;
addr.sin_port = htons(port);
connect(sd, (struct sockaddr *) &addr, sizeof (addr));
FD_ZERO(&sfds);
FD_SET(sd, &sfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd;
return e_timeout;
int transfer(int fd_in, char *buf, int buf_len, int fd_out)
int len = read(fd_in, buf, buf_len);
return len > 0? len - write(fd_out, buf, len) : -1;
int print_error(Error e)
char *msg;
switch (e)
case e_socket:
msg = e_socket_msg;
break;
case e_sockopt:
msg = e_sockopt_msg;
break;
case e_parse:
msg = e_parse_msg;
break;
case e_timeout:
msg = e_timeout_msg;
break;
case e_io:
msg = e_io_msg;
break;
case e_resolve:
msg = e_resolve_msg;
break;
default:
msg = e_generic_msg;
break;
(void) write(STDERR_FILENO, msg, strlen(msg));
return -e;
c io networking socket web-services
add a comment |Â
up vote
6
down vote
favorite
I wrote a Network... thing (not really telnet); and it's pretty simple. No options, just straight I/O. It seems programs get so bloated easily.
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
sig_atomic_t run = 1;
sig_atomic_t sd = 1;
char e_socket_msg = "socket creation failedn";
char e_sockopt_msg = "set socket non-block failedn";
char e_parse_msg = "address parsing failedn";
char e_timeout_msg = "connection attempt timed outn";
char e_io_msg = "i/o errorn";
char e_generic_msg = "unknown or unexpected errorn";
char e_resolve_msg = "unable to resolve addressn";
typedef enum
e_resolve = -1,
e_socket = -2,
e_sockopt = -3,
e_parse = -4,
e_timeout = -5,
e_io = -6
Error;
void input(char *input, char *output, int len);
int resolve(char *host);
void sig_handler(int sig);
int connect_to(char *host, int port);
int transfer(int fd_in, char *buf, int buf_len, int fd_out);
int print_error(Error e);
int main(void)
fd_set fds;
struct timeval tv;
int rv;
char buffer[BUFLEN];
char host[64], port[16];
char host_msg = "host:t";
char port_msg = "port:t";
input(host_msg, host, 64);
input(port_msg, port, 16);
sd = connect_to(host, atoi(port));
if (sd < 0)
rv = resolve(host);
if (rv < 0) return print_error(rv);
sd = connect_to(host, atoi(port));
if (sd < 0) return print_error(sd);
signal(SIGINT, sig_handler);
signal(SIGPIPE, sig_handler);
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 300000;
while (run)
FD_SET(sd, &fds);
FD_SET(STDIN_FILENO, &fds);
rv = select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);
else if (FD_ISSET(sd, &fds))
rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO);
if (rv != 0)
run = 0;
if (rv > 0) print_error(e_io);
close(sd);
return 0;
void input(char *input, char *output, int len)
int rv;
(void) write(STDOUT_FILENO, input, strlen(input));
rv = read(STDIN_FILENO, output, len - 1);
output[rv - 1] = '';
void sig_handler(int sig)
run = 0;
close(sd);
int resolve(char *host)
struct addrinfo hints, *servinfo;
struct in_addr addr;
char *addr_tmp;
int rv = 0;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
rv = getaddrinfo(host, NULL, &hints, &servinfo);
if (rv) return print_error(e_resolve);
addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr;
addr_tmp = inet_ntoa(addr);
memset(host, 0, 64);
memcpy(host, addr_tmp, strlen(addr_tmp));
freeaddrinfo(servinfo);
return rv;
int connect_to(char *host, int port)
int sd;
struct sockaddr_in addr;
fd_set sfds;
struct timeval tv;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) return e_socket;
if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return e_sockopt;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1)
return e_parse;
addr.sin_port = htons(port);
connect(sd, (struct sockaddr *) &addr, sizeof (addr));
FD_ZERO(&sfds);
FD_SET(sd, &sfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd;
return e_timeout;
int transfer(int fd_in, char *buf, int buf_len, int fd_out)
int len = read(fd_in, buf, buf_len);
return len > 0? len - write(fd_out, buf, len) : -1;
int print_error(Error e)
char *msg;
switch (e)
case e_socket:
msg = e_socket_msg;
break;
case e_sockopt:
msg = e_sockopt_msg;
break;
case e_parse:
msg = e_parse_msg;
break;
case e_timeout:
msg = e_timeout_msg;
break;
case e_io:
msg = e_io_msg;
break;
case e_resolve:
msg = e_resolve_msg;
break;
default:
msg = e_generic_msg;
break;
(void) write(STDERR_FILENO, msg, strlen(msg));
return -e;
c io networking socket web-services
1
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefere_socket_msg*
toe_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.
â vaxquis
Jul 15 at 11:05
2
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handler
as a special case - it must be followed by 0x00. Note thatr
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0a
â slebetman
Jul 15 at 14:37
2
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
I wrote a Network... thing (not really telnet); and it's pretty simple. No options, just straight I/O. It seems programs get so bloated easily.
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
sig_atomic_t run = 1;
sig_atomic_t sd = 1;
char e_socket_msg = "socket creation failedn";
char e_sockopt_msg = "set socket non-block failedn";
char e_parse_msg = "address parsing failedn";
char e_timeout_msg = "connection attempt timed outn";
char e_io_msg = "i/o errorn";
char e_generic_msg = "unknown or unexpected errorn";
char e_resolve_msg = "unable to resolve addressn";
typedef enum
e_resolve = -1,
e_socket = -2,
e_sockopt = -3,
e_parse = -4,
e_timeout = -5,
e_io = -6
Error;
void input(char *input, char *output, int len);
int resolve(char *host);
void sig_handler(int sig);
int connect_to(char *host, int port);
int transfer(int fd_in, char *buf, int buf_len, int fd_out);
int print_error(Error e);
int main(void)
fd_set fds;
struct timeval tv;
int rv;
char buffer[BUFLEN];
char host[64], port[16];
char host_msg = "host:t";
char port_msg = "port:t";
input(host_msg, host, 64);
input(port_msg, port, 16);
sd = connect_to(host, atoi(port));
if (sd < 0)
rv = resolve(host);
if (rv < 0) return print_error(rv);
sd = connect_to(host, atoi(port));
if (sd < 0) return print_error(sd);
signal(SIGINT, sig_handler);
signal(SIGPIPE, sig_handler);
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 300000;
while (run)
FD_SET(sd, &fds);
FD_SET(STDIN_FILENO, &fds);
rv = select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);
else if (FD_ISSET(sd, &fds))
rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO);
if (rv != 0)
run = 0;
if (rv > 0) print_error(e_io);
close(sd);
return 0;
void input(char *input, char *output, int len)
int rv;
(void) write(STDOUT_FILENO, input, strlen(input));
rv = read(STDIN_FILENO, output, len - 1);
output[rv - 1] = '';
void sig_handler(int sig)
run = 0;
close(sd);
int resolve(char *host)
struct addrinfo hints, *servinfo;
struct in_addr addr;
char *addr_tmp;
int rv = 0;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
rv = getaddrinfo(host, NULL, &hints, &servinfo);
if (rv) return print_error(e_resolve);
addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr;
addr_tmp = inet_ntoa(addr);
memset(host, 0, 64);
memcpy(host, addr_tmp, strlen(addr_tmp));
freeaddrinfo(servinfo);
return rv;
int connect_to(char *host, int port)
int sd;
struct sockaddr_in addr;
fd_set sfds;
struct timeval tv;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) return e_socket;
if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return e_sockopt;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1)
return e_parse;
addr.sin_port = htons(port);
connect(sd, (struct sockaddr *) &addr, sizeof (addr));
FD_ZERO(&sfds);
FD_SET(sd, &sfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd;
return e_timeout;
int transfer(int fd_in, char *buf, int buf_len, int fd_out)
int len = read(fd_in, buf, buf_len);
return len > 0? len - write(fd_out, buf, len) : -1;
int print_error(Error e)
char *msg;
switch (e)
case e_socket:
msg = e_socket_msg;
break;
case e_sockopt:
msg = e_sockopt_msg;
break;
case e_parse:
msg = e_parse_msg;
break;
case e_timeout:
msg = e_timeout_msg;
break;
case e_io:
msg = e_io_msg;
break;
case e_resolve:
msg = e_resolve_msg;
break;
default:
msg = e_generic_msg;
break;
(void) write(STDERR_FILENO, msg, strlen(msg));
return -e;
c io networking socket web-services
I wrote a Network... thing (not really telnet); and it's pretty simple. No options, just straight I/O. It seems programs get so bloated easily.
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define BUFLEN 1024
sig_atomic_t run = 1;
sig_atomic_t sd = 1;
char e_socket_msg = "socket creation failedn";
char e_sockopt_msg = "set socket non-block failedn";
char e_parse_msg = "address parsing failedn";
char e_timeout_msg = "connection attempt timed outn";
char e_io_msg = "i/o errorn";
char e_generic_msg = "unknown or unexpected errorn";
char e_resolve_msg = "unable to resolve addressn";
typedef enum
e_resolve = -1,
e_socket = -2,
e_sockopt = -3,
e_parse = -4,
e_timeout = -5,
e_io = -6
Error;
void input(char *input, char *output, int len);
int resolve(char *host);
void sig_handler(int sig);
int connect_to(char *host, int port);
int transfer(int fd_in, char *buf, int buf_len, int fd_out);
int print_error(Error e);
int main(void)
fd_set fds;
struct timeval tv;
int rv;
char buffer[BUFLEN];
char host[64], port[16];
char host_msg = "host:t";
char port_msg = "port:t";
input(host_msg, host, 64);
input(port_msg, port, 16);
sd = connect_to(host, atoi(port));
if (sd < 0)
rv = resolve(host);
if (rv < 0) return print_error(rv);
sd = connect_to(host, atoi(port));
if (sd < 0) return print_error(sd);
signal(SIGINT, sig_handler);
signal(SIGPIPE, sig_handler);
FD_ZERO(&fds);
tv.tv_sec = 0;
tv.tv_usec = 300000;
while (run)
FD_SET(sd, &fds);
FD_SET(STDIN_FILENO, &fds);
rv = select(sd + 1, &fds, NULL, NULL, &tv);
if (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);
else if (FD_ISSET(sd, &fds))
rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO);
if (rv != 0)
run = 0;
if (rv > 0) print_error(e_io);
close(sd);
return 0;
void input(char *input, char *output, int len)
int rv;
(void) write(STDOUT_FILENO, input, strlen(input));
rv = read(STDIN_FILENO, output, len - 1);
output[rv - 1] = '';
void sig_handler(int sig)
run = 0;
close(sd);
int resolve(char *host)
struct addrinfo hints, *servinfo;
struct in_addr addr;
char *addr_tmp;
int rv = 0;
memset(&hints, 0, sizeof hints);
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
rv = getaddrinfo(host, NULL, &hints, &servinfo);
if (rv) return print_error(e_resolve);
addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr;
addr_tmp = inet_ntoa(addr);
memset(host, 0, 64);
memcpy(host, addr_tmp, strlen(addr_tmp));
freeaddrinfo(servinfo);
return rv;
int connect_to(char *host, int port)
int sd;
struct sockaddr_in addr;
fd_set sfds;
struct timeval tv;
sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) return e_socket;
if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return e_sockopt;
memset(&addr, 0, sizeof (addr));
addr.sin_family = AF_INET;
if (inet_pton(AF_INET, host, &addr.sin_addr) != 1)
return e_parse;
addr.sin_port = htons(port);
connect(sd, (struct sockaddr *) &addr, sizeof (addr));
FD_ZERO(&sfds);
FD_SET(sd, &sfds);
tv.tv_sec = 4;
tv.tv_usec = 0;
if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd;
return e_timeout;
int transfer(int fd_in, char *buf, int buf_len, int fd_out)
int len = read(fd_in, buf, buf_len);
return len > 0? len - write(fd_out, buf, len) : -1;
int print_error(Error e)
char *msg;
switch (e)
case e_socket:
msg = e_socket_msg;
break;
case e_sockopt:
msg = e_sockopt_msg;
break;
case e_parse:
msg = e_parse_msg;
break;
case e_timeout:
msg = e_timeout_msg;
break;
case e_io:
msg = e_io_msg;
break;
case e_resolve:
msg = e_resolve_msg;
break;
default:
msg = e_generic_msg;
break;
(void) write(STDERR_FILENO, msg, strlen(msg));
return -e;
c io networking socket web-services
edited Jul 16 at 6:17
asked Jul 15 at 2:42
motoku
1,0961139
1,0961139
1
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefere_socket_msg*
toe_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.
â vaxquis
Jul 15 at 11:05
2
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handler
as a special case - it must be followed by 0x00. Note thatr
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0a
â slebetman
Jul 15 at 14:37
2
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41
add a comment |Â
1
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefere_socket_msg*
toe_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.
â vaxquis
Jul 15 at 11:05
2
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handler
as a special case - it must be followed by 0x00. Note thatr
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0a
â slebetman
Jul 15 at 14:37
2
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41
1
1
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefer
e_socket_msg*
to e_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.â vaxquis
Jul 15 at 11:05
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefer
e_socket_msg*
to e_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.â vaxquis
Jul 15 at 11:05
2
2
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handle
r
as a special case - it must be followed by 0x00. Note that r
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0aâ slebetman
Jul 15 at 14:37
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handle
r
as a special case - it must be followed by 0x00. Note that r
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0aâ slebetman
Jul 15 at 14:37
2
2
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
9
down vote
accepted
There is no guarantee that
write
writes out the entirebuffer
. This means thatif (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);may lose data. Consider looping until all data gone out.
As long as the portability is concerned, the timeout parameter of
select
needs attention. The BSD implementation doesn't change it, Linux does (POSIX considers both compliant), WSA says nothing. It is prudent to re-initializetv
inside the loop.Getting host and port from
stdin
seriously restricts the utility of the program. It cannot be used as a filter. Consider passing them via command line arguments.Make up your mind on who is responsible for error reporting. For example,
resolve
does callprint_error
, and so doesmain
on resolve's failure. The error message gots printed twice.geraddrinfo
returns some valuable information inservinfo
, which you effectively throw away - what was the reason to call it?. Still you shouldfreeaddrinfo
afterwards.
add a comment |Â
up vote
9
down vote
the posted code causes the compiler to output several warning messages.
When compiling, always enable the warnings, then fix those warnings.
Here is the compile statement and the resulting warning messages.
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -ggdb -c "untitled2.c"
untitled2.c: In function âÂÂinputâÂÂ:
untitled2.c:86:37: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~
untitled2.c:86:10: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~~
untitled2.c: In function âÂÂsig_handlerâÂÂ:
untitled2.c:90:22: warning: unused parameter âÂÂsigâ [-Wunused-parameter]
void sig_handler(int sig) {
^~~
untitled2.c: In function âÂÂconnect_toâÂÂ:
untitled2.c:127:27: warning: conversion to âÂÂuint16_t aka short unsigned intâ from âÂÂintâ may alter its value [-Wconversion]
addr.sin_port = htons(port);
^~~~
untitled2.c: In function âÂÂtransferâÂÂ:
untitled2.c:138:32: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
int len = read(fd_in, buf, buf_len);
^~~~~~~
untitled2.c:138:15: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
int len = read(fd_in, buf, buf_len);
^~~~
untitled2.c:139:46: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
return len > 0? len - write(fd_out, buf, len) : -1;
^~~
untitled2.c:139:51: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
return len > 0? len - write(fd_out, buf, len) : -1;
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
accepted
There is no guarantee that
write
writes out the entirebuffer
. This means thatif (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);may lose data. Consider looping until all data gone out.
As long as the portability is concerned, the timeout parameter of
select
needs attention. The BSD implementation doesn't change it, Linux does (POSIX considers both compliant), WSA says nothing. It is prudent to re-initializetv
inside the loop.Getting host and port from
stdin
seriously restricts the utility of the program. It cannot be used as a filter. Consider passing them via command line arguments.Make up your mind on who is responsible for error reporting. For example,
resolve
does callprint_error
, and so doesmain
on resolve's failure. The error message gots printed twice.geraddrinfo
returns some valuable information inservinfo
, which you effectively throw away - what was the reason to call it?. Still you shouldfreeaddrinfo
afterwards.
add a comment |Â
up vote
9
down vote
accepted
There is no guarantee that
write
writes out the entirebuffer
. This means thatif (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);may lose data. Consider looping until all data gone out.
As long as the portability is concerned, the timeout parameter of
select
needs attention. The BSD implementation doesn't change it, Linux does (POSIX considers both compliant), WSA says nothing. It is prudent to re-initializetv
inside the loop.Getting host and port from
stdin
seriously restricts the utility of the program. It cannot be used as a filter. Consider passing them via command line arguments.Make up your mind on who is responsible for error reporting. For example,
resolve
does callprint_error
, and so doesmain
on resolve's failure. The error message gots printed twice.geraddrinfo
returns some valuable information inservinfo
, which you effectively throw away - what was the reason to call it?. Still you shouldfreeaddrinfo
afterwards.
add a comment |Â
up vote
9
down vote
accepted
up vote
9
down vote
accepted
There is no guarantee that
write
writes out the entirebuffer
. This means thatif (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);may lose data. Consider looping until all data gone out.
As long as the portability is concerned, the timeout parameter of
select
needs attention. The BSD implementation doesn't change it, Linux does (POSIX considers both compliant), WSA says nothing. It is prudent to re-initializetv
inside the loop.Getting host and port from
stdin
seriously restricts the utility of the program. It cannot be used as a filter. Consider passing them via command line arguments.Make up your mind on who is responsible for error reporting. For example,
resolve
does callprint_error
, and so doesmain
on resolve's failure. The error message gots printed twice.geraddrinfo
returns some valuable information inservinfo
, which you effectively throw away - what was the reason to call it?. Still you shouldfreeaddrinfo
afterwards.
There is no guarantee that
write
writes out the entirebuffer
. This means thatif (FD_ISSET(STDIN_FILENO, &fds))
rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd);may lose data. Consider looping until all data gone out.
As long as the portability is concerned, the timeout parameter of
select
needs attention. The BSD implementation doesn't change it, Linux does (POSIX considers both compliant), WSA says nothing. It is prudent to re-initializetv
inside the loop.Getting host and port from
stdin
seriously restricts the utility of the program. It cannot be used as a filter. Consider passing them via command line arguments.Make up your mind on who is responsible for error reporting. For example,
resolve
does callprint_error
, and so doesmain
on resolve's failure. The error message gots printed twice.geraddrinfo
returns some valuable information inservinfo
, which you effectively throw away - what was the reason to call it?. Still you shouldfreeaddrinfo
afterwards.
edited Jul 15 at 5:17
answered Jul 15 at 5:09
vnp
36.3k12890
36.3k12890
add a comment |Â
add a comment |Â
up vote
9
down vote
the posted code causes the compiler to output several warning messages.
When compiling, always enable the warnings, then fix those warnings.
Here is the compile statement and the resulting warning messages.
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -ggdb -c "untitled2.c"
untitled2.c: In function âÂÂinputâÂÂ:
untitled2.c:86:37: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~
untitled2.c:86:10: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~~
untitled2.c: In function âÂÂsig_handlerâÂÂ:
untitled2.c:90:22: warning: unused parameter âÂÂsigâ [-Wunused-parameter]
void sig_handler(int sig) {
^~~
untitled2.c: In function âÂÂconnect_toâÂÂ:
untitled2.c:127:27: warning: conversion to âÂÂuint16_t aka short unsigned intâ from âÂÂintâ may alter its value [-Wconversion]
addr.sin_port = htons(port);
^~~~
untitled2.c: In function âÂÂtransferâÂÂ:
untitled2.c:138:32: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
int len = read(fd_in, buf, buf_len);
^~~~~~~
untitled2.c:138:15: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
int len = read(fd_in, buf, buf_len);
^~~~
untitled2.c:139:46: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
return len > 0? len - write(fd_out, buf, len) : -1;
^~~
untitled2.c:139:51: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
return len > 0? len - write(fd_out, buf, len) : -1;
add a comment |Â
up vote
9
down vote
the posted code causes the compiler to output several warning messages.
When compiling, always enable the warnings, then fix those warnings.
Here is the compile statement and the resulting warning messages.
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -ggdb -c "untitled2.c"
untitled2.c: In function âÂÂinputâÂÂ:
untitled2.c:86:37: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~
untitled2.c:86:10: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~~
untitled2.c: In function âÂÂsig_handlerâÂÂ:
untitled2.c:90:22: warning: unused parameter âÂÂsigâ [-Wunused-parameter]
void sig_handler(int sig) {
^~~
untitled2.c: In function âÂÂconnect_toâÂÂ:
untitled2.c:127:27: warning: conversion to âÂÂuint16_t aka short unsigned intâ from âÂÂintâ may alter its value [-Wconversion]
addr.sin_port = htons(port);
^~~~
untitled2.c: In function âÂÂtransferâÂÂ:
untitled2.c:138:32: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
int len = read(fd_in, buf, buf_len);
^~~~~~~
untitled2.c:138:15: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
int len = read(fd_in, buf, buf_len);
^~~~
untitled2.c:139:46: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
return len > 0? len - write(fd_out, buf, len) : -1;
^~~
untitled2.c:139:51: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
return len > 0? len - write(fd_out, buf, len) : -1;
add a comment |Â
up vote
9
down vote
up vote
9
down vote
the posted code causes the compiler to output several warning messages.
When compiling, always enable the warnings, then fix those warnings.
Here is the compile statement and the resulting warning messages.
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -ggdb -c "untitled2.c"
untitled2.c: In function âÂÂinputâÂÂ:
untitled2.c:86:37: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~
untitled2.c:86:10: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~~
untitled2.c: In function âÂÂsig_handlerâÂÂ:
untitled2.c:90:22: warning: unused parameter âÂÂsigâ [-Wunused-parameter]
void sig_handler(int sig) {
^~~
untitled2.c: In function âÂÂconnect_toâÂÂ:
untitled2.c:127:27: warning: conversion to âÂÂuint16_t aka short unsigned intâ from âÂÂintâ may alter its value [-Wconversion]
addr.sin_port = htons(port);
^~~~
untitled2.c: In function âÂÂtransferâÂÂ:
untitled2.c:138:32: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
int len = read(fd_in, buf, buf_len);
^~~~~~~
untitled2.c:138:15: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
int len = read(fd_in, buf, buf_len);
^~~~
untitled2.c:139:46: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
return len > 0? len - write(fd_out, buf, len) : -1;
^~~
untitled2.c:139:51: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
return len > 0? len - write(fd_out, buf, len) : -1;
the posted code causes the compiler to output several warning messages.
When compiling, always enable the warnings, then fix those warnings.
Here is the compile statement and the resulting warning messages.
gcc -Wall -Wextra -Wconversion -pedantic -std=gnu11 -ggdb -c "untitled2.c"
untitled2.c: In function âÂÂinputâÂÂ:
untitled2.c:86:37: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~
untitled2.c:86:10: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
rv = read(STDIN_FILENO, output, len - 1);
^~~~
untitled2.c: In function âÂÂsig_handlerâÂÂ:
untitled2.c:90:22: warning: unused parameter âÂÂsigâ [-Wunused-parameter]
void sig_handler(int sig) {
^~~
untitled2.c: In function âÂÂconnect_toâÂÂ:
untitled2.c:127:27: warning: conversion to âÂÂuint16_t aka short unsigned intâ from âÂÂintâ may alter its value [-Wconversion]
addr.sin_port = htons(port);
^~~~
untitled2.c: In function âÂÂtransferâÂÂ:
untitled2.c:138:32: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
int len = read(fd_in, buf, buf_len);
^~~~~~~
untitled2.c:138:15: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
int len = read(fd_in, buf, buf_len);
^~~~
untitled2.c:139:46: warning: conversion to âÂÂsize_t aka long unsigned intâ from âÂÂintâ may change the sign of the result [-Wsign-conversion]
return len > 0? len - write(fd_out, buf, len) : -1;
^~~
untitled2.c:139:51: warning: conversion to âÂÂintâ from âÂÂssize_t aka long intâ may alter its value [-Wconversion]
return len > 0? len - write(fd_out, buf, len) : -1;
answered Jul 15 at 6:25
user3629249
1,44749
1,44749
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f199524%2fnetwork-interface-object%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
FWIW, some nitpicks: 1. using FULL_CAPS for C constant values (most people include enums here) seems to be the norm for readability, 2. prefer
e_socket_msg*
toe_socket_msg
for string constants (i.e. unless you explicitly want to edit that string later on), 3. since your errors are 1:1 mapped to error codes, use a map (or even simply an array, when your key values are consecutive integers) and access it to get messages, instead of switching over the key.â vaxquis
Jul 15 at 11:05
2
You have not implemented telnet. Telnet is an actual protocol, not just a raw TCP session. You need to handle the byte 0xff as a special case. To send 0xff you need to send 0xff,0xff. You also need to handle
r
as a special case - it must be followed by 0x00. Note thatr
is different depending on weather you are talking to an EBDIC or ASCII system but I think we can safely ignore EBDIC these days unless we're talking to IBM mainframes. So assuming ASCII, every time you detect 0x0d that is not followed by 0x0a it must be sent as 0x0d, 0x00. But if it is followed by 0x0a it is 0x0d, 0x0aâ slebetman
Jul 15 at 14:37
2
What you have implemented here is something similar to netcat
â slebetman
Jul 15 at 14:40
A lot of the code seems to be based on error handling. Look into errno and strerror... Let the c libraries handle this all for you. It's more elegant, smaller, and won't be wrong
â sudo rm -rf slash
Jul 15 at 15:41