+static int
+make_socket(
+ sa_family_t family)
+{
+ int s;
+ int save_errno;
+#if defined(SO_KEEPALIVE) || defined(USE_REUSEADDR)
+ int on=1;
+ int r;
+#endif
+
+ s = socket(family, SOCK_STREAM, 0);
+ if (s == -1) {
+ save_errno = errno;
+ dbprintf(_("make_socket: socket() failed: %s\n"), strerror(save_errno));
+ errno = save_errno;
+ return -1;
+ }
+ if (s < 0 || s >= (int)FD_SETSIZE) {
+ aclose(s);
+ errno = EMFILE; /* out of range */
+ return -1;
+ }
+
+#ifdef USE_REUSEADDR
+ r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (r < 0) {
+ save_errno = errno;
+ dbprintf(_("make_socket: setsockopt(SO_REUSEADDR) failed: %s\n"),
+ strerror(errno));
+ errno = save_errno;
+ }
+#endif
+
+#ifdef SO_KEEPALIVE
+ r = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
+ (void *)&on, SIZEOF(on));
+ if (r == -1) {
+ save_errno = errno;
+ dbprintf(_("make_socket: setsockopt() failed: %s\n"),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ return -1;
+ }
+#endif
+
+ return s;
+}
+
+/* addrp is my address */
+/* svaddr is the address of the remote machine */
+/* return socket on success */
+/* return -1 on failure */
+int
+connect_portrange(
+ struct sockaddr_storage *addrp,
+ in_port_t first_port,
+ in_port_t last_port,
+ char * proto,
+ struct sockaddr_storage *svaddr,
+ int nonblock)
+{
+ int s;
+ in_port_t port;
+ static in_port_t port_in_use[1024];
+ static int nb_port_in_use = 0;
+ int i;
+
+ assert(first_port <= last_port);
+ /* Try a port already used */
+ for(i=0; i < nb_port_in_use; i++) {
+ port = port_in_use[i];
+ if(port >= first_port && port <= last_port) {
+ s = connect_port(addrp, port, proto, svaddr, nonblock);
+ if(s == -2) return -1;
+ if(s > 0) {
+ return s;
+ }
+ }
+ }
+
+ /* Try a port in the range */
+ for (port = first_port; port <= last_port; port++) {
+ s = connect_port(addrp, port, proto, svaddr, nonblock);
+ if(s == -2) return -1;
+ if(s > 0) {
+ port_in_use[nb_port_in_use++] = port;
+ return s;
+ }
+ }
+
+ dbprintf(_("connect_portrange: All ports between %d and %d are busy.\n"),
+ first_port,
+ last_port);
+ errno = EAGAIN;
+ return -1;
+}
+
+/* addrp is my address */
+/* svaddr is the address of the remote machine */
+/* return -2: Don't try again */
+/* return -1: Try with another port */
+/* return >0: this is the connected socket */
+int
+connect_port(
+ struct sockaddr_storage *addrp,
+ in_port_t port,
+ char * proto,
+ struct sockaddr_storage *svaddr,
+ int nonblock)
+{
+ int save_errno;
+ struct servent * servPort;
+ socklen_t len;
+ socklen_t socklen;
+ int s;
+
+ servPort = getservbyport((int)htons(port), proto);
+ if (servPort != NULL && !strstr(servPort->s_name, "amanda")) {
+ dbprintf(_("connect_port: Skip port %d: owned by %s.\n"),
+ port, servPort->s_name);
+ return -1;
+ }
+
+ if ((s = make_socket(addrp->ss_family)) == -1) return -2;
+
+ SS_SET_PORT(addrp, port);
+ socklen = SS_LEN(addrp);
+ if (bind(s, (struct sockaddr *)addrp, socklen) != 0) {
+ save_errno = errno;
+ aclose(s);
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - %s\n"),
+ port, strerror(errno));
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - %s\n"),
+ port, servPort->s_name, strerror(errno));
+ }
+ if (save_errno != EADDRINUSE) {
+ errno = save_errno;
+ return -2;
+ }
+
+ errno = save_errno;
+ return -1;
+ }
+ if(servPort == NULL) {
+ dbprintf(_("connect_port: Try port %d: available - Success\n"), port);
+ } else {
+ dbprintf(_("connect_port: Try port %d: owned by %s - Success\n"),
+ port, servPort->s_name);
+ }
+
+ /* find out what port was actually used */
+
+ len = sizeof(*addrp);
+ if (getsockname(s, (struct sockaddr *)addrp, &len) == -1) {
+ save_errno = errno;
+ dbprintf(_("connect_port: getsockname() failed: %s\n"),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ return -1;
+ }
+
+ if (nonblock)
+ fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
+ if (connect(s, (struct sockaddr *)svaddr, SS_LEN(svaddr)) == -1 && !nonblock) {
+ save_errno = errno;
+ dbprintf(_("connect_portrange: Connect from %s failed: %s\n"),
+ str_sockaddr(addrp),
+ strerror(save_errno));
+ dbprintf(_("connect_portrange: connect to %s failed: %s\n"),
+ str_sockaddr(svaddr),
+ strerror(save_errno));
+ aclose(s);
+ errno = save_errno;
+ if (save_errno == ECONNREFUSED ||
+ save_errno == EHOSTUNREACH ||
+ save_errno == ENETUNREACH ||
+ save_errno == ETIMEDOUT) {
+ return -2 ;
+ }
+ return -1;
+ }
+
+ dbprintf(_("connected to %s\n"),
+ str_sockaddr(svaddr));
+ dbprintf(_("our side is %s\n"),
+ str_sockaddr(addrp));
+ return s;
+}
+
+