Add recvmmsg and sendmmsg syscalls.

Also add the corresponding constant, struct, and function declarations
to <sys/socket.h>, and perfunctory tests so we know that the symbols
actually exist.

Signed-off-by: Guillaume Ranquet <guillaumex.ranquet@intel.com>
Change-Id: Ib0d854239d3716be90ad70973c579aff4895a4f7
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index ee3a05b..1928168 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -247,6 +247,8 @@
 int           getsockopt(int, int, int, void*, socklen_t*)    arm,arm64,mips,mips64,x86_64
 int           sendmsg(int, const struct msghdr*, unsigned int)  arm,arm64,mips,mips64,x86_64
 int           recvmsg(int, struct msghdr*, unsigned int)   arm,arm64,mips,mips64,x86_64
+int           recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   arm,arm64,mips,mips64,x86_64
+int           sendmmsg(int, struct mmsghdr*, unsigned int, int)   arm,arm64,mips,mips64,x86_64
 
 # sockets for x86. These are done as an "indexed" call to socketcall syscall.
 int           socket:socketcall:1(int, int, int) x86
@@ -264,6 +266,8 @@
 int           getsockopt:socketcall:15(int, int, int, void*, socklen_t*)    x86
 int           sendmsg:socketcall:16(int, const struct msghdr*, unsigned int)  x86
 int           recvmsg:socketcall:17(int, struct msghdr*, unsigned int)   x86
+int           recvmmsg:socketcall:19(int, struct mmsghdr*, unsigned int, int, const struct timespec*)   x86
+int           sendmmsg:socketcall:20(int, struct mmsghdr*, unsigned int, int)   x86
 
 # scheduler & real-time
 int sched_setscheduler(pid_t pid, int policy, const struct sched_param* param)  all
