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