コード例 #1
0
/* callback when the "open" command has been processed
 * Most importantly, this function needs to check if we are
 * compatible with the server-provided offers and terminate if
 * not. If we are, we must set our own parameters to match the
 * server-provided ones. Please note that the offer processing here
 * is the last and final. So the ultimate decision is made and if we
 * are unhappy with something that we can not ignore, we must
 * terminate with an error status.
 * In such cases, we flag the session as broken, as theoretically
 * it is possible to fix it by restarting the server with a set
 * of different parameters. The question remains, though, if that's
 * the smartest route to take...
 * Note that offer-processing is very similiar to offer-processing
 * at the server end (copen.c). We may be able to combine some of
 * it in the future (or may not, depending on the subtly different
 * needs both parts have. For now I leave this to a ... TODO ;)).
 * rgerhards, 2008-03-25
 */
static relpRetVal
relpSessCBrspOpen(relpSess_t *pThis, relpFrame_t *pFrame)
{
	relpEngine_t *pEngine;
	relpOffers_t *pOffers = NULL;
	relpOffer_t *pOffer;
	relpOfferValue_t *pOfferVal;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	RELPOBJ_assert(pFrame, Frame);
	pEngine = pThis->pEngine;

	/* first get the offers list from the server response */
	CHKRet(relpOffersConstructFromFrame(&pOffers, pFrame));

	/* we loop through the offers and set session parameters. If we find
	 * something truely unacceptable, we break the session.
	 */
	for(pOffer = pOffers->pRoot ; pOffer != NULL ; pOffer = pOffer->pNext) {
		pEngine->dbgprint("processing server offer '%s'\n", pOffer->szName);
		if(!strcmp((char*)pOffer->szName, "relp_version")) {
			if(pOffer->pValueRoot == NULL)
				ABORT_FINALIZE(RELP_RET_INVALID_OFFER);
			if(pOffer->pValueRoot->intVal == -1)
				ABORT_FINALIZE(RELP_RET_INVALID_OFFER);
			if(pOffer->pValueRoot->intVal > pEngine->protocolVersion)
				ABORT_FINALIZE(RELP_RET_INCOMPAT_OFFERS);
			/* Once we support multiple versions, we may need to check what we
			 * are compatible with. For now, we accept anything, because there is
			 * nothing else yet ;)
			 */
			relpSessSetProtocolVersion(pThis, pOffer->pValueRoot->intVal);
		} else if(!strcmp((char*)pOffer->szName, "commands")) {
			for(pOfferVal = pOffer->pValueRoot ; pOfferVal != NULL ; pOfferVal = pOfferVal->pNext) {
				/* we do not care about return code in this case */
				relpSessSetEnableCmd(pThis, pOfferVal->szVal, eRelpCmdState_Enabled);
				pEngine->dbgprint("enabled command '%s'\n", pOfferVal->szVal);
			}
		} else if(!strcmp((char*)pOffer->szName, "relp_software")) {
			/* we know this parameter, but we do not do anything
			 * with it -- this may change if we need to emulate
			 * something based on known bad relp software behaviour.
			 */
		} else {
			/* if we do not know an offer name, we ignore it - in this
			 * case, we may simply not support it (but the client does and
			 * must now live without it...)
			 */
			pEngine->dbgprint("ignoring unknown server offer '%s'\n", pOffer->szName);
		}
	}
	relpSessSetSessState(pThis, eRelpSessState_INIT_RSP_RCVD);

finalize_it:
	if(pOffers != NULL)
		relpOffersDestruct(&pOffers);

	LEAVE_RELPFUNC;
}
コード例 #2
0
/* add an entry to our unacked frame list. The sendbuf object is handed over and must
 * no longer be accessed by the caller.
 * NOTE: we do not need mutex locks. This changes when we have a background transfer
 * thread (which we currently do not have).
 * rgerhards, 2008-03-20
 */
