diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-15 19:29:32 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-15 19:29:32 +0000 |
commit | a23897e2db8db3730c9c4fc34faa4f39761d5ac2 (patch) | |
tree | edd0ce58351e559d753903da27350c47f06ab2b6 | |
parent | 58d0a6b4483b41dbfbdad0e703c7a558e857da75 (diff) | |
download | gnunet-a23897e2db8db3730c9c4fc34faa4f39761d5ac2.tar.gz gnunet-a23897e2db8db3730c9c4fc34faa4f39761d5ac2.zip |
make external-IP api non-blocking
-rw-r--r-- | src/include/gnunet_nat_lib.h | 41 | ||||
-rw-r--r-- | src/nat/nat_mini.c | 192 |
2 files changed, 186 insertions, 47 deletions
diff --git a/src/include/gnunet_nat_lib.h b/src/include/gnunet_nat_lib.h index 57eaac606..2ab3eccb6 100644 --- a/src/include/gnunet_nat_lib.h +++ b/src/include/gnunet_nat_lib.h | |||
@@ -186,19 +186,44 @@ void | |||
186 | GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst); | 186 | GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst); |
187 | 187 | ||
188 | 188 | ||
189 | /** | ||
190 | * Signature of a callback that is given an IP address. | ||
191 | * | ||
192 | * @param cls closure | ||
193 | * @param addr the address, NULL on errors | ||
194 | */ | ||
195 | typedef void (*GNUNET_NAT_IPCallback)(void *cls, | ||
196 | const struct in_addr *addr); | ||
197 | |||
198 | |||
199 | |||
200 | /** | ||
201 | * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. | ||
202 | */ | ||
203 | struct GNUNET_NAT_ExternalHandle; | ||
204 | |||
189 | 205 | ||
190 | /** | 206 | /** |
191 | * Try to get the external IPv4 address of this peer. | 207 | * Try to get the external IPv4 address of this peer. |
192 | * Note: calling this function may block this process | ||
193 | * for a few seconds (!). | ||
194 | * | 208 | * |
195 | * @param addr address to set | 209 | * @param timeout when to fail |
196 | * @return GNUNET_OK on success, | 210 | * @param cb function to call with result |
197 | * GNUNET_NO if the result is questionable, | 211 | * @param cb_cls closure for 'cb' |
198 | * GNUNET_SYSERR on error | 212 | * @return handle for cancellation (can only be used until 'cb' is called), NULL on error |
199 | */ | 213 | */ |
200 | int | 214 | struct GNUNET_NAT_ExternalHandle * |
201 | GNUNET_NAT_mini_get_external_ipv4 (struct in_addr *addr); | 215 | GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, |
216 | GNUNET_NAT_IPCallback cb, | ||
217 | void *cb_cls); | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Cancel operation. | ||
222 | * | ||
223 | * @param eh operation to cancel | ||
224 | */ | ||
225 | void | ||
226 | GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh); | ||
202 | 227 | ||
203 | 228 | ||
204 | /** | 229 | /** |
diff --git a/src/nat/nat_mini.c b/src/nat/nat_mini.c index b3eb4e38e..058e8dda2 100644 --- a/src/nat/nat_mini.c +++ b/src/nat/nat_mini.c | |||
@@ -46,63 +46,177 @@ | |||
46 | #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | 46 | #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) |
47 | 47 | ||
48 | 48 | ||
49 | |||
49 | /** | 50 | /** |
50 | * Try to get the external IPv4 address of this peer. | 51 | * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. |
51 | * Note: calling this function may block this process | ||
52 | * for a few seconds (!). | ||
53 | * | ||
54 | * @param addr address to set | ||
55 | * @return GNUNET_OK on success, | ||
56 | * GNUNET_NO if the result is questionable, | ||
57 | * GNUNET_SYSERR on error | ||
58 | */ | 52 | */ |
59 | int | 53 | struct GNUNET_NAT_ExternalHandle |
60 | GNUNET_NAT_mini_get_external_ipv4 (struct in_addr *addr) | ||
61 | { | 54 | { |
55 | |||
56 | /** | ||
57 | * Function to call with the result. | ||
58 | */ | ||
59 | GNUNET_NAT_IPCallback cb; | ||
60 | |||
61 | /** | ||
62 | * Closure for 'cb'. | ||
63 | */ | ||
64 | void *cb_cls; | ||
65 | |||
66 | /** | ||
67 | * Read task. | ||
68 | */ | ||
69 | GNUNET_SCHEDULER_TaskIdentifier task; | ||
70 | |||
71 | /** | ||
72 | * Handle to 'external-ip' process. | ||
73 | */ | ||
62 | struct GNUNET_OS_Process *eip; | 74 | struct GNUNET_OS_Process *eip; |
75 | |||
76 | /** | ||
77 | * Handle to stdout pipe of 'external-ip'. | ||
78 | */ | ||
63 | struct GNUNET_DISK_PipeHandle *opipe; | 79 | struct GNUNET_DISK_PipeHandle *opipe; |
80 | |||
81 | /** | ||
82 | * Read handle of 'opipe'. | ||
83 | */ | ||
64 | const struct GNUNET_DISK_FileHandle *r; | 84 | const struct GNUNET_DISK_FileHandle *r; |
85 | |||
86 | /** | ||
87 | * When should this operation time out? | ||
88 | */ | ||
89 | struct GNUNET_TIME_Absolute timeout; | ||
90 | |||
91 | /** | ||
92 | * Number of bytes in 'buf' that are valid. | ||
93 | */ | ||
65 | size_t off; | 94 | size_t off; |
95 | |||
96 | /** | ||
97 | * Destination of our read operation (output of 'external-ip'). | ||
98 | */ | ||
66 | char buf[17]; | 99 | char buf[17]; |
100 | |||
101 | }; | ||
102 | |||
103 | |||
104 | /** | ||
105 | * Read the output of 'external-ip' into buf. When complete, parse the | ||
106 | * address and call our callback. | ||
107 | * | ||
108 | * @param cls the 'struct GNUNET_NAT_ExternalHandle' | ||
109 | * @param tc scheduler context | ||
110 | */ | ||
111 | static void | ||
112 | read_external_ipv4 (void *cls, | ||
113 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
114 | { | ||
115 | struct GNUNET_NAT_ExternalHandle *eh = cls; | ||
67 | ssize_t ret; | 116 | ssize_t ret; |
117 | struct in_addr addr; | ||
68 | int iret; | 118 | int iret; |
69 | 119 | ||
70 | opipe = GNUNET_DISK_pipe (GNUNET_YES, | 120 | eh->task = GNUNET_SCHEDULER_NO_TASK; |
71 | GNUNET_NO, | 121 | if (GNUNET_YES == |
72 | GNUNET_YES); | 122 | GNUNET_NETWORK_fdset_handle_isset (tc->read_ready, |
73 | if (NULL == opipe) | 123 | eh->r)) |
74 | return GNUNET_SYSERR; | 124 | ret = GNUNET_DISK_file_read (eh->r, |
75 | eip = GNUNET_OS_start_process (NULL, | 125 | &eh->buf[eh->off], |
76 | opipe, | 126 | sizeof (eh->buf)-eh->off); |
77 | "external-ip", | 127 | else |
78 | "external-ip", NULL); | 128 | ret = -1; /* error reading, timeout, etc. */ |
79 | if (NULL == eip) | 129 | if (ret > 0) |
80 | { | 130 | { |
81 | GNUNET_DISK_pipe_close (opipe); | 131 | /* try to read more */ |
82 | return GNUNET_SYSERR; | 132 | eh->off += ret; |
133 | eh->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_absolute_get_remaining (eh->timeout), | ||
134 | eh->r, | ||
135 | &read_external_ipv4, | ||
136 | eh); | ||
137 | return; | ||
83 | } | 138 | } |
84 | GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE); | 139 | iret = GNUNET_NO; |
85 | iret = GNUNET_SYSERR; | 140 | if ( (eh->off > 7) && |
86 | r = GNUNET_DISK_pipe_handle (opipe, | 141 | (eh->buf[eh->off-1] == '\n') ) |
87 | GNUNET_DISK_PIPE_END_READ); | ||
88 | off = 0; | ||
89 | while (0 < (ret = GNUNET_DISK_file_read (r, &buf[off], sizeof (buf)-off))) | ||
90 | off += ret; | ||
91 | if ( (off > 7) && | ||
92 | (buf[off-1] == '\n') ) | ||
93 | { | 142 | { |
94 | buf[off-1] = '\0'; | 143 | eh->buf[eh->off-1] = '\0'; |
95 | if (1 == inet_pton (AF_INET, buf, addr)) | 144 | if (1 == inet_pton (AF_INET, eh->buf, &addr)) |
96 | { | 145 | { |
97 | if (addr->s_addr == 0) | 146 | if (addr.s_addr == 0) |
98 | iret = GNUNET_NO; /* got 0.0.0.0 */ | 147 | iret = GNUNET_NO; /* got 0.0.0.0 */ |
99 | iret = GNUNET_OK; | 148 | else |
149 | iret = GNUNET_OK; | ||
100 | } | 150 | } |
101 | } | 151 | } |
102 | (void) GNUNET_OS_process_kill (eip, SIGKILL); | 152 | eh->cb (eh->cb_cls, |
103 | GNUNET_OS_process_close (eip); | 153 | (iret == GNUNET_OK) ? &addr : NULL); |
104 | GNUNET_DISK_pipe_close (opipe); | 154 | GNUNET_NAT_mini_get_external_ipv4_cancel (eh); |
105 | return iret; | 155 | } |
156 | |||
157 | |||
158 | /** | ||
159 | * Try to get the external IPv4 address of this peer. | ||
160 | * | ||
161 | * @param timeout when to fail | ||
162 | * @param cb function to call with result | ||
163 | * @param cb_cls closure for 'cb' | ||
164 | * @return handle for cancellation (can only be used until 'cb' is called), NULL on error | ||
165 | */ | ||
166 | struct GNUNET_NAT_ExternalHandle * | ||
167 | GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout, | ||
168 | GNUNET_NAT_IPCallback cb, | ||
169 | void *cb_cls) | ||
170 | { | ||
171 | struct GNUNET_NAT_ExternalHandle *eh; | ||
172 | |||
173 | eh = GNUNET_malloc (sizeof (struct GNUNET_NAT_ExternalHandle)); | ||
174 | eh->cb = cb; | ||
175 | eh->cb_cls = cb_cls; | ||
176 | eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, | ||
177 | GNUNET_NO, | ||
178 | GNUNET_YES); | ||
179 | if (NULL == eh->opipe) | ||
180 | { | ||
181 | GNUNET_free (eh); | ||
182 | return NULL; | ||
183 | } | ||
184 | eh->eip = GNUNET_OS_start_process (NULL, | ||
185 | eh->opipe, | ||
186 | "external-ip", | ||
187 | "external-ip", NULL); | ||
188 | if (NULL == eh->eip) | ||
189 | { | ||
190 | GNUNET_DISK_pipe_close (eh->opipe); | ||
191 | GNUNET_free (eh); | ||
192 | return NULL; | ||
193 | } | ||
194 | GNUNET_DISK_pipe_close_end (eh->opipe, GNUNET_DISK_PIPE_END_WRITE); | ||
195 | eh->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
196 | eh->r = GNUNET_DISK_pipe_handle (eh->opipe, | ||
197 | GNUNET_DISK_PIPE_END_READ); | ||
198 | eh->task = GNUNET_SCHEDULER_add_read_file (timeout, | ||
199 | eh->r, | ||
200 | &read_external_ipv4, | ||
201 | eh); | ||
202 | return eh; | ||
203 | } | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Cancel operation. | ||
208 | * | ||
209 | * @param eh operation to cancel | ||
210 | */ | ||
211 | void | ||
212 | GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh) | ||
213 | { | ||
214 | (void) GNUNET_OS_process_kill (eh->eip, SIGKILL); | ||
215 | GNUNET_OS_process_close (eh->eip); | ||
216 | GNUNET_DISK_pipe_close (eh->opipe); | ||
217 | if (GNUNET_SCHEDULER_NO_TASK != eh->task) | ||
218 | GNUNET_SCHEDULER_cancel (eh->task); | ||
219 | GNUNET_free (eh); | ||
106 | } | 220 | } |
107 | 221 | ||
108 | 222 | ||