Add Socket Library applications.
[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 {
108 case DATA_TYPE_UNKNOWN:
109 Print ( L"%a:", pOption->pOptionName );
110 pEnd = &Value.u8 [ LengthInBytes ];
111 while ( pEnd > Value.u8 ) {
112 Print ( L" %02x", *Value.u8 );
113 Value.u8 += 1;
114 }
115 break;
116
117 case DATA_TYPE_INT32_DECIMAL:
118 if ( 4 == LengthInBytes ) {
119 Print ( L"%d", *Value.i32 );
120 }
121 else {
122 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
123 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
124 }
125 break;
126
127 case DATA_TYPE_SOCKET_TYPE:
128 if ( 4 == LengthInBytes ) {
129 if (( SOCK_STREAM <= *Value.i32 ) && ( SOCK_SEQPACKET >= *Value.i32 )) {
130 pString = mSocketType [ *Value.i32 - SOCK_STREAM ];
131 Print ( L"%a", pString );
132 }
133 else {
134 Print ( L"%08x (unknown type)", *Value.i32 );
135 }
136 }
137 else {
138 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
139 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
140 }
141 break;
142
143 case DATA_TYPE_TIMEVAL:
144 if ( sizeof ( *Value.TimeVal ) == LengthInBytes ) {
145 if (( 0 == Value.TimeVal->tv_sec )
146 && ( 0 == Value.TimeVal->tv_usec )) {
147 Print ( L"Infinite" );
148 }
149 else {
150 Print ( L"%d.%06d sec",
151 Value.TimeVal->tv_sec,
152 Value.TimeVal->tv_usec );
153 }
154 }
155 else {
156 errno = ( 4 > LengthInBytes ) ? EBUFSIZE : ERANGE;
157 Print ( L"\r\nERROR - Invalid length, errno: %d\r\n", errno );
158 }
159 break;
160 }
161
162 //
163 // Terminate the line
164 //
165 if ( bDisplayCrLf ) {
166 Print ( L"\r\n" );
167 }
168 }
169
170 socklen_t
171 GetOptionValue (
172 CONST OPTIONS * pOption,
173 char * pValue
174 )
175 {
176 socklen_t BytesToWrite;
177 union {
178 UINT8 * u8;
179 INT32 * i32;
180 struct timeval * TimeVal;
181 } Value;
182 int Values;
183
184 //
185 // Assume failure
186 //
187 errno = EINVAL;
188 BytesToWrite = 0;
189
190 //
191 // Determine the type of parameter
192 //
193 if ( pOption->bSetAllowed ) {
194 Value.u8 = &mValue[0];
195 switch ( pOption->DataType ) {
196 case DATA_TYPE_INT32_DECIMAL:
197 Values = sscanf ( pValue, "%d", Value.i32 );
198 if ( 1 == Values ) {
199 BytesToWrite = sizeof ( *Value.i32);
200 errno = 0;
201 }
202 break;
203
204 case DATA_TYPE_TIMEVAL:
205 Values = sscanf ( pValue, "%d.%0d",
206 &Value.TimeVal->tv_sec,
207 &Value.TimeVal->tv_usec );
208 if (( 2 == Values )
209 && ( 0 <= Value.TimeVal->tv_sec )
210 && ( 0 <= Value.TimeVal->tv_usec )
211 && ( 1000000 > Value.TimeVal->tv_usec )){
212 BytesToWrite = sizeof ( *Value.TimeVal );
213 errno = 0;
214 }
215 }
216 }
217
218 //
219 // Display the error
220 //
221 if ( 0 == BytesToWrite ) {
222 Print ( L"ERROR - Invalid value!\r\n" );
223 }
224
225 //
226 // Return the number of bytes to be written
227 //
228 return BytesToWrite;
229 }
230
231
232 /**
233 Set the socket options
234
235 @param [in] Argc The number of arguments
236 @param [in] Argv The argument value array
237
238 @retval 0 The application exited normally.
239 @retval Other An error occurred.
240 **/
241 int
242 main (
243 IN int Argc,
244 IN char **Argv
245 )
246 {
247 socklen_t BytesToWrite;
248 socklen_t LengthInBytes;
249 CONST OPTIONS * pEnd;
250 CONST OPTIONS * pOption;
251 int s;
252 int Status;
253
254 DEBUG (( DEBUG_INFO,
255 "%a starting\r\n",
256 Argv[0]));
257
258 //
259 // Parse the socket option
260 //
261 pOption = &mOptions[0];
262 pEnd = &pOption[sizeof ( mOptions ) / sizeof ( mOptions[0])];
263 if ( 2 <= Argc ) {
264 while ( pEnd > pOption ) {
265 if ( 0 == strcmp ( Argv[1], pOption->pOptionName )) {
266 break;
267 }
268 pOption += 1;
269 }
270 if ( pEnd <= pOption ) {
271 Print ( L"ERROR: Invalid option: %a\r\n", Argv[1]);
272 Argc = 1;
273 }
274 }
275
276 //
277 // Display the help if necessary
278 //
279 if (( 2 > Argc ) || ( 3 < Argc )) {
280 Print ( L"%a <option>\r\n", Argv[0]);
281 Print ( L"\r\n" );
282 Print ( L"Option one of:\r\n" );
283 pOption = &mOptions[0];
284 while ( pEnd > pOption ) {
285 Print ( L" %a: %a\r\n",
286 pOption->pOptionName,
287 pOption->bSetAllowed ? "get/set" : "get" );
288 pOption += 1;
289 }
290 errno = EINVAL;
291 }
292 else {
293 //
294 // Determine if the value is to be set
295 //
296 BytesToWrite = 0;
297 if (( 3 > Argc )
298 || ( 0 < ( BytesToWrite = GetOptionValue ( pOption, Argv [2])))) {
299 //
300 // Get the socket
301 //
302 s = socket ( AF_INET, 0, 0 );
303 if ( -1 == s ) {
304 Print ( L"ERROR - Unable to open the socket, errno: %d\r\n", errno );
305 }
306 else {
307 //
308 // Display the option value
309 //
310 LengthInBytes = sizeof ( mBuffer );
311 Status = getsockopt ( s,
312 pOption->OptionLevel,
313 pOption->OptionValue,
314 &mBuffer,
315 &LengthInBytes );
316 if ( -1 == Status ) {
317 Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
318 }
319 else {
320 DisplayOption ( pOption,
321 LengthInBytes,
322 FALSE,
323 (BOOLEAN)( 0 == BytesToWrite ));
324
325 //
326 // Determine if the value is to be set
327 //
328 if (( 0 < BytesToWrite )
329 && ( BytesToWrite == LengthInBytes )) {
330 //
331 // Set the option value
332 //
333 Status = setsockopt ( s,
334 pOption->OptionLevel,
335 pOption->OptionValue,
336 &mValue,
337 BytesToWrite );
338 if ( -1 == Status ) {
339 Print ( L"ERROR - setsockopt failed, errno: %d\r\n", errno );
340 }
341 else {
342 //
343 // Display the updated option value
344 //
345 Status = getsockopt ( s,
346 pOption->OptionLevel,
347 pOption->OptionValue,
348 &mBuffer,
349 &LengthInBytes );
350 if ( -1 == Status ) {
351 Print ( L"ERROR - getsockopt failed, errno: %d\r\n", errno );
352 }
353 else {
354 DisplayOption ( pOption,
355 LengthInBytes,
356 TRUE,
357 TRUE );
358 }
359 }
360 }
361 }
362
363 //
364 // Done with the socket
365 //
366 close ( s );
367 }
368 }
369 }
370
371 //
372 // All done
373 //
374 DEBUG (( DEBUG_INFO,
375 "%a exiting, errno: %d\r\n",
376 Argv[0],
377 errno ));
378 return errno;
379 }