]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Sockets/SetSockOpt/SetSockOpt.c
0df143a5144783ce9d8150725e13d938cc35bf7a
[mirror_edk2.git] / AppPkg / Applications / Sockets / SetSockOpt / SetSockOpt.c
1 /** @file
2 Set the socket options
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 <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <Uefi.h>
19 #include <unistd.h>
20
21 #include <Library/DebugLib.h>
22 #include <Library/UefiLib.h>
23
24 #include <sys/socket.h>
25 #include <sys/time.h>
26
27 typedef enum _DATA_TYPE {
28 DATA_TYPE_UNKNOWN = 0,
29 DATA_TYPE_INT32_DECIMAL,
30 DATA_TYPE_SOCKET_TYPE,
31 DATA_TYPE_TIMEVAL
32 } DATA_TYPE;
33
34 typedef struct {
35 char * pOptionName;
36 int OptionValue;
37 int OptionLevel;
38 BOOLEAN bSetAllowed;
39 DATA_TYPE DataType;
40 } OPTIONS;
41
42 CONST OPTIONS mOptions[] = {
43 { "SO_ACCEPTCONN", SO_ACCEPTCONN, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN },
44 { "SO_BROADCAST", SO_BROADCAST, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
45 { "SO_DEBUG", SO_DEBUG, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
46 { "SO_DONTROUTE", SO_DONTROUTE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
47 { "SO_ERROR", SO_ERROR, SOL_SOCKET, FALSE, DATA_TYPE_UNKNOWN },
48 { "SO_KEEPALIVE", SO_KEEPALIVE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
49 { "SO_OOBINLINE", SO_OOBINLINE, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
50 { "SO_OVERFLOWED", SO_OVERFLOWED, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
51 { "SO_RCVBUF", SO_RCVBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL },
52 { "SO_RCVLOWAT", SO_RCVLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
53 { "SO_RCVTIMEO", SO_RCVTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_TIMEVAL },
54 { "SO_REUSEADDR", SO_REUSEADDR, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
55 { "SO_REUSEPORT", SO_REUSEPORT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
56 { "SO_SNDBUF", SO_SNDBUF, SOL_SOCKET, TRUE, DATA_TYPE_INT32_DECIMAL },
57 { "SO_SNDLOWAT", SO_SNDLOWAT, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
58 { "SO_SNDTIMEO", SO_SNDTIMEO, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
59 { "SO_TIMESTAMP", SO_TIMESTAMP, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN },
60 { "SO_TYPE", SO_TYPE, SOL_SOCKET, FALSE, DATA_TYPE_SOCKET_TYPE },
61 { "SO_USELOOPBACK", SO_USELOOPBACK, SOL_SOCKET, TRUE, DATA_TYPE_UNKNOWN }
62 };
63
64
65 UINT8 mBuffer[ 65536 ];
66 UINT8 mValue[ 65536 ];
67 char * mSocketType[] = {
68 "SOCK_STREAM",
69 "SOCK_DGRAM",
70 "SOCK_RAW",
71 "SOCK_RDM",
72 "SOCK_SEQPACKET"
73 };
74
75 void
76 DisplayOption (
77 CONST OPTIONS * pOption,
78 socklen_t LengthInBytes,
79 BOOLEAN bDisplayUpdate,
80 BOOLEAN bDisplayCrLf
81 )
82 {
83 UINT8 * pEnd;
84 char * pString;
85 union {
86 UINT8 * u8;
87 INT32 * i32;
88 struct timeval * TimeVal;
89 } Value;
90
91 //
92 // Display the value length
93 //
94 if ( !bDisplayUpdate ) {
95 Print ( L"LengthInBytes: %d\r\n", LengthInBytes );
96 Print ( L"%a: ", pOption->pOptionName );
97 }
98 else {
99 Print ( L" --> " );
100 }
101
102 //
103 // Display the value
104 //
105 Value.u8 = &mBuffer[0];
106 switch ( pOption->DataType ) {
107 case DATA_TYPE_UNKNOWN:
108 Print ( L"%a:", pOption->pOptionName );
109 pEnd = &Value.u8[ LengthInBytes ];
110 while ( pEnd > Value.u8 ) {
111 Print ( L" %02x", *Value.u8 );
112 Value.u8 += 1;
113 }
114 break;
115
116 case DATA_TYPE_INT32_DECIMAL:
117 if ( 4 == LengthInBytes ) {
118 Print ( L"%d", *Value.i32 );
119 }
120 else {
121 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
122 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
123 }
124 break;
125
126 case DATA_TYPE_SOCKET_TYPE:
127 if ( 4 == LengthInBytes ) {
128 if (( SOCK_STREAM <= *Value.i32 ) && ( SOCK_SEQPACKET >= *Value.i32 )) {
129 pString = mSocketType[ *Value.i32 - SOCK_STREAM ];
130 Print ( L"%a", pString );
131 }
132 else {
133 Print ( L"%08x (unknown type)", *Value.i32 );
134 }
135 }
136 else {
137 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
138 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
139 }
140 break;
141
142 case DATA_TYPE_TIMEVAL:
143 if ( sizeof ( *Value.TimeVal ) == LengthInBytes ) {
144 if (( 0 == Value.TimeVal->tv_sec )
145 && ( 0 == Value.TimeVal->tv_usec )) {
146 Print ( L"Infinite" );
147 }
148 else {
149 Print ( L"%d.%06d sec",
150 Value.TimeVal->tv_sec,
151 Value.TimeVal->tv_usec );
152 }
153 }
154 else {
155 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
156 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
157 }
158 break;
159 }
160
161 //
162 // Terminate the line
163 //
164 if ( bDisplayCrLf ) {
165 Print ( L"\r\n" );
166 }
167 }
168
169 socklen_t
170 GetOptionValue (
171 CONST OPTIONS * pOption,
172 char * pValue
173 )
174 {
175 socklen_t BytesToWrite;
176 union {
177 UINT8 * u8;
178 INT32 * i32;
179 struct timeval * TimeVal;
180 } Value;
181 int Values;
182
183 //
184 // Assume failure
185 //
186 errno = EINVAL;
187 BytesToWrite = 0;
188
189 //
190 // Determine the type of parameter
191 //
192 if ( pOption->bSetAllowed ) {
193 Value.u8 = &mValue[0];
194 switch ( pOption->DataType ) {
195 default:
196 break;
197
198 case DATA_TYPE_INT32_DECIMAL:
199 Values = sscanf ( pValue, "%d", Value.i32 );
200 if ( 1 == Values ) {
201 BytesToWrite = sizeof ( *Value.i32);
202 errno = 0;
203 }
204 break;
205
206 case DATA_TYPE_TIMEVAL:
207 Values = sscanf ( pValue, "%d.%d",
208 &Value.TimeVal->tv_sec,
209 &Value.TimeVal->tv_usec );
210 if (( 2 == Values )
211 && ( 0 <= Value.TimeVal->tv_sec )
212 && ( 0 <= Value.TimeVal->tv_usec )
213 && ( 1000000 > Value.TimeVal->tv_usec )){
214 BytesToWrite = sizeof ( *Value.TimeVal );
215 errno = 0;
216 }
217 }
218 }
219
220 //
221 // Display the error
222 //
223 if ( 0 == BytesToWrite ) {
224 Print ( L"ERROR - Invalid value!\r\n" );
225 }
226
227 //
228 // Return the number of bytes to be written
229 //
230 return BytesToWrite;
231 }
232
233
234 /**
235 Set the socket options
236
237 @param [in] Argc The number of arguments
238 @param [in] Argv The argument value array
239
240 @retval 0 The application exited normally.
241 @retval Other An error occurred.
242 **/
243 int
244 main (
245 IN int Argc,
246 IN char **Argv
247 )
248 {
249 socklen_t BytesToWrite;
250 socklen_t LengthInBytes;
251 CONST OPTIONS * pEnd;
252 CONST OPTIONS * pOption;
253 int s;
254 int Status;
255
256 DEBUG (( DEBUG_INFO,
257 "%a starting\r\n",
258 Argv[0]));
259
260 //
261 // Parse the socket option
262 //
263 pOption = &mOptions[0];
264 pEnd = &pOption[sizeof ( mOptions ) / sizeof ( mOptions[0])];
265 if ( 2 <= Argc ) {
266 while ( pEnd > pOption ) {
267 if ( 0 == strcmp ( Argv[1], pOption->pOptionName )) {
268 break;
269 }
270 pOption += 1;
271 }
272 if ( pEnd <= pOption ) {
273 Print ( L"ERROR: Invalid option: %a\r\n", Argv[1]);
274 Argc = 1;
275 }
276 }
277
278 //
279 // Display the help if necessary
280 //
281 if (( 2 > Argc ) || ( 3 < Argc )) {
282 Print ( L"%a <option>\r\n", Argv[0]);
283 Print ( L"\r\n" );
284 Print ( L"Option one of:\r\n" );
285 pOption = &mOptions[0];
286 while ( pEnd > pOption ) {
287 Print ( L" %a: %a\r\n",
288 pOption->pOptionName,
289 pOption->bSetAllowed ? "get/set" : "get" );
290 pOption += 1;
291 }
292 errno = EINVAL;
293 }
294 else {
295 //
296 // Determine if the value is to be set
297 //
298 BytesToWrite = 0;
299 if (( 3 > Argc )
300 || ( 0 < ( BytesToWrite = GetOptionValue ( pOption, Argv[2])))) {
301 //
302 // Get the socket
303 //
304 s = socket ( AF_INET, 0, 0 );
305 if ( -1 == s ) {
306 Print ( L"ERROR - Unable to open the socket, errno: %d\r\n", errno );
307 }
308 else {
309 //
310 // Display the option value
311 //
312 LengthInBytes = sizeof ( mBuffer );
313 Status = getsockopt ( s,
314 pOption->OptionLevel,
315 pOption->OptionValue,
316 &mBuffer,
317 &LengthInBytes );
318 if ( -1 == Status ) {
319 Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
320 }
321 else {
322 DisplayOption ( pOption,
323 LengthInBytes,
324 FALSE,
325 (BOOLEAN)( 0 == BytesToWrite ));
326
327 //
328 // Determine if the value is to be set
329 //
330 if (( 0 < BytesToWrite )
331 && ( BytesToWrite == LengthInBytes )) {
332 //
333 // Set the option value
334 //
335 Status = setsockopt ( s,
336 pOption->OptionLevel,
337 pOption->OptionValue,
338 &mValue,
339 BytesToWrite );
340 if ( -1 == Status ) {
341 Print ( L"ERROR - setsockopt failed, errno: %d\r\n", errno );
342 }
343 else {
344 //
345 // Display the updated option value
346 //
347 Status = getsockopt ( s,
348 pOption->OptionLevel,
349 pOption->OptionValue,
350 &mBuffer,
351 &LengthInBytes );
352 if ( -1 == Status ) {
353 Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
354 }
355 else {
356 DisplayOption ( pOption,
357 LengthInBytes,
358 TRUE,
359 TRUE );
360 }
361 }
362 }
363 }
364
365 //
366 // Done with the socket
367 //
368 close ( s );
369 }
370 }
371 }
372
373 //
374 // All done
375 //
376 DEBUG (( DEBUG_INFO,
377 "%a exiting, errno: %d\r\n",
378 Argv[0],
379 errno ));
380 return errno;
381 }