+
+
+/* Server side */
+
+int mr_listen(char *port)
+{
+ struct sockaddr_in sin;
+ int s, on = 1;
+
+ memset(&sin, 0, sizeof(sin));
+ if (port[0] == '#')
+ sin.sin_port = atoi(port + 1);
+ else
+ {
+ struct servent *s;
+ s = getservbyname(port, "tcp");
+ if (s)
+ sin.sin_port = s->s_port;
+ else
+ return -1;
+ }
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0)
+ return -1;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(int)) < 0)
+ {
+ closesocket(s);
+ return -1;
+ }
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+ {
+ closesocket(s);
+ return -1;
+ }
+ if (listen(s, 5) < 0)
+ {
+ closesocket(s);
+ return -1;
+ }
+
+ return s;
+}
+
+/* mr_accept returns -1 on accept() error, 0 on bad connection,
+ or connection fd on success */
+
+int mr_accept(int s, struct sockaddr_in *sin)
+{
+ int conn = -1, addrlen = sizeof(struct sockaddr_in), nread, status;
+ char *buf = NULL;
+
+ while (conn < 0)
+ {
+ conn = accept(s, (struct sockaddr *)sin, &addrlen);
+ if (conn < 0 && errno != EINTR
+#ifdef ERESTART
+ && errno != ERESTART
+#endif
+ )
+ return -1;
+ }
+
+ do
+ status = mr_cont_accept(conn, &buf, &nread);
+ while (status == -1);
+
+ return status;
+}
+
+/* mr_cont_accept returns 0 if it has failed, an fd if it has succeeded,
+ or -1 if it is still making progress */
+
+int mr_cont_accept(int conn, char **buf, int *nread)
+{
+ long len, more;
+
+ if (!*buf)
+ {
+ char lbuf[4];
+ if (recv(conn, lbuf, 4, 0) != 4)
+ {
+ closesocket(conn);
+ return 0;
+ }
+ getlong(lbuf, len);
+ len += 4;
+
+ *buf = malloc(len);
+ if (!*buf || len < 58)
+ {
+ closesocket(conn);
+ free(*buf);
+ return 0;
+ }
+ putlong(*buf, len);
+ *nread = 4;
+ return -1;
+ }
+ else
+ getlong(*buf, len);
+
+ more = recv(conn, *buf + *nread, len - *nread, 0);
+
+ if (more == -1 && errno != EINTR)
+ {
+ closesocket(conn);
+ free(*buf);
+ return 0;
+ }
+
+ *nread += more;
+
+ if (*nread != len)
+ return -1;
+
+ if (memcmp(*buf + 4, challenge + 4, 34))
+ {
+ closesocket(conn);
+ free(*buf);
+ return 0;
+ }
+
+ /* good enough */
+ free(*buf);
+
+ if (send(conn, response, sizeof(response), 0) != sizeof(response))
+ {
+ closesocket(conn);
+ return 0;
+ }
+ return conn;
+}