relpRetVal
relpSessAddUnacked(relpSess_t *pThis, relpSendbuf_t *pSendbuf)
{
	relpSessUnacked_t *pUnackedLstEntry;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	RELPOBJ_assert(pSendbuf, Sendbuf);

	if((pUnackedLstEntry = calloc(1, sizeof(relpSessUnacked_t))) == NULL)
		ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);

	pUnackedLstEntry->pSendbuf = pSendbuf;

	DLL_Add(pUnackedLstEntry, pThis->pUnackedLstRoot, pThis->pUnackedLstLast);
	++pThis->lenUnackedLst;

	if(pThis->lenUnackedLst >= pThis->sizeWindow) {
		/* in theory, we would need to check if the session is initialized, as
		 * we would mess up session state in that case. However, as the init
		 * process is just one frame, we can never run into the situation that
		 * the window is exhausted during init, so we do not check it.
		 */
		relpSessSetSessState(pThis, eRelpSessState_WINDOW_FULL);
		if(pThis->lenUnackedLst >= pThis->sizeWindow)
			pThis->pEngine->dbgprint("Warning: exceeding window size, max %d, curr %d\n",
						 pThis->lenUnackedLst, pThis->sizeWindow);
	}
	pThis->pEngine->dbgprint("ADD sess %p unacked %d, sessState %d\n", pThis, pThis->lenUnackedLst, pThis->sessState);

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #3
0
ファイル: sendbuf.c プロジェクト: methodmissing/librelp
/* This functions sends a complete sendbuf (a blocking call). It
 * is intended for use by clients. Do NOT use it on servers as
 * that will block other activity. bAddToUnacked specifies if the
 * sendbuf should be linked to the unacked list (if 1). If it is 0
 * this shall NOT happen. Mode 0 is used for session reestablishment,
 * when the unacked list needs to be retransmitted.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSendbufSendAll(relpSendbuf_t *pThis, relpSess_t *pSess, int bAddToUnacked)
{
	ssize_t lenToWrite;
	ssize_t lenWritten;
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sendbuf);
	RELPOBJ_assert(pSess,  Sess);

	lenToWrite = pThis->lenData - pThis->bufPtr;
	while(lenToWrite != 0) {
		lenWritten = lenToWrite;
//pSess->pEngine->dbgprint("sendbuf len %d, still to write %d\n", (int) pThis->lenData, (int) lenToWrite);
		CHKRet(relpTcpSend(pSess->pTcp, pThis->pData + (9 - pThis->lenTxnr) + pThis->bufPtr, &lenWritten));

		if(lenWritten == -1) {
			ABORT_FINALIZE(RELP_RET_IO_ERR);
		} else if(lenWritten == lenToWrite) {
			lenToWrite = 0;
		} else {
			pThis->bufPtr += lenWritten;
			lenToWrite = pThis->lenData - pThis->bufPtr;
		}
	}

	/* ok, we now have sent the full buf. So we now need to add it to the unacked list, so that
	 * we know what to do when the "rsp" packet comes in. -- rgerhards, 2008-03-20
	 */
	if(bAddToUnacked) {
		if((iRet = relpSessAddUnacked(pSess, pThis)) != RELP_RET_OK) {
			relpSendbufDestruct(&pThis);
			FINALIZE;
		}
pSess->pEngine->dbgprint("sendbuf added to unacked list\n");
#if 0
{
	relpSessUnacked_t *pUnackedEtry;
	pUnackedEtry = pThis->pUnackedLstRoot;
	if(pUnackedEtry != NULL) {
pThis->pEngine->dbgprint("resending frame '%s'\n", pUnackedEtry->pSendbuf->pData + 9 - pUnackedEtry->pSendbuf->lenTxnr);
		CHKRet(relpFrameRewriteTxnr(pUnackedEtry->pSendbuf, pThis->txnr));
		pThis->txnr = relpEngineNextTXNR(pThis->txnr);
		CHKRet(relpSendbufSendAll(pUnackedEtry->pSendbuf, pThis, 0));
		pUnackedEtry = pUnackedEtry->pNext;
	}
}
#endif
	}
else pSess->pEngine->dbgprint("sendbuf NOT added to unacked list\n");

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #4
0
ファイル: relpclt.c プロジェクト: methodmissing/librelp
/** Try to reconnect a broken session to the remote
 * server. The main difference to relpCltConnect() is that the
 * session object is already existing and session parameters (like
 * remote host) can not be changed.
 * rgerhards, 2008-03-23
 */
relpRetVal
relpCltReconnect(relpClt_t *pThis)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Clt);
	RELPOBJ_assert(pThis->pSess, Sess);

	CHKRet(relpSessTryReestablish(pThis->pSess));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #5
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* This accepts a new session, and, if all goes well, constructs a new
 * session object and adds it to the engine's list of sessions.
 * rgerhards, 2008-03-17
 */
