 /****************************************************************************

   mod_dav_pgsql (DASL) for apache 2.X
   CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
   CopyRight(C) 2006 Netomi Inc. All Rights reserved.
   Author : elenoa lazyfake (elenoa@solutionbox.co.kr)

   $Id: share.c,v 1.8 2007/02/22 08:22:13 elenoa Exp $

   Redistribution and use in source and binary forms, with or with out
   modification, are not permitted in outside of SolutionBox Inc.

 ****************************************************************************/
#include <unistd.h>
#include <ctype.h>
#include <math.h>

#include <httpd.h>
#include <http_config.h>
#include <http_protocol.h>
#include <http_log.h>
#include <http_core.h>      /* for ap_construct_url */
#include <http_request.h>

#include <apr_strings.h>
#include <apr_signal.h>

#include "dav_repos.h"
#include "dbms.h"
#include "util.h"
#include "share_common.h"
#include "share_statistic.h"

#ifndef __OPENDISK_SOLUTION_NOT_USE_TS__
/* for statistics */
static struct shm_mgnt stat_mgnt = {
	NULL, NULL, SHM_STAT, SHM_STAT_LOCK, 0, 0
};

struct service_network_stat *g_ts;
static int maxvol = 0;

int dav_initialize_shared_statistic(dav_repos_server_conf *dsc, server_rec *s, apr_pool_t *p)
{
	if (dsc->user_cache <= 0) {
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "OPENDAV: initialize_shared_memory: "
			"MaxUserCache <= 0 (%d)", dsc->user_cache);
		return !OK;
	}

	maxvol = dsc->user_cache;

	/* statistics : calculate shared memory size from max_volume value */
	stat_mgnt.size = (sizeof(struct service_network_stat) * maxvol * 2);
	g_ts = (struct service_network_stat *)dav_shared_get_new_memory(&stat_mgnt, s, p, true);

	if (!g_ts) return !OK;

	return OK;
}

void dav_cleanup_shared_statistic()
{
	if (stat_mgnt.shm) {
		apr_shm_detach(stat_mgnt.shm);
	}

	if (stat_mgnt.lock) {
		apr_global_mutex_destroy(stat_mgnt.lock);
	}
}

static void dav_shared_ts_init(struct service_network_stat *ts, char *volume, unsigned int stamp)
{
	acct_info id_parse;

	// CHG 2019-08-28 huibong 불필요 변수 삭제 (#32780)
	// - 불필요 함수 호출 결과 저장 변수를 제거한다.
	// - at_split() 호출 실패시에도 해당 함수내에서 id_parse 변수를 초기화 하므로....
	//   호출 결과에 따른 다른 조치는 불필요.
	//int res = at_split(volume, &id_parse);
	at_split(volume, &id_parse);

	//memset(ts, 0, sizeof(struct service_network_stat));
	ts->nServiceSeq = atoi(id_parse.szVolumeID);
	ts->nUserSeq = atoi(id_parse.szUserID);
	ts->down_content_size = 0;
	ts->up_content_size = 0;
	ts->down_traffic = 0;
	ts->up_traffic = 0;

	ts->timestamp = stamp;
}

// CHG 2010-08-30 huibong
// 각 함수에서 통계정보 저장을 위한 본함수 호출시 내부의 apr_pstrcat() 함수 사용으로 인해
// 각 접속 세션마다 메모리 할당 현상이 반복하여 발생.
// 특히 대용량 파일에 대한 업로드/다운로드 세션인 경우
// 불필요한 세션 메모리 pool 을 계속적으로 할당하여 결국 시스템 메모리가 부족, 
// swap 메모리 임계치 초과 현상이 발생하는 문제점을 발생.
// 따라서 이 문제를 해결하기 위해 apr_pstrcat() 함수 사용부분을 제거후 지역변수를 사용하도록 변경처리한다.
static struct service_network_stat *dav_shared_ts_find(request_rec *r)
{
#ifndef __OPENDAV_SHARED_NOT_USE
	time_t t = time(0);
	unsigned int stamp = STAT_STAMP(t);

