b67e04e28e1b144c5ddba8dbf3be541ba03da7e2
[framework/uifw/ecore.git] / src / examples / ecore_fd_handler_gnutls_example.c
1 #include <Ecore.h>
2 #include <fcntl.h>
3 #include <netinet/tcp.h>
4 #include <netinet/in.h>
5 #include <sys/socket.h>
6 #include <arpa/inet.h>
7 #include <errno.h>
8 #include <unistd.h>
9 #include <gnutls/gnutls.h>
10
11 /* Ecore_Fd_Handler example
12  * 2010 Mike Blumenkrantz
13  * compile with gcc $(pkgconfig --cflags --libs gnutls ecore)
14  */
15
16
17 #define print(...) fprintf(stderr, "line %i: ", __LINE__); fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n")
18
19 static int done = 0;
20
21 static void
22 tls_log_func (int level, const char *str)
23 {
24   fprintf(stderr, "|<%d>| %s", level, str);
25 }
26
27 static const char*
28 SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
29 {
30    switch (status)
31      {
32       case GNUTLS_HANDSHAKE_HELLO_REQUEST:
33         return "Hello request";
34       case GNUTLS_HANDSHAKE_CLIENT_HELLO:
35         return "Client hello";
36       case GNUTLS_HANDSHAKE_SERVER_HELLO:
37         return "Server hello";
38       case GNUTLS_HANDSHAKE_CERTIFICATE_PKT:
39         return "Certificate packet";
40       case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE:
41         return "Server key exchange";
42       case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
43         return "Certificate request";
44       case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
45         return "Server hello done";
46       case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
47         return "Certificate verify";
48       case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
49         return "Client key exchange";
50       case GNUTLS_HANDSHAKE_FINISHED:
51         return "Finished";
52       case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
53         return "Supplemental";
54      }
55    return NULL;
56 }
57
58 /* Connects to the peer and returns a socket
59  * descriptor.
60  */
61 static int
62 tcp_connect (void)
63 {
64   const char *PORT = "443";
65   const char *SERVER = "69.58.181.89"; //verisign.com
66   int err, sd;
67   int flag = 1, curstate = 0;
68   struct sockaddr_in sa;
69
70   /* sets some fd options such as nonblock */
71   sd = socket (AF_INET, SOCK_STREAM, 0);
72   fcntl(sd, F_SETFL, O_NONBLOCK);
73   fcntl(sd, F_SETFD, FD_CLOEXEC);
74   setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, sizeof(curstate));
75
76   setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
77
78   memset (&sa, '\0', sizeof (sa));
79   sa.sin_family = AF_INET;
80   sa.sin_port = htons (atoi (PORT));
81   inet_pton (AF_INET, SERVER, &sa.sin_addr);
82
83   /* connects to server
84    */
85   err = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
86   if ((err < 0) && (errno != EINPROGRESS))
87     {
88       print("Connect error\n");
89       exit (1);
90     }
91
92   return sd;
93 }
94
95 /* closes the given socket descriptor.
96  */
97 static void
98 tcp_close (int sd)
99 {
100   shutdown (sd, SHUT_RDWR);     /* no more receptions */
101   close (sd);
102 }
103
104 static Eina_Bool
105 _process_data(gnutls_session_t client, Ecore_Fd_Handler *fd_handler)
106 {
107    static int ret, lastret;
108    static unsigned int count = 0;
109    
110    if (!done)
111      {
112         lastret = ret;
113         ret = gnutls_handshake (client);
114         count++;
115         if (gnutls_record_get_direction(client))
116           ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_WRITE);
117         else
118           ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_READ);
119         /* avoid printing messages infinity times */
120         if (lastret != ret)
121           {
122              print("gnutls returned with: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
123              if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
124                print("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(client)));
125              print("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(client)));
126              print("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(client)));
127           }
128
129         if (gnutls_error_is_fatal(ret))
130           {
131              print("yarrr this be an error!");
132              exit(1);
133           }
134         
135      }
136   if (ret == GNUTLS_E_SUCCESS)
137     {
138        done = 1;
139        print("Handshake successful in %u handshake calls!", count);
140        ecore_main_loop_quit();
141     }
142
143    return ECORE_CALLBACK_RENEW;
144 }
145
146 int
147 main (void)
148 {
149   /* credentials */
150   gnutls_anon_client_credentials_t c_anoncred;
151   gnutls_certificate_credentials_t c_certcred;
152   
153   gnutls_session_t client;
154   int sd;
155
156   /* General init. */
157   gnutls_global_init ();
158   ecore_init();
159   gnutls_global_set_log_function (tls_log_func);
160     gnutls_global_set_log_level (6);
161
162   /* Init client */
163   gnutls_anon_allocate_client_credentials (&c_anoncred);
164   gnutls_certificate_allocate_credentials (&c_certcred);
165   gnutls_init (&client, GNUTLS_CLIENT);
166   /* set very specific priorities */
167   gnutls_priority_set_direct(client, "NONE:%VERIFY_ALLOW_X509_V1_CA_CRT:+RSA:+DHE-RSA:+DHE-DSS:+ANON-DH:+COMP-DEFLATE:+COMP-NULL:+CTYPE-X509:+SHA1:+SHA256:+SHA384:+SHA512:+AES-256-CBC:+AES-128-CBC:+3DES-CBC:+VERS-TLS1.2:+VERS-TLS1.1:+VERS-TLS1.0:+VERS-SSL3.0", NULL);
168   gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred);
169   gnutls_credentials_set (client, GNUTLS_CRD_CERTIFICATE, c_certcred);
170   gnutls_server_name_set(client, GNUTLS_NAME_DNS, "www.verisign.com", strlen("www.verisign.com"));
171
172
173   /* connect to the peer
174    */
175   sd = tcp_connect ();
176
177   /* associate gnutls with socket */
178   gnutls_transport_set_ptr (client, (gnutls_transport_ptr_t) sd);
179   /* add a callback for data being available for send/receive on socket */
180   if (!ecore_main_fd_handler_add(sd, ECORE_FD_READ | ECORE_FD_WRITE, (Ecore_Fd_Cb)_process_data, client, NULL, NULL))
181     {
182        print("could not create fd handler!");
183        exit(1);
184     }
185   /* begin main loop */
186   ecore_main_loop_begin();
187
188   gnutls_bye (client, GNUTLS_SHUT_RDWR);
189
190   gnutls_deinit (client);
191
192   tcp_close (sd);
193   
194   return 0;
195 }