relpRetVal
relpSessAcceptAndConstruct(relpSess_t **ppThis, relpSrv_t *pSrv, int sock)
{
	relpSess_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	RELPOBJ_assert(pSrv, Srv);
	assert(sock >= 0);

	CHKRet(relpSessConstruct(&pThis, pSrv->pEngine, pSrv));
	CHKRet(relpTcpAcceptConnReq(&pThis->pTcp, sock, pThis->pEngine));

	/* TODO: check hostname against ACL (callback?) */
	/* TODO: check against max# sessions */

	*ppThis = pThis;

finalize_it:
pSrv->pEngine->dbgprint("relp session accepted with state %d\n", iRet);
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL)
			relpSessDestruct(&pThis);
	}

	LEAVE_RELPFUNC;
}
コード例 #6
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* Send a command to the server.
 * The is the "regular" function which ensures that server messages are received
 * and messages are only sent when we have space left in our window. This function
 * must only be called after the session is fully initialized. Calling it before
 * initialization is finished will probably hang the client.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessSendCommand(relpSess_t *pThis, unsigned char *pCmd, size_t lenCmd,
		    unsigned char *pData, size_t lenData, relpRetVal (*rspHdlr)(relpSess_t*,relpFrame_t*))
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	/* this both reads server responses as well as makes sure we have space left
	 * in our window. We provide a nearly eternal timeout (3 minutes). If we are not
	 * ready to send in that period, something is awfully wrong. TODO: we may want
	 * to make this timeout configurable, but I don't think it is a priority.
	 */
	//CHKRet(relpSessWaitState(pThis, eRelpSessState_READY_TO_SEND, 2));
	CHKRet(relpSessWaitState(pThis, eRelpSessState_READY_TO_SEND, 180));

	/* re-try once if automatic retry mode is set */
pThis->pEngine->dbgprint("send command relp sess state %d\n", pThis->sessState);
	if(pThis->bAutoRetry && pThis->sessState == eRelpSessState_BROKEN) {
pThis->pEngine->dbgprint("SendCommand does auto-retry\n");
		CHKRet(relpSessTryReestablish(pThis));
	}

pThis->pEngine->dbgprint("sendcommand ready to send, relp sess state %d\n", pThis->sessState);
	/* then send our data */
	if(pThis->sessState == eRelpSessState_BROKEN)
		ABORT_FINALIZE(RELP_RET_SESSION_BROKEN);

	CHKRet(relpSessRawSendCommand(pThis, pCmd, lenCmd, pData, lenData, rspHdlr));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #7
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* Try to restablish a broken session. A single try is made and the result
 * reported back. RELP_RET_OK if we could get a new session, a RELP error state
 * otherwise (e.g. RELP_RET_SESSION_BROKEN, but could also be a more precise
 * error code). If the session can be re-established, any unsent frames are
 * resent. The function returns only after that happened.
 * rgerhards, 2008-03-22
 */
relpRetVal
relpSessTryReestablish(relpSess_t *pThis)
{
	relpSessUnacked_t *pUnackedEtry;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	assert(pThis->sessState = eRelpSessState_BROKEN);

	CHKRet(relpTcpAbortDestruct(&pThis->pTcp));
	CHKRet(relpSessConnect(pThis, pThis->protFamily, pThis->srvPort, pThis->srvAddr));
	/* if we reach this point, we could re-establish the session. We now
	 * need to resend any unacked data. Note that we need to patch in new txnr's
	 * into the existing frames. We need to do a special send command, as the usual
	 * one would maintain the unacked list, what we can not do right now (because
	 * it is not to be modified.
	 */
	pUnackedEtry = pThis->pUnackedLstRoot;
	if(pUnackedEtry != NULL)
		pThis->pEngine->dbgprint("relp session %p reestablished, now resending %d unacked frames\n",
					  pThis, pThis->lenUnackedLst);
	while(pUnackedEtry != NULL) {
pThis->pEngine->dbgprint("resending frame '%s'\n", pUnackedEtry->pSendbuf->pData + 9 - pUnackedEtry->pSendbuf->lenTxnr);
		CHKRet(relpFrameRewriteTxnr(pUnackedEtry->pSendbuf, pThis->txnr));
		pThis->txnr = relpEngineNextTXNR(pThis->txnr);
		CHKRet(relpSendbufSendAll(pUnackedEtry->pSendbuf, pThis, 0));
		pUnackedEtry = pUnackedEtry->pNext;
	}

finalize_it:
pThis->pEngine->dbgprint("after TryReestablish, sess state %d\n", pThis->sessState);
	LEAVE_RELPFUNC;
}
コード例 #8
0
/* Send a command to the server.
 * The is the "regular" function which ensures that server messages are received
 * and messages are only sent when we have space left in our window. This function
 * must only be called after the session is fully initialized. Calling it before
 * initialization is finished will probably hang the client.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessSendCommand(relpSess_t *pThis, unsigned char *pCmd, size_t lenCmd,
		    unsigned char *pData, size_t lenData, relpRetVal (*rspHdlr)(relpSess_t*,relpFrame_t*))
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	/* this both reads server responses as well as makes sure we have space
	 * left in our window.
	 */
	CHKRet(relpSessWaitState(pThis, eRelpSessState_READY_TO_SEND,
		pThis->timeout));

	/* re-try once if automatic retry mode is set */
	if(pThis->bAutoRetry && pThis->sessState == eRelpSessState_BROKEN) {
		CHKRet(relpSessTryReestablish(pThis));
	}

	/* then send our data */
	if(pThis->sessState == eRelpSessState_BROKEN)
		ABORT_FINALIZE(RELP_RET_SESSION_BROKEN);

	CHKRet(relpSessRawSendCommand(pThis, pCmd, lenCmd, pData, lenData, rspHdlr));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #9
