Allow user to change his status, sending a broadcast presence
[cascardo/hcxmpp.git] / tcp_connect.c
1 /*
2  * Copyright (C) 2008  Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <udns.h>
26 #include "sort_udns.h"
27
28 int tcp_connect_a4 (struct in_addr addr, int port)
29 {
30   int fd;
31   struct sockaddr_in in4;
32   fd = socket (PF_INET, SOCK_STREAM, 0);
33   if (fd < 0)
34     return -1;
35   in4.sin_family = AF_INET;
36   in4.sin_port = htons (port);
37   in4.sin_addr = addr;
38   if (connect (fd, (struct sockaddr *) &in4, sizeof (in4)) < 0)
39     {
40       close (fd);
41       return -1;
42     }
43   return fd;
44 }
45
46 int
47 tcp_connect_a6 (struct in6_addr addr, int port)
48 {
49   int fd;
50   struct sockaddr_in6 in6;
51   fd = socket (PF_INET6, SOCK_STREAM, 0);
52   if (fd < 0)
53     return -1;
54   memset (&in6, sizeof (in6), 0);
55   in6.sin6_family = AF_INET6;
56   in6.sin6_port = htons (port);
57   in6.sin6_addr = addr;
58   if (connect (fd, (struct sockaddr *) &in6, sizeof (in6)) < 0)
59     {
60       close (fd);
61       return -1;
62     }
63   return fd;
64 }
65
66 int
67 tcp_connect4 (struct dns_srv srv)
68 {
69   struct dns_rr_a4 *a4;
70   int i;
71   int fd;
72   a4 = dns_resolve_a4 (NULL, srv.name, 0);
73   if (a4 == NULL)
74     return -1;
75   for (i = 0; i < a4->dnsa4_nrr; i++)
76     {
77       fd = tcp_connect_a4 (a4->dnsa4_addr[i], srv.port);
78       if (fd >= 0)
79         {
80           free (a4);
81           return fd;
82         }
83     }
84   free (a4);
85   return -1;
86 }
87
88 int
89 tcp_connect6 (struct dns_srv srv)
90 {
91   struct dns_rr_a6 *a6;
92   int i;
93   int fd;
94   a6 = dns_resolve_a6 (NULL, srv.name, 0);
95   if (a6 == NULL)
96     return -1;
97   for (i = 0; i < a6->dnsa6_nrr; i++)
98     {
99       fd = tcp_connect_a6 (a6->dnsa6_addr[i], srv.port);
100       if (fd >= 0)
101         {
102           free (a6);
103           return fd;
104         }
105     }
106   free (a6);
107   return -1;
108 }
109
110 int
111 hc_tcp_connect (char *server, char *service)
112 {
113   struct dns_rr_srv *srv;
114   int i;
115   int fd;
116   srv = dns_resolve_srv (NULL, server, service, "tcp", 0);
117   if (srv == NULL)
118     return -1;
119   hc_dns_srv_sort (srv->dnssrv_srv, srv->dnssrv_nrr);
120   for (i = 0; i < srv->dnssrv_nrr; i++)
121     {
122       fd = tcp_connect6 (srv->dnssrv_srv[i]);
123       if (fd < 0)
124         fd = tcp_connect4 (srv->dnssrv_srv[i]);
125       if (fd >= 0)
126         {
127           free (srv);
128           return fd;
129         }
130      }
131   free (srv);
132   return -1;
133 }
134
135 #ifdef TEST
136 int
137 main (int argc, char **argv)
138 {
139   char *server;
140   char *service;
141   int fd;
142   dns_init (NULL, 1);
143   server = (argc >= 2) ? argv[1] : "holoscopio.com";
144   service = (argc >= 3) ? argv[2] : "xmpp-client";
145   fd = hc_tcp_connect (server, service);
146   if (fd > 0)
147     close (fd);
148   return 0;
149 }
150 #endif