File: socket.c

package info (click to toggle)
mgetty 1.2.1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,872 kB
  • sloc: ansic: 42,728; sh: 6,487; perl: 6,262; makefile: 1,457; tcl: 756; lisp: 283
file content (151 lines) | stat: -rw-r--r-- 4,332 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#ident "$Id: socket.c,v 4.2 2014/01/28 13:44:14 gert Exp $"

/* socket.c - part of mgetty+sendfax
 *
 * open TCP/IP sockets to talk to remote fax modems (sendfax)
 *
 * $Log: socket.c,v $
 * Revision 4.2  2014/01/28 13:44:14  gert
 * log_init_path() with infix => last 4 digits of "remote tty" (R104, etc.)
 *
 * set SIGPIPE to SIG_IGN - if the remote end of the socket is closed
 * unexpectedly, write() might return an error, or raise SIGPIPE -> code
 * handles errors, so ignore SIGPIPE.
 *
 * Revision 4.1  2014/01/28 13:15:50  gert
 * Basic "open TCP/IP socket to remote machine" implementation
 * (name of remote + tcp portnumber are magick'ed out of ttyRI<n><mm>)
 *
 */

#include "policy.h"
#ifdef FAX_SEND_SOCKETS

#include <stdio.h>
#include "syslibs.h"
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <netdb.h>
#include <netinet/in.h>

#include "mgetty.h"

extern boolean verbose;		/* sendfax.c */
extern char * Device;		/* sendfax.c */

/* sendfax' logic for "what is a remote tty" is currently hardwired
 * (to be able to actually get something in place, without rewriting 
 * most of the config file infrastructure) - if the tty name matches
 * "ttyRInmm", it will be treated as "connect to 'modemserver<n>' on
 * port 50000+<mm>, raw socket, no modem control / telnet escapes"
 *
 * This might get enhanced later on with modem control (RFC 2217) or 
 * configfile-settable ports.  For now, we start with *this*.
 *
 * return value: -1 -> fail, >= 0 -> socket FD
 */

int connect_to_remote_tty _P1( (fax_tty), char * fax_tty )
{
    int line, r;
    int sock = -1;
    char hostname[20];
    char servname[10];
    struct addrinfo hints;
    struct addrinfo * res0, *res;

    /* ttyRI<n> */
    if ( !isdigit( (int) fax_tty[5] ) )
    {
	lprintf( L_ERROR, "invalid tty format: '%s' - 6th char must be 0..9", fax_tty );
	return -1;
    }
    sprintf( hostname, "modemserver%c", fax_tty[5] );

    line = atoi( &fax_tty[6] );
    if ( line < 1 || line > 999 )
    {
	lprintf( L_ERROR, "invalid tty format: '%s' - port number must be 01..999", fax_tty );
	return -1;
    }
    sprintf( servname, "%d", line + 50000 );

    lprintf( L_MESG, "trying '%s' on port %s...", hostname, servname );
    if (verbose) putchar( '\n' );

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_NUMERICSERV;
    r = getaddrinfo( hostname, servname, &hints, &res0 );

    if ( r != 0 )
    {
	errno = 0;
	lprintf( L_ERROR, "getaddrinfo(%s) failed: %s", hostname, gai_strerror(r));
	return -1;
    }

    /* connect loop from "man getaddrinfo"... */
    for ( res = res0; res != NULL; res = res->ai_next )
    {
	char nbuf[NI_MAXHOST];
	r = getnameinfo( res->ai_addr, res->ai_addrlen, nbuf, sizeof(nbuf)-1, 
		         NULL, 0, NI_NUMERICHOST );
	if ( r != 0 )
	    { lprintf( L_ERROR, "error in getnameinfo (canthappen!)" ); continue; }

        if ( verbose ) 
	    { printf( "  connecting to %s... ", nbuf ); fflush(stdout); }

	sock = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
	if ( sock < 0 )
		{ lprintf( L_ERROR, "error in socket()" ); continue; }

	if ( connect( sock, res->ai_addr, res->ai_addrlen ) < 0 )
	{
	    int save_errno = errno;
	    lprintf( L_ERROR, "error in connect(%s:%s)", nbuf, servname );
	    if ( verbose )
		printf( "connect failed: %s\n", strerror(save_errno) );
	    close(sock);
	    sock = -1;
	    continue;
	}

	if ( verbose ) printf( "OK\n" );
	lprintf( L_MESG, "connection to '%s':'%s' succeeded, sock=%d",
			nbuf, servname, sock );
	break;
    }

    freeaddrinfo(res0);

    if ( sock >= 0 )		/* success? */
    {
	/* make device name externally visible (faxrec())
	 */
	Device = safe_strdup( fax_tty );

	log_init_paths( NULL, NULL, &fax_tty[ strlen(fax_tty)-4 ] );

	/* The rest of the code assumes that a tty fd might return an 
         * error write()ing to it, but not that it might go away completely 
         * and give us an SIGPIPE.  Ignore.  Sue me.
         */
	signal( SIGPIPE, SIG_IGN );
    }

    /* sock is either a connected socket now, or "-1" -> pass up */
    return sock;
}


#endif	/* FAX_SEND_SOCKETS */