import amtterm-1.0
[amt] / tcp.c
1 /*
2 * TCP helper functions.
3 *
4 * Copyright (C) 2007 Gerd Hoffmann <kraxel@redhat.com
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27
28 #include "tcp.h"
29
30 int tcp_verbose;
31
32 /* ------------------------------------------------------------------ */
33
34 static char *strfamily(int family)
35 {
36 switch (family) {
37 case PF_INET6: return "ipv6";
38 case PF_INET: return "ipv4";
39 case PF_UNIX: return "unix";
40 }
41 return "????";
42 }
43
44 int tcp_connect(struct addrinfo *ai,
45 char *addr, char *port,
46 char *host, char *serv)
47 {
48 struct addrinfo *res,*e;
49 struct addrinfo *lres, ask;
50 char uaddr[INET6_ADDRSTRLEN+1];
51 char uport[33];
52 char uhost[INET6_ADDRSTRLEN+1];
53 char userv[33];
54 int sock,rc,opt=1;
55
56 /* lookup peer */
57 ai->ai_flags = AI_CANONNAME;
58 if (0 != (rc = getaddrinfo(host, serv, ai, &res))) {
59 if (tcp_verbose)
60 fprintf(stderr,"getaddrinfo (peer): %s\n", gai_strerror(rc));
61 return -1;
62 }
63 for (e = res; e != NULL; e = e->ai_next) {
64 if (0 != getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
65 uhost,INET6_ADDRSTRLEN,userv,32,
66 NI_NUMERICHOST | NI_NUMERICSERV)) {
67 if (tcp_verbose)
68 fprintf(stderr,"getnameinfo (peer): oops\n");
69 continue;
70 }
71 if (-1 == (sock = socket(e->ai_family, e->ai_socktype,
72 e->ai_protocol))) {
73 if (tcp_verbose)
74 fprintf(stderr,"socket (%s): %s\n",
75 strfamily(e->ai_family),strerror(errno));
76 continue;
77 }
78 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
79 if (NULL != addr || NULL != port) {
80 /* bind local port */
81 memset(&ask,0,sizeof(ask));
82 ask.ai_flags = AI_PASSIVE;
83 ask.ai_family = e->ai_family;
84 ask.ai_socktype = e->ai_socktype;
85 if (0 != (rc = getaddrinfo(addr, port, &ask, &lres))) {
86 if (tcp_verbose)
87 fprintf(stderr,"getaddrinfo (local): %s\n",
88 gai_strerror(rc));
89 continue;
90 }
91 if (0 != getnameinfo((struct sockaddr*)lres->ai_addr,
92 lres->ai_addrlen,
93 uaddr,INET6_ADDRSTRLEN,uport,32,
94 NI_NUMERICHOST | NI_NUMERICSERV)) {
95 if (tcp_verbose)
96 fprintf(stderr,"getnameinfo (local): oops\n");
97 continue;
98 }
99 if (-1 == bind(sock, lres->ai_addr, lres->ai_addrlen)) {
100 if (tcp_verbose)
101 fprintf(stderr,"%s [%s] %s bind: %s\n",
102 strfamily(lres->ai_family),uaddr,uport,
103 strerror(errno));
104 continue;
105 }
106 }
107 /* connect to peer */
108 if (-1 == connect(sock,e->ai_addr,e->ai_addrlen)) {
109 if (tcp_verbose)
110 fprintf(stderr,"%s %s [%s] %s connect: %s\n",
111 strfamily(e->ai_family),e->ai_canonname,uhost,userv,
112 strerror(errno));
113 close(sock);
114 continue;
115 }
116 if (tcp_verbose)
117 fprintf(stderr,"%s %s [%s] %s open\n",
118 strfamily(e->ai_family),e->ai_canonname,uhost,userv);
119 fcntl(sock,F_SETFL,O_NONBLOCK);
120 return sock;
121 }
122 return -1;
123 }
124
125 int tcp_listen(struct addrinfo *ai, char *addr, char *port)
126 {
127 struct addrinfo *res,*e;
128 char uaddr[INET6_ADDRSTRLEN+1];
129 char uport[33];
130 int slisten,rc,opt=1;
131
132 /* lookup */
133 ai->ai_flags = AI_PASSIVE;
134 if (0 != (rc = getaddrinfo(addr, port, ai, &res))) {
135 if (tcp_verbose)
136 fprintf(stderr,"getaddrinfo: %s\n",gai_strerror(rc));
137 exit(1);
138 }
139
140 /* create socket + bind */
141 for (e = res; e != NULL; e = e->ai_next) {
142 getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
143 uaddr,INET6_ADDRSTRLEN,uport,32,
144 NI_NUMERICHOST | NI_NUMERICSERV);
145 if (-1 == (slisten = socket(e->ai_family, e->ai_socktype,
146 e->ai_protocol))) {
147 if (tcp_verbose)
148 fprintf(stderr,"socket (%s): %s\n",
149 strfamily(e->ai_family),strerror(errno));
150 continue;
151 }
152 opt = 1;
153 setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
154 if (-1 == bind(slisten, e->ai_addr, e->ai_addrlen)) {
155 if (tcp_verbose)
156 fprintf(stderr,"%s [%s] %s bind: %s\n",
157 strfamily(e->ai_family),uaddr,uport,
158 strerror(errno));
159 continue;
160 }
161 listen(slisten,1);
162 break;
163 }
164 if (NULL == e)
165 return -1;
166
167 /* wait for a incoming connection */
168 if (tcp_verbose)
169 fprintf(stderr,"listen on %s [%s] %s ...\n",
170 strfamily(e->ai_family),uaddr,uport);
171 fcntl(slisten,F_SETFL,O_NONBLOCK);
172 return slisten;
173 }
Impressum, Datenschutz