1 /* source: xio-ipapp.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
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
); free(opts
); opts
= copyopts(opts0
, GROUP_ALL
);
99 #endif /* WITH_RETRY */
101 free(opts0
);free(opts
);
109 if (xfd
->forever
|| xfd
->retry
) {
110 level
= E_WARN
; /* most users won't expect a problem here,
111 so Notice is too weak */
113 while ((pid
= xio_fork(false, level
)) < 0) {
114 if (xfd
->forever
|| --xfd
->retry
) {
115 Nanosleep(&xfd
->intervall
, NULL
); continue;
118 return STAT_RETRYLATER
;
121 if (pid
== 0) { /* child process */
122 xfd
->forever
= false; xfd
->retry
= 0;
128 /* with and without retry */
129 Nanosleep(&xfd
->intervall
, NULL
);
130 dropopts(opts
, PH_ALL
); free(opts
); opts
= copyopts(opts0
, GROUP_ALL
);
131 continue; /* with next socket() bind() connect() */
133 #endif /* WITH_RETRY */
138 /* only "active" process breaks (master without fork, or child) */
140 if ((result
= _xio_openlate(xfd
, opts
)) < 0) {
141 free(opts0
);free(opts
);
144 free(opts0
);free(opts
);
149 /* returns STAT_OK on success or some other value on failure
150 applies and consumes the following options:
152 OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SOURCEPORT, OPT_LOWPORT
155 _xioopen_ipapp_prepare(struct opt
*opts
, struct opt
**opts0
,
156 const char *hostname
,
157 const char *portname
,
160 unsigned long res_opts0
, unsigned long res_opts1
,
161 union sockaddr_union
*them
, socklen_t
*themlen
,
162 union sockaddr_union
*us
, socklen_t
*uslen
,
163 bool *needbind
, bool *lowport
,
169 retropt_socket_pf(opts
, pf
);
172 xiogetaddrinfo(hostname
, portname
,
173 *pf
, socktype
, protocol
,
174 (union sockaddr_union
*)them
, themlen
,
178 return STAT_NORETRY
; /*! STAT_RETRYLATER? */
180 if (*pf
== PF_UNSPEC
) {
181 *pf
= them
->soa
.sa_family
;
184 applyopts(-1, opts
, PH_EARLY
);
186 /* 3 means: IP address AND port accepted */
187 if (retropt_bind(opts
, *pf
, socktype
, protocol
, (struct sockaddr
*)us
, uslen
, 3,
188 res_opts0
, res_opts1
)
194 case PF_INET
: socket_in_init(&us
->ip4
); *uslen
= sizeof(us
->ip4
); break;
195 #endif /* WITH_IP4 */
197 case PF_INET6
: socket_in6_init(&us
->ip6
); *uslen
= sizeof(us
->ip6
); break;
198 #endif /* WITH_IP6 */
202 if (retropt_2bytes(opts
, OPT_SOURCEPORT
, &port
) >= 0) {
205 case PF_INET
: us
->ip4
.sin_port
= htons(port
); break;
206 #endif /* WITH_IP4 */
208 case PF_INET6
: us
->ip6
.sin6_port
= htons(port
); break;
209 #endif /* WITH_IP6 */
210 default: Error("unsupported protocol family");
215 retropt_bool(opts
, OPT_LOWPORT
, lowport
);
217 *opts0
= copyopts(opts
, GROUP_ALL
);
219 Notice1("opening connection to %s",
220 sockaddr_info((struct sockaddr
*)them
, *themlen
, infobuff
, sizeof(infobuff
)));
223 #endif /* WITH_IP4 */
226 #if WITH_TCP && WITH_LISTEN
228 applies and consumes the following options:
229 OPT_PROTOCOL_FAMILY, OPT_BIND
231 int _xioopen_ipapp_listen_prepare(struct opt
*opts
, struct opt
**opts0
,
232 const char *portname
, int *pf
, int ipproto
,
233 unsigned long res_opts0
,
234 unsigned long res_opts1
,
235 union sockaddr_union
*us
, socklen_t
*uslen
,
237 char *bindname
= NULL
;
240 retropt_socket_pf(opts
, pf
);
242 retropt_string(opts
, OPT_BIND
, &bindname
);
244 xiogetaddrinfo(bindname
, portname
, *pf
, socktype
, ipproto
,
245 (union sockaddr_union
*)us
, uslen
,
246 res_opts0
, res_opts1
))
252 *opts0
= copyopts(opts
, GROUP_ALL
);
257 /* we expect the form: port */
258 /* currently only used for TCP4 */
259 int xioopen_ipapp_listen(int argc
, const char *argv
[], struct opt
*opts
,
260 int xioflags
, xiofile_t
*fd
,
261 unsigned groups
, int socktype
,
262 int ipproto
, int pf
) {
263 struct opt
*opts0
= NULL
;
264 union sockaddr_union us_sa
, *us
= &us_sa
;
265 socklen_t uslen
= sizeof(us_sa
);
269 Error2("%s: wrong number of parameters (%d instead of 1)", argv
[0], argc
-1);
272 if (pf
== PF_UNSPEC
) {
273 #if WITH_IP4 && WITH_IP6
274 pf
= xioopts
.default_ip
=='6'?PF_INET6
:PF_INET
;
282 fd
->stream
.howtoend
= END_SHUTDOWN
;
284 if (applyopts_single(&fd
->stream
, opts
, PH_INIT
) < 0) return -1;
285 applyopts(-1, opts
, PH_INIT
);
286 applyopts(-1, opts
, PH_EARLY
);
288 if (_xioopen_ipapp_listen_prepare(opts
, &opts0
, argv
[1], &pf
, ipproto
,
289 fd
->stream
.para
.socket
.ip
.res_opts
[1],
290 fd
->stream
.para
.socket
.ip
.res_opts
[0],
291 us
, &uslen
, socktype
)
297 xioopen_listen(&fd
->stream
, xioflags
,
298 (struct sockaddr
*)us
, uslen
,
299 opts
, opts0
, pf
, socktype
, ipproto
))
304 #endif /* WITH_IP4 && WITH_TCP && WITH_LISTEN */
306 #endif /* WITH_TCP || WITH_UDP */