Imported Upstream version 3.0.21
[platform/upstream/gnutls.git] / src / socket.c
1 /*
2  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuTLS.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21
22 #if HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
24 #elif HAVE_WS2TCPIP_H
25 # include <ws2tcpip.h>
26 #endif
27 #include <netdb.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/select.h>
31 #include <sys/types.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #ifndef _WIN32
36 # include <signal.h>
37 #endif
38 #include <socket.h>
39 #include "sockets.h"
40
41 #define MAX_BUF 4096
42
43 extern unsigned int verbose;
44 /* Functions to manipulate sockets
45  */
46
47 ssize_t
48 socket_recv (const socket_st * socket, void *buffer, int buffer_size)
49 {
50   int ret;
51
52   if (socket->secure)
53     do
54       {
55         ret = gnutls_record_recv (socket->session, buffer, buffer_size);
56       }
57     while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
58   else
59     do
60       {
61         ret = recv (socket->fd, buffer, buffer_size, 0);
62       }
63     while (ret == -1 && errno == EINTR);
64
65   return ret;
66 }
67
68 ssize_t
69 socket_send (const socket_st * socket, const void *buffer, int buffer_size)
70 {
71   int ret;
72
73   if (socket->secure)
74     do
75       {
76         ret = gnutls_record_send (socket->session, buffer, buffer_size);
77       }
78     while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
79   else
80     do
81       {
82         ret = send (socket->fd, buffer, buffer_size, 0);
83       }
84     while (ret == -1 && errno == EINTR);
85
86   if (ret > 0 && ret != buffer_size && verbose)
87     fprintf (stderr,
88              "*** Only sent %d bytes instead of %d.\n", ret, buffer_size);
89
90   return ret;
91 }
92
93 void
94 socket_bye (socket_st * socket)
95 {
96   int ret;
97   if (socket->secure)
98     {
99       do
100         ret = gnutls_bye (socket->session, GNUTLS_SHUT_WR);
101       while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN);
102       if (ret < 0)
103         fprintf (stderr, "*** gnutls_bye() error: %s\n",
104                  gnutls_strerror (ret));
105       gnutls_deinit (socket->session);
106       socket->session = NULL;
107     }
108
109   freeaddrinfo (socket->addr_info);
110   socket->addr_info = socket->ptr = NULL;
111
112   free (socket->ip);
113   free (socket->hostname);
114   free (socket->service);
115
116   shutdown (socket->fd, SHUT_RDWR);     /* no more receptions */
117   close (socket->fd);
118
119   socket->fd = -1;
120   socket->secure = 0;
121 }
122
123 void
124 socket_connect (const socket_st * hd)
125 {
126   int err;
127
128   printf ("Connecting to '%s:%s'...\n", hd->ip, hd->service);
129
130   err = connect (hd->fd, hd->ptr->ai_addr, hd->ptr->ai_addrlen);
131   if (err < 0)
132     {
133       fprintf (stderr, "Cannot connect to %s:%s: %s\n", hd->hostname,
134                hd->service, strerror (errno));
135       exit (1);
136     }
137 }
138
139 void
140 socket_open (socket_st * hd, const char *hostname, const char *service, int udp)
141 {
142   struct addrinfo hints, *res, *ptr;
143   int sd, err;
144   char buffer[MAX_BUF + 1];
145   char portname[16] = { 0 };
146
147   printf ("Resolving '%s'...\n", hostname);
148   /* get server name */
149   memset (&hints, 0, sizeof (hints));
150   hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
151   if ((err = getaddrinfo (hostname, service, &hints, &res)))
152     {
153       fprintf (stderr, "Cannot resolve %s:%s: %s\n", hostname, service,
154                gai_strerror (err));
155       exit (1);
156     }
157
158   sd = -1;
159   for (ptr = res; ptr != NULL; ptr = ptr->ai_next)
160     {
161       sd = socket (ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
162       if (sd == -1)
163         continue;
164
165       if ((err = getnameinfo (ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF,
166                               portname, sizeof (portname),
167                               NI_NUMERICHOST | NI_NUMERICSERV)) != 0)
168         {
169           fprintf (stderr, "getnameinfo(): %s\n", gai_strerror (err));
170           freeaddrinfo (res);
171           exit (1);
172         }
173
174       break;
175     }
176
177   if (sd == -1)
178     {
179       fprintf (stderr, "socket(): %s\n", strerror (errno));
180       exit (1);
181     }
182
183   if (hints.ai_socktype == SOCK_DGRAM)
184     {
185 #if defined(IP_DONTFRAG)
186       int yes = 1;
187       if (setsockopt (sd, IPPROTO_IP, IP_DONTFRAG,
188                       (const void *) &yes, sizeof (yes)) < 0)
189         perror ("setsockopt(IP_DF) failed");
190 #elif defined(IP_MTU_DISCOVER)
191       int yes = IP_PMTUDISC_DO;
192       if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, 
193                      (const void*) &yes, sizeof (yes)) < 0)
194         perror ("setsockopt(IP_DF) failed");
195 #endif
196     }
197
198   hd->secure = 0;
199   hd->fd = sd;
200   hd->hostname = strdup (hostname);
201   hd->ip = strdup (buffer);
202   hd->service = strdup (portname);
203   hd->ptr = ptr;
204   hd->addr_info = res;
205
206   return;
207 }
208
209 void
210 sockets_init (void)
211 {
212 #ifdef _WIN32
213     WORD wVersionRequested;
214     WSADATA wsaData;
215
216     wVersionRequested = MAKEWORD (1, 1);
217     if (WSAStartup (wVersionRequested, &wsaData) != 0)
218       {
219           perror ("WSA_STARTUP_ERROR");
220       }
221 #else
222   signal (SIGPIPE, SIG_IGN);
223 #endif
224
225 }