/*
* Copyright (c) 1990-1996
* Joe Greco. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Joe Greco.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOE GRECO AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL JOE GRECO OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include "defs.h"
Prototype int make_tcp_sockaddr(struct sockaddr_in *addr, char *ascii);
Prototype int connect_tcp_socket(char *address, int opt, int port);
Prototype int connect_tcp_socket_by_sockaddr(struct sockaddr_in *address, int opt, int port);
#define DIE(x) if (errno != EWOULDBLOCK) {perror(x);} return(-1);
#define BACKLOG 32 /* Maximum pending incoming TCP connections allowed */
#define LIN_DEL 3 /* Seconds to wait for pending data to flush on close */
#define X11_DSP 6000 /* Base X11 display port number */
#define bcopy(x, y, z) memcpy((y), (x), (z))
#ifdef ULTRIX
static char *
strdup(char *x)
{
char *rval;
if (! (rval = malloc(strlen(x) + 1))) {
return(NULL);
}
bcopy(x, rval, strlen(x) + 1);
return(rval);
}
#endif
#if 0
int create_named_socket(pathname, opt)
char *pathname;
int opt;
{
int s, i, j;
struct sockaddr_un sun;
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
DIE("create_named_socket: socket");
}
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, pathname);
i = 1;
j = sizeof(i);
if (opt & OPT_REUSEADDR && setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, j) < 0) {
close(s);
DIE("create_named_socket: setsockopt");
}
if (bind(s, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
close(s);
DIE("create_named_socket: bind");
}
if (listen(s, BACKLOG) < 0) {
close(s);
DIE("create_named_socket: listen");
}
if (opt & OPT_NONBLOCK && fcntl(s, F_SETFL, O_NDELAY) < 0) {
close(s);
DIE("create_named_socket: fcntl ndelay");
}
if (opt & OPT_VERBOSE) {
printf("accepting connections on named socket %s\n", pathname);
}
return(s);
}
#endif
int
create_tcp_listen_socket(int port, int opt, char *bindaddr)
{
int s, i, j;
struct sockaddr_in sin;
struct linger lin;
(void)memset((char *)&sin, 0, sizeof(sin));
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
if (bindaddr) {
sin.sin_addr.s_addr = inet_addr(bindaddr);
} else {
sin.sin_addr.s_addr = htonl(INADDR_ANY);
}
lin.l_onoff = 1;
lin.l_linger = LIN_DEL;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
DIE("create_tcp_listen_socket: socket");
}
i = 1;
j = sizeof(i);
if (opt & OPT_REUSEADDR && setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, j) < 0) {
close(s);
DIE("create_tcp_listen_socket: setsockopt");
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
DIE("create_tcp_listen_socket: bind");
}
if (listen(s, BACKLOG) < 0) {
close(s);
DIE("create_tcp_listen_socket: listen");
}
if (opt & OPT_NONBLOCK && fcntl(s, F_SETFL, O_NDELAY) < 0) {
close(s);
DIE("create_tcp_listen_socket: fcntl ndelay");
}
if (opt & OPT_VERBOSE) {
printf("accepting connections on port %d\n", port);
}
return(s);
}
int
accept_tcp_connection(int s, int opt)
{
int ns;
struct sockaddr_in sin;
struct linger lin;
int addrlen = sizeof(sin);
struct hostent *host;
char *hostname;
int ka, kalen = sizeof(ka);
if ((ns = accept(s, (struct sockaddr *)&sin, &addrlen)) < 0) {
DIE("accept_tcp_connection: accept");
}
if (opt & OPT_LINGER && setsockopt(ns, SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin)) < 0) {
close(ns);
DIE("accept_tcp_connection: setsockopt linger");
}
ka = 1;
if (opt & OPT_KEEPALIVE && setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, kalen) < 0) {
close(ns);
DIE("accept_tcp_connection: setsockopt keepalive");
}
if (opt & OPT_NONBLOCK && fcntl(ns, F_SETFL, O_NDELAY) < 0) {
close(ns);
DIE("accept_tcp_connection: fcntl ndelay");
}
if (opt & OPT_VERBOSE) {
if (! (host = gethostbyaddr((char *)&sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr), AF_INET))) {
hostname = inet_ntoa(sin.sin_addr);
} else {
hostname = host->h_name;
}
printf("accepted tcp connection: fd %2d from %s.%d\n", ns, hostname, ntohs(sin.sin_port));
}
return(ns);
}
/*
* int make_tcp_sockaddr(struct sockaddr_in *addr, char *ascii)
*
* Given an ASCII string, make an intelligent guess as to what the
* user wants. It's assumed we want an X11 socket, but others may be
* specified. We ambitiously try to deal with:
*
* dom.ain (assumed to be port 6000)
* a.b.c.d ( " " " " )
* dom.ain.6000
* a.b.c.d.6000
* dom.ain:0
* a.b.c.d:0
*/
int
make_tcp_sockaddr(struct sockaddr_in *addr, char *ascii)
{
struct hostent *host;
int dots = 0;
int numeric = 0;
char *str = strdup(ascii);
char *colon = strrchr(str, ':');
char *lastdot = strrchr(str, '.');
char *ptr;
if (! str) {
DIE("make_tcp_sockaddr: malloc");
}
addr->sin_port = htons(X11_DSP);
addr->sin_family = AF_INET;
/* Count the number of dots in the address. */
for (ptr = str; *ptr; ptr++) {
if (*ptr == '.') {
dots++;
}
}
/* Check if it seems to be numeric. */
numeric = isdigit((int)*str);
/* If numeric and four dots, we have a.b.c.d.6000 */
if (numeric && dots == 4) {
*lastdot = '\0';
addr->sin_port = htons(atoi(lastdot + 1));
}
/* If nonnumeric and no colon, check if the last part is a port */
if (! numeric && ! colon && lastdot && isdigit((int)*(lastdot + 1))) {
*lastdot = '\0';
addr->sin_port = htons(atoi(lastdot + 1));
}
/* We might have a :0 display. */
if (colon) {
*colon = '\0';
addr->sin_port = htons(atoi(colon + 1) + X11_DSP);
}
/* Now do we have a numeric address */
if (numeric) {
addr->sin_addr.s_addr = inet_addr(str);
free(str);
return(0);
}
/* Or a name */
if (! (host = gethostbyname(str))) {
free(str);
DIE("make_tcp_sockaddr: gethostbyname");
}
bcopy(host->h_addr_list[0], (char *)&addr->sin_addr.s_addr, sizeof(addr->sin_addr.s_addr));
free(str);
return(0);
}
int
connect_tcp_socket(char *address, int opt, int port)
{
int s, i, j;
struct sockaddr_in sin;
struct linger lin;
int ka, kalen = sizeof(ka);
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
lin.l_onoff = 1;
lin.l_linger = LIN_DEL;
if (opt & OPT_VERBOSE) {
printf("opening a connection to %s...", address);
}
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
DIE("connect_tcp_socket: socket");
}
i = 1;
j = sizeof(i);
if (opt & OPT_REUSEADDR && setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, j) < 0) {
close(s);
DIE("connect_tcp_socket: setsockopt");
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
DIE("connect_tcp_socket: bind");
}
if (make_tcp_sockaddr(&sin, address) < 0) {
close(s);
return(-1);
}
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
DIE("connect_tcp_socket: connect");
}
if (opt & OPT_LINGER && setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin)) < 0) {
close(s);
DIE("connect_tcp_socket: setsockopt linger");
}
ka = 1;
if (opt & OPT_KEEPALIVE && setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, kalen) < 0) {
close(s);
DIE("accept_tcp_connection: setsockopt keepalive");
}
if (opt & OPT_NONBLOCK && fcntl(s, F_SETFL, O_NDELAY) < 0) {
close(s);
DIE("connect_tcp_socket: fcntl ndelay");
}
if (opt & OPT_VERBOSE) {
printf(" connected\n");
}
return(s);
}
int
connect_tcp_socket_by_sockaddr(struct sockaddr_in *address, int opt, int port)
{
int s, i, j;
struct sockaddr_in sin;
struct linger lin;
int ka, kalen = sizeof(ka);
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
lin.l_onoff = 1;
lin.l_linger = LIN_DEL;
if (opt & OPT_VERBOSE) {
printf("opening a connection to %s...", inet_ntoa(address->sin_addr));
}
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
DIE("connect_tcp_socket_by_sockaddr: socket");
}
i = 1;
j = sizeof(i);
if (opt & OPT_REUSEADDR && setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, j) < 0) {
close(s);
DIE("create_tcp_socket_by_sockaddr: setsockopt");
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
close(s);
DIE("connect_tcp_socket_by_sockaddr: bind");
}
if (connect(s, (struct sockaddr *)address, sizeof(*address)) < 0) {
close(s);
DIE("connect_tcp_socket_by_sockaddr: bind");
}
if (opt & OPT_LINGER && setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&lin, sizeof(lin)) < 0) {
close(s);
DIE("connect_tcp_socket_by_sockaddr: setsockopt linger");
}
ka = 1;
if (opt & OPT_KEEPALIVE && setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&ka, kalen) < 0) {
close(s);
DIE("accept_tcp_connection: setsockopt keepalive");
}
if (opt & OPT_NONBLOCK && fcntl(s, F_SETFL, O_NDELAY) < 0) {
close(s);
DIE("connect_tcp_socket_by_sockaddr: fcntl ndelay");
}
if (opt & OPT_VERBOSE) {
printf(" connected\n");
}
return(s);
}
syntax highlighted by Code2HTML, v. 0.9.1