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