0
/* Send a response to the client.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessSendResponse(relpSess_t *pThis, relpTxnr_t txnr, unsigned char *pData, size_t lenData)
{
	relpSendbuf_t *pSendbuf;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	CHKRet(relpFrameBuildSendbuf(&pSendbuf, txnr, (unsigned char*)"rsp", 3,
				     pData, lenData, pThis, NULL));
	/* now enqueue it to the sendq (which means "send it" ;)) */
	CHKRet(relpSendqAddBuf(pThis->pSendq, pSendbuf, pThis->pTcp));

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(iRet == RELP_RET_IO_ERR) {
			pThis->pEngine->dbgprint("relp session %p is broken, io error\n", pThis);
			pThis->sessState = eRelpSessState_BROKEN;
			}

		if(pSendbuf != NULL)
			relpSendbufDestruct(&pSendbuf);
	}

	LEAVE_RELPFUNC;
}
コード例 #10
0
ファイル: offers.c プロジェクト: davidelang/librelp
/* Construct an offer with name pszName and add it to the offers list.
 * The offer object is returned to the caller. It is read-only and MUST NOT
 * be destructed.
 * rgerhards, 2008-03-24
 */
relpRetVal
relpOfferAdd(relpOffer_t **ppThis, unsigned char *pszName, relpOffers_t *pOffers)
{
	relpOffer_t *pThis = NULL;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	assert(pszName != NULL);
	RELPOBJ_assert(pOffers, Offers);

	CHKRet(relpOfferConstruct(&pThis, pOffers->pEngine));
	strncpy((char*)pThis->szName, (char*)pszName, sizeof(pThis->szName));
	pThis->pNext = pOffers->pRoot;
	pOffers->pRoot = pThis;

	*ppThis = pThis;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL)
			relpOfferDestruct(&pThis);
	}

	LEAVE_RELPFUNC;
}
コード例 #11
0
/* Delete an entry from our unacked list. The list entry is destructed, but
 * the sendbuf not.
 * rgerhards, 2008-03-20
 */
static relpRetVal
relpSessDelUnacked(relpSess_t *pThis, relpSessUnacked_t *pUnackedLstEntry)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	assert(pUnackedLstEntry != NULL);

	DLL_Del(pUnackedLstEntry, pThis->pUnackedLstRoot, pThis->pUnackedLstLast);
	--pThis->lenUnackedLst;

	if(   pThis->lenUnackedLst < pThis->sizeWindow
	   && relpSessGetSessState(pThis) == eRelpSessState_WINDOW_FULL) {
		/* here, we need to check if we had WINDOW_FULL condition. The reason is that
		 * we otherwise mess up the session init handling - contrary to ...AddUnacked(),
		 * we run into the situation of a session state change on init. So we
		 * need to make sure it works.
		 */
		relpSessSetSessState(pThis, eRelpSessState_READY_TO_SEND);
	}

	free(pUnackedLstEntry);

	pThis->pEngine->dbgprint("DEL sess %p unacked %d, sessState %d\n", pThis, pThis->lenUnackedLst, pThis->sessState);
	LEAVE_RELPFUNC;
}
コード例 #12
0
ファイル: offers.c プロジェクト: davidelang/librelp
/** Destruct a RELP offers list
 * rgerhards, 2008-03-24
 */
relpRetVal
relpOffersDestruct(relpOffers_t **ppThis)
{
	relpOffers_t *pThis;
	relpOffer_t *pOffer;
	relpOffer_t *pOfferToDel;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	pThis = *ppThis;
	RELPOBJ_assert(pThis, Offers);

	pOffer = pThis->pRoot;
	while(pOffer != NULL) {
		pOfferToDel = pOffer;
		pOffer = pOffer->pNext;
		relpOfferDestruct(&pOfferToDel);
	}

	/* done with de-init work, now free offers object itself */
	free(pThis);
	*ppThis = NULL;

	LEAVE_RELPFUNC;
}
コード例 #13
0
/** Destruct a RELP sess instance
 */
