1 /* source: xio-ipapp.c */
2 /* Copyright Gerhard Rieger 2001-2008 */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for TCP and UDP related options */
7 #include "xiosysincludes.h"
9 #if WITH_TCP || WITH_UDP
12 #include "xio-socket.h"
14 #include "xio-listen.h"
16 #include "xio-ipapp.h"
18 const struct optdesc opt_sourceport
= { "sourceport", "sp", OPT_SOURCEPORT
, GROUP_IPAPP
, PH_LATE
,TYPE_2BYTE
, OFUNC_SPEC
};
19 /*const struct optdesc opt_port = { "port", NULL, OPT_PORT, GROUP_IPAPP, PH_BIND, TYPE_USHORT, OFUNC_SPEC };*/
20 const struct optdesc opt_lowport
= { "lowport", NULL
, OPT_LOWPORT
, GROUP_IPAPP
, PH_LATE
, TYPE_BOOL
, OFUNC_SPEC
};
23 /* we expect the form "host:port" */
24 int xioopen_ipapp_connect(int argc
, const char *argv
[], struct opt
*opts
,
25 int xioflags
, xiofile_t
*xxfd
,
26 unsigned groups
, int socktype
, int ipproto
,
28 struct single
*xfd
= &xxfd
->stream
;
29 struct opt
*opts0
= NULL
;
30 const char *hostname
= argv
[1], *portname
= argv
[2];
32 union sockaddr_union us_sa
, *us
= &us_sa
;
33 union sockaddr_union them_sa
, *them
= &them_sa
;
34 socklen_t uslen
= sizeof(us_sa
);
35 socklen_t themlen
= sizeof(them_sa
);
36 bool needbind
= false;
42 Error2("%s: wrong number of parameters (%d instead of 2)", argv
[0], argc
-1);
45 xfd
->howtoend
= END_SHUTDOWN
;
47 if (applyopts_single(xfd
, opts
, PH_INIT
) < 0) return -1;
48 applyopts(-1, opts
, PH_INIT
);
50 retropt_bool(opts
, OPT_FORK
, &dofork
);
52 if (_xioopen_ipapp_prepare(opts
, &opts0
, hostname
, portname
, &pf
, ipproto
,
53 xfd
->para
.socket
.ip
.res_opts
[1],
54 xfd
->para
.socket
.ip
.res_opts
[0],
55 them
, &themlen
, us
, &uslen
, &needbind
, &lowport
,
56 socktype
) != STAT_OK
) {
61 xiosetchilddied(); /* set SIGCHLD handler */
64 if (xioopts
.logopt
== 'm') {
65 Info("starting connect loop, switching to syslog");
66 diag_set('y', xioopts
.syslogfac
); xioopts
.logopt
= 'y';
68 Info("starting connect loop");
71 do { /* loop over retries and forks */
74 if (xfd
->forever
|| xfd
->retry
) {
77 #endif /* WITH_RETRY */
82 needbind
?(struct sockaddr
*)us
:NULL
, uslen
,
83 (struct sockaddr
*)them
, themlen
,
84 opts
, pf
, socktype
, ipproto
, lowport
, level
);
90 if (xfd
->forever
|| xfd
->retry
) {
92 if (result
== STAT_RETRYLATER
) {
93 Nanosleep(&xfd
->intervall
, NULL
);
95 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
99 #endif /* WITH_RETRY */
108 if (xfd
->forever
|| xfd
->retry
) {
109 level
= E_WARN
; /* most users won't expect a problem here,
110 so Notice is too weak */
112 while ((pid
= xio_fork(false, level
)) < 0) {
113 if (xfd
->forever
|| --xfd
->retry
) {
114 Nanosleep(&xfd
->intervall
, NULL
); continue;
116 return STAT_RETRYLATER
;
119 if (pid
== 0) { /* child process */
120 xfd
->forever
= false; xfd
->retry
= 0;
126 /* with and without retry */
127 Nanosleep(&xfd
->intervall
, NULL
);
128 dropopts(opts
, PH_ALL
); opts
= copyopts(opts0
, GROUP_ALL
);
129 continue; /* with next socket() bind() connect() */
131 #endif /* WITH_RETRY */
136 /* only "active" process breaks (master without fork, or child) */
138 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
145 /* returns STAT_OK on success or some other value on failure
146 applies and consumes the following options:
148 OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
151 _xioopen_ipapp_prepare(struct opt
*opts
, struct opt
**opts0
,
152 const char *hostname
,
153 const char *portname
,
156 unsigned long res_opts0
, unsigned long res_opts1
,
157 union sockaddr_union
*them
, socklen_t
*themlen
,
158 union sockaddr_union
*us
, socklen_t
*uslen
,
159 bool *needbind
, bool *lowport
,
165 retropt_socket_pf(opts
, pf
);
168 xiogetaddrinfo(hostname
, portname
,
169 *pf
, socktype
, protocol
,
170 (union sockaddr_union
*)them
, themlen
,
174 return STAT_NORETRY
; /*! STAT_RETRYLATER? */
176 if (*pf
== PF_UNSPEC
) {
177 *pf
= them
->soa
.sa_family
;
180 applyopts(-1, opts
, PH_EARLY
);
182 /* 3 means: IP address AND port accepted */
183 if (retropt_bind(opts
, *pf
, socktype
, protocol
, (struct sockaddr
*)us
, uslen
, 3,
184 res_opts0
, res_opts1
)
190 case PF_INET
: socket_in_init(&us
->ip4
); *uslen
= sizeof(us
->ip4
); break;
191 #endif /* WITH_IP4 */
193 case PF_INET6
: socket_in6_init(&us
->ip6
); *uslen
= sizeof(us
->ip6
); break;
194 #endif /* WITH_IP6 */
198 if (retropt_2bytes(opts
, OPT_SOURCEPORT
, &port
) >= 0) {
201 case PF_INET
: us
->ip4
.sin_port
= htons(port
); break;
202 #endif /* WITH_IP4 */
204 case PF_INET6
: us
->ip6
.sin6_port
= htons(port
); break;
205 #endif /* WITH_IP6 */
206 default: Error("unsupported protocol family");
211 retropt_bool(opts
, OPT_LOWPORT
, lowport
);
213 *opts0
= copyopts(opts
, GROUP_ALL
);
215 Notice1("opening connection to %s",
216 sockaddr_info((struct sockaddr
*)them
, *themlen
, infobuff
, sizeof(infobuff
)));
219 #endif /* WITH_IP4 */
222 #if WITH_TCP && WITH_LISTEN
224 applies and consumes the following options:
225 OPT_PROTOCOL_FAMILY, OPT_BIND
227 int _xioopen_ipapp_listen_prepare(struct opt
*opts
, struct opt
**opts0
,
228 const char *portname
, int *pf
, int ipproto
,
229 unsigned long res_opts0
,
230 unsigned long res_opts1
,
231 union sockaddr_union
*us
, socklen_t
*uslen
,
233 char *bindname
= NULL
;
236 retropt_socket_pf(opts
, pf
);
238 retropt_string(opts
, OPT_BIND
, &bindname
);
240 xiogetaddrinfo(bindname
, portname
, *pf
, socktype
, ipproto
,
241 (union sockaddr_union
*)us
, uslen
,
242 res_opts0
, res_opts1
))
248 *opts0
= copyopts(opts
, GROUP_ALL
);
253 /* we expect the form: port */
254 /* currently only used for TCP4 */
255 int xioopen_ipapp_listen(int argc
, const char *argv
[], struct opt
*opts
,
256 int xioflags
, xiofile_t
*fd
,
257 unsigned groups
, int socktype
,
258 int ipproto
, int pf
) {
259 struct opt
*opts0
= NULL
;
260 union sockaddr_union us_sa
, *us
= &us_sa
;
261 socklen_t uslen
= sizeof(us_sa
);
265 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
268 if (pf
== PF_UNSPEC
) {
269 #if WITH_IP4 && WITH_IP6
270 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
278 fd
->stream
.howtoend
= END_SHUTDOWN
;
280 if (applyopts_single(&fd
->stream
, opts
, PH_INIT
) < 0) return -1;
281 applyopts(-1, opts
, PH_INIT
);
282 applyopts(-1, opts
, PH_EARLY
);
284 if (_xioopen_ipapp_listen_prepare(opts
, &opts0
, argv
[1], &pf
, ipproto
,
285 fd
->stream
.para
.socket
.ip
.res_opts
[1],
286 fd
->stream
.para
.socket
.ip
.res_opts
[0],
287 us
, &uslen
, socktype
)
293 xioopen_listen(&fd
->stream
, xioflags
,
294 (struct sockaddr
*)us
, uslen
,
295 opts
, opts0
, pf
, socktype
, ipproto
))
300 #endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
302 #endif /* WITH_TCP || WITH_UDP */