static char sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************/
/*												*/
/*  akblib.c									*/
/*												*/
/*			coded by A.Kobayashi 2010.6.9		*/
/*												*/
/************************************************/
#include "akbcommon.h"

/********************************************************/
/*														*/
/********************************************************/
void akb_crt_err_packet(pPacket,iErrorCode)
pCommPackHead	pPacket;		/* 作成するエラーパケット */
int iErrorCode;
{
	short sErrorCode;

	/* エラーパケットの作成 */
	sErrorCode = iErrorCode;
	akb_exchg_indicate(pPacket);
	/* 処理ＩＤが０の方にエラーフラグを設定する */
	if (pPacket->cph_sinf.ind_thrd)
		pPacket->cph_dinf.ind_pano = htons(sErrorCode);
	else
		pPacket->cph_sinf.ind_pano = htons(sErrorCode);
}

/********************************************************/
/*														*/
/********************************************************/
int akb_is_packet(pH)
pCommPackHead pH;
{
	tdtCommPackHead Head,*pHead;
	char ver;
	int cmd_pack,akb_error,akb_opt,ret;

	ver = pH->cph_prt.prt_ver;
	pHead = pH;
	if (pHead->cph_sinf.ind_thrd) {	/* 発信パケット */
		akb_error = pHead->cph_dinf.ind_pano;
		akb_opt = pHead->cph_dinf.ind_disp;
		cmd_pack = 1;
	}
	else {	/* 返信パケット */
		akb_error = pHead->cph_sinf.ind_pano;
		akb_opt = pHead->cph_sinf.ind_disp;
		cmd_pack = 0;
	}
	ret = 0;
	/* エラーパケットか否かの検査 */
	if (akb_error) ret |= D_PACKET_IS_ERROR;	/* エラーパケット */
	if (akb_opt & AKB_AKO_NOREPLY) ret |= D_PACKET_IS_NOREPLY;
	if (akb_opt & AKB_AKO_ROUTED)  ret |= D_PACKET_IS_ROUTED;
	/* 発信パケットか否かの検査 */
	if (cmd_pack) {
		/* 発信パケット */
		ret |= D_PACKET_IS_SEND;
	} else {
		/* 返信パケット */
		ret |= D_PACKET_IS_RESEND;
	}
	return ret;
}

/********************************************************/
/*														*/
/********************************************************/
int akb_set_rb_pack_err_cd(iCh,pPacket,pRbCtl,iErrorCode)
int				iCh;			/* エラーパケットを送付するソケット */
pCommPackHead	pPacket;		/* 送付するエラーパケットの素 */
tdtRbCtl  *pRbCtl;
int  iErrorCode;
{
	pSdPacketTable  pNew ;
	int iRc;

	if (iCh < 0) return (-1);

	/* 対象となるパケットがエラーパケットか否かチェックする */
	iRc = akb_is_packet(pPacket);
	if (iRc & (D_PACKET_IS_ERROR | D_PACKET_IS_NOREPLY | D_PACKET_IS_BROADCAST)) {
		/* エラーパケットなので消滅させる */
		ERROROUT3("akb_set_rb_pack_err_cd:drop packet(%d) iCh=%d iErrorCode=%d",iRc,iCh,iErrorCode);
		return(iRc);
	}

	/* エラーパケットの作成 */
	akb_crt_err_packet(pPacket,iErrorCode);

	/* エラーパケットの送信 */
	pNew = akb_packet_tbl_new(0);
	if ( pNew == NULL ) {
       	return(D_ERR_MEM_ALLOC);
	}
	pNew->sp_content = (char *)pPacket;
	pNew->sp_len = sizeof(tdtCommPackHead) + ntohl(pPacket->cph_plen);
	pNew->sp_ch      = iCh ;
	pNew->sp_offset   = 0;
	if (!akxs_rb_set_n(pRbCtl,pNew)) {
		Free(pNew);
		return -1;
	}
	/* 正常終了 */
	return 0;
}

/********************************************************/
/*														*/
/********************************************************/
pSdPacketTable akb_packet_tbl_new(len)
int len;
{
	pSdPacketTable pNew;

	if (pNew=(pSdPacketTable)Malloc(sizeof(tdtRcSdPacketTable))) {
		memset(pNew,0,sizeof(tdtRcSdPacketTable));
		if (len > 0) {
			pNew->sp_len = len;
			if (!(pNew->sp_content = Malloc(len))) {
				Free(pNew);
				pNew = NULL;
			}
		}
	}
	return pNew;
}

/********************************************************/
/*														*/
/********************************************************/
int akb_exchg_indicate(pPacket)
pCommPackHead pPacket;
{
	tdtIndicate temp;

	memcpy(&temp,&pPacket->cph_sinf, sizeof(tdtIndicate) );
	memcpy(&pPacket->cph_sinf, &pPacket->cph_dinf, sizeof(tdtIndicate));
	memcpy(&pPacket->cph_dinf, &temp, sizeof(tdtIndicate));

	return 0;
}