relpRetVal
relpSessDestruct(relpSess_t **ppThis)
{
	relpSess_t *pThis;
	relpSessUnacked_t *pUnacked;
	relpSessUnacked_t *pUnackedToDel;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	pThis = *ppThis;
	RELPOBJ_assert(pThis, Sess);

	/* pTcp may be NULL if we run into the destructor due to an error that occured
	 * during construction.
	 */
	if(pThis->pTcp != NULL) {
		if(pThis->pSrv != NULL) {
			relpSessSrvDoDisconnect(pThis);
		} else {
			/* we are at the client side of the connection */
			if(   pThis->sessState != eRelpSessState_DISCONNECTED
			   && pThis->sessState != eRelpSessState_BROKEN) {
				relpSessCltDoDisconnect(pThis);
			}
		}
	}

	if(pThis->pSendq != NULL)
		relpSendqDestruct(&pThis->pSendq);
	if(pThis->pTcp != NULL)
		relpTcpDestruct(&pThis->pTcp);

	/* unacked list */
	for(pUnacked = pThis->pUnackedLstRoot ; pUnacked != NULL ; ) {
		pUnackedToDel = pUnacked;
		pUnacked = pUnacked->pNext;
		relpSendbufDestruct(&pUnackedToDel->pSendbuf);
		free(pUnackedToDel);
	}

	free(pThis->srvPort);
	free(pThis->srvAddr);
	free(pThis->clientIP);
	free(pThis->pristring);
	free(pThis->ownCertFile);
	free(pThis->privKeyFile);
	relpSessFreePermittedPeers(pThis);

	pthread_mutex_destroy(&pThis->mutSend);
	/* done with de-init work, now free object itself */
	free(pThis);
	*ppThis = NULL;

	LEAVE_RELPFUNC;
}
コード例 #14
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* actually send to the remote peer
 * This function takes data from the sendq and sends as much as
 * possible to the remote peer.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessSndData(relpSess_t *pThis)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	CHKRet(relpSendqSend(pThis->pSendq, pThis->pTcp));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #15
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* Connect to the server. All session parameters (like remote address) must
 * already have been set.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessConnect(relpSess_t *pThis, int protFamily, unsigned char *port, unsigned char *host)
{
	relpOffers_t *pOffers;
	unsigned char *pszOffers = NULL;
	size_t lenOffers;
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	CHKRet(relpSessFixCmdStates(pThis));
	if(pThis->srvAddr == NULL) { /* initial connect, need to save params */
		pThis->protFamily = protFamily;
		if((pThis->srvPort = (unsigned char*) strdup((char*)port)) == NULL)
			ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
		if((pThis->srvAddr = (unsigned char*) strdup((char*)host)) == NULL)
			ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
	}

	/* (re-)init some counters */
	pThis->txnr = 1;
	pThis->sessType = eRelpSess_Client;	/* indicate we have a client session */

	CHKRet(relpTcpConstruct(&pThis->pTcp, pThis->pEngine));
	CHKRet(relpTcpConnect(pThis->pTcp, protFamily, port, host));
	relpSessSetSessState(pThis, eRelpSessState_PRE_INIT);

	/* create offers */
	CHKRet(relpSessConstructOffers(pThis, &pOffers));
	CHKRet(relpOffersToString(pOffers, NULL, 0, &pszOffers, &lenOffers));
	CHKRet(relpOffersDestruct(&pOffers));

	CHKRet(relpSessRawSendCommand(pThis, (unsigned char*)"open", 4, pszOffers, lenOffers,
				      relpSessCBrspOpen));
	relpSessSetSessState(pThis, eRelpSessState_INIT_CMD_SENT);
	CHKRet(relpSessWaitState(pThis, eRelpSessState_INIT_RSP_RCVD, pThis->timeout));

	/* we now have received the server's response. Now is a good time to check if the offers
	 * received back are compatible with what we need - and, if not, terminate the session...
	 */
pThis->pEngine->dbgprint("pre CltConnChkOffers %d\n", iRet);
	CHKRet(relpSessCltConnChkOffers(pThis));
	/* TODO: flag sesssion as broken if we did not succeed? */

	/* if we reach this point, we have a valid relp session */
	relpSessSetSessState(pThis, eRelpSessState_READY_TO_SEND); /* indicate session startup */

finalize_it:
pThis->pEngine->dbgprint("end relpSessConnect, iRet %d\n", iRet);
	if(pszOffers != NULL)
		free(pszOffers);

	LEAVE_RELPFUNC;
}
コード例 #16
0
/* actually send to the remote peer
 * This function takes data from the sendq and sends as much as
 * possible to the remote peer.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSessSndData(relpSess_t *pThis)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	if (pThis->sessState != eRelpSessState_BROKEN) {
		CHKRet(relpSendqSend(pThis->pSendq, pThis->pTcp));
	}

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #17
0
ファイル: sendbuf.c プロジェクト: methodmissing/librelp
/* set send buffer contents. The provided data pointer is handed *over* to
 * the sendbuf, so the caller can no longer access it. Most importantly, the
 * caller MUST NOT free the buffer!
 * rgerhards, 2008-03-17
 */
