aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-09-24 16:12:39 +0800
committerHarald Welte <laforge@gnumonks.org>2017-09-24 16:12:39 +0800
commit471e349ecc46e2bd89d69d6e46a38cd5136bd401 (patch)
tree70037882cf586ee233079c1842927c8c3a2f2a1a
parent7e1175f6d8d96f5c45d3d880945895698d02d5a0 (diff)
libgtp: Avoid extra memcpy() in gtp_data_req() by using sendmsg()
Adresses two "TODO Should be avoided" comments about an extra memcpy() before sendto() that can be replaced by a single sendmsg() call with an iovec array: 1 record for the GTP header + 1 record for the user payload. Change-Id: Ie332a6b15972330fcf540753898eb84ecb84fe24
-rw-r--r--gtp/gtp.c49
1 files changed, 20 insertions, 29 deletions
diff --git a/gtp/gtp.c b/gtp/gtp.c
index 27a07b1..e41e692 100644
--- a/gtp/gtp.c
+++ b/gtp/gtp.c
@@ -3146,20 +3146,34 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
{
union gtp_packet packet;
struct sockaddr_in addr;
+ struct msghdr msgh;
+ struct iovec iov[2];
int fd;
- int length;
+ /* prepare destination address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
#if defined(__FreeBSD__) || defined(__APPLE__)
addr.sin_len = sizeof(addr);
#endif
-
memcpy(&addr.sin_addr, pdp->gsnru.v, pdp->gsnru.l); /* TODO range check */
+ /* prepare msghdr */
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_name = &addr;
+ msgh.msg_namelen = sizeof(addr);
+ msgh.msg_iov = iov;
+ msgh.msg_iovlen = ARRAY_SIZE(iov);
+
+ /* prepare iovectors */
+ iov[0].iov_base = &packet;
+ /* iov[0].iov_len is not known here yet */
+ iov[1].iov_base = pack;
+ iov[1].iov_len = len;
+
if (pdp->version == 0) {
- length = GTP0_HEADER_SIZE + len;
+ iov[0].iov_len = GTP0_HEADER_SIZE;
addr.sin_port = htons(GTP0_PORT);
fd = gsn->fd0;
@@ -3168,19 +3182,9 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
packet.gtp0.h.seq = hton16(pdp->gtpsntx++);
packet.gtp0.h.flow = hton16(pdp->flru);
packet.gtp0.h.tid = htobe64(pdp_gettid(pdp->imsi, pdp->nsapi));
-
- if (len > sizeof(union gtp_packet) - sizeof(struct gtp0_header)) {
- gsn->err_memcpy++;
- LOGP(DLGTP, LOGL_ERROR,
- "Memcpy failed: %u > %zu\n", len,
- sizeof(union gtp_packet) -
- sizeof(struct gtp0_header));
- return EOF;
- }
- memcpy(packet.gtp0.p, pack, len); /* TODO Should be avoided! */
} else if (pdp->version == 1) {
- length = GTP1_HEADER_SIZE_LONG + len;
+ iov[0].iov_len = GTP1_HEADER_SIZE_LONG;
addr.sin_port = htons(GTP1U_PORT);
fd = gsn->fd1u;
@@ -3189,18 +3193,6 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
GTP1_HEADER_SIZE_LONG);
packet.gtp1l.h.seq = hton16(pdp->gtpsntx++);
packet.gtp1l.h.tei = hton32(pdp->teid_gn);
-
- if (len >
- sizeof(union gtp_packet) -
- sizeof(struct gtp1_header_long)) {
- gsn->err_memcpy++;
- LOGP(DLGTP, LOGL_ERROR,
- "Memcpy failed: %u > %zu\n", len,
- sizeof(union gtp_packet) -
- sizeof(struct gtp0_header));
- return EOF;
- }
- memcpy(packet.gtp1l.p, pack, len); /* TODO Should be avoided! */
} else {
LOGP(DLGTP, LOGL_ERROR, "Unknown version: %d\n", pdp->version);
return EOF;
@@ -3211,11 +3203,10 @@ int gtp_data_req(struct gsn_t *gsn, struct pdp_t *pdp, void *pack, unsigned len)
return -1;
}
- if (sendto(fd, &packet, length, 0,
- (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (sendmsg(fd, &msgh, 0) < 0) {
gsn->err_sendto++;
LOGP(DLGTP, LOGL_ERROR,
- "Sendto(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
+ "sendmsg(fd=%d, msg=%lx, len=%d) failed: Error = %s\n", fd,
(unsigned long)&packet, GTP0_HEADER_SIZE + len,
strerror(errno));
return EOF;