summaryrefslogtreecommitdiff
path: root/ucspi-tcp-0.88/remoteinfo.c
blob: 6c437c048376dc870ad2d0afb458d741fe704a72 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include "fmt.h"
#include "buffer.h"
#include "socket.h"
#include "error.h"
#include "iopause.h"
#include "timeoutconn.h"
#include "remoteinfo.h"

static struct taia now;
static struct taia deadline;

static int mywrite(int fd,char *buf,int len)
{
  iopause_fd x;

  x.fd = fd;
  x.events = IOPAUSE_WRITE;
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = error_timeout;
      return -1;
    }
  }
  return write(fd,buf,len);
}

static int myread(int fd,char *buf,int len)
{
  iopause_fd x;

  x.fd = fd;
  x.events = IOPAUSE_READ;
  for (;;) {
    taia_now(&now);
    iopause(&x,1,&deadline,&now);
    if (x.revents) break;
    if (taia_less(&deadline,&now)) {
      errno = error_timeout;
      return -1;
    }
  }
  return read(fd,buf,len);
}

static int doit(stralloc *out,int s,char ipremote[4],uint16 portremote,char iplocal[4],uint16 portlocal,unsigned int timeout)
{
  buffer b;
  char bspace[128];
  char strnum[FMT_ULONG];
  int numcolons;
  char ch;

  if (socket_bind4(s,iplocal,0) == -1) return -1;
  if (timeoutconn(s,ipremote,113,timeout) == -1) return -1;

  buffer_init(&b,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,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[4],uint16 portremote,char iplocal[4],uint16 portlocal,unsigned int timeout)
{
  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);
  close(s);
  return r;
}