]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/recvfrom.c
Fix @return Doxygen commands to be singular instead of plural.
[mirror_edk2.git] / StdLib / BsdSocketLib / recvfrom.c
1 /** @file
2 Implement the recvfrom API.
3
4 Copyright (c) 2011, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <SocketInternals.h>
16
17
18 /**
19 Receive data from a network connection and return the remote system's address.
20
21 The ::recvfrom routine waits for receive data from a remote network
22 connection. The
23 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html">POSIX</a>
24 documentation is available online.
25
26 @param [in] s Socket file descriptor returned from ::socket.
27
28 @param [in] buffer Address of a buffer to receive the data.
29
30 @param [in] length Length of the buffer in bytes.
31
32 @param [in] flags Message control flags
33
34 @param [out] address Network address to receive the remote system address
35
36 @param [in] address_len Length of the remote network address structure
37
38 @return ::recvfrom returns the number of valid bytes in the buffer,
39 zero if no data was received, and -1 when an error occurs.
40 In the case of an error, errno contains more details.
41
42 **/
43 ssize_t
44 recvfrom (
45 int s,
46 void * buffer,
47 size_t length,
48 int flags,
49 struct sockaddr * address,
50 socklen_t * address_len
51 )
52 {
53 socklen_t ByteCount;
54 ssize_t LengthInBytes;
55 UINT8 * pData;
56 EFI_SOCKET_PROTOCOL * pSocketProtocol;
57 EFI_STATUS Status;
58 struct timeval TimeVal;
59 EFI_EVENT pTimer;
60 UINT64 Timeout;
61 ssize_t TotalBytes;
62
63 //
64 // Assume failure
65 //
66 LengthInBytes = -1;
67
68 //
69 // Locate the context for this socket
70 //
71 pSocketProtocol = BslFdToSocketProtocol ( s, NULL, &errno );
72 if ( NULL != pSocketProtocol ) {
73 //
74 // Receive the data from the socket
75 //
76 Status = pSocketProtocol->pfnReceive ( pSocketProtocol,
77 flags,
78 length,
79 buffer,
80 (size_t *)&LengthInBytes,
81 address,
82 address_len,
83 &errno );
84 if ( EFI_ERROR ( Status )) {
85 LengthInBytes = -1;
86 if ( EAGAIN == errno ) {
87 //
88 // Get the timeout
89 //
90 ByteCount = sizeof ( TimeVal );
91 LengthInBytes = getsockopt ( s,
92 SOL_SOCKET,
93 SO_RCVTIMEO,
94 &TimeVal,
95 &ByteCount );
96 if ( 0 == LengthInBytes ) {
97 //
98 // Compute the timeout
99 //
100 Timeout = TimeVal.tv_sec;
101 Timeout *= 1000 * 1000;
102 Timeout += TimeVal.tv_usec;
103 Timeout *= 10;
104
105 //
106 // The timer is only necessary if a timeout is running
107 //
108 LengthInBytes = -1;
109 Status = EFI_SUCCESS;
110 pTimer = NULL;
111 if ( 0 != Timeout ) {
112 Status = gBS->CreateEvent ( EVT_TIMER,
113 TPL_NOTIFY,
114 NULL,
115 NULL,
116 &pTimer );
117 }
118 if ( !EFI_ERROR ( Status )) {
119 //
120 // Start the timer
121 //
122 if ( NULL != pTimer ) {
123 Status = gBS->SetTimer ( pTimer,
124 TimerRelative,
125 Timeout );
126 }
127 if ( !EFI_ERROR ( Status )) {
128 //
129 // Loop until data is received or the timeout
130 // expires
131 //
132 TotalBytes = 0;
133 pData = (UINT8 *)buffer;
134 do {
135 //
136 // Determine if the timeout expired
137 //
138 if ( NULL != pTimer ) {
139 Status = gBS->CheckEvent ( pTimer );
140 if ( EFI_SUCCESS == Status ) {
141 errno = ETIMEDOUT;
142 if ( 0 == TotalBytes ) {
143 TotalBytes = -1;
144 }
145 break;
146 }
147 }
148
149 //
150 // Attempt to receive some data
151 //
152 Status = pSocketProtocol->pfnReceive ( pSocketProtocol,
153 flags,
154 length,
155 pData,
156 (size_t *)&LengthInBytes,
157 address,
158 address_len,
159 &errno );
160 if ( !EFI_ERROR ( Status )) {
161 //
162 // Account for the data received
163 //
164 TotalBytes += LengthInBytes;
165 pData += LengthInBytes;
166 length -= LengthInBytes;
167 }
168 } while ( EFI_NOT_READY == Status );
169 LengthInBytes = TotalBytes;
170
171 //
172 // Stop the timer
173 //
174 if ( NULL != pTimer ) {
175 gBS->SetTimer ( pTimer,
176 TimerCancel,
177 0 );
178 }
179 }
180
181 //
182 // Release the timer
183 //
184 if ( NULL != pTimer ) {
185 gBS->CloseEvent ( pTimer );
186 }
187 }
188 }
189 }
190 }
191 }
192
193 //
194 // Return the receive data length, -1 for errors
195 //
196 return LengthInBytes;
197 }