1 /* iksemel (XML parser for Jabber)
2 ** Copyright (C) 2004 Gurer Ozen <madcat@e-kolay.net>
3 ** This code is free software; you can redistribute it and/or
4 ** modify it under the terms of GNU Lesser General Public License.
5 */
6 
7 #include "common.h"
8 #include "iksemel.h"
9 
10 #ifdef _WIN32
11 #include <winsock.h>
12 #else
13 #include <netdb.h>
14 #include <sys/time.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #endif
18 
19 static void
io_close(void * socket)20 io_close (void *socket)
21 {
22 	int sock = (int) socket;
23 #ifdef _WIN32
24 	closesocket (sock);
25 #else
26 	close (sock);
27 #endif
28 }
29 
30 static int
io_connect(iksparser * prs,void ** socketptr,const char * server,int port)31 io_connect (iksparser *prs, void **socketptr, const char *server, int port)
32 {
33 	int sock = -1;
34 	int tmp;
35 #ifdef HAVE_GETADDRINFO
36 	struct addrinfo hints;
37 	struct addrinfo *addr_res, *addr_ptr;
38 	char port_str[6];
39 	int err = 0;
40 	int family = AF_INET;
41 
42 	if (strchr(server, ':')) {
43 		family = AF_INET6;
44 	}
45 
46 	hints.ai_flags = AI_CANONNAME;
47 	hints.ai_family = family;
48 	hints.ai_socktype = SOCK_STREAM;
49 	hints.ai_protocol = 0;
50 	hints.ai_addrlen = 0;
51 	hints.ai_canonname = NULL;
52 	hints.ai_addr = NULL;
53 	hints.ai_next = NULL;
54 	sprintf (port_str, "%i", port);
55 
56 	if (getaddrinfo (server, port_str, &hints, &addr_res) != 0)
57 		return IKS_NET_NODNS;
58 
59 	addr_ptr = addr_res;
60 	while (addr_ptr) {
61 		err = IKS_NET_NOSOCK;
62 		sock = socket (addr_ptr->ai_family, addr_ptr->ai_socktype, addr_ptr->ai_protocol);
63 		if (sock != -1) {
64 			err = IKS_NET_NOCONN;
65 			tmp = connect (sock, addr_ptr->ai_addr, addr_ptr->ai_addrlen);
66 
67 			if (tmp == 0) break;
68 			io_close ((void *) sock);
69 			sock = -1;
70 		}
71 		addr_ptr = addr_ptr->ai_next;
72 	}
73 	freeaddrinfo (addr_res);
74 
75 	if (sock == -1) return err;
76 #else
77 	struct hostent *host;
78 	struct sockaddr_in sin;
79 
80 	host = gethostbyname (server);
81 	if (!host) return IKS_NET_NODNS;
82 
83 	memcpy (&sin.sin_addr, host->h_addr, host->h_length);
84 	sin.sin_family = host->h_addrtype;
85 	sin.sin_port = htons (port);
86 	sock = socket (host->h_addrtype, SOCK_STREAM, 0);
87 	if (sock == -1) return IKS_NET_NOSOCK;
88 
89 	tmp = connect (sock, (struct sockaddr *)&sin, sizeof (struct sockaddr_in));
90 	if (tmp != 0) {
91 		io_close ((void *) sock);
92 		return IKS_NET_NOCONN;
93 	}
94 #endif
95 
96 	*socketptr = (void *) sock;
97 
98 	return IKS_OK;
99 }
100 
101 static int
io_send(void * socket,const char * data,size_t len)102 io_send (void *socket, const char *data, size_t len)
103 {
104 	int sock = (int) socket;
105 
106 	if (send (sock, data, len, 0) == -1) return IKS_NET_RWERR;
107 	return IKS_OK;
108 }
109 
110 static int
io_recv(void * socket,char * buffer,size_t buf_len,int timeout)111 io_recv (void *socket, char *buffer, size_t buf_len, int timeout)
112 {
113 	int sock = (int) socket;
114 	fd_set fds;
115 	struct timeval tv, *tvptr;
116 	int len;
117 	char *bound;
118 
119 	tv.tv_sec = 0;
120 	tv.tv_usec = 0;
121 
122 	FD_ZERO (&fds);
123 	FD_SET (sock, &fds);
124 	tv.tv_sec = timeout;
125 
126 	if (timeout != -1) tvptr = &tv; else tvptr = NULL;
127 	if (select (sock + 1, &fds, NULL, NULL, tvptr) > 0) {
128 		len = recv (sock, buffer, buf_len, 0);
129 		if (len > 0) {
130 			char *p, *e = NULL, *t = NULL;
131 			bound = buffer + (len -1);
132 
133 			for (p = buffer; p < bound; p++) {
134 				if (*p == '>') {
135 					e = p;
136 					t = p+1;
137 					if (*t == '<') {
138 						continue;
139 					}
140 					while(p < bound && t < bound) {
141 						if (*t != ' ' && *t != '<') {
142 							t = e = NULL;
143 							break;
144 						}
145 						if (*t == '<') {
146 							p = t;
147 							*(p-1) = '>';
148 							*e = ' ';
149 							e = NULL;
150 							break;
151 						}
152 
153 						t++;
154 					}
155 				}
156 			}
157 			return len;
158 		} else if (len <= 0) {
159 			return -1;
160 		}
161 	}
162 	return 0;
163 }
164 
165 ikstransport iks_default_transport = {
166 	IKS_TRANSPORT_V1,
167 	io_connect,
168 	io_send,
169 	io_recv,
170 	io_close,
171 	NULL
172 };
173