summaryrefslogtreecommitdiff
path: root/src/remoteinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/remoteinfo.c')
-rw-r--r--src/remoteinfo.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/remoteinfo.c b/src/remoteinfo.c
new file mode 100644
index 0000000..665d2e5
--- /dev/null
+++ b/src/remoteinfo.c
@@ -0,0 +1,102 @@
+#include <unistd.h>
+#include "fmt.h"
+#include "buffer.h"
+#include "socket_if.h"
+#include "error.h"
+#include "iopause.h"
+#include "timeoutconn.h"
+#include "dnsresolv.h"
+#include "remoteinfo.h"
+
+static struct taia now;
+static struct taia deadline;
+
+static int mywrite(int fd,char *buf,int len)
+{
+ iopause_fd x;
+ int r;
+
+ x.fd = fd;
+ x.events = IOPAUSE_WRITE;
+ for (;;) {
+ taia_now(&now);
+ r = iopause(&x,1,&deadline,&now);
+ if (r > 0 && x.revents) break;
+ if (taia_less(&deadline,&now)) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ return write(fd,buf,len);
+}
+
+static int myread(int fd,char *buf,int len)
+{
+ iopause_fd x;
+ int r;
+
+ x.fd = fd;
+ x.events = IOPAUSE_READ;
+ for (;;) {
+ taia_now(&now);
+ r = iopause(&x,1,&deadline,&now);
+ if (r > 0 && x.revents) break;
+ if (taia_less(&deadline,&now)) {
+ errno = ETIMEDOUT;
+ return -1;
+ }
+ }
+ return read(fd,buf,len);
+}
+
+static int doit(stralloc *out,int s,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
+{
+ buffer b;
+ char bspace[128];
+ char strnum[FMT_ULONG];
+ int numcolons;
+ char ch;
+
+ if (socket_bind(s,iplocal,0,netif) == -1) return -1;
+ if (timeoutconn(s,ipremote,113,timeout,netif) == -1) return -1;
+
+ buffer_init(&b,(ssize_t (*)())mywrite,s,bspace,sizeof(bspace));
+ buffer_put(&b,strnum,fmt_ulong(strnum,portremote));
+ buffer_put(&b," , ",3);
+ buffer_put(&b,strnum,fmt_ulong(strnum,portlocal));
+ buffer_put(&b,"\r\n",2);
+ if (buffer_flush(&b) == -1) return -1;
+
+ buffer_init(&b,(ssize_t (*)())myread,s,bspace,sizeof(bspace));
+ numcolons = 0;
+ for (;;) {
+ if (buffer_get(&b,&ch,1) != 1) return -1;
+ if ((ch == ' ') || (ch == '\t') || (ch == '\r')) continue;
+ if (ch == '\n') return 0;
+ if (numcolons < 3) {
+ if (ch == ':') ++numcolons;
+ }
+ else {
+ if (!stralloc_append(out,&ch)) return -1;
+ if (out->len > 256) return 0;
+ }
+ }
+}
+
+int remoteinfo(stralloc *out,char ipremote[16],uint16 portremote,char iplocal[16],uint16 portlocal,unsigned int timeout,uint32 netif)
+{
+ int s;
+ int r;
+
+ if (!stralloc_copys(out,"")) return -1;
+
+ taia_now(&now);
+ taia_uint(&deadline,timeout);
+ taia_add(&deadline,&now,&deadline);
+
+ s = socket_tcp();
+ if (s == -1) return -1;
+ r = doit(out,s,ipremote,portremote,iplocal,portlocal,timeout,netif);
+ close(s);
+ return r;
+}