relpRetVal
relpSendbufSetData(relpSendbuf_t *pThis, relpOctet_t *pData, size_t lenData)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Engine);
	assert(pData != NULL);
	assert(lenData > 0);

	pThis->pData = pData;
	pThis->lenData = lenData;
	pThis->bufPtr = 0;

	LEAVE_RELPFUNC;
}
コード例 #18
0
ファイル: sendbuf.c プロジェクト: methodmissing/librelp
/* Sends as much data from the send buffer as possible.
 * This function tries to send as much data from the send buffer
 * as possible. For partial writes, the sendbuffer is updated to
 * contain the correct "already written" count.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpSendbufSend(relpSendbuf_t *pThis, relpTcp_t *pTcp)
{
	ssize_t lenToWrite;
	ssize_t lenWritten;
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sendbuf);
	RELPOBJ_assert(pTcp,  Tcp);

	lenToWrite = pThis->lenData - pThis->bufPtr;
	lenWritten = lenToWrite;
//pTcp->pEngine->dbgprint("sendbuf len %d, still to write %d\n", (int) pThis->lenData, (int) lenToWrite);

	CHKRet(relpTcpSend(pTcp, pThis->pData + (9 - pThis->lenTxnr) + pThis->bufPtr, &lenWritten));

	if(lenWritten != lenToWrite) {
		pThis->bufPtr += lenWritten;
		iRet = RELP_RET_PARTIAL_WRITE;
	}

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #19
0
/* Check if the set of offers inclulded in our session is compatible with
 * what we need. By now, all session parameters should be set to enabled. If
 * there are some left as "Required", they are not supported by the server,
 * in which case we can not open the session. -- rgerhards, 2008-03-27
 */
relpRetVal
relpSessCltConnChkOffers(relpSess_t *pThis)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	if(pThis->stateCmdSyslog == eRelpCmdState_Required)
		ABORT_FINALIZE(RELP_RET_RQD_FEAT_MISSING);

finalize_it:
	if(iRet != RELP_RET_OK)
		pThis->sessState = eRelpSessState_BROKEN;

	LEAVE_RELPFUNC;
}
コード例 #20
0
/** Construct a RELP sess instance
 *  the pSrv parameter may be set to NULL if the session object is for a client.
 */
relpRetVal
relpSessConstruct(relpSess_t **ppThis, relpEngine_t *pEngine, int connType, void *pParent)
{
	relpSess_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	RELPOBJ_assert(pEngine, Engine);

	if((pThis = calloc(1, sizeof(relpSess_t))) == NULL) {
		ABORT_FINALIZE(RELP_RET_OUT_OF_MEMORY);
	}

	RELP_CORE_CONSTRUCTOR(pThis, Sess);
	pThis->pEngine = pEngine;
	/* use Engine's command enablement states as default */
	pThis->stateCmdSyslog = pEngine->stateCmdSyslog;
	if(connType == RELP_SRV_CONN) {
		pThis->pSrv = (relpSrv_t*) pParent;
	} else {
		pThis->pClt = (relpClt_t*) pParent;
	}
	pThis->txnr = 1; /* txnr start at 1 according to spec */
	pThis->timeout = 90;
	pThis->pUsr = NULL;
	pThis->sizeWindow = RELP_DFLT_WINDOW_SIZE;
	pThis->maxDataSize = RELP_DFLT_MAX_DATA_SIZE;
	pThis->authmode = eRelpAuthMode_None;
	pThis->pristring = NULL;
	pThis->caCertFile = NULL;
	pThis->ownCertFile = NULL;
	pThis->privKeyFile = NULL;
	pThis->permittedPeers.nmemb = 0;

	CHKRet(relpSendqConstruct(&pThis->pSendq, pThis->pEngine));
	pthread_mutex_init(&pThis->mutSend, NULL);

	*ppThis = pThis;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL) {
			relpSessDestruct(&pThis);
		}
	}

	LEAVE_RELPFUNC;
}
コード例 #21
0
ファイル: offers.c プロジェクト: davidelang/librelp
/** Destruct a RELP offer value instance
 * rgerhards, 2008-03-24
 */
static relpRetVal
relpOfferValueDestruct(relpOfferValue_t **ppThis)
{
	relpOfferValue_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	pThis = *ppThis;
	RELPOBJ_assert(pThis, OfferValue);

	/* done with de-init work, now free offers object itself */
	free(pThis);
	*ppThis = NULL;

	LEAVE_RELPFUNC;
}
コード例 #22
0
/* Disconnect from the client. After disconnect, the session object
 * is destructed. This is the server-side disconnect and must be called
 * for server sessions only.
 * rgerhards, 2008-03-31
 */
