diff options
Diffstat (limited to 'src/nat/nat_mini.c')
-rw-r--r-- | src/nat/nat_mini.c | 192 |
1 files changed, 153 insertions, 39 deletions
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 | ||