diff --git a/libc/arch-arm/syscalls/recvmmsg.S b/libc/arch-arm/syscalls/recvmmsg.S
new file mode 100644
index 0000000..dd8cd8c
--- /dev/null
+++ b/libc/arch-arm/syscalls/recvmmsg.S
@@ -0,0 +1,22 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    mov     ip, sp
+    stmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 16
+    .cfi_rel_offset r4, 0
+    .cfi_rel_offset r5, 4
+    .cfi_rel_offset r6, 8
+    .cfi_rel_offset r7, 12
+    ldmfd   ip, {r4, r5, r6}
+    ldr     r7, =__NR_recvmmsg
+    swi     #0
+    ldmfd   sp!, {r4, r5, r6, r7}
+    .cfi_def_cfa_offset 0
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(recvmmsg)
diff --git a/libc/arch-arm/syscalls/sendmmsg.S b/libc/arch-arm/syscalls/sendmmsg.S
new file mode 100644
index 0000000..04c3fe3
--- /dev/null
+++ b/libc/arch-arm/syscalls/sendmmsg.S
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    mov     ip, r7
+    ldr     r7, =__NR_sendmmsg
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno
+END(sendmmsg)
diff --git a/libc/arch-arm64/syscalls/recvmmsg.S b/libc/arch-arm64/syscalls/recvmmsg.S
new file mode 100644
index 0000000..44875cc
--- /dev/null
+++ b/libc/arch-arm64/syscalls/recvmmsg.S
@@ -0,0 +1,21 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    stp     x29, x30, [sp, #-16]!
+    mov     x29,  sp
+    str     x8,       [sp, #-16]!
+
+    mov     x8, __NR_recvmmsg
+    svc     #0
+
+    ldr     x8,       [sp], #16
+    ldp     x29, x30, [sp], #16
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(recvmmsg)
diff --git a/libc/arch-arm64/syscalls/sendmmsg.S b/libc/arch-arm64/syscalls/sendmmsg.S
new file mode 100644
index 0000000..43b2fbf
--- /dev/null
+++ b/libc/arch-arm64/syscalls/sendmmsg.S
@@ -0,0 +1,21 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    stp     x29, x30, [sp, #-16]!
+    mov     x29,  sp
+    str     x8,       [sp, #-16]!
+
+    mov     x8, __NR_sendmmsg
+    svc     #0
+
+    ldr     x8,       [sp], #16
+    ldp     x29, x30, [sp], #16
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno
+
+    ret
+END(sendmmsg)
diff --git a/libc/arch-mips/syscalls/recvmmsg.S b/libc/arch-mips/syscalls/recvmmsg.S
new file mode 100644
index 0000000..23e511b
--- /dev/null
+++ b/libc/arch-mips/syscalls/recvmmsg.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_recvmmsg
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno
+    j t9
+    nop
+    .set reorder
+END(recvmmsg)
diff --git a/libc/arch-mips/syscalls/sendmmsg.S b/libc/arch-mips/syscalls/sendmmsg.S
new file mode 100644
index 0000000..d99ba93
--- /dev/null
+++ b/libc/arch-mips/syscalls/sendmmsg.S
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_sendmmsg
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno
+    j t9
+    nop
+    .set reorder
+END(sendmmsg)
diff --git a/libc/arch-mips64/syscalls/recvmmsg.S b/libc/arch-mips64/syscalls/recvmmsg.S
new file mode 100644
index 0000000..fa9fbb2
--- /dev/null
+++ b/libc/arch-mips64/syscalls/recvmmsg.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    .set push
+    .set noreorder
+    li v0, __NR_recvmmsg
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(recvmmsg)
diff --git a/libc/arch-mips64/syscalls/sendmmsg.S b/libc/arch-mips64/syscalls/sendmmsg.S
new file mode 100644
index 0000000..e4d8019
--- /dev/null
+++ b/libc/arch-mips64/syscalls/sendmmsg.S
@@ -0,0 +1,25 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    .set push
+    .set noreorder
+    li v0, __NR_sendmmsg
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(sendmmsg)
diff --git a/libc/arch-x86/syscalls/recvmmsg.S b/libc/arch-x86/syscalls/recvmmsg.S
new file mode 100644
index 0000000..a7adac8
--- /dev/null
+++ b/libc/arch-x86/syscalls/recvmmsg.S
@@ -0,0 +1,27 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    pushl   %ebx
+    pushl   %ecx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    .cfi_rel_offset ecx, 4
+    mov     $19, %ebx
+    mov     %esp, %ecx
+    addl    $12, %ecx
+    movl    $__NR_socketcall, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %ecx
+    popl    %ebx
+    ret
+END(recvmmsg)
diff --git a/libc/arch-x86/syscalls/sendmmsg.S b/libc/arch-x86/syscalls/sendmmsg.S
new file mode 100644
index 0000000..46dd6cd
--- /dev/null
+++ b/libc/arch-x86/syscalls/sendmmsg.S
@@ -0,0 +1,27 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    pushl   %ebx
+    pushl   %ecx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    .cfi_rel_offset ecx, 4
+    mov     $20, %ebx
+    mov     %esp, %ecx
+    addl    $12, %ecx
+    movl    $__NR_socketcall, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno
+    addl    $4, %esp
+    orl     $-1, %eax
+1:
+    popl    %ecx
+    popl    %ebx
+    ret
+END(sendmmsg)
diff --git a/libc/arch-x86_64/syscalls/recvmmsg.S b/libc/arch-x86_64/syscalls/recvmmsg.S
new file mode 100644
index 0000000..9da70e2
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/recvmmsg.S
@@ -0,0 +1,17 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(recvmmsg)
+    movq    %rcx, %r10
+    movl    $__NR_recvmmsg, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+    orq     $-1, %rax
+1:
+    ret
+END(recvmmsg)
diff --git a/libc/arch-x86_64/syscalls/sendmmsg.S b/libc/arch-x86_64/syscalls/sendmmsg.S
new file mode 100644
index 0000000..7407c12
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/sendmmsg.S
@@ -0,0 +1,17 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(sendmmsg)
+    movq    %rcx, %r10
+    movl    $__NR_sendmmsg, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+    orq     $-1, %rax
+1:
+    ret
+END(sendmmsg)
diff --git a/libc/include/sys/socket.h b/libc/include/sys/socket.h
index 5eb7e3d..b6107a5 100644
--- a/libc/include/sys/socket.h
+++ b/libc/include/sys/socket.h
@@ -75,40 +75,45 @@
 };
 
 struct sockaddr {
- sa_family_t sa_family;
- char sa_data[14];
+  sa_family_t sa_family;
+  char sa_data[14];
 };
 
 struct linger {
- int l_onoff;
- int l_linger;
+  int l_onoff;
+  int l_linger;
 };
 
 struct msghdr {
- void * msg_name;
- int msg_namelen;
- struct iovec * msg_iov;
- __kernel_size_t msg_iovlen;
- void * msg_control;
- __kernel_size_t msg_controllen;
- unsigned msg_flags;
+  void* msg_name;
+  socklen_t msg_namelen;
+  struct iovec* msg_iov;
+  size_t msg_iovlen;
+  void* msg_control;
+  size_t msg_controllen;
+  int msg_flags;
+};
+
+struct mmsghdr {
+  struct msghdr msg_hdr;
+  unsigned int msg_len;
 };
 
 struct cmsghdr {
- __kernel_size_t cmsg_len;
- int cmsg_level;
- int cmsg_type;
+  size_t cmsg_len;
+  int cmsg_level;
+  int cmsg_type;
 };
 
 #define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg))
 #define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg))
 #define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) )
-#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
+#define CMSG_DATA(cmsg) ((void*)((char*)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr))))
 #define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len))
 #define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
-#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ?   (struct cmsghdr *)(ctl) :   (struct cmsghdr *)NULL)
+#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ?   (struct cmsghdr*)(ctl) :   (struct cmsghdr*)NULL)
 #define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
-#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) &&   (cmsg)->cmsg_len <= (unsigned long)   ((mhdr)->msg_controllen -   ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) &&   (cmsg)->cmsg_len <= (unsigned long)   ((mhdr)->msg_controllen -   ((char*)(cmsg) - (char*)(mhdr)->msg_control)))
 
 #ifdef __GNUC__
 #define __KINLINE static __inline__
@@ -118,16 +123,17 @@
 #define __KINLINE static
 #endif
 
-__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size, struct cmsghdr *__cmsg) {
- struct cmsghdr * __ptr;
- __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
- if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
- return (struct cmsghdr *)0;
- return __ptr;
+__KINLINE struct cmsghdr* __cmsg_nxthdr(void* __ctl, size_t __size, struct cmsghdr* __cmsg) {
+  struct cmsghdr* __ptr;
+  __ptr = (struct cmsghdr*)(((unsigned char*) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len));
+  if ((unsigned long)((char*)(__ptr+1) - (char*) __ctl) > __size) {
+    return NULL;
+  }
+  return __ptr;
 }
 
-__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg) {
- return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
+__KINLINE struct cmsghdr* cmsg_nxthdr (struct msghdr* __msg, struct cmsghdr* __cmsg) {
+  return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
 }
 
 #define SCM_RIGHTS 0x01
@@ -135,9 +141,9 @@
 #define SCM_SECURITY 0x03
 
 struct ucred {
- __u32 pid;
- __u32 uid;
- __u32 gid;
+  pid_t pid;
+  uid_t uid;
+  gid_t gid;
 };
 
 #define AF_UNSPEC 0
@@ -241,6 +247,9 @@
 #define MSG_ERRQUEUE 0x2000
 #define MSG_NOSIGNAL 0x4000
 #define MSG_MORE 0x8000
+#define MSG_WAITFORONE 0x10000
+#define MSG_FASTOPEN 0x20000000
+#define MSG_CMSG_CLOEXEC 0x40000000
 #define MSG_EOF MSG_FIN
 #define MSG_CMSG_COMPAT 0
 
@@ -276,30 +285,32 @@
 # define __socketcall extern
 #endif
 
-__socketcall int socket(int, int, int);
-__socketcall int bind(int, const struct sockaddr *, int);
-__socketcall int connect(int, const struct sockaddr *, socklen_t);
+__socketcall int accept(int, struct sockaddr*, socklen_t*);
+__socketcall int bind(int, const struct sockaddr*, int);
+__socketcall int connect(int, const struct sockaddr*, socklen_t);
+__socketcall int getpeername(int, struct sockaddr*, socklen_t*);
+__socketcall int getsockname(int, struct sockaddr*, socklen_t*);
+__socketcall int getsockopt(int, int, int, void*, socklen_t*);
 __socketcall int listen(int, int);
-__socketcall int accept(int, struct sockaddr *, socklen_t *);
-__socketcall int getsockname(int, struct sockaddr *, socklen_t *);
-__socketcall int getpeername(int, struct sockaddr *, socklen_t *);
-__socketcall int socketpair(int, int, int, int *);
+__socketcall int recvmmsg(int, struct mmsghdr*, unsigned int, int, const struct timespec*);
+__socketcall int recvmsg(int, struct msghdr*, unsigned int);
+__socketcall int sendmmsg(int, const struct mmsghdr*, unsigned int, int);
+__socketcall int sendmsg(int, const struct msghdr*, unsigned int);
+__socketcall int setsockopt(int, int, int, const void*, socklen_t);
 __socketcall int shutdown(int, int);
-__socketcall int setsockopt(int, int, int, const void *, socklen_t);
-__socketcall int getsockopt(int, int, int, void *, socklen_t *);
-__socketcall int sendmsg(int, const struct msghdr *, unsigned int);
-__socketcall int recvmsg(int, struct msghdr *, unsigned int);
+__socketcall int socket(int, int, int);
+__socketcall int socketpair(int, int, int, int*);
 
-extern  ssize_t  send(int, const void *, size_t, unsigned int);
-extern  ssize_t  recv(int, void *, size_t, unsigned int);
+extern ssize_t send(int, const void*, size_t, unsigned int);
+extern ssize_t recv(int, void*, size_t, unsigned int);
 
-__socketcall ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
-__socketcall ssize_t recvfrom(int, void *, size_t, unsigned int, const struct sockaddr *, socklen_t *);
+__socketcall ssize_t sendto(int, const void*, size_t, int, const struct sockaddr*, socklen_t);
+__socketcall ssize_t recvfrom(int, void*, size_t, unsigned int, const struct sockaddr*, socklen_t*);
 
 #if defined(__BIONIC_FORTIFY)
 __errordecl(__recvfrom_error, "recvfrom called with size bigger than buffer");
-extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, unsigned int, const struct sockaddr*, socklen_t *);
-extern ssize_t __recvfrom_real(int, void *, size_t, unsigned int, const struct sockaddr*, socklen_t*)
+extern ssize_t __recvfrom_chk(int, void*, size_t, size_t, unsigned int, const struct sockaddr*, socklen_t*);
+extern ssize_t __recvfrom_real(int, void*, size_t, unsigned int, const struct sockaddr*, socklen_t*)
     __asm__(__USER_LABEL_PREFIX__ "recvfrom");
 
 __BIONIC_FORTIFY_INLINE
@@ -324,7 +335,7 @@
 }
 
 __BIONIC_FORTIFY_INLINE
-ssize_t recv(int socket, void *buf, size_t buflen, unsigned int flags) {
+ssize_t recv(int socket, void* buf, size_t buflen, unsigned int flags) {
   return recvfrom(socket, buf, buflen, flags, NULL, 0);
 }
 
diff --git a/tests/Android.mk b/tests/Android.mk
index 5fafba6..451b3a9 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -71,6 +71,7 @@
     sys_resource_test.cpp \
     sys_select_test.cpp \
     sys_sendfile_test.cpp \
+    sys_socket_test.cpp \
     sys_stat_test.cpp \
     sys_statvfs_test.cpp \
     sys_syscall_test.cpp \
diff --git a/tests/sys_socket_test.cpp b/tests/sys_socket_test.cpp
new file mode 100644
index 0000000..901ac17
--- /dev/null
+++ b/tests/sys_socket_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <sys/socket.h>
+
+TEST(sys_socket, recvmmsg) {
+#if !defined(__GLIBC__) // TODO: Android's prebuilt gcc is too old for recvmmsg/sendmmsg.
+  ASSERT_EQ(-1, recvmmsg(-1, NULL, 0, 0, NULL));
+  ASSERT_EQ(EBADF, errno);
+#endif
+}
+
+TEST(sys_socket, sendmmsg) {
+#if !defined(__GLIBC__) // TODO: Android's prebuilt gcc is too old for recvmmsg/sendmmsg.
+  ASSERT_EQ(-1, sendmmsg(-1, NULL, 0, 0));
+  ASSERT_EQ(EBADF, errno);
+#endif
+}