diff --git a/src/transport/tcp.c b/src/transport/tcp.c index 305693e..63468f7 100644 --- a/src/transport/tcp.c +++ b/src/transport/tcp.c @@ -16,8 +16,14 @@ #include +#include #include +#include +#ifdef DEBUG +# include +#endif #include +#include #include #include #include @@ -49,6 +55,8 @@ static int _tcp_error(char const * message, int code); /* callbacks */ static int _tcp_callback_accept(int fd, TCP * tcp); +static int _tcp_callback_connect(int fd, TCP * tcp); +static int _tcp_callback_read(int fd, TCP * tcp); /* public */ @@ -68,8 +76,10 @@ AppTransportPluginDefinition definition = /* functions */ /* plug-in */ /* tcp_init */ +static int _init_address(char const * name, struct sockaddr_in * sa); static int _init_client(TCP * tcp, char const * name); static int _init_server(TCP * tcp, char const * name); +static int _init_socket(TCP * tcp); static TCP * _tcp_init(AppTransportPluginHelper * helper, AppTransportMode mode, char const * name) @@ -99,33 +109,87 @@ static TCP * _tcp_init(AppTransportPluginHelper * helper, return tcp; } +static int _init_address(char const * name, struct sockaddr_in * sa) +{ + long l; + char const * p; + char * q; + + /* obtain the port number */ + if((p = strrchr(name, ':')) == NULL) + return -error_set_code(1, "%s", strerror(EINVAL)); + l = strtol(++p, &q, 10); + if(p[0] == '\0' || *q != '\0' || l < 0 || l > 65535) + return -error_set_code(1, "%s", strerror(EINVAL)); + sa->sin_family = AF_INET; + sa->sin_port = htons(l); + /* FIXME hard-coded */ + sa->sin_addr.s_addr = htons(INADDR_LOOPBACK); + return 0; +} + static int _init_client(TCP * tcp, char const * name) { - if((tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return -_tcp_error("socket", 1); - /* FIXME really implement */ - return -1; + struct sockaddr_in sa; + + /* obtain the remote address */ + if(_init_address(name, &sa) != 0) + return -1; + /* create the socket */ + if(_init_socket(tcp) != 0) + return -1; + /* connect to the remote host */ + if(connect(tcp->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) + { + if(errno != EINPROGRESS) + return -_tcp_error("socket", 1); + else + event_register_io_write(tcp->helper->event, tcp->fd, + (EventIOFunc)_tcp_callback_connect, + tcp); + } + else + event_register_io_read(tcp->helper->event, tcp->fd, + (EventIOFunc)_tcp_callback_read, tcp); + return 0; } static int _init_server(TCP * tcp, char const * name) { struct sockaddr_in sa; - if((tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return -_tcp_error("socket", 1); - sa.sin_family = AF_INET; - sa.sin_port = htons(4241); /* XXX hard-coded */ - sa.sin_addr.s_addr = htonl(INADDR_ANY); + /* obtain the local address */ + if(_init_address(name, &sa) != 0) + return -1; + /* create the socket */ + if(_init_socket(tcp) != 0) + return -1; + /* accept incoming connections */ if(bind(tcp->fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) return -_tcp_error("bind", 1); if(listen(tcp->fd, 5) != 0) return -_tcp_error("listen", 1); event_register_io_read(tcp->helper->event, tcp->fd, - _tcp_callback_accept, tcp); + (EventIOFunc)_tcp_callback_accept, tcp); /* FIXME implement */ return -1; } +static int _init_socket(TCP * tcp) +{ + int flags; + + if((tcp->fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return -_tcp_error("socket", 1); + /* set the socket as non-blocking */ + if((flags = fcntl(tcp->fd, F_GETFL)) == -1) + return -_tcp_error("fcntl", 1); + if((flags & O_NONBLOCK) == 0) + if(fcntl(tcp->fd, F_SETFL, flags | O_NONBLOCK) == -1) + return -_tcp_error("fcntl", 1); + return 0; +} + /* tcp_destroy */ static void _tcp_destroy(TCP * tcp) @@ -154,9 +218,62 @@ static int _tcp_callback_accept(int fd, TCP * tcp) socklen_t sa_size = sizeof(sa); int newfd; + /* check parameters */ + if(tcp->fd != fd) + return -1; if((newfd = accept(fd, (struct sockaddr *)&sa, &sa_size)) < 0) return _tcp_error("accept", 1); /* FIXME really implement */ close(newfd); return 0; } + + +/* tcp_callback_connect */ +static int _tcp_callback_connect(int fd, TCP * tcp) +{ + int res; + socklen_t s = sizeof(res); + + /* check parameters */ + if(tcp->fd != fd) + return -1; + if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &s) != 0) + { + close(fd); + tcp->fd = -1; + /* FIXME report error */ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(errno)); +#endif + return -1; + } + if(res != 0) + { + close(fd); + tcp->fd = -1; + /* FIXME report error */ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(errno)); +#endif + return -1; + } + /* listen for any incoming message */ + event_register_io_read(tcp->helper->event, tcp->fd, + (EventIOFunc)_tcp_callback_read, tcp); + /* XXX check the return value (stop polling on writes) */ + return 1; +} + + +/* tcp_callback_read */ +static int _tcp_callback_read(int fd, TCP * tcp) +{ + /* check parameters */ + if(tcp->fd != fd) + return -1; + /* FIXME really implement */ + close(fd); + tcp->fd = -1; + return -1; +}