Changeset b5e68c8 in mainline for uspace/app/netecho/netecho.c
- Timestamp:
- 2011-05-12T16:49:44Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- f36787d7
- Parents:
- e80329d6 (diff), 750636a (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/netecho/netecho.c
re80329d6 rb5e68c8 28 28 29 29 /** @addtogroup netecho 30 * 30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * Network echo application. 35 * Answers received packets. 34 * Network echo server. 35 * 36 * Sockets-based server that echoes incomming messages. If stream mode 37 * is selected, accepts incoming connections. 36 38 */ 37 39 38 #include < malloc.h>40 #include <assert.h> 39 41 #include <stdio.h> 42 #include <stdlib.h> 40 43 #include <str.h> 41 44 #include <task.h> 42 45 #include <arg_parse.h> 43 #include <err.h>44 46 45 47 #include <net/in.h> … … 51 53 #include "print_error.h" 52 54 53 /** Network echo module name. 54 */ 55 #define NAME "Network Echo" 56 57 /** Prints the application help. 58 */ 59 void echo_print_help(void);60 61 /** Module entry point. 62 * Reads command line parameters and starts listenning. 63 * @param[in] argc The number of command line parameters. 64 * @param[in] argv The command line parameters. 65 * @returns EOK on success. 66 */ 67 int main(int argc, char * argv[]); 68 69 void echo_print_help(void){55 #define NAME "netecho" 56 57 static int count = -1; 58 static int family = PF_INET; 59 static sock_type_t type = SOCK_DGRAM; 60 static uint16_t port = 7; 61 static int backlog = 3; 62 static size_t size = 1024; 63 static int verbose = 0; 64 65 static char *reply = NULL; 66 static size_t reply_length; 67 68 static char *data; 69 70 static void echo_print_help(void) 71 { 70 72 printf( 71 "Network Echo aplication\n" \ 72 "Usage: echo [options]\n" \ 73 "Where options are:\n" \ 74 "-b backlog | --backlog=size\n" \ 75 "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \ 76 "\n" \ 77 "-c count | --count=count\n" \ 78 "\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \ 79 "\n" \ 80 "-f protocol_family | --family=protocol_family\n" \ 81 "\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n" 82 "\n" \ 83 "-h | --help\n" \ 84 "\tShow this application help.\n" 85 "\n" \ 86 "-p port_number | --port=port_number\n" \ 87 "\tThe port number the application should listen at. The default is 7.\n" \ 88 "\n" \ 89 "-r reply_string | --reply=reply_string\n" \ 90 "\tThe constant reply string. The default is the original data received.\n" \ 91 "\n" \ 92 "-s receive_size | --size=receive_size\n" \ 93 "\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \ 94 "\n" \ 95 "-t socket_type | --type=socket_type\n" \ 96 "\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \ 97 "\n" \ 98 "-v | --verbose\n" \ 99 "\tShow all output messages.\n" 73 "Network echo server\n" 74 "Usage: " NAME " [options]\n" 75 "Where options are:\n" 76 "-b backlog | --backlog=size\n" 77 "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. " 78 "The default is 3.\n" 79 "\n" 80 "-c count | --count=count\n" 81 "\tThe number of received messages to handle. A negative number " 82 "means infinity. The default is infinity.\n" 83 "\n" 84 "-f protocol_family | --family=protocol_family\n" 85 "\tThe listenning socket protocol family. Only the PF_INET and " 86 "PF_INET6 are supported.\n" 87 "\n" 88 "-h | --help\n" 89 "\tShow this application help.\n" 90 "\n" 91 "-p port_number | --port=port_number\n" 92 "\tThe port number the application should listen at. The default " 93 "is 7.\n" 94 "\n" 95 "-r reply_string | --reply=reply_string\n" 96 "\tThe constant reply string. The default is the original data " 97 "received.\n" 98 "\n" 99 "-s receive_size | --size=receive_size\n" 100 "\tThe maximum receive data size the application should accept. " 101 "The default is 1024 bytes.\n" 102 "\n" 103 "-t socket_type | --type=socket_type\n" 104 "\tThe listenning socket type. Only the SOCK_DGRAM and the " 105 "SOCK_STREAM are supported.\n" 106 "\n" 107 "-v | --verbose\n" 108 "\tShow all output messages.\n" 100 109 ); 101 110 } 102 111 103 int main(int argc, char * argv[]){ 104 ERROR_DECLARE; 105 106 size_t size = 1024; 107 int verbose = 0; 108 char * reply = NULL; 109 sock_type_t type = SOCK_DGRAM; 110 int count = -1; 111 int family = PF_INET; 112 uint16_t port = 7; 113 int backlog = 3; 114 115 socklen_t max_length = sizeof(struct sockaddr_in6); 116 uint8_t address_data[max_length]; 117 struct sockaddr * address = (struct sockaddr *) address_data; 118 struct sockaddr_in * address_in = (struct sockaddr_in *) address; 119 struct sockaddr_in6 * address_in6 = (struct sockaddr_in6 *) address; 112 static int netecho_parse_option(int argc, char *argv[], int *index) 113 { 114 int value; 115 int rc; 116 117 switch (argv[*index][1]) { 118 case 'b': 119 rc = arg_parse_int(argc, argv, index, &backlog, 0); 120 if (rc != EOK) 121 return rc; 122 break; 123 case 'c': 124 rc = arg_parse_int(argc, argv, index, &count, 0); 125 if (rc != EOK) 126 return rc; 127 break; 128 case 'f': 129 rc = arg_parse_name_int(argc, argv, index, &family, 0, 130 socket_parse_protocol_family); 131 if (rc != EOK) 132 return rc; 133 break; 134 case 'h': 135 echo_print_help(); 136 exit(0); 137 break; 138 case 'p': 139 rc = arg_parse_int(argc, argv, index, &value, 0); 140 if (rc != EOK) 141 return rc; 142 port = (uint16_t) value; 143 break; 144 case 'r': 145 rc = arg_parse_string(argc, argv, index, &reply, 0); 146 if (rc != EOK) 147 return rc; 148 break; 149 case 's': 150 rc = arg_parse_int(argc, argv, index, &value, 0); 151 if (rc != EOK) 152 return rc; 153 size = (value >= 0) ? (size_t) value : 0; 154 break; 155 case 't': 156 rc = arg_parse_name_int(argc, argv, index, &value, 0, 157 socket_parse_socket_type); 158 if (rc != EOK) 159 return rc; 160 type = (sock_type_t) value; 161 break; 162 case 'v': 163 verbose = 1; 164 break; 165 /* Long options with double dash */ 166 case '-': 167 if (str_lcmp(argv[*index] + 2, "backlog=", 6) == 0) { 168 rc = arg_parse_int(argc, argv, index, &backlog, 8); 169 if (rc != EOK) 170 return rc; 171 } else if (str_lcmp(argv[*index] + 2, "count=", 6) == 0) { 172 rc = arg_parse_int(argc, argv, index, &count, 8); 173 if (rc != EOK) 174 return rc; 175 } else if (str_lcmp(argv[*index] + 2, "family=", 7) == 0) { 176 rc = arg_parse_name_int(argc, argv, index, &family, 9, 177 socket_parse_protocol_family); 178 if (rc != EOK) 179 return rc; 180 } else if (str_lcmp(argv[*index] + 2, "help", 5) == 0) { 181 echo_print_help(); 182 exit(0); 183 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) { 184 rc = arg_parse_int(argc, argv, index, &value, 7); 185 if (rc != EOK) 186 return rc; 187 port = (uint16_t) value; 188 } else if (str_lcmp(argv[*index] + 2, "reply=", 6) == 0) { 189 rc = arg_parse_string(argc, argv, index, &reply, 8); 190 if (rc != EOK) 191 return rc; 192 } else if (str_lcmp(argv[*index] + 2, "size=", 5) == 0) { 193 rc = arg_parse_int(argc, argv, index, &value, 7); 194 if (rc != EOK) 195 return rc; 196 size = (value >= 0) ? (size_t) value : 0; 197 } else if (str_lcmp(argv[*index] + 2, "type=", 5) == 0) { 198 rc = arg_parse_name_int(argc, argv, index, &value, 7, 199 socket_parse_socket_type); 200 if (rc != EOK) 201 return rc; 202 type = (sock_type_t) value; 203 } else if (str_lcmp(argv[*index] + 2, "verbose", 8) == 0) { 204 verbose = 1; 205 } else { 206 echo_print_help(); 207 return EINVAL; 208 } 209 break; 210 default: 211 echo_print_help(); 212 return EINVAL; 213 } 214 215 return EOK; 216 } 217 218 /** Echo one message (accept one connection and echo message). 219 * 220 * @param listening_id Listening socket. 221 * @return EOK on success or negative error code. 222 */ 223 static int netecho_socket_process_message(int listening_id) 224 { 225 uint8_t address_buf[sizeof(struct sockaddr_in6)]; 226 120 227 socklen_t addrlen; 228 int socket_id; 229 ssize_t rcv_size; 230 size_t length; 231 uint8_t *address_start; 232 121 233 char address_string[INET6_ADDRSTRLEN]; 122 uint8_t * address_start; 123 int socket_id; 124 int listening_id; 125 char * data; 126 size_t length; 127 int index; 128 size_t reply_length; 129 int value; 130 131 // parse the command line arguments 132 for(index = 1; index < argc; ++ index){ 133 if(argv[index][0] == '-'){ 134 switch(argv[index][1]){ 135 case 'b': 136 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 0)); 234 struct sockaddr_in *address_in = (struct sockaddr_in *) address_buf; 235 struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address_buf; 236 struct sockaddr *address = (struct sockaddr *) address_buf; 237 238 int rc; 239 240 if (type == SOCK_STREAM) { 241 /* Accept a socket if a stream socket is used */ 242 addrlen = sizeof(address_buf); 243 socket_id = accept(listening_id, (void *) address_buf, &addrlen); 244 if (socket_id <= 0) { 245 socket_print_error(stderr, socket_id, "Socket accept: ", "\n"); 246 } else { 247 if (verbose) 248 printf("Socket %d accepted\n", socket_id); 249 } 250 251 assert((size_t) addrlen <= sizeof(address_buf)); 252 } else { 253 socket_id = listening_id; 254 } 255 256 /* if the datagram socket is used or the stream socked was accepted */ 257 if (socket_id > 0) { 258 259 /* Receive a message to echo */ 260 rcv_size = recvfrom(socket_id, data, size, 0, address, 261 &addrlen); 262 if (rcv_size < 0) { 263 socket_print_error(stderr, rcv_size, "Socket receive: ", "\n"); 264 } else { 265 length = (size_t) rcv_size; 266 if (verbose) { 267 /* Print the header */ 268 269 /* Get the source port and prepare the address buffer */ 270 address_start = NULL; 271 switch (address->sa_family) { 272 case AF_INET: 273 port = ntohs(address_in->sin_port); 274 address_start = (uint8_t *) &address_in->sin_addr.s_addr; 137 275 break; 138 case 'c': 139 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 0)); 140 break; 141 case 'f': 142 ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family)); 143 break; 144 case 'h': 145 echo_print_help(); 146 return EOK; 147 break; 148 case 'p': 149 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0)); 150 port = (uint16_t) value; 151 break; 152 case 'r': 153 ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 0)); 154 break; 155 case 's': 156 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 0)); 157 size = (value >= 0) ? (size_t) value : 0; 158 break; 159 case 't': 160 ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type)); 161 type = (sock_type_t) value; 162 break; 163 case 'v': 164 verbose = 1; 165 break; 166 // long options with the double minus sign ('-') 167 case '-': 168 if(str_lcmp(argv[index] + 2, "backlog=", 6) == 0){ 169 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &backlog, 8)); 170 }else if(str_lcmp(argv[index] + 2, "count=", 6) == 0){ 171 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &count, 8)); 172 }else if(str_lcmp(argv[index] + 2, "family=", 7) == 0){ 173 ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family)); 174 }else if(str_lcmp(argv[index] + 2, "help", 5) == 0){ 175 echo_print_help(); 176 return EOK; 177 }else if(str_lcmp(argv[index] + 2, "port=", 5) == 0){ 178 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7)); 179 port = (uint16_t) value; 180 }else if(str_lcmp(argv[index] + 2, "reply=", 6) == 0){ 181 ERROR_PROPAGATE(arg_parse_string(argc, argv, &index, &reply, 8)); 182 }else if(str_lcmp(argv[index] + 2, "size=", 5) == 0){ 183 ERROR_PROPAGATE(arg_parse_int(argc, argv, &index, &value, 7)); 184 size = (value >= 0) ? (size_t) value : 0; 185 }else if(str_lcmp(argv[index] + 2, "type=", 5) == 0){ 186 ERROR_PROPAGATE(arg_parse_name_int(argc, argv, &index, &value, 7, socket_parse_socket_type)); 187 type = (sock_type_t) value; 188 }else if(str_lcmp(argv[index] + 2, "verbose", 8) == 0){ 189 verbose = 1; 190 }else{ 191 echo_print_help(); 192 return EINVAL; 193 } 276 case AF_INET6: 277 port = ntohs(address_in6->sin6_port); 278 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr; 194 279 break; 195 280 default: 196 echo_print_help(); 197 return EINVAL; 281 fprintf(stderr, "Address family %u (%#x) is not supported.\n", 282 address->sa_family, address->sa_family); 283 } 284 285 /* Parse source address */ 286 if (address_start) { 287 rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)); 288 if (rc != EOK) { 289 fprintf(stderr, "Received address error %d\n", rc); 290 } else { 291 data[length] = '\0'; 292 printf("Socket %d received %zu bytes from %s:%d\n%s\n", 293 socket_id, length, address_string, port, data); 294 } 295 } 198 296 } 199 }else{ 297 298 /* Answer the request either with the static reply or the original data */ 299 rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen); 300 if (rc != EOK) 301 socket_print_error(stderr, rc, "Socket send: ", "\n"); 302 } 303 304 /* Close accepted stream socket */ 305 if (type == SOCK_STREAM) { 306 rc = closesocket(socket_id); 307 if (rc != EOK) 308 socket_print_error(stderr, rc, "Close socket: ", "\n"); 309 } 310 311 } 312 313 return EOK; 314 } 315 316 317 int main(int argc, char *argv[]) 318 { 319 struct sockaddr *address;; 320 struct sockaddr_in address_in; 321 struct sockaddr_in6 address_in6; 322 socklen_t addrlen; 323 324 int listening_id; 325 int index; 326 int rc; 327 328 /* Parse command line arguments */ 329 for (index = 1; index < argc; ++index) { 330 if (argv[index][0] == '-') { 331 rc = netecho_parse_option(argc, argv, &index); 332 if (rc != EOK) 333 return rc; 334 } else { 200 335 echo_print_help(); 201 336 return EINVAL; … … 203 338 } 204 339 205 / / check the buffer size206 if (size <= 0){207 fprintf(stderr, "Receive size too small (% d). Using 1024 bytes instead.\n", size);340 /* Check buffer size */ 341 if (size <= 0) { 342 fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size); 208 343 size = 1024; 209 344 } 210 // size plus the terminating null (\0) 345 346 /* size plus the terminating null character. */ 211 347 data = (char *) malloc(size + 1); 212 if (! data){348 if (!data) { 213 349 fprintf(stderr, "Failed to allocate receive buffer.\n"); 214 350 return ENOMEM; 215 351 } 216 352 217 / / set the reply size if set353 /* Set the reply size if set */ 218 354 reply_length = reply ? str_length(reply) : 0; 219 355 220 // prepare the address buffer 221 bzero(address_data, max_length); 222 switch(family){ 223 case PF_INET: 224 address_in->sin_family = AF_INET; 225 address_in->sin_port = htons(port); 226 addrlen = sizeof(struct sockaddr_in); 227 break; 228 case PF_INET6: 229 address_in6->sin6_family = AF_INET6; 230 address_in6->sin6_port = htons(port); 231 addrlen = sizeof(struct sockaddr_in6); 232 break; 233 default: 234 fprintf(stderr, "Protocol family is not supported\n"); 235 return EAFNOSUPPORT; 236 } 237 238 // get a listening socket 356 /* Prepare the address buffer */ 357 switch (family) { 358 case PF_INET: 359 address_in.sin_family = AF_INET; 360 address_in.sin_port = htons(port); 361 address = (struct sockaddr *) &address_in; 362 addrlen = sizeof(address_in); 363 break; 364 case PF_INET6: 365 address_in6.sin6_family = AF_INET6; 366 address_in6.sin6_port = htons(port); 367 address = (struct sockaddr *) &address_in6; 368 addrlen = sizeof(address_in6); 369 break; 370 default: 371 fprintf(stderr, "Protocol family is not supported\n"); 372 return EAFNOSUPPORT; 373 } 374 375 /* Get a listening socket */ 239 376 listening_id = socket(family, type, 0); 240 if (listening_id < 0){377 if (listening_id < 0) { 241 378 socket_print_error(stderr, listening_id, "Socket create: ", "\n"); 242 379 return listening_id; 243 380 } 244 381 245 / / if the stream socket is used246 if (type == SOCK_STREAM){247 / / check the backlog248 if (backlog <= 0){249 fprintf(stderr, "Accepted sockets queue size too small (% d). Using 3 instead.\n", size);382 /* if the stream socket is used */ 383 if (type == SOCK_STREAM) { 384 /* Check backlog size */ 385 if (backlog <= 0) { 386 fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size); 250 387 backlog = 3; 251 388 } 252 // set the backlog 253 if(ERROR_OCCURRED(listen(listening_id, backlog))){ 254 socket_print_error(stderr, ERROR_CODE, "Socket listen: ", "\n"); 255 return ERROR_CODE; 256 } 257 } 258 259 // bind the listenning socket 260 if(ERROR_OCCURRED(bind(listening_id, address, addrlen))){ 261 socket_print_error(stderr, ERROR_CODE, "Socket bind: ", "\n"); 262 return ERROR_CODE; 263 } 264 265 if(verbose){ 389 390 /* Set the backlog */ 391 rc = listen(listening_id, backlog); 392 if (rc != EOK) { 393 socket_print_error(stderr, rc, "Socket listen: ", "\n"); 394 return rc; 395 } 396 } 397 398 /* Bind the listening socket */ 399 rc = bind(listening_id, address, addrlen); 400 if (rc != EOK) { 401 socket_print_error(stderr, rc, "Socket bind: ", "\n"); 402 return rc; 403 } 404 405 if (verbose) 266 406 printf("Socket %d listenning at %d\n", listening_id, port); 267 } 268 269 socket_id = listening_id; 270 271 // do count times 272 // or indefinitely if set to a negative value 273 while(count){ 274 275 addrlen = max_length; 276 if(type == SOCK_STREAM){ 277 // acceept a socket if the stream socket is used 278 socket_id = accept(listening_id, address, &addrlen); 279 if(socket_id <= 0){ 280 socket_print_error(stderr, socket_id, "Socket accept: ", "\n"); 281 }else{ 282 if(verbose){ 283 printf("Socket %d accepted\n", socket_id); 284 } 285 } 286 } 287 288 // if the datagram socket is used or the stream socked was accepted 289 if(socket_id > 0){ 290 291 // receive an echo request 292 value = recvfrom(socket_id, data, size, 0, address, &addrlen); 293 if(value < 0){ 294 socket_print_error(stderr, value, "Socket receive: ", "\n"); 295 }else{ 296 length = (size_t) value; 297 if(verbose){ 298 // print the header 299 300 // get the source port and prepare the address buffer 301 address_start = NULL; 302 switch(address->sa_family){ 303 case AF_INET: 304 port = ntohs(address_in->sin_port); 305 address_start = (uint8_t *) &address_in->sin_addr.s_addr; 306 break; 307 case AF_INET6: 308 port = ntohs(address_in6->sin6_port); 309 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr; 310 break; 311 default: 312 fprintf(stderr, "Address family %d (0x%X) is not supported.\n", address->sa_family); 313 } 314 // parse the source address 315 if(address_start){ 316 if(ERROR_OCCURRED(inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)))){ 317 fprintf(stderr, "Received address error %d\n", ERROR_CODE); 318 }else{ 319 data[length] = '\0'; 320 printf("Socket %d received %d bytes from %s:%d\n%s\n", socket_id, length, address_string, port, data); 321 } 322 } 323 } 324 325 // answer the request either with the static reply or the original data 326 if(ERROR_OCCURRED(sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen))){ 327 socket_print_error(stderr, ERROR_CODE, "Socket send: ", "\n"); 328 } 329 330 } 331 332 // close the accepted stream socket 333 if(type == SOCK_STREAM){ 334 if(ERROR_OCCURRED(closesocket(socket_id))){ 335 socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n"); 336 } 337 } 338 339 } 340 341 // decrease the count if positive 342 if(count > 0){ 343 -- count; 344 if(verbose){ 345 printf("Waiting for next %d packet(s)\n", count); 346 } 347 } 348 } 349 350 if(verbose){ 407 408 /* 409 * do count times 410 * or indefinitely if set to a negative value 411 */ 412 while (count) { 413 rc = netecho_socket_process_message(listening_id); 414 if (rc != EOK) 415 break; 416 417 /* Decrease count if positive */ 418 if (count > 0) { 419 count--; 420 if (verbose) 421 printf("Waiting for next %d message(s)\n", count); 422 } 423 } 424 425 if (verbose) 351 426 printf("Closing the socket\n"); 352 } 353 354 // close the listenning socket355 if (ERROR_OCCURRED(closesocket(listening_id))){356 socket_print_error(stderr, ERROR_CODE, "Close socket: ", "\n");357 return ERROR_CODE;358 } 359 360 if (verbose){427 428 /* Close listenning socket */ 429 rc = closesocket(listening_id); 430 if (rc != EOK) { 431 socket_print_error(stderr, rc, "Close socket: ", "\n"); 432 return rc; 433 } 434 435 if (verbose) 361 436 printf("Exiting\n"); 362 }363 437 364 438 return EOK;
Note:
See TracChangeset
for help on using the changeset viewer.