ei_connect.c

来自「OTP是开放电信平台的简称」· C语言 代码 · 共 1,724 行 · 第 1/3 页

C
1,724
字号
#endifstatic void gen_digest(unsigned challenge, char cookie[], 		       unsigned char digest[16]){    MD5_CTX c;        char chbuf[20];        sprintf(chbuf,"%u", challenge);    ei_MD5Init(&c);    ei_MD5Update(&c, (unsigned char *) cookie, 	       (unsigned) strlen(cookie));    ei_MD5Update(&c, (unsigned char *) chbuf, 	       (unsigned) strlen(chbuf));    ei_MD5Final(digest, &c);}static char *hex(char digest[16]){    unsigned char *d = (unsigned char *) digest;    /* FIXME problem for threaded ? */    static char buff[sizeof(digest)*2 + 1];    char *p = buff;    static char tab[] = "0123456789abcdef";    int i;        for (i = 0; i < sizeof(digest); ++i) {	*p++ = tab[(int)((*d) >> 4)];	*p++ = tab[(int)((*d++) & 0xF)];    }    *p = '\0';    return buff;}static int read_2byte_package(int fd, char **buf, int *buflen, 			      int *is_static, unsigned ms){    unsigned char nbuf[2];    unsigned char *x = nbuf;    unsigned len;    int res;        if((res = ei_read_fill_t(fd, nbuf, 2, ms)) != 2) {	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }    len = get16be(x);        if (len > *buflen) {	if (*is_static) {	    char *tmp = malloc(len);	    if (!tmp) {		erl_errno = ENOMEM;		return -1;	    }	    *buf = tmp;	    *is_static = 0;	    *buflen = len;	} else {	    char *tmp = realloc(*buf, len);	    if (!tmp) {		erl_errno = ENOMEM;		return -1;	    }	    *buf = tmp;	    *buflen = len;	}    }    if ((res = ei_read_fill_t(fd, *buf, len, ms)) != len) {	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }    return len;}static int send_status(int fd, char *status, unsigned ms){    char *buf, *s;    char dbuf[DEFBUF_SIZ];    int siz = strlen(status) + 1 + 2;    int res;    buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;    if (!buf) {	erl_errno = ENOMEM;	return -1;    }    s = buf;    put16be(s,siz - 2);    put8(s, 's');    memcpy(s, status, strlen(status));    if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {	EI_TRACE_ERR0("send_status","-> SEND_STATUS socket write failed");	if (buf != dbuf)	    free(buf);	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }    EI_TRACE_CONN1("send_status","-> SEND_STATUS (%s)",status);    if (buf != dbuf)	free(buf);    return 0;}static int recv_status(int fd, unsigned ms){    char dbuf[DEFBUF_SIZ];    char *buf = dbuf;    int is_static = 1;    int buflen = DEFBUF_SIZ;    int rlen;        if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {	EI_TRACE_ERR1("recv_status",		      "<- RECV_STATUS socket read failed (%d)", rlen);	goto error;    }    if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' && 	buf[2] == 'k') {	if (!is_static)	    free(buf);	EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)");	return 0;    }error:    if (!is_static)	free(buf);    return -1;}/* FIXME fix the signed/unsigned mess..... */static int send_name_or_challenge(int fd, char *nodename,				  int f_chall,				  unsigned challenge,				  unsigned version,				  unsigned ms) {    char *buf;    unsigned char *s;    char dbuf[DEFBUF_SIZ];    int siz = 2 + 1 + 2 + 4 + strlen(nodename);    const char* function[] = {"SEND_NAME", "SEND_CHALLENGE"};    int res;    if (f_chall)	siz += 4;    buf = (siz > DEFBUF_SIZ) ? malloc(siz) : dbuf;    if (!buf) {	erl_errno = ENOMEM;	return -1;    }    s = (unsigned char *)buf;    put16be(s,siz - 2);    put8(s, 'n');    put16be(s, version);    put32be(s, (DFLAG_EXTENDED_REFERENCES		| DFLAG_EXTENDED_PIDS_PORTS		| DFLAG_FUN_TAGS		| DFLAG_NEW_FUN_TAGS));    if (f_chall)	put32be(s, challenge);    memcpy(s, nodename, strlen(nodename));        if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {	EI_TRACE_ERR1("send_name_or_challenge",		      "-> %s socket write failed", function[f_chall]);	if (buf != dbuf)	    free(buf);	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }        if (buf != dbuf)	free(buf);    return 0;}static int recv_challenge(int fd, unsigned *challenge, 			  unsigned *version,			  unsigned *flags, ErlConnect *namebuf, unsigned ms){    char dbuf[DEFBUF_SIZ];    char *buf = dbuf;    int is_static = 1;    int buflen = DEFBUF_SIZ;    int rlen;    char *s;    struct sockaddr_in sin;    int sin_len = sizeof(sin);    char tag;        erl_errno = EIO;		/* Default */    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {	EI_TRACE_ERR1("recv_challenge",		      "<- RECV_CHALLENGE socket read failed (%d)",rlen);	goto error;    }    if ((rlen - 11) > MAXNODELEN) {	EI_TRACE_ERR1("recv_challenge",		      "<- RECV_CHALLENGE nodename too long (%d)",rlen - 11);	goto error;    }    s = buf;    if ((tag = get8(s)) != 'n') {	EI_TRACE_ERR2("recv_challenge",		      "<- RECV_CHALLENGE incorrect tag, "		      "expected 'n' got '%c' (%u)",tag,tag);	goto error;    }    *version = get16be(s);    *flags = get32be(s);    *challenge = get32be(s);    if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {	EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "		      "handle extended references");	goto error;    }    if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)	&& !ei_internal_use_r9_pids_ports()) {	EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE peer cannot "		      "handle extended pids and ports");	erl_errno = EIO;	goto error;    }	        if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {	EI_TRACE_ERR0("recv_challenge","<- RECV_CHALLENGE can't get peername");	erl_errno = errno;	goto error;    }    memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), 	sizeof(sin.sin_addr.s_addr));    memcpy(namebuf->nodename, s, rlen - 11);    namebuf->nodename[rlen - 11] = '\0';    if (!is_static)	free(buf);    EI_TRACE_CONN4("recv_challenge","<- RECV_CHALLENGE (ok) node = %s, "	    "version = %u, "	    "flags = %u, "	    "challenge = %d",	    namebuf->nodename,	    *version,	    *flags,	    *challenge	    );    erl_errno = 0;    return 0;error:    if (!is_static)	free(buf);    return -1;}static int send_challenge_reply(int fd, unsigned char digest[16], 				unsigned challenge, unsigned ms) {    char *s;    char buf[DEFBUF_SIZ];    int siz = 2 + 1 + 4 + 16;    int res;    s = buf;    put16be(s,siz - 2);    put8(s, 'r');    put32be(s, challenge);    memcpy(s, digest, 16);        if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {	EI_TRACE_ERR0("send_challenge_reply",		      "-> SEND_CHALLENGE_REPLY socket write failed");	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }        EI_TRACE_CONN2("send_challenge_reply",		   "-> SEND_CHALLENGE_REPLY (ok) challenge = %d, digest = %s",		   challenge,hex(digest));    return 0;}static int recv_challenge_reply (int fd, 				 unsigned our_challenge,				 char cookie[], 				 unsigned *her_challenge,				 unsigned ms){    char dbuf[DEFBUF_SIZ];    char *buf = dbuf;    int is_static = 1;    int buflen = DEFBUF_SIZ;    int rlen;    char *s;    char tag;    char her_digest[16], expected_digest[16];        erl_errno = EIO;		/* Default */    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 21) {	EI_TRACE_ERR1("recv_challenge_reply",		      "<- RECV_CHALLENGE_REPLY socket read failed (%d)",rlen);	goto error;    }        s = buf;    if ((tag = get8(s)) != 'r') {	EI_TRACE_ERR2("recv_challenge_reply",		      "<- RECV_CHALLENGE_REPLY incorrect tag, "		      "expected 'r' got '%c' (%u)",tag,tag);	goto error;    }    *her_challenge = get32be(s);    memcpy(her_digest, s, 16);    gen_digest(our_challenge, cookie, (unsigned char*)expected_digest);    if (memcmp(her_digest, expected_digest, 16)) {	EI_TRACE_ERR0("recv_challenge_reply",		      "<- RECV_CHALLENGE_REPLY authorization failure");	goto error;    }    if (!is_static)	free(buf);    EI_TRACE_CONN2("recv_challenge_reply",		   "<- RECV_CHALLENGE_REPLY (ok) challenge = %u, digest = %s",		   *her_challenge,hex(her_digest));    erl_errno = 0;    return 0;    error:    if (!is_static)	free(buf);    return -1;}static int send_challenge_ack(int fd, unsigned char digest[16], unsigned ms) {    char *s;    char buf[DEFBUF_SIZ];    int siz = 2 + 1 + 16;    int res;    s = buf;        put16be(s,siz - 2);    put8(s, 'a');    memcpy(s, digest, 16);    if ((res = ei_write_fill_t(fd, buf, siz, ms)) != siz) {	EI_TRACE_ERR0("recv_challenge_reply",		      "-> SEND_CHALLENGE_ACK socket write failed");	erl_errno = (res == -2) ? ETIMEDOUT : EIO;	return -1;    }        EI_TRACE_CONN1("recv_challenge_reply",		   "-> SEND_CHALLENGE_ACK (ok) digest = %s",hex(digest));        return 0;}static int recv_challenge_ack(int fd, 			      unsigned our_challenge,			      char cookie[], unsigned ms){    char dbuf[DEFBUF_SIZ];    char *buf = dbuf;    int is_static = 1;    int buflen = DEFBUF_SIZ;    int rlen;    char *s;    char tag;    char her_digest[16], expected_digest[16];        erl_errno = EIO;		/* Default */    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) != 17) {	EI_TRACE_ERR1("recv_challenge_ack",		      "<- RECV_CHALLENGE_ACK socket read failed (%d)",rlen);	goto error;    }        s = buf;    if ((tag = get8(s)) != 'a') {	EI_TRACE_ERR2("recv_challenge_ack",		      "<- RECV_CHALLENGE_ACK incorrect tag, "		      "expected 'a' got '%c' (%u)",tag,tag);	goto error;    }    memcpy(her_digest, s, 16);    gen_digest(our_challenge, cookie, (unsigned char *)expected_digest);    if (memcmp(her_digest, expected_digest, 16)) {	EI_TRACE_ERR0("recv_challenge_ack",		      "<- RECV_CHALLENGE_ACK authorization failure");	goto error;    }    if (!is_static)	free(buf);    EI_TRACE_CONN1("recv_challenge_ack",		   "<- RECV_CHALLENGE_ACK (ok) digest = %s",hex(her_digest));    erl_errno = 0;    return 0;error:    if (!is_static)	free(buf);    return -1;}static int send_name(int fd, char *nodename, unsigned version, unsigned ms) {    return send_name_or_challenge(fd, nodename, 0, 0, version, ms);}static int send_challenge(int fd, char *nodename, 			  unsigned challenge, unsigned version, unsigned ms){    return send_name_or_challenge(fd, nodename, 1, challenge, version, ms);}static int recv_name(int fd, 		     unsigned *version,		     unsigned *flags, ErlConnect *namebuf, unsigned ms){    char dbuf[DEFBUF_SIZ];    char *buf = dbuf;    int is_static = 1;    int buflen = DEFBUF_SIZ;    int rlen;    char *s;    struct sockaddr_in sin;    int sin_len = sizeof(sin);    char tag;        erl_errno = EIO;		/* Default */    if ((rlen = read_2byte_package(fd, &buf, &buflen, &is_static, ms)) <= 0) {	EI_TRACE_ERR1("recv_name","<- RECV_NAME socket read failed (%d)",rlen);	goto error;    }    if ((rlen - 7) > MAXNODELEN) {	EI_TRACE_ERR1("recv_name","<- RECV_NAME nodename too long (%d)",rlen-7);	goto error;    }    s = buf;    tag = get8(s);    if (tag != 'n') {	EI_TRACE_ERR2("recv_name","<- RECV_NAME incorrect tag, "		      "expected 'n' got '%c' (%u)",tag,tag);	goto error;    }    *version = get16be(s);    *flags = get32be(s);    if (!(*flags & DFLAG_EXTENDED_REFERENCES)) {	EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot handle"		      "extended references");	goto error;    }    if (!(*flags & DFLAG_EXTENDED_PIDS_PORTS)	&& !ei_internal_use_r9_pids_ports()) {	EI_TRACE_ERR0("recv_name","<- RECV_NAME peer cannot "		      "handle extended pids and ports");	erl_errno = EIO;	goto error;    }	      if (getpeername(fd, (struct sockaddr *) &sin, &sin_len) < 0) {	EI_TRACE_ERR0("recv_name","<- RECV_NAME can't get peername");	erl_errno = errno;	goto error;    }    memcpy(namebuf->ipadr, &(sin.sin_addr.s_addr), 	sizeof(sin.sin_addr.s_addr));    memcpy(namebuf->nodename, s, rlen - 7);    namebuf->nodename[rlen - 7] = '\0';    if (!is_static)	free(buf);    EI_TRACE_CONN3("recv_name",		   "<- RECV_NAME (ok) node = %s, version = %u, flags = %u",		   namebuf->nodename,*version,*flags);    erl_errno = 0;    return 0;    error:    if (!is_static)	free(buf);    return -1;}/*************************************************************************** * *  Returns 1 on success and 0 on failure. * ***************************************************************************//* size is the buffer size, e.i. string length + 1 */static int get_home(char *buf, int size){    char* homedrive;    char* homepath;    #ifdef __WIN32__    homedrive = getenv("HOMEDRIVE");    homepath = getenv("HOMEPATH");#else    homedrive = "";    homepath = getenv("HOME");#endif        if (!homedrive || !homepath) {	buf[0] = '.';	buf[1] = '\0';	return 1;    } else if (strlen(homedrive)+strlen(homepath) < size-1) {	strcpy(buf, homedrive);	strcat(buf, homepath);	return 1;    }        return 0;}static int get_cookie(char *buf, int bufsize){    char fname[EI_MAX_HOME_PATH + sizeof(COOKIE_FILE) + 1];    int fd;    int len;    unsigned char next_c;        if (!get_home(fname, EI_MAX_HOME_PATH+1)) {	fprintf(stderr,"<ERROR> get_cookie: too long path to home");	return 0;    }    strcat(fname, COOKIE_FILE);    if ((fd = open(fname, O_RDONLY, 0777)) < 0) {	fprintf(stderr,"<ERROR> get_cookie: can't open cookie file");	return 0;    }        if ((len = read(fd, buf, bufsize-1)) < 0) {	fprintf(stderr,"<ERROR> get_cookie: reading cookie file");	close(fd);	return 0;    }    /* If more to read it is too long. Not 100% correct test but will do. */    if (read(fd, &next_c, 1) > 0 && !isspace(next_c)) {	fprintf(stderr,"<ERROR> get_cookie: cookie in %s is too long",fname);	close(fd);	return 0;    }    close(fd);    /* Remove all newlines after the first newline */    buf[len] = '\0';		/* Terminate string */    len = strcspn(buf,"\r\n");    buf[len] = '\0';		/* Terminate string again */    return 1;			/* Success! */}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?