6 |
6 |
7 // XXX: errors |
7 // XXX: errors |
8 static err_t sock_gnutls_read (struct sock_stream *base_sock, void *buf, size_t *len) |
8 static err_t sock_gnutls_read (struct sock_stream *base_sock, void *buf, size_t *len) |
9 { |
9 { |
10 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
10 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
|
11 struct error_info *err = SOCK_GNUTLS_ERR(sock); |
11 int ret; |
12 int ret; |
12 |
13 |
13 // just map to gnutls_record_recv |
14 // read gnutls record |
14 if ((ret = gnutls_record_recv(sock->session, buf, *len)) < 0) |
15 ret = gnutls_record_recv(sock->session, buf, *len); |
15 RETURN_SET_ERROR_ERRNO(SOCK_GNUTLS_ERR(sock), ERR_GNUTLS_RECORD_RECV); |
16 |
16 |
17 // errors |
17 // updated length |
18 if (ret < 0 && ret != GNUTLS_E_AGAIN) |
18 *len = ret; |
19 RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_RECV, ret); |
|
20 |
|
21 else if (ret == 0) |
|
22 return SET_ERROR(err, ERR_READ_EOF); |
|
23 |
|
24 |
|
25 // eagain? |
|
26 if (ret == 0) { |
|
27 *len = 0; |
|
28 |
|
29 } else { |
|
30 // updated length |
|
31 *len = ret; |
|
32 |
|
33 } |
19 |
34 |
20 return SUCCESS; |
35 return SUCCESS; |
21 } |
36 } |
22 |
37 |
23 static err_t sock_gnutls_write (struct sock_stream *base_sock, const void *buf, size_t *len) |
38 static err_t sock_gnutls_write (struct sock_stream *base_sock, const void *buf, size_t *len) |
24 { |
39 { |
25 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
40 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
|
41 struct error_info *err = SOCK_GNUTLS_ERR(sock); |
26 int ret; |
42 int ret; |
27 |
43 |
28 // just map to gnutls_record_send |
44 // read gnutls record |
29 if ((ret = gnutls_record_send(sock->session, buf, *len)) < 0) |
45 ret = gnutls_record_send(sock->session, buf, *len); |
30 RETURN_SET_ERROR_ERRNO(SOCK_GNUTLS_ERR(sock), ERR_GNUTLS_RECORD_SEND); |
46 |
31 |
47 // errors |
32 // updated length |
48 if (ret < 0 && ret != GNUTLS_E_AGAIN) |
33 *len = ret; |
49 RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_RECV, ret); |
34 |
50 |
35 return SUCCESS; |
51 else if (ret == 0) |
|
52 return SET_ERROR(err, ERR_READ_EOF); |
|
53 |
|
54 |
|
55 // eagain? |
|
56 if (ret == 0) { |
|
57 *len = 0; |
|
58 |
|
59 } else { |
|
60 // updated length |
|
61 *len = ret; |
|
62 } |
|
63 |
|
64 return SUCCESS; |
|
65 } |
|
66 |
|
67 static void sock_gnutls_event_handler (int fd, short what, void *arg) |
|
68 { |
|
69 struct sock_gnutls *sock = arg; |
|
70 |
|
71 // gnutls might be able to proceed now, so ask user to try what didn't work before now, using the mask given to |
|
72 // event_enable(). |
|
73 sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask); |
36 } |
74 } |
37 |
75 |
38 static err_t sock_gnutls_event_init (struct sock_stream *base_sock) |
76 static err_t sock_gnutls_event_init (struct sock_stream *base_sock) |
39 { |
77 { |
40 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
78 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
41 |
79 |
|
80 err_t err; |
|
81 |
|
82 // set nonblocking |
|
83 if ((err = sock_tcp_set_nonblock(SOCK_GNUTLS_TCP(sock), 1))) |
|
84 return err; |
|
85 |
|
86 // add ourselves as the event handler |
|
87 if ((err = sock_tcp_init_ev(SOCK_GNUTLS_TCP(sock), &sock_gnutls_event_handler, sock))) |
|
88 return err; |
|
89 |
|
90 // ok |
42 return SUCCESS; |
91 return SUCCESS; |
43 } |
92 } |
44 |
93 |
45 static err_t sock_gnutls_event_enable (struct sock_stream *base_sock, short mask) |
94 static err_t sock_gnutls_event_enable (struct sock_stream *base_sock, short mask) |
46 { |
95 { |
47 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
96 struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls); |
48 |
97 int ret; |
|
98 |
|
99 // store the ev_mask. We don't care about it here, because we assume that event_enable is only called once read or |
|
100 // write, respectively, return zero. This is really the only case we can handle with gnutls. |
|
101 sock->ev_mask = mask; |
|
102 |
|
103 // gnutls_record_get_direction tells us what I/O operation gnutls would have required for the last |
|
104 // operation, so we can use that to determine what events to register |
|
105 switch ((ret = gnutls_record_get_direction(sock->session))) { |
|
106 case 0: |
|
107 // read more data |
|
108 sock_tcp_add_event(SOCK_GNUTLS_TCP(sock), EV_READ); |
|
109 break; |
|
110 |
|
111 case 1: |
|
112 // write buffer full |
|
113 sock_tcp_add_event(SOCK_GNUTLS_TCP(sock), EV_WRITE); |
|
114 break; |
|
115 |
|
116 default: |
|
117 // random error |
|
118 RETURN_SET_ERROR_EXTRA(SOCK_GNUTLS_ERR(sock), ERR_GNUTLS_RECORD_GET_DIRECTION, ret); |
|
119 } |
|
120 |
|
121 // ok... wait |
49 return SUCCESS; |
122 return SUCCESS; |
50 } |
123 } |
51 |
124 |
52 /* |
125 /* |
53 * Our sock_stream_Type |
126 * Our sock_stream_Type |