증상
HTTPS 사용 시 ONVIF 응답 지연 발생
원인
[gsoap] gsoap은 하나의 Response를 위해 여러 번의 send를 한다.
soap_send_raw(soap, "<", 1);
soap_send_raw(soap, "SOAP-ENV:Envelope", ...);
soap_send_raw(soap, ">", 1);
...
[lighttpd] gsoap으로부터 recv한 패킷들을 각각 SSL_write → 오버헤드로 인한 전송 지연
[963760976.648370]: ssl write begin
[963760976.649320]: SSL_write
[963760976.650925]: SSL_write
[963760976.652421]: SSL_write
[963760976.653860]: SSL_write
[963760976.655395]: SSL_write
[963760976.657133]: SSL_write
......
[963760977.318255]: SSL_write
[963760977.320038]: SSL_write
[963760977.321517]: SSL_write
[963760977.324003]: ssl write end // (676ms 소요)
대책
1. gsoap 초기화 시 SOAP_IO_BUFFER 옵션 적용
-# define SOAP_IO_DEFAULT (SOAP_IO_FLUSH | SOAP_XML_DEFAULTNS)
+# define SOAP_IO_DEFAULT (SOAP_IO_BUFFER | SOAP_XML_DEFAULTNS)
2. [gsoap] Response 문자열을 버퍼링하여 한 번에 send
/* stdsoap2.c */
...
#ifndef PALM_1
SOAP_FMAC1
int
SOAP_FMAC2
#ifdef KHB_FEATURE_SOAP_BUFFER
soap_send_raw_(struct soap *soap, const char *s, size_t n)
#else
soap_send_raw(struct soap *soap, const char *s, size_t n)
#endif
{ if (!n)
return SOAP_OK;
#ifndef WITH_LEANER
if (soap->fpreparesend && (soap->mode & SOAP_IO) != SOAP_IO_STORE && (soap->mode & SOAP_IO_LENGTH) && (soap->error = soap->fpreparesend(soap, s, n)))
return soap->error;
if (soap->ffiltersend && (soap->error = soap->ffiltersend(soap, &s, &n)))
return soap->error;
#endif
if (soap->mode & SOAP_IO_LENGTH)
soap->count += n;
else if (soap->mode & SOAP_IO)
{ register size_t i = SOAP_BUFLEN - soap->bufidx;
while (n >= i)
{ memcpy(soap->buf + soap->bufidx, s, i);
soap->bufidx = SOAP_BUFLEN;
if (soap_flush(soap))
return soap->error;
s += i;
n -= i;
i = SOAP_BUFLEN;
}
memcpy(soap->buf + soap->bufidx, s, n);
soap->bufidx += n;
}
else
return soap_flush_raw(soap, s, n);
return SOAP_OK;
}
#ifdef KHB_FEATURE_SOAP_BUFFER
struct _gsoap
{ char buf[SOAP_BUFLEN];
char *pbuf;
size_t bufidx;
};
static struct _gsoap gsoap;
SOAP_FMAC1
int
SOAP_FMAC2
soap_send_final(struct soap *soap)
{
int r = soap_send_raw_(soap, gsoap.buf, gsoap.bufidx);
memset(&gsoap, 0, sizeof(gsoap));
gsoap.pbuf = gsoap.buf;
return r;
}
SOAP_FMAC1
int
SOAP_FMAC2
soap_send_raw(struct soap *soap, const char *s, size_t n)
{ static int init = 0;
if (!init)
{ memset(&gsoap, 0, sizeof(gsoap));
gsoap.pbuf = gsoap.buf;
init = 1;
}
if (!n)
return SOAP_OK;
if(gsoap.bufidx + n >= SOAP_BUFLEN)
{ int r = soap_send_final(soap);
if(r != SOAP_OK)
return r;
}
memcpy(gsoap.pbuf, s, n);
gsoap.pbuf += n;
gsoap.bufidx += n;
return SOAP_OK;
}
#endif
#endif
...
#ifndef PALM_2
SOAP_FMAC1
int
SOAP_FMAC2
soap_envelope_end_out(struct soap *soap)
{ if (soap_element_end_out(soap, "SOAP-ENV:Envelope")
|| soap_send_raw(soap, "\r\n", 2)) /* 2.8: always emit \r\n */
return soap->error;
#ifdef KHB_FEATURE_SOAP_BUFFER
if (soap_send_final(soap))
return soap->error;
#endif
#ifndef WITH_LEANER
if ((soap->mode & SOAP_IO_LENGTH) && (soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
{ soap->dime.size = soap->count - soap->dime.size; /* DIME in MIME correction */
sprintf(soap->id, soap->dime_id_format, 0);
soap->dime.id = soap->id;
if (soap->local_namespaces)
{ if (soap->local_namespaces[0].out)
soap->dime.type = (char*)soap->local_namespaces[0].out;
else
soap->dime.type = (char*)soap->local_namespaces[0].ns;
}
soap->dime.options = NULL;
soap->dime.flags = SOAP_DIME_MB | SOAP_DIME_ABSURI;
if (!soap->dime.first)
soap->dime.flags |= SOAP_DIME_ME;
soap->count += 12 + ((strlen(soap->dime.id)+3)&(~3)) + (soap->dime.type ? ((strlen(soap->dime.type)+3)&(~3)) : 0);
}
if ((soap->mode & SOAP_ENC_DIME) && !(soap->mode & SOAP_ENC_MTOM))
return soap_send_raw(soap, SOAP_STR_PADDING, -(long)soap->dime.size&3);
#endif
soap->part = SOAP_END_ENVELOPE;
return SOAP_OK;
}
#endif
결과
[963786468.956911]: ssl write begin
[963786468.957803]: SSL_write // contents-length를 위한 Response
[963786468.964595]: SSL_write // xml response
[963786468.969947]: ssl write end // (13ms 소요)
'Network' 카테고리의 다른 글
tcp_tw_reuse와 SO_REUSEADDR의 차이 (0) | 2017.02.08 |
---|---|
OAuth2.0 (0) | 2017.01.19 |
HTTP Digest 인증과 토큰 기반 인증 (0) | 2015.05.10 |
[TCP] window size full (0) | 2015.03.18 |
[gsoap] recv, send 함수 흐름 (0) | 2015.02.27 |