blob: 12d21e9138005306539dd669591e713e7608810c [file] [log] [blame]
/*
tcp.c - tcp handling for lrzsz
Copyright (C) 1997 Uwe Ohse
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
originally written by Uwe Ohse
*/
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#include <errno.h>
#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include "zglobal.h"
#include <stdlib.h>
#include "error.h"
static RETSIGTYPE
tcp_alarm_handler(int dummy)
{
dummy++; /* doesn't need to do anything */
}
typedef union {
struct sockaddr sa;
struct sockaddr_in in;
} sock_addr;
/* server/lsz:
* Get a TCP socket, bind it, listen, figure out the port,
* and build the magic string for lrz in "buf".
*/
int
tcp_server (char *buf)
{
int sock;
sock_addr s;
sock_addr t;
int on=1;
socklen_t len;
if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
error(1,errno,"socket");
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) {
error(1,errno,"setsockopt (reuse address)");
}
memset (&s, 0, sizeof (s));
s.in.sin_family = AF_INET;
s.in.sin_port=0; /* let system fill it in */
s.in.sin_addr.s_addr=htonl(INADDR_ANY);
if (bind(sock, &s.sa, sizeof (s)) < 0) {
error(1,errno,"bind");
}
len=sizeof(t);
if (getsockname (sock, &t.sa, &len)) {
error(1,errno,"getsockname");
}
sprintf(buf,"[%s] <%d>\n",inet_ntoa(t.in.sin_addr),ntohs(t.in.sin_port));
if (listen(sock, 1) < 0) {
error(1,errno,"listen");
}
getsockname (sock, &t.sa, &len);
return (sock);
}
/* server/lsz: accept a connection */
int
tcp_accept (int d)
{
int so;
sock_addr s;
socklen_t namelen;
int num=0;
namelen = sizeof(s);
memset((char*)&s,0, namelen);
retry:
signal(SIGALRM, tcp_alarm_handler);
alarm(30);
if ((so = accept(d, &s.sa, &namelen)) < 0) {
if (errno == EINTR) {
if (++num<=5)
goto retry;
}
error(1,errno,"accept");
}
alarm(0);
return so;
}
/* client/lrz:
* "Connect" to the TCP socket decribed in "buf" and
* return the connected socket.
*/
int
tcp_connect (char *buf)
{
int sock;
sock_addr s_in;
char *p;
char *q;
memset(&s_in,0,sizeof(s_in));
s_in.in.sin_family = AF_INET;
/* i _really_ distrust scanf & co. Or maybe i distrust bad input */
if (*buf!='[') {
error(1,0,_("tcp_connect: illegal format1\n"));
}
p=strchr(buf+1,']');
if (!p) {
error(1,0,_("tcp_connect: illegal format2\n"));
}
*p++=0;
s_in.in.sin_addr.s_addr=inet_addr(buf+1);
#ifndef INADDR_NONE
#define INADDR_NONE (-1)
#endif
if (s_in.in.sin_addr.s_addr== (unsigned long) INADDR_NONE) {
struct hostent *h=gethostbyname(buf+1);
if (!h)
error(1,0,_("tcp_connect: illegal format3\n"));
memcpy(& s_in.in.sin_addr.s_addr,h->h_addr,h->h_length);
}
while (isspace((unsigned char)(*p)))
p++;
if (*p!='<') {
error(1,0,_("tcp_connect: illegal format4\n"));
}
q=strchr(p+1,'>');
if (!q)
error(1,0,_("tcp_connect: illegal format5\n"));
s_in.in.sin_port = htons(strtol(p+1,NULL,10));
if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
error(1,errno,"socket");
}
signal(SIGALRM, tcp_alarm_handler);
alarm(30);
if (connect (sock, &s_in.sa, sizeof (s_in)) < 0) {
error(1,errno,"connect");
}
alarm(0);
return (sock);
}