static relpRetVal
relpSessSrvDoDisconnect(relpSess_t *pThis)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	/* Try to hint the client that we are closing the session. If the hint does
	 * not make it through to the client, that's ok, too. Then, it'll notice when it
	 * tries to use the connection. In any case, it can handle that (but obviously its
	 * better if the client is able to receive the hint, as this cleans up things a bit
	 * faster).
	 */
	CHKRet(relpSessSrvSendHint(pThis, (unsigned char*)"serverclose", 11, (unsigned char*)"", 0));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #23
0
ファイル: relpclt.c プロジェクト: methodmissing/librelp
/** open a relp session to a remote peer
 * remote servers parameters must already have been set.
 * rgerhards, 2008-03-19
 */
relpRetVal
relpCltConnect(relpClt_t *pThis, int protFamily, unsigned char *port, unsigned char *host)
{
	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Clt);

	CHKRet(relpSessConstruct(&pThis->pSess, pThis->pEngine, NULL));
	CHKRet(relpSessConnect(pThis->pSess, protFamily, port, host));

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis->pSess != NULL) {
			relpSessDestruct(&pThis->pSess);
		}
	}

	LEAVE_RELPFUNC;
}
コード例 #24
0
ファイル: offers.c プロジェクト: davidelang/librelp
/* Construct a offer value with pszVal and add it to the offer value
 * list. This function also checks if the value is an integer and, if so,
 * sets the integer value. If no string pointer is provided, the integer
 * value is added. The integer is ignored if a string pointer is present.
 * rgerhards, 2008-03-24
 */
relpRetVal
relpOfferValueAdd(unsigned char *pszVal, int intVal, relpOffer_t *pOffer)
{
	relpOfferValue_t *pThis = NULL;
	int i;
	int Val;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pOffer, Offer);

	CHKRet(relpOfferValueConstruct(&pThis, pOffer->pEngine));

	/* check which value we need to use */
	if(pszVal == NULL) {
		snprintf((char*)pThis->szVal, sizeof(pThis->szVal), "%d", intVal);
		pThis->intVal = intVal;
	} else {
		strncpy((char*)pThis->szVal, (char*)pszVal, sizeof(pThis->szVal));
		/* check if the string actually is an integer... */
		Val = 0;
		i = 0;
		while(pszVal[i]) {
			if(isdigit(pszVal[i]))
				Val = Val * 10 + pszVal[i] - '0';
			else
				break;
			++i;
		}
		if(pszVal[i] != '\0')
			Val = -1; /* no (unsigned!) integer! */
		pThis->intVal = Val;
	}

	pThis->pNext = pOffer->pValueRoot;
	pOffer->pValueRoot = pThis;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL)
			relpOfferValueDestruct(&pThis);
	}

	LEAVE_RELPFUNC;
}
コード例 #25
0
ファイル: relpsess.c プロジェクト: methodmissing/librelp
/* Send a command hint to the remote peer. This function works for the 
 * server-side of the connection. A modified version must be used for the
 * client side (because we have different ways of sending the data). We do
 * not yet need the client side. If we do, way should think about a generic
 * approach, eg by using function pointers for the send function.
 * rgerhards, 2008-03-31
 */
