Changeset ea28272 in mainline for uspace/app/netecho/netecho.c
- Timestamp:
- 2010-12-30T13:43:27Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- d770deb
- Parents:
- d70d80ed (diff), f418e51 (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
rd70d80ed rea28272 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> … … 50 53 #include "print_error.h" 51 54 52 /** Network echo module name. */ 53 #define NAME "Network Echo" 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; 54 69 55 70 static void echo_print_help(void) 56 71 { 57 72 printf( 58 "Network Echo aplication\n" \ 59 "Usage: echo [options]\n" \ 60 "Where options are:\n" \ 61 "-b backlog | --backlog=size\n" \ 62 "\tThe size of the accepted sockets queue. Only for SOCK_STREAM. The default is 3.\n" \ 63 "\n" \ 64 "-c count | --count=count\n" \ 65 "\tThe number of received messages to handle. A negative number means infinity. The default is infinity.\n" \ 66 "\n" \ 67 "-f protocol_family | --family=protocol_family\n" \ 68 "\tThe listenning socket protocol family. Only the PF_INET and PF_INET6 are supported.\n" 69 "\n" \ 70 "-h | --help\n" \ 71 "\tShow this application help.\n" 72 "\n" \ 73 "-p port_number | --port=port_number\n" \ 74 "\tThe port number the application should listen at. The default is 7.\n" \ 75 "\n" \ 76 "-r reply_string | --reply=reply_string\n" \ 77 "\tThe constant reply string. The default is the original data received.\n" \ 78 "\n" \ 79 "-s receive_size | --size=receive_size\n" \ 80 "\tThe maximum receive data size the application should accept. The default is 1024 bytes.\n" \ 81 "\n" \ 82 "-t socket_type | --type=socket_type\n" \ 83 "\tThe listenning socket type. Only the SOCK_DGRAM and the SOCK_STREAM are supported.\n" \ 84 "\n" \ 85 "-v | --verbose\n" \ 86 "\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" 87 109 ); 88 110 } 89 111 90 int main(int argc, char *argv[])112 static int netecho_parse_option(int argc, char *argv[], int *index) 91 113 { 92 size_t size = 1024;93 int verbose = 0;94 char *reply = NULL;95 sock_type_t type = SOCK_DGRAM;96 int count = -1;97 int family = PF_INET;98 uint16_t port = 7;99 int backlog = 3;100 101 socklen_t max_length = sizeof(struct sockaddr_in6);102 uint8_t address_data[max_length];103 struct sockaddr *address = (struct sockaddr *) address_data;104 struct sockaddr_in *address_in = (struct sockaddr_in *) address;105 struct sockaddr_in6 *address_in6 = (struct sockaddr_in6 *) address;106 socklen_t addrlen;107 char address_string[INET6_ADDRSTRLEN];108 uint8_t *address_start;109 int socket_id;110 int listening_id;111 char *data;112 size_t length;113 int index;114 size_t reply_length;115 114 int value; 116 115 int rc; 117 116 118 // parse the command line arguments 119 for (index = 1; index < argc; ++ index) { 120 if (argv[index][0] == '-') { 121 switch (argv[index][1]) { 122 case 'b': 123 rc = arg_parse_int(argc, argv, &index, &backlog, 0); 124 if (rc != EOK) 125 return rc; 126 break; 127 case 'c': 128 rc = arg_parse_int(argc, argv, &index, &count, 0); 129 if (rc != EOK) 130 return rc; 131 break; 132 case 'f': 133 rc = arg_parse_name_int(argc, argv, &index, &family, 0, socket_parse_protocol_family); 134 if (rc != EOK) 135 return rc; 136 break; 137 case 'h': 138 echo_print_help(); 139 return EOK; 140 break; 141 case 'p': 142 rc = arg_parse_int(argc, argv, &index, &value, 0); 143 if (rc != EOK) 144 return rc; 145 port = (uint16_t) value; 146 break; 147 case 'r': 148 rc = arg_parse_string(argc, argv, &index, &reply, 0); 149 if (rc != EOK) 150 return rc; 151 break; 152 case 's': 153 rc = arg_parse_int(argc, argv, &index, &value, 0); 154 if (rc != EOK) 155 return rc; 156 size = (value >= 0) ? (size_t) value : 0; 157 break; 158 case 't': 159 rc = arg_parse_name_int(argc, argv, &index, &value, 0, socket_parse_socket_type); 160 if (rc != EOK) 161 return rc; 162 type = (sock_type_t) value; 163 break; 164 case 'v': 165 verbose = 1; 166 break; 167 // long options with the double minus sign ('-') 168 case '-': 169 if (str_lcmp(argv[index] + 2, "backlog=", 6) == 0) { 170 rc = arg_parse_int(argc, argv, &index, &backlog, 8); 171 if (rc != EOK) 172 return rc; 173 } else if (str_lcmp(argv[index] + 2, "count=", 6) == 0) { 174 rc = arg_parse_int(argc, argv, &index, &count, 8); 175 if (rc != EOK) 176 return rc; 177 } else if (str_lcmp(argv[index] + 2, "family=", 7) == 0) { 178 rc = arg_parse_name_int(argc, argv, &index, &family, 9, socket_parse_protocol_family); 179 if (rc != EOK) 180 return rc; 181 } else if (str_lcmp(argv[index] + 2, "help", 5) == 0) { 182 echo_print_help(); 183 return EOK; 184 } else if (str_lcmp(argv[index] + 2, "port=", 5) == 0) { 185 rc = arg_parse_int(argc, argv, &index, &value, 7); 186 if (rc != EOK) 187 return rc; 188 port = (uint16_t) value; 189 } else if (str_lcmp(argv[index] + 2, "reply=", 6) == 0) { 190 rc = arg_parse_string(argc, argv, &index, &reply, 8); 191 if (rc != EOK) 192 return rc; 193 } else if (str_lcmp(argv[index] + 2, "size=", 5) == 0) { 194 rc = arg_parse_int(argc, argv, &index, &value, 7); 195 if (rc != EOK) 196 return rc; 197 size = (value >= 0) ? (size_t) value : 0; 198 } else if (str_lcmp(argv[index] + 2, "type=", 5) == 0) { 199 rc = arg_parse_name_int(argc, argv, &index, &value, 7, 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 } 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 return EOK; 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; 214 205 } else { 215 206 echo_print_help(); 216 207 return EINVAL; 217 208 } 218 } 219 220 // check the buffer size 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 227 socklen_t addrlen; 228 int socket_id; 229 ssize_t rcv_size; 230 size_t length; 231 uint8_t *address_start; 232 233 char address_string[INET6_ADDRSTRLEN]; 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; 275 break; 276 case AF_INET6: 277 port = ntohs(address_in6->sin6_port); 278 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr; 279 break; 280 default: 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 } 296 } 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 { 335 echo_print_help(); 336 return EINVAL; 337 } 338 } 339 340 /* Check buffer size */ 221 341 if (size <= 0) { 222 342 fprintf(stderr, "Receive size too small (%zu). Using 1024 bytes instead.\n", size); 223 343 size = 1024; 224 344 } 225 // size plus the terminating null (\0) 345 346 /* size plus the terminating null character. */ 226 347 data = (char *) malloc(size + 1); 227 348 if (!data) { … … 230 351 } 231 352 232 / / set the reply size if set353 /* Set the reply size if set */ 233 354 reply_length = reply ? str_length(reply) : 0; 234 355 235 // prepare the address buffer 236 bzero(address_data, max_length); 356 /* Prepare the address buffer */ 237 357 switch (family) { 238 358 case PF_INET: 239 address_in->sin_family = AF_INET; 240 address_in->sin_port = htons(port); 241 addrlen = sizeof(struct sockaddr_in); 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); 242 363 break; 243 364 case PF_INET6: 244 address_in6->sin6_family = AF_INET6; 245 address_in6->sin6_port = htons(port); 246 addrlen = sizeof(struct sockaddr_in6); 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); 247 369 break; 248 370 default: … … 251 373 } 252 374 253 / / get a listening socket375 /* Get a listening socket */ 254 376 listening_id = socket(family, type, 0); 255 377 if (listening_id < 0) { … … 258 380 } 259 381 260 / / if the stream socket is used382 /* if the stream socket is used */ 261 383 if (type == SOCK_STREAM) { 262 / / check the backlog384 /* Check backlog size */ 263 385 if (backlog <= 0) { 264 386 fprintf(stderr, "Accepted sockets queue size too small (%zu). Using 3 instead.\n", size); 265 387 backlog = 3; 266 388 } 267 // set the backlog 389 390 /* Set the backlog */ 268 391 rc = listen(listening_id, backlog); 269 392 if (rc != EOK) { … … 273 396 } 274 397 275 / / bind the listenning socket398 /* Bind the listening socket */ 276 399 rc = bind(listening_id, address, addrlen); 277 400 if (rc != EOK) { … … 283 406 printf("Socket %d listenning at %d\n", listening_id, port); 284 407 285 socket_id = listening_id;286 287 // do count times288 // or indefinitely if set to a negative value408 /* 409 * do count times 410 * or indefinitely if set to a negative value 411 */ 289 412 while (count) { 290 291 addrlen = max_length; 292 if (type == SOCK_STREAM) { 293 // acceept a socket if the stream socket is used 294 socket_id = accept(listening_id, address, &addrlen); 295 if (socket_id <= 0) { 296 socket_print_error(stderr, socket_id, "Socket accept: ", "\n"); 297 } else { 298 if (verbose) 299 printf("Socket %d accepted\n", socket_id); 300 } 301 } 302 303 // if the datagram socket is used or the stream socked was accepted 304 if (socket_id > 0) { 305 306 // receive an echo request 307 value = recvfrom(socket_id, data, size, 0, address, &addrlen); 308 if (value < 0) { 309 socket_print_error(stderr, value, "Socket receive: ", "\n"); 310 } else { 311 length = (size_t) value; 312 if (verbose) { 313 // print the header 314 315 // get the source port and prepare the address buffer 316 address_start = NULL; 317 switch (address->sa_family) { 318 case AF_INET: 319 port = ntohs(address_in->sin_port); 320 address_start = (uint8_t *) &address_in->sin_addr.s_addr; 321 break; 322 case AF_INET6: 323 port = ntohs(address_in6->sin6_port); 324 address_start = (uint8_t *) &address_in6->sin6_addr.s6_addr; 325 break; 326 default: 327 fprintf(stderr, "Address family %u (%#x) is not supported.\n", 328 address->sa_family, address->sa_family); 329 } 330 // parse the source address 331 if (address_start) { 332 rc = inet_ntop(address->sa_family, address_start, address_string, sizeof(address_string)); 333 if (rc != EOK) { 334 fprintf(stderr, "Received address error %d\n", rc); 335 } else { 336 data[length] = '\0'; 337 printf("Socket %d received %zu bytes from %s:%d\n%s\n", 338 socket_id, length, address_string, port, data); 339 } 340 } 341 } 342 343 // answer the request either with the static reply or the original data 344 rc = sendto(socket_id, reply ? reply : data, reply ? reply_length : length, 0, address, addrlen); 345 if (rc != EOK) 346 socket_print_error(stderr, rc, "Socket send: ", "\n"); 347 } 348 349 // close the accepted stream socket 350 if (type == SOCK_STREAM) { 351 rc = closesocket(socket_id); 352 if (rc != EOK) 353 socket_print_error(stderr, rc, "Close socket: ", "\n"); 354 } 355 356 } 357 358 // decrease the count if positive 413 rc = netecho_socket_process_message(listening_id); 414 if (rc != EOK) 415 break; 416 417 /* Decrease count if positive */ 359 418 if (count > 0) { 360 419 count--; 361 420 if (verbose) 362 printf("Waiting for next %d packet(s)\n", count);421 printf("Waiting for next %d message(s)\n", count); 363 422 } 364 423 } … … 367 426 printf("Closing the socket\n"); 368 427 369 / / close the listenning socket428 /* Close listenning socket */ 370 429 rc = closesocket(listening_id); 371 430 if (rc != EOK) {
Note:
See TracChangeset
for help on using the changeset viewer.