aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/gnunet_nat_lib.h41
-rw-r--r--src/nat/nat_mini.c192
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
186GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst); 186GNUNET_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 */
195typedef 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 */
203struct 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 */
200int 214struct GNUNET_NAT_ExternalHandle *
201GNUNET_NAT_mini_get_external_ipv4 (struct in_addr *addr); 215GNUNET_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 */
225void
226GNUNET_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 */
59int 53struct GNUNET_NAT_ExternalHandle
60GNUNET_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 */
111static void
112read_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 */
166struct GNUNET_NAT_ExternalHandle *
167GNUNET_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 */
211void
212GNUNET_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