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