/* * Copyright (C) 2000-2012 Free Software Foundation, Inc. * * This file is part of GnuTLS. * * GnuTLS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GnuTLS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #if HAVE_SYS_SOCKET_H #include #elif HAVE_WS2TCPIP_H #include #endif #include #include #include #include #include #include #include #include #ifndef _WIN32 #include #endif #include #include "sockets.h" #define MAX_BUF 4096 extern unsigned int verbose; /* Functions to manipulate sockets */ ssize_t socket_recv(const socket_st * socket, void *buffer, int buffer_size) { int ret; if (socket->secure) { do { ret = gnutls_record_recv(socket->session, buffer, buffer_size); if (ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED) gnutls_heartbeat_pong(socket->session, 0); } while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED); } else do { ret = recv(socket->fd, buffer, buffer_size, 0); } while (ret == -1 && errno == EINTR); return ret; } ssize_t socket_send(const socket_st * socket, const void *buffer, int buffer_size) { return socket_send_range(socket, buffer, buffer_size, NULL); } ssize_t socket_send_range(const socket_st * socket, const void *buffer, int buffer_size, gnutls_range_st * range) { int ret; if (socket->secure) do { if (range == NULL) ret = gnutls_record_send(socket->session, buffer, buffer_size); else ret = gnutls_record_send_range(socket-> session, buffer, buffer_size, range); } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED); else do { ret = send(socket->fd, buffer, buffer_size, 0); } while (ret == -1 && errno == EINTR); if (ret > 0 && ret != buffer_size && verbose) fprintf(stderr, "*** Only sent %d bytes instead of %d.\n", ret, buffer_size); return ret; } void socket_bye(socket_st * socket) { int ret; if (socket->secure) { do ret = gnutls_bye(socket->session, GNUTLS_SHUT_WR); while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN); if (ret < 0) fprintf(stderr, "*** gnutls_bye() error: %s\n", gnutls_strerror(ret)); gnutls_deinit(socket->session); socket->session = NULL; } freeaddrinfo(socket->addr_info); socket->addr_info = socket->ptr = NULL; free(socket->ip); free(socket->hostname); free(socket->service); shutdown(socket->fd, SHUT_RDWR); /* no more receptions */ close(socket->fd); socket->fd = -1; socket->secure = 0; } void socket_open(socket_st * hd, const char *hostname, const char *service, int udp) { struct addrinfo hints, *res, *ptr; int sd, err; char buffer[MAX_BUF + 1]; char portname[16] = { 0 }; printf("Resolving '%s'...\n", hostname); /* get server name */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; if ((err = getaddrinfo(hostname, service, &hints, &res))) { fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname, service, gai_strerror(err)); exit(1); } sd = -1; for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (sd == -1) continue; if ((err = getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF, portname, sizeof(portname), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(err)); continue; } if (hints.ai_socktype == SOCK_DGRAM) { #if defined(IP_DONTFRAG) int yes = 1; if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #elif defined(IP_MTU_DISCOVER) int yes = IP_PMTUDISC_DO; if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #endif } printf("Connecting to '%s:%s'...\n", buffer, portname); err = connect(sd, ptr->ai_addr, ptr->ai_addrlen); if (err < 0) { int e = errno; fprintf(stderr, "Cannot connect to %s:%s: %s\n", buffer, portname, strerror(e)); continue; } break; } if (err != 0) exit(1); if (sd == -1) { fprintf(stderr, "Could not find a supported socket\n"); exit(1); } hd->secure = 0; hd->fd = sd; hd->hostname = strdup(hostname); hd->ip = strdup(buffer); hd->service = strdup(portname); hd->ptr = ptr; hd->addr_info = res; return; } void sockets_init(void) { #ifdef _WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(1, 1); if (WSAStartup(wVersionRequested, &wsaData) != 0) { perror("WSA_STARTUP_ERROR"); } #else signal(SIGPIPE, SIG_IGN); #endif }