1 /* net.c --
2  * Created: Fri Feb 21 20:58:10 1997 by faith@dict.org
3  * Copyright 1997, 1998, 1999, 2000, 2002 Rickard E. Faith (faith@dict.org)
4  * Copyright 2002-2008 Aleksey Cheusov (vle@gmx.net)
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 1, or (at your option) any
9  * later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 #include "dictP.h"
22 
23 #include <sys/ioctl.h>
24 #include <sys/stat.h>
25 #include <sys/socket.h>
26 #include <sys/param.h>
27 #include <fcntl.h>
28 
29 #include "dictd.h"
30 
31 #ifndef MAXHOSTNAMELEN
32 #define MAXHOSTNAMELEN 64
33 #endif
34 
35 #ifndef INADDR_NONE
36 #define INADDR_NONE (-1)
37 #endif
38 
inet_ntopW(struct sockaddr * sa)39 const char *inet_ntopW (struct sockaddr *sa) {
40    static char buf[40];
41 
42    switch (sa->sa_family) {
43    case AF_INET:
44       return inet_ntop (sa->sa_family, &(((struct sockaddr_in *)sa)->sin_addr), buf, sizeof(buf));
45    case AF_INET6:
46       return inet_ntop (sa->sa_family, &(((struct sockaddr_in6 *)sa)->sin6_addr), buf, sizeof(buf));
47    default:
48       errno = EAFNOSUPPORT;
49       return NULL;
50    }
51 }
52 
net_hostname(void)53 const char *net_hostname( void )
54 {
55    static char hostname[128] = "";
56    int err;
57 
58    if (!hostname[0]) {
59       if (err = gethostname(hostname, sizeof(hostname)), err != 0) {
60 	 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err));
61 	 exit(EXIT_FAILURE);
62       }
63    }
64 
65    hostname[sizeof(hostname)-1] = '\0';
66    return hostname;
67 }
68 
net_connect_tcp(const char * host,const char * service,int address_family)69 int net_connect_tcp( const char *host, const char *service, int address_family )
70 {
71    struct addrinfo *r = NULL;
72    struct addrinfo *rtmp = NULL;
73    struct addrinfo hints;
74    int s;
75 
76    memset (&hints, 0, sizeof (struct addrinfo));
77    hints.ai_family = address_family;
78    hints.ai_protocol = IPPROTO_TCP;
79    hints.ai_socktype = SOCK_STREAM;
80    hints.ai_flags = AI_ADDRCONFIG;
81 
82    if (getaddrinfo (host, service, &hints, &r) != 0) {
83       return NET_NOHOST;
84    }
85 
86    for (rtmp = r; r != NULL; r = r->ai_next) {
87       s = socket (r->ai_family, r->ai_socktype, r->ai_protocol);
88       if (s < 0) {
89 	 if (r->ai_next != NULL)
90 	    continue;
91 
92 	 err_fatal_errno( __FUNCTION__, "Can't open socket\n");
93       }
94 
95       PRINTF(DBG_VERBOSE,("Trying %s (%s)...", host, inet_ntopW(r->ai_addr)));
96 
97       if (connect (s, r->ai_addr, r->ai_addrlen) >= 0) {
98 	 PRINTF(DBG_VERBOSE,("Connected."));
99 	 freeaddrinfo (rtmp);
100 	 return s;
101       }
102 
103       PRINTF(DBG_VERBOSE,("Failed: %s\n", strerror (errno)));
104 
105       close (s);
106    }
107    freeaddrinfo (rtmp);
108 
109    return NET_NOCONNECT;
110 }
111 
net_open_tcp(const char * address,const char * service,int queueLength,int address_family)112 int net_open_tcp (
113    const char *address,
114    const char *service,
115    int queueLength,
116    int address_family)
117 {
118    struct addrinfo hints, *r, *rtmp;
119    int s = -1;
120    int err;
121 
122    memset (&hints, 0, sizeof (struct addrinfo));
123    hints.ai_family = address_family;
124    hints.ai_protocol = IPPROTO_TCP;
125    hints.ai_socktype = SOCK_STREAM;
126    hints.ai_flags = AI_PASSIVE;
127 
128    if (getaddrinfo (address, service, &hints, &r) != 0)
129       err_fatal ( __FUNCTION__, "getaddrinfo: Failed, address = \"%s\", service = \"%s\"\n", address, service);
130 
131    for (rtmp = r; r != NULL; r = r->ai_next) {
132       s = socket (r->ai_family, r->ai_socktype, r->ai_protocol);
133 
134       if (s < 0) {
135 	 if (r->ai_next != NULL)
136 	    continue;
137 
138 	 freeaddrinfo (rtmp);
139 	 err_fatal_errno (__FUNCTION__, "Can't open socket\n");
140       }
141 
142       {
143 	 const int one = 1;
144 	 err = setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one));
145 	 if (err != 0){
146 	    err_fatal_errno (__FUNCTION__, "Can't setsockopt\n");
147 	 }
148       }
149 
150       if (bind(s, r->ai_addr, r->ai_addrlen) < 0) {
151 	 if (r->ai_next != NULL) {
152 	    close (s);
153 	    continue;
154 	 }
155 	 freeaddrinfo (rtmp);
156 	 err_fatal_errno( __FUNCTION__, "Can't bind %s/tcp to %s\n",
157 			  service, address?address:"ANY" );
158       }
159 
160       if (listen( s, queueLength ) < 0) {
161 	 if (r->ai_next != NULL) {
162 	    close (s);
163 	    continue;
164 	 }
165 	 freeaddrinfo (rtmp);
166 	 err_fatal_errno( __FUNCTION__, "Can't listen to %s/tcp on %s\n",
167 			  service, address );
168       }
169 
170       break;
171    }
172    freeaddrinfo (rtmp);
173 
174    return s;
175 }
176 
net_read(int s,char * buf,int maxlen)177 int net_read( int s, char *buf, int maxlen )
178 {
179    int  len;
180    int  n = 0;
181    char c;
182    char *pt = buf;
183 
184    *pt = '\0';
185 
186    for (len = 0; len < maxlen && (n = read( s, &c, 1 )) > 0; /*void*/) {
187       switch (c) {
188       case '\n': *pt = '\0';       return len;
189       case '\r':                   break;
190       default:   *pt++ = c; ++len; break;
191       }
192    }
193    *pt = '\0';
194    if (!n) return len ? len : EOF;
195    return n;			/* error code */
196 }
197 
net_write(int s,const char * buf,int len)198 int net_write( int s, const char *buf, int len )
199 {
200    int left = len;
201    int count;
202 
203    while (left) {
204       if ((count = write(s, buf, left)) != left) {
205 	 if (count <= 0) return count; /* error code */
206       }
207       left -= count;
208    }
209    return len;
210 }
211