	// 2010-08-30 huibong
	//char *service = r->user;
	char service[128];			// service 저장 정보 형식은 238.0@168 등의 형식임

	acct_info acctinfo;
	int i;

	if (g_ts == NULL)
	{
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: dav_shared_ts_find: global ts is null");
		return NULL;
	}

	if (at_split(r->user, &acctinfo) <= 0)
		return NULL;

	/* 2010-08-30 huibong
	* apr_pstrcat() 함수의 반복 사용으로 인한 메모리 중복 allocation 문제로 인해 코드 수정처리
	service = apr_pstrcat(r->pool, acctinfo.szVolumeID,
	#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
	".", acctinfo.szTCClassID,
	#endif
	"@", acctinfo.szUserID, NULL);
	*/

#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
	snprintf(service, sizeof(service), "%s.%s@%s", acctinfo.szVolumeID, acctinfo.szTCClassID, acctinfo.szUserID);
#else // !__CLASSIFIED_TRAFFIC_MANAGE__
	snprintf(service, sizeof(service), "%s@%s", acctinfo.szVolumeID, acctinfo.szUserID);
#endif // __CLASSIFIED_TRAFFIC_MANAGE__

	int nSvcsqe = atoi(acctinfo.szVolumeID);

	if (nSvcsqe <= 0)
	{
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: dav_shared_ts_find: not found Service seq : %s", service);
		return NULL;
	}

#define TS		(g_ts + (i << 1) + STAT_LOC(stamp))

	for (i = 0; i < maxvol; i++)
	{
		if (TS->nServiceSeq == 0)
			break;

		if (TS->nServiceSeq == nSvcsqe)
		{
			if (TS->timestamp != stamp)
			{
				dav_shared_ts_init(TS, service, stamp);
			}

			return TS;
		}
	}

	if (i < maxvol)
	{
		dav_shared_ts_init((g_ts + (i << 1)), service, stamp);
		dav_shared_ts_init((g_ts + (i << 1) + 1), service, stamp);
		return TS;
	}

	ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: dav_shared_ts_find: volume limit exceeded: %s %d", service, i);
#endif // !__OPENDAV_SHARED_NOT_USE

	return NULL;
}

int dav_shared_ts_access_statistic(request_rec *r)
{
#ifndef __OPENDAV_SHARED_NOT_USE

#endif // !__OPENDAV_SHARED_NOT_USE

	return OK;
}

void dav_shared_ts_open_stream(request_rec *r, int bound)
{
	DBG0("dav_shared_ts_open_stream debugging #0");

#ifndef __OPENDAV_SHARED_NOT_USE
#endif // !__OPENDISK_SOLUTION_NOT_USE_TS__
}

void dav_shared_ts_close_stream(request_rec *r, int bound)
{
#ifndef __OPENDAV_SHARED_NOT_USE
#endif // !__OPENDISK_SOLUTION_NOT_USE_TS__
}

void dav_shared_ts_transfer_data(request_rec *r, int bound, apr_size_t size, apr_size_t org_sent)
{
#ifndef __OPENDAV_SHARED_NOT_USE
	if (r == NULL) return;

	if (stat_mgnt.lock == NULL) {
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: "
			"dav_shared_ts_transfer_data: lock null");
		return;
	}

	if (size < 0) return;

	apr_global_mutex_lock(stat_mgnt.lock);

	struct service_network_stat *ts = dav_shared_ts_find(r);
	if (ts == NULL) {
		ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: "
			"dav_shared_ts_transfer_data: cannot get transfer structure");
		apr_global_mutex_unlock(stat_mgnt.lock);
		return;
	}

	if (bound == INB)
	{
		ts->up_content_size += size;
		ts->up_traffic += CONTENT_TO_TRAFFIC(size);
	}
	else
	{
		ts->down_content_size += size;
		ts->down_traffic += CONTENT_TO_TRAFFIC(size);
	}

	apr_global_mutex_unlock(stat_mgnt.lock);
#endif //  !__OPENDAV_SHARED_NOT_USE
}

#endif // !__OPENDISK_SOLUTION_NOT_USE_TS__