static relpRetVal
relpSessSrvSendHint(relpSess_t *pThis, unsigned char *pHint, size_t lenHint,
		    unsigned char *pData, size_t lenData)
{
	relpSendbuf_t *pSendbuf;

	ENTER_RELPFUNC;
	assert(pHint != NULL);
	assert(lenHint != 0);
	RELPOBJ_assert(pThis, Sess);

	CHKRet(relpFrameBuildSendbuf(&pSendbuf, 0, pHint, lenHint, pData, lenData, pThis, NULL));
	/* now send it */
pThis->pEngine->dbgprint("hint-frame to send: '%s'\n", pSendbuf->pData + (9 - pSendbuf->lenTxnr));
	CHKRet(relpSendbufSend(pSendbuf, pThis->pTcp));

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #26
0
ファイル: relpclt.c プロジェクト: methodmissing/librelp
/** Destruct a RELP clt instance
 */
relpRetVal
relpCltDestruct(relpClt_t **ppThis)
{
	relpClt_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	pThis = *ppThis;
	RELPOBJ_assert(pThis, Clt);

	if(pThis->pSess != NULL)
		relpSessDestruct(&pThis->pSess);

	/* done with de-init work, now free clt object itself */
	free(pThis);
	*ppThis = NULL;

	LEAVE_RELPFUNC;
}
コード例 #27
0
ファイル: sendbuf.c プロジェクト: methodmissing/librelp
/** Destruct a RELP sendbuf instance
 */
relpRetVal
relpSendbufDestruct(relpSendbuf_t **ppThis)
{
	relpSendbuf_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	pThis = *ppThis;
	RELPOBJ_assert(pThis, Sendbuf);
pThis->pSess->pEngine->dbgprint("in destructor: sendbuf %p\n", pThis);

	if(pThis->pData != NULL)
		free(pThis->pData);

	/* done with de-init work, now free sendbuf object itself */
	free(pThis);
	*ppThis = NULL;

	LEAVE_RELPFUNC;
}
コード例 #28
0
/* receive data from a socket
 * The following function is called when the relp engine has detected
 * that data is available on the socket. This function reads the available
 * data and submits it for processing.
 * rgerhards, 2008-03-17
 */
relpRetVal
relpSessRcvData(relpSess_t *pThis)
{
	relpOctet_t rcvBuf[RELP_RCV_BUF_SIZE+1];
	ssize_t lenBuf;
	ssize_t i;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);

	lenBuf = RELP_RCV_BUF_SIZE;
	CHKRet(relpTcpRcv(pThis->pTcp, rcvBuf, &lenBuf));

	if(lenBuf == 0) {
		pThis->pEngine->dbgprint("server closed relp session %p, session broken\n", pThis);
		/* even though we had a "normal" close, it is unexpected at this
		 * stage. Consequently, we consider the session to be broken, because
		 * the recovery action is the same no matter how it is broken.
		 */
		pThis->sessState = eRelpSessState_BROKEN;
		ABORT_FINALIZE(RELP_RET_SESSION_BROKEN);
	} else if ((int) lenBuf == -1) { /* I don't know why we need to cast to int, but we must... */
		if(errno != EAGAIN) {
			pThis->pEngine->dbgprint("errno %d during relp session %p, session broken\n", errno,pThis);
			pThis->sessState = eRelpSessState_BROKEN;
			ABORT_FINALIZE(RELP_RET_SESSION_BROKEN);
		}
	} else {
		/* Terminate buffer and output received data to debug*/
		rcvBuf[lenBuf] = '\0';
		pThis->pEngine->dbgprint("relp session read %d octets, buf '%s'\n", (int) lenBuf, rcvBuf);

		/* we have regular data, which we now can process */
		for(i = 0 ; i < lenBuf ; ++i) {
			CHKRet(relpFrameProcessOctetRcvd(&pThis->pCurrRcvFrame, rcvBuf[i], pThis));
		}
	}

finalize_it:
	LEAVE_RELPFUNC;
}
コード例 #29
0
/* This accepts a new session, and, if all goes well, constructs a new
 * session object and adds it to the engine's list of sessions.
 * rgerhards, 2008-03-17
 */
relpRetVal
relpSessAcceptAndConstruct(relpSess_t **ppThis, relpSrv_t *pSrv, int sock)
{
	relpSess_t *pThis;

	ENTER_RELPFUNC;
	assert(ppThis != NULL);
	RELPOBJ_assert(pSrv, Srv);
	assert(sock >= 0);

	CHKRet(relpSessConstruct(&pThis, pSrv->pEngine, RELP_SRV_CONN, pSrv));
	CHKRet(relpTcpAcceptConnReq(&pThis->pTcp, sock, pSrv));

	*ppThis = pThis;

finalize_it:
	if(iRet != RELP_RET_OK) {
		if(pThis != NULL)
			relpSessDestruct(&pThis);
	}

	LEAVE_RELPFUNC;
}
コード例 #30
0
/* find an entry in the unacked list and provide it to the caller. The entry is handed
 * over to the caller and removed from the queue of unacked entries. It is the caller's
 * duty to destruct the sendbuf when it is done with it.
 * rgerhards, 20080-03-20
 */
relpRetVal
relpSessGetUnacked(relpSess_t *pThis, relpSendbuf_t **ppSendbuf, relpTxnr_t txnr)
{
	relpSessUnacked_t *pUnackedEtry;

	ENTER_RELPFUNC;
	RELPOBJ_assert(pThis, Sess);
	assert(ppSendbuf != NULL);
	
	for(  pUnackedEtry = pThis->pUnackedLstRoot
	    ; pUnackedEtry != NULL && pUnackedEtry->pSendbuf->txnr != txnr
	    ; pUnackedEtry = pUnackedEtry->pNext)
	   	/*JUST SKIP*/;

	if(pUnackedEtry == NULL)
		ABORT_FINALIZE(RELP_RET_NOT_FOUND);

	*ppSendbuf = pUnackedEtry->pSendbuf;
	relpSessDelUnacked(pThis, pUnackedEtry);

finalize_it:
	LEAVE_RELPFUNC;
}