/********************************************************/
/*														*/
/********************************************************/
int akb_get_host_addr(Hostname,ulpaddr_h)
char  *Hostname;
UINT4 *ulpaddr_h;
{
	struct hostent  *he;
	UINT4  taddr_n;
	char   szHostName[HOST_NAME_LEN],c,*host,*p;
	int    irc,len,n;

	len = 0;
	host = Hostname;
	if (host && (c=*host)) {
		if (c == '#') {
			if ((len = atoi(host+1)) < 0) len = 0;
		}
		else {
/* この処理はgethostbynameの中でやっているらしい
			if (*Hostname>='0' && *Hostname<='9') {
				if (ulpaddr_h) {
					taddr_n = inet_addr(Hostname);
					if ((INT4)taddr_n == -1) return -13;
					*ulpaddr_h = ntohl(taddr_n);
				}
				return 0;
			}
*/
			if (c == '[') {	/* for IPv6 Host addr */
				n = strlen(++host);
				if (*(p=host+n-1) == ']') p = '\0';
			}
			strnzcpy(szHostName,host,HOST_NAME_LEN-1);
			len = -1;
		}
	}
	if (len >= 0) {
		/* 自ホストＩＤを取得 */
		if (irc = gethostname(szHostName ,HOST_NAME_LEN)) {
			ERROROUT("gethostname failed");
			return -11;
		}
		if (len > 0) strnzcpy(Hostname,szHostName,len-1);
	}
	if (ulpaddr_h) {
		/* ホスト名に対するＩＰアドレスを得る */
DEBUGOUT("gethostbyname");
		if (!(he = gethostbyname(szHostName))) {
			ERROROUT1("hostname(%s) not found in etc/hosts",szHostName);
			return -12;
		}
		memcpy((char *) &taddr_n, he->h_addr, he->h_length);
		*ulpaddr_h = ntohl(taddr_n);
	}
	return 0;
}

/********************************************************/
/*														*/
/********************************************************/
int akb_error_code(iError,ipErrInfo)
int iError,*ipErrInfo;
{
	int iEr,iErU;

	if ((iEr=iError) < 0) iEr = -iEr;

	iErU = iEr / 10000;
	if (ipErrInfo) *ipErrInfo = iErU;

	if (iErU>=1 && iErU<=3) {
		iEr %= 10000;
		if (iEr <= 999) {
			iEr += 9000;
			if (iError < 0) iEr = -iEr;
			return iEr;
		}
	}

	return iError;
}

/********************************************************/
/*														*/
/********************************************************/
typedef struct {
	int err_no;
	char *errmsg;
} tdtErrMsgTbl;

static tdtErrMsgTbl errmsgtbl[]=
	{0 ,"No error"
	,D_ERR_PACKET_ID		,ERRMSG_PACKET_ID
	,D_ERR_NO_PASSWORD		,ERRMSG_NO_PASSWORD
	,D_ERR_UNKNOWN_CMD		,ERRMSG_UNKNOWN_CMD
	,D_ERR_UNKNOWN_CLASS	,ERRMSG_UNKNOWN_CLASS
	,D_ERR_NO_PROCESS		,ERRMSG_NO_PROCESS
	,D_ERR_RCO_RECVPROC		,ERRMSG_NOT_RECVPROC
	,D_ERR_MEM_ALLOC		,ERRMSG_MEM_ALLOC
	,D_ERR_FORM_CHANGE		,ERRMSG_FORM_CHANGE
	,D_ERR_SOCKET_CLOSED	,ERRMSG_SOCKET_CLOSED
	,D_ERR_SHUT_MODE		,ERRMSG_SHUT_MODE
	,D_ERR_SHUT_WAKEUP		,ERRMSG_SHUT_WAKEUP
	,D_ERR_MSG_TIMEOUT		,ERRMSG_MSG_TIMEOUT
	,D_ERR_NO_NETM			,ERRMSG_NO_NETM
	,0 ,NULL
	};

char *akb_str_error(err_no)
int err_no;
{
	int err;
	tdtErrMsgTbl *e;
	char *msg;

	err = akb_error_code(err_no,NULL);
	for (e=&errmsgtbl[0];msg=e->errmsg;e++) {
		if (err == e->err_no) {
			return msg;
		}
	}
	return "";
}

/********************************************************/
/*														*/
/********************************************************/
int akb_get_text_addr4(in, buf, len)
struct in_addr in;
char *buf;
int  len;
{
	char *p;

	if (!buf || len<=0) return -1;
	if (p = inet_ntoa(in)) {
		strnzcpy(buf,p,len-1);
	}
	else {
		*buf = '\0';
		return -2;
	}
	return 0;
}
