2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
6 * GnuTLS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * In addition, as a special exception, the copyright holders give
20 * permission to link the code of portions of this program with the
21 * OpenSSL library under certain conditions as described in each
22 * individual source file, and distribute linked combinations including
25 * You must obey the GNU General Public License in all respects for all
26 * of the code used other than OpenSSL. If you modify file(s) with this
27 * exception, you may extend this exception to your version of the
28 * file(s), but you are not obligated to do so. If you do not wish to do
29 * so, delete this exception statement from your version. If you delete
30 * this exception statement from all source files in the program, then
31 * also delete it here.
37 #include <sys/socket.h>
44 #include <sys/select.h>
45 #include <sys/types.h>
50 #include <arpa/inet.h>
59 /* Functions to manipulate sockets
63 socket_recv(const socket_st * socket, void *buffer, int buffer_size)
70 gnutls_record_recv(socket->session, buffer,
72 if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED)
73 gnutls_heartbeat_pong(socket->session, 0);
75 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN
76 || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED);
80 ret = recv(socket->fd, buffer, buffer_size, 0);
82 while (ret == -1 && errno == EINTR);
88 socket_recv_timeout(const socket_st * socket, void *buffer, int buffer_size, unsigned ms)
93 gnutls_record_set_timeout(socket->session, ms);
94 ret = socket_recv(socket, buffer, buffer_size);
97 gnutls_record_set_timeout(socket->session, 0);
103 socket_send(const socket_st * socket, const void *buffer, int buffer_size)
105 return socket_send_range(socket, buffer, buffer_size, NULL);
110 socket_send_range(const socket_st * socket, const void *buffer,
111 int buffer_size, gnutls_range_st * range)
119 gnutls_record_send(socket->session,
124 gnutls_record_send_range(socket->
130 while (ret == GNUTLS_E_AGAIN
131 || ret == GNUTLS_E_INTERRUPTED);
134 ret = send(socket->fd, buffer, buffer_size, 0);
136 while (ret == -1 && errno == EINTR);
138 if (ret > 0 && ret != buffer_size && socket->verbose)
140 "*** Only sent %d bytes instead of %d.\n", ret,
147 ssize_t send_line(int fd, const char *txt)
149 int len = strlen(txt);
152 ret = send(fd, txt, len, 0);
155 fprintf(stderr, "error sending %s\n", txt);
163 ssize_t wait_for_text(int fd, const char *txt, unsigned txt_size)
173 FD_SET(fd, &read_fds);
176 ret = select(fd + 1, &read_fds, NULL, NULL, &tv);
180 ret = recv(fd, buf, sizeof(buf)-1, 0);
182 fprintf(stderr, "error receiving %s\n", txt);
187 p = memmem(buf, ret, txt, txt_size);
188 if (p != NULL && p != buf) {
193 } while(ret < (int)txt_size || strncmp(buf, txt, txt_size) != 0);
199 socket_starttls(socket_st * socket, const char *app_proto)
204 if (app_proto == NULL || strcasecmp(app_proto, "https") == 0)
207 if (strcasecmp(app_proto, "smtp") == 0 || strcasecmp(app_proto, "submission") == 0) {
209 printf("Negotiating SMTP STARTTLS\n");
211 wait_for_text(socket->fd, "220 ", 4);
212 send_line(socket->fd, "EHLO mail.example.com\n");
213 wait_for_text(socket->fd, "250 ", 4);
214 send_line(socket->fd, "STARTTLS\n");
215 wait_for_text(socket->fd, "220 ", 4);
216 } else if (strcasecmp(app_proto, "imap") == 0 || strcasecmp(app_proto, "imap2") == 0) {
218 printf("Negotiating IMAP STARTTLS\n");
220 send_line(socket->fd, "a CAPABILITY\r\n");
221 wait_for_text(socket->fd, "a OK", 4);
222 send_line(socket->fd, "a STARTTLS\r\n");
223 wait_for_text(socket->fd, "a OK", 4);
224 } else if (strcasecmp(app_proto, "ftp") == 0 || strcasecmp(app_proto, "ftps") == 0) {
226 printf("Negotiating FTP STARTTLS\n");
228 send_line(socket->fd, "FEAT\n");
229 wait_for_text(socket->fd, "211 End", 7);
230 send_line(socket->fd, "AUTH TLS\n");
231 wait_for_text(socket->fd, "234", 3);
233 if (!c_isdigit(app_proto[0])) {
234 static int warned = 0;
236 fprintf(stderr, "unknown protocol %s\n", app_proto);
245 void socket_bye(socket_st * socket)
248 if (socket->secure) {
250 ret = gnutls_bye(socket->session, GNUTLS_SHUT_WR);
251 while (ret == GNUTLS_E_INTERRUPTED
252 || ret == GNUTLS_E_AGAIN);
254 fprintf(stderr, "*** gnutls_bye() error: %s\n",
255 gnutls_strerror(ret));
256 gnutls_deinit(socket->session);
257 socket->session = NULL;
260 freeaddrinfo(socket->addr_info);
261 socket->addr_info = socket->ptr = NULL;
264 free(socket->hostname);
265 free(socket->service);
267 shutdown(socket->fd, SHUT_RDWR); /* no more receptions */
275 socket_open(socket_st * hd, const char *hostname, const char *service,
276 int udp, const char *msg)
278 struct addrinfo hints, *res, *ptr;
280 char buffer[MAX_BUF + 1];
281 char portname[16] = { 0 };
284 printf("Resolving '%s'...\n", hostname);
286 /* get server name */
287 memset(&hints, 0, sizeof(hints));
290 hints.ai_flags = AI_IDN|AI_IDN_ALLOW_UNASSIGNED;
293 hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
294 if ((err = getaddrinfo(hostname, service, &hints, &res))) {
295 fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname,
296 service, gai_strerror(err));
301 for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
302 sd = socket(ptr->ai_family, ptr->ai_socktype,
308 getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer,
309 MAX_BUF, portname, sizeof(portname),
310 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
311 fprintf(stderr, "getnameinfo(): %s\n",
316 if (hints.ai_socktype == SOCK_DGRAM) {
317 #if defined(IP_DONTFRAG)
319 if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG,
322 perror("setsockopt(IP_DF) failed");
323 #elif defined(IP_MTU_DISCOVER)
324 int yes = IP_PMTUDISC_DO;
325 if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER,
328 perror("setsockopt(IP_DF) failed");
334 printf("%s '%s:%s'...\n", msg, buffer, portname);
336 err = connect(sd, ptr->ai_addr, ptr->ai_addrlen);
339 fprintf(stderr, "Cannot connect to %s:%s: %s\n",
340 buffer, portname, strerror(e));
350 fprintf(stderr, "Could not find a supported socket\n");
356 hd->hostname = strdup(hostname);
357 hd->ip = strdup(buffer);
358 hd->service = strdup(portname);
365 void sockets_init(void)
368 WORD wVersionRequested;
371 wVersionRequested = MAKEWORD(1, 1);
372 if (WSAStartup(wVersionRequested, &wsaData) != 0) {
373 perror("WSA_STARTUP_ERROR");
376 signal(SIGPIPE, SIG_IGN);
381 /* converts a textual service or port to
384 const char *port_to_service(const char *sport, const char *proto)
389 if (!c_isdigit(sport[0]))
398 sr = getservbyport(port, proto);
401 "Warning: getservbyport(%s) failed. Using port number as service.\n", sport);
408 int service_to_port(const char *service, const char *proto)
413 port = atoi(service);
417 sr = getservbyname(service, proto);
419 fprintf(stderr, "Warning: getservbyname() failed.\n");
423 return ntohs(sr->s_port);