]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/BsdSocketLib/recvfrom.c
Fix a bug about the iSCSI DHCP dependency issue.
[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
a88c3163 21 The recvfrom routine waits for receive data from a remote network\r
22 connection. This routine is typically called for SOCK_DGRAM sockets\r
23 when the socket is being shared by multiple remote systems and it is\r
24 important to get the remote system address for a response.\r
25\r
26 The\r
d7ce7006 27 <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html">POSIX</a>\r
28 documentation is available online.\r
29\r
30 @param [in] s Socket file descriptor returned from ::socket.\r
31\r
32 @param [in] buffer Address of a buffer to receive the data.\r
7dc13291 33\r
d7ce7006 34 @param [in] length Length of the buffer in bytes.\r
35\r
36 @param [in] flags Message control flags\r
37\r
38 @param [out] address Network address to receive the remote system address\r
39\r
40 @param [in] address_len Length of the remote network address structure\r
41\r
a88c3163 42 @return This routine returns the number of valid bytes in the buffer,\r
d7ce7006 43 zero if no data was received, and -1 when an error occurs.\r
a88c3163 44 In the case of an error, ::errno contains more details.\r
d7ce7006 45\r
46 **/\r
47ssize_t\r
48recvfrom (\r
49 int s,\r
50 void * buffer,\r
51 size_t length,\r
52 int flags,\r
53 struct sockaddr * address,\r
54 socklen_t * address_len\r
55 )\r
56{\r
57 socklen_t ByteCount;\r
58 ssize_t LengthInBytes;\r
59 UINT8 * pData;\r
60 EFI_SOCKET_PROTOCOL * pSocketProtocol;\r
61 EFI_STATUS Status;\r
62 struct timeval TimeVal;\r
63 EFI_EVENT pTimer;\r
64 UINT64 Timeout;\r
65 ssize_t TotalBytes;\r
66\r
67 //\r
68 // Assume failure\r
69 //\r
70 LengthInBytes = -1;\r
71\r
72 //\r
73 // Locate the context for this socket\r
74 //\r
75 pSocketProtocol = BslFdToSocketProtocol ( s, NULL, &errno );\r
76 if ( NULL != pSocketProtocol ) {\r
77 //\r
78 // Receive the data from the socket\r
79 //\r
80 Status = pSocketProtocol->pfnReceive ( pSocketProtocol,\r
81 flags,\r
82 length,\r
83 buffer,\r
84 (size_t *)&LengthInBytes,\r
85 address,\r
86 address_len,\r
87 &errno );\r
88 if ( EFI_ERROR ( Status )) {\r
89 LengthInBytes = -1;\r
90 if ( EAGAIN == errno ) {\r
91 //\r
92 // Get the timeout\r
93 //\r
94 ByteCount = sizeof ( TimeVal );\r
95 LengthInBytes = getsockopt ( s,\r
96 SOL_SOCKET,\r
97 SO_RCVTIMEO,\r
98 &TimeVal,\r
99 &ByteCount );\r
100 if ( 0 == LengthInBytes ) {\r
101 //\r
102 // Compute the timeout\r
103 //\r
104 Timeout = TimeVal.tv_sec;\r
105 Timeout *= 1000 * 1000;\r
106 Timeout += TimeVal.tv_usec;\r
107 Timeout *= 10;\r
108\r
109 //\r
110 // The timer is only necessary if a timeout is running\r
111 //\r
112 LengthInBytes = -1;\r
113 Status = EFI_SUCCESS;\r
114 pTimer = NULL;\r
115 if ( 0 != Timeout ) {\r
116 Status = gBS->CreateEvent ( EVT_TIMER,\r
117 TPL_NOTIFY,\r
118 NULL,\r
119 NULL,\r
120 &pTimer );\r
121 }\r
122 if ( !EFI_ERROR ( Status )) {\r
123 //\r
124 // Start the timer\r
125 //\r
126 if ( NULL != pTimer ) {\r
127 Status = gBS->SetTimer ( pTimer,\r
128 TimerRelative,\r
129 Timeout );\r
130 }\r
131 if ( !EFI_ERROR ( Status )) {\r
132 //\r
133 // Loop until data is received or the timeout\r
134 // expires\r
135 //\r
136 TotalBytes = 0;\r
137 pData = (UINT8 *)buffer;\r
138 do {\r
139 //\r
140 // Determine if the timeout expired\r
141 //\r
142 if ( NULL != pTimer ) {\r
143 Status = gBS->CheckEvent ( pTimer );\r
144 if ( EFI_SUCCESS == Status ) {\r
145 errno = ETIMEDOUT;\r
146 if ( 0 == TotalBytes ) {\r
147 TotalBytes = -1;\r
148 }\r
149 break;\r
150 }\r
151 }\r
152\r
153 //\r
154 // Attempt to receive some data\r
155 //\r
156 Status = pSocketProtocol->pfnReceive ( pSocketProtocol,\r
157 flags,\r
158 length,\r
159 pData,\r
160 (size_t *)&LengthInBytes,\r
161 address,\r
162 address_len,\r
163 &errno );\r
164 if ( !EFI_ERROR ( Status )) {\r
165 //\r
166 // Account for the data received\r
167 //\r
168 TotalBytes += LengthInBytes;\r
169 pData += LengthInBytes;\r
170 length -= LengthInBytes;\r
171 }\r
172 } while ( EFI_NOT_READY == Status );\r
173 LengthInBytes = TotalBytes;\r
174\r
175 //\r
176 // Stop the timer\r
177 //\r
178 if ( NULL != pTimer ) {\r
179 gBS->SetTimer ( pTimer,\r
180 TimerCancel,\r
181 0 );\r
182 }\r
183 }\r
184\r
185 //\r
186 // Release the timer\r
187 //\r
188 if ( NULL != pTimer ) {\r
189 gBS->CloseEvent ( pTimer );\r
190 }\r
191 }\r
192 }\r
193 }\r
194 }\r
195 }\r
196\r
197 //\r
198 // Return the receive data length, -1 for errors\r
199 //\r
200 return LengthInBytes;\r
201}\r