blob: 1a084cae37004ca327bd97f3309d21acacf8cdf8 [file] [log] [blame]
/* Copyright (c) 2014 The Regents of the University of California
* Barret Rhoden <brho@cs.berkeley.edu>
* See LICENSE for details.
*
* Networking helpers for dealing with the plan 9 interface. */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <parlib/assert.h>
#include <parlib/net.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* my cheap dial, assumes either /net/ or a protocol first, with !s btw the
* proto, host, and port. it also will modify addr temporarily. */
int cheap_dial(char *addr, char *local, char *dir, int *cfdp)
{
int ret, ctlfd, datafd, conv_id;
char *prefix;
char *hostname; /* including !port */
size_t buf_len = strlen(addr) + 30; /* 30 should be enough extra */
char *buf = malloc(buf_len);
if (!buf) {
perror("Unable to malloc buf!");
return -1;
}
if (local || dir) {
perror("Cheap dial doesn't support local or dir");
ret = -1;
goto out_buf;
}
hostname = strchr(addr, '!');
if (!hostname) {
perror("No first bang");
ret = -1;
goto out_buf;
}
*hostname++ = '\0';
prefix = (addr[0] == '/' ? "" : "/net/");
ret = snprintf(buf, buf_len, "%s%s/clone", prefix, addr);
if (snprintf_error(ret, buf_len)) {
perror("Clone chan path too long");
ret = -1;
goto out_readdr;
}
ctlfd = open(buf, O_RDWR);
if (ctlfd < 0) {
perror("Can't clone a conversation");
ret = -1;
goto out_readdr;
}
ret = read(ctlfd, buf, buf_len - 1);
if (ret <= 0) {
if (!ret)
printf("Got early EOF from ctl\n");
else
perror("Can't read ctl");
ret = -1;
goto out_ctlfd;
}
buf[ret] = 0;
conv_id = atoi(buf);
ret = snprintf(buf, buf_len, "connect %s", hostname);
if (snprintf_error(ret, buf_len)) {
perror("Connect string too long");
ret = -1;
goto out_ctlfd;
}
if ((write(ctlfd, buf, strlen(buf)) <= 0)) {
perror("Failed to connect");
ret = -1;
goto out_ctlfd;
}
ret = snprintf(buf, buf_len, "%s%s/%d/data", prefix, addr, conv_id);
if (snprintf_error(ret, buf_len)) {
perror("Data chan path too long");
ret = -1;
goto out_ctlfd;
}
datafd = open(buf, O_RDWR);
if (datafd < 0) {
perror("Failed to open data chan");
ret = -1;
goto out_ctlfd;
}
if (cfdp)
*cfdp = ctlfd;
else
close(ctlfd);
ret = datafd;
/* skip over the ctlfd close */
goto out_readdr;
out_ctlfd:
close(ctlfd);
out_readdr:
/* restore the change we made to addr */
*--hostname = '!';
out_buf:
free(buf);
return ret;
}