- GNUNET_DISK_pipe_close_end (opipe, GNUNET_DISK_PIPE_END_WRITE);
- iret = GNUNET_SYSERR;
- r = GNUNET_DISK_pipe_handle (opipe,
- GNUNET_DISK_PIPE_END_READ);
- off = 0;
- while (0 < (ret = GNUNET_DISK_file_read (r, &buf[off], sizeof (buf)-off)))
- off += ret;
- if ( (off > 7) &&
- (buf[off-1] == '\n') )
- {
- buf[off-1] = '\0';
- if (1 == inet_pton (AF_INET, buf, addr))
- {
- if (addr->s_addr == 0)
- iret = GNUNET_NO; /* got 0.0.0.0 */
- iret = GNUNET_OK;
- }
- }
- (void) GNUNET_OS_process_kill (eip, SIGKILL);
- GNUNET_OS_process_close (eip);
- GNUNET_DISK_pipe_close (opipe);
- return iret;
+ }
+ eh->cb (eh->cb_cls,
+ (GNUNET_OK == iret)
+ ? &addr :
+ NULL,
+ (GNUNET_OK == iret)
+ ? NULL
+ : _("no valid address was returned by `external-ip'"));
+ GNUNET_NAT_mini_get_external_ipv4_cancel (eh);
+}
+
+
+/**
+ * (Asynchronously) signal error invoking "external-ip" to client.
+ *
+ * @param cls the `struct GNUNET_NAT_ExternalHandle` (freed)
+ * @param tc scheduler context
+ */
+static void
+signal_external_ip_error (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_NAT_ExternalHandle *eh = cls;
+
+ eh->task = GNUNET_SCHEDULER_NO_TASK;
+ eh->cb (eh->cb_cls,
+ NULL,
+ _("`external-ip' command not found"));
+ GNUNET_free (eh);
+}
+
+
+/**
+ * Try to get the external IPv4 address of this peer.
+ *
+ * @param timeout when to fail
+ * @param cb function to call with result
+ * @param cb_cls closure for @a cb
+ * @return handle for cancellation (can only be used until @a cb is called), NULL on error
+ */
+struct GNUNET_NAT_ExternalHandle *
+GNUNET_NAT_mini_get_external_ipv4 (struct GNUNET_TIME_Relative timeout,
+ GNUNET_NAT_IPCallback cb, void *cb_cls)
+{
+ struct GNUNET_NAT_ExternalHandle *eh;
+
+ eh = GNUNET_new (struct GNUNET_NAT_ExternalHandle);
+ eh->cb = cb;
+ eh->cb_cls = cb_cls;
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_check_helper_binary ("external-ip", GNUNET_NO, NULL))
+ {
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ _("`external-ip' command not found\n"));
+ eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error,
+ eh);
+ return eh;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Running `external-ip' to determine our external IP\n");
+ eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
+ if (NULL == eh->opipe)
+ {
+ eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error,
+ eh);
+ return eh;
+ }
+ eh->eip =
+ GNUNET_OS_start_process (GNUNET_NO, 0, NULL, eh->opipe,
+ "external-ip", "external-ip",
+ NULL);
+ if (NULL == eh->eip)
+ {
+ GNUNET_DISK_pipe_close (eh->opipe);
+ eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error,
+ eh);
+ return eh;
+ }
+ GNUNET_DISK_pipe_close_end (eh->opipe, GNUNET_DISK_PIPE_END_WRITE);
+ eh->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ eh->r = GNUNET_DISK_pipe_handle (eh->opipe, GNUNET_DISK_PIPE_END_READ);
+ eh->task =
+ GNUNET_SCHEDULER_add_read_file (timeout,
+ eh->r,
+ &read_external_ipv4, eh);
+ return eh;
+}
+
+
+/**
+ * Cancel operation.
+ *
+ * @param eh operation to cancel
+ */
+void
+GNUNET_NAT_mini_get_external_ipv4_cancel (struct GNUNET_NAT_ExternalHandle *eh)
+{
+ if (NULL != eh->eip)
+ {
+ (void) GNUNET_OS_process_kill (eh->eip, SIGKILL);
+ GNUNET_OS_process_destroy (eh->eip);
+ }
+ if (NULL != eh->opipe)
+ GNUNET_DISK_pipe_close (eh->opipe);
+ if (GNUNET_SCHEDULER_NO_TASK != eh->task)
+ GNUNET_SCHEDULER_cancel (eh->task);
+ GNUNET_free (eh);