Changeset 89c57b6 in mainline for uspace/srv/net/tl/udp/udp.c
- Timestamp:
- 2011-04-13T14:45:41Z (15 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 88634420
- Parents:
- cefb126 (diff), 17279ead (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
-
uspace/srv/net/tl/udp/udp.c (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/net/tl/udp/udp.c
rcefb126 r89c57b6 28 28 29 29 /** @addtogroup udp 30 * @{30 * @{ 31 31 */ 32 32 33 33 /** @file 34 * UDP module implementation.35 * @see udp.h34 * UDP module implementation. 35 * @see udp.h 36 36 */ 37 37 … … 40 40 #include <malloc.h> 41 41 #include <stdio.h> 42 #include <ipc/ipc.h>43 42 #include <ipc/services.h> 44 45 #include <net_err.h> 46 #include <net_messages.h> 47 #include <net_modules.h> 43 #include <ipc/net.h> 44 #include <ipc/tl.h> 45 #include <ipc/socket.h> 48 46 #include <adt/dynamic_fifo.h> 49 #include <packet/packet_client.h> 47 #include <errno.h> 48 49 #include <net/socket_codes.h> 50 #include <net/ip_protocols.h> 51 #include <net/in.h> 52 #include <net/in6.h> 53 #include <net/inet.h> 54 #include <net/modules.h> 55 56 #include <packet_client.h> 50 57 #include <packet_remote.h> 51 58 #include <net_checksum.h> 52 #include <in.h>53 #include <in6.h>54 #include <inet.h>55 59 #include <ip_client.h> 56 60 #include <ip_interface.h> 57 #include <ip_protocols.h>58 61 #include <icmp_client.h> 59 #include <icmp_ interface.h>62 #include <icmp_remote.h> 60 63 #include <net_interface.h> 61 #include <socket_codes.h>62 #include <socket_errno.h>63 64 #include <socket_core.h> 64 #include <socket_messages.h>65 65 #include <tl_common.h> 66 #include <tl_local.h> 67 #include <tl_interface.h> 68 #include <tl_messages.h> 66 #include <tl_remote.h> 67 #include <tl_skel.h> 69 68 70 69 #include "udp.h" 71 70 #include "udp_header.h" 72 #include "udp_module.h" 73 74 /** UDP module name. 75 */ 76 #define NAME "UDP protocol" 77 78 /** Default UDP checksum computing. 79 */ 71 72 /** UDP module name. */ 73 #define NAME "udp" 74 75 /** Default UDP checksum computing. */ 80 76 #define NET_DEFAULT_UDP_CHECKSUM_COMPUTING true 81 77 82 /** Default UDP autobind when sending via unbound sockets. 83 */ 78 /** Default UDP autobind when sending via unbound sockets. */ 84 79 #define NET_DEFAULT_UDP_AUTOBINDING true 85 80 86 /** Maximum UDP fragment size. 87 */ 88 #define MAX_UDP_FRAGMENT_SIZE 65535 89 90 /** Free ports pool start. 91 */ 92 #define UDP_FREE_PORTS_START 1025 93 94 /** Free ports pool end. 95 */ 81 /** Maximum UDP fragment size. */ 82 #define MAX_UDP_FRAGMENT_SIZE 65535 83 84 /** Free ports pool start. */ 85 #define UDP_FREE_PORTS_START 1025 86 87 /** Free ports pool end. */ 96 88 #define UDP_FREE_PORTS_END 65535 97 89 90 /** UDP global data. */ 91 udp_globals_t udp_globals; 92 93 /** Releases the packet and returns the result. 94 * 95 * @param[in] packet The packet queue to be released. 96 * @param[in] result The result to be returned. 97 * @return The result parameter. 98 */ 99 static int udp_release_and_return(packet_t *packet, int result) 100 { 101 pq_release_remote(udp_globals.net_phone, packet_get_id(packet)); 102 return result; 103 } 104 98 105 /** Processes the received UDP packet queue. 99 * Is used as an entry point from the underlying IP module. 100 * Locks the global lock and calls udp_process_packet() function. 101 * @param[in] device_id The receiving device identifier. 102 * @param[in,out] packet The received packet queue. 103 * @param receiver The target service. Ignored parameter. 104 * @param[in] error The packet error reporting service. Prefixes the received packet. 105 * @returns EOK on success. 106 * @returns Other error codes as defined for the udp_process_packet() function. 107 */ 108 int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error); 106 * 107 * Notifies the destination socket application. 108 * Releases the packet on error or sends an ICMP error notification. 109 * 110 * @param[in] device_id The receiving device identifier. 111 * @param[in,out] packet The received packet queue. 112 * @param[in] error The packet error reporting service. Prefixes the 113 * received packet. 114 * @return EOK on success. 115 * @return EINVAL if the packet is not valid. 116 * @return EINVAL if the stored packet address is not the 117 * an_addr_t. 118 * @return EINVAL if the packet does not contain any data. 119 * @return NO_DATA if the packet content is shorter than the user 120 * datagram header. 121 * @return ENOMEM if there is not enough memory left. 122 * @return EADDRNOTAVAIL if the destination socket does not exist. 123 * @return Other error codes as defined for the 124 * ip_client_process_packet() function. 125 */ 126 static int udp_process_packet(device_id_t device_id, packet_t *packet, 127 services_t error) 128 { 129 size_t length; 130 size_t offset; 131 int result; 132 udp_header_t *header; 133 socket_core_t *socket; 134 packet_t *next_packet; 135 size_t total_length; 136 uint32_t checksum; 137 int fragments; 138 packet_t *tmp_packet; 139 icmp_type_t type; 140 icmp_code_t code; 141 void *ip_header; 142 struct sockaddr *src; 143 struct sockaddr *dest; 144 packet_dimension_t *packet_dimension; 145 int rc; 146 147 switch (error) { 148 case SERVICE_NONE: 149 break; 150 case SERVICE_ICMP: 151 /* Ignore error */ 152 // length = icmp_client_header_length(packet); 153 154 /* Process error */ 155 result = icmp_client_process_packet(packet, &type, 156 &code, NULL, NULL); 157 if (result < 0) 158 return udp_release_and_return(packet, result); 159 length = (size_t) result; 160 rc = packet_trim(packet, length, 0); 161 if (rc != EOK) 162 return udp_release_and_return(packet, rc); 163 break; 164 default: 165 return udp_release_and_return(packet, ENOTSUP); 166 } 167 168 /* TODO process received ipopts? */ 169 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL); 170 if (result < 0) 171 return udp_release_and_return(packet, result); 172 offset = (size_t) result; 173 174 length = packet_get_data_length(packet); 175 if (length <= 0) 176 return udp_release_and_return(packet, EINVAL); 177 if (length < UDP_HEADER_SIZE + offset) 178 return udp_release_and_return(packet, NO_DATA); 179 180 /* Trim all but UDP header */ 181 rc = packet_trim(packet, offset, 0); 182 if (rc != EOK) 183 return udp_release_and_return(packet, rc); 184 185 /* Get UDP header */ 186 header = (udp_header_t *) packet_get_data(packet); 187 if (!header) 188 return udp_release_and_return(packet, NO_DATA); 189 190 /* Find the destination socket */ 191 socket = socket_port_find(&udp_globals.sockets, 192 ntohs(header->destination_port), (uint8_t *) SOCKET_MAP_KEY_LISTENING, 0); 193 if (!socket) { 194 if (tl_prepare_icmp_packet(udp_globals.net_phone, 195 udp_globals.icmp_phone, packet, error) == EOK) { 196 icmp_destination_unreachable_msg(udp_globals.icmp_phone, 197 ICMP_PORT_UNREACH, 0, packet); 198 } 199 return EADDRNOTAVAIL; 200 } 201 202 /* Count the received packet fragments */ 203 next_packet = packet; 204 fragments = 0; 205 total_length = ntohs(header->total_length); 206 207 /* Compute header checksum if set */ 208 if (header->checksum && !error) { 209 result = packet_get_addr(packet, (uint8_t **) &src, 210 (uint8_t **) &dest); 211 if (result <= 0) 212 return udp_release_and_return(packet, result); 213 214 rc = ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest, 215 result, total_length, &ip_header, &length); 216 if (rc != EOK) { 217 return udp_release_and_return(packet, rc); 218 } else { 219 checksum = compute_checksum(0, ip_header, length); 220 /* 221 * The udp header checksum will be added with the first 222 * fragment later. 223 */ 224 free(ip_header); 225 } 226 } else { 227 header->checksum = 0; 228 checksum = 0; 229 } 230 231 do { 232 fragments++; 233 length = packet_get_data_length(next_packet); 234 if (length <= 0) 235 return udp_release_and_return(packet, NO_DATA); 236 237 if (total_length < length) { 238 rc = packet_trim(next_packet, 0, length - total_length); 239 if (rc != EOK) 240 return udp_release_and_return(packet, rc); 241 242 /* Add partial checksum if set */ 243 if (header->checksum) { 244 checksum = compute_checksum(checksum, 245 packet_get_data(packet), 246 packet_get_data_length(packet)); 247 } 248 249 /* Relese the rest of the packet fragments */ 250 tmp_packet = pq_next(next_packet); 251 while (tmp_packet) { 252 next_packet = pq_detach(tmp_packet); 253 pq_release_remote(udp_globals.net_phone, 254 packet_get_id(tmp_packet)); 255 tmp_packet = next_packet; 256 } 257 258 /* Exit the loop */ 259 break; 260 } 261 total_length -= length; 262 263 /* Add partial checksum if set */ 264 if (header->checksum) { 265 checksum = compute_checksum(checksum, 266 packet_get_data(packet), 267 packet_get_data_length(packet)); 268 } 269 270 } while ((next_packet = pq_next(next_packet)) && (total_length > 0)); 271 272 /* Verify checksum */ 273 if (header->checksum) { 274 if (flip_checksum(compact_checksum(checksum)) != 275 IP_CHECKSUM_ZERO) { 276 if (tl_prepare_icmp_packet(udp_globals.net_phone, 277 udp_globals.icmp_phone, packet, error) == EOK) { 278 /* Checksum error ICMP */ 279 icmp_parameter_problem_msg( 280 udp_globals.icmp_phone, ICMP_PARAM_POINTER, 281 ((size_t) ((void *) &header->checksum)) - 282 ((size_t) ((void *) header)), packet); 283 } 284 return EINVAL; 285 } 286 } 287 288 /* Queue the received packet */ 289 rc = dyn_fifo_push(&socket->received, packet_get_id(packet), 290 SOCKET_MAX_RECEIVED_SIZE); 291 if (rc != EOK) 292 return udp_release_and_return(packet, rc); 293 294 rc = tl_get_ip_packet_dimension(udp_globals.ip_phone, 295 &udp_globals.dimensions, device_id, &packet_dimension); 296 if (rc != EOK) 297 return udp_release_and_return(packet, rc); 298 299 /* Notify the destination socket */ 300 fibril_rwlock_write_unlock(&udp_globals.lock); 301 async_msg_5(socket->phone, NET_SOCKET_RECEIVED, 302 (sysarg_t) socket->socket_id, packet_dimension->content, 0, 0, 303 (sysarg_t) fragments); 304 305 return EOK; 306 } 109 307 110 308 /** Processes the received UDP packet queue. 111 * Notifies the destination socket application. 112 * Releases the packet on error or sends an ICMP error notification.. 113 * @param[in] device_id The receiving device identifier. 114 * @param[in,out] packet The received packet queue. 115 * @param[in] error The packet error reporting service. Prefixes the received packet. 116 * @returns EOK on success. 117 * @returns EINVAL if the packet is not valid. 118 * @returns EINVAL if the stored packet address is not the an_addr_t. 119 * @returns EINVAL if the packet does not contain any data. 120 * @returns NO_DATA if the packet content is shorter than the user datagram header. 121 * @returns ENOMEM if there is not enough memory left. 122 * @returns EADDRNOTAVAIL if the destination socket does not exist. 123 * @returns Other error codes as defined for the ip_client_process_packet() function. 124 */ 125 int udp_process_packet(device_id_t device_id, packet_t packet, services_t error); 126 127 /** Releases the packet and returns the result. 128 * @param[in] packet The packet queue to be released. 129 * @param[in] result The result to be returned. 130 * @return The result parameter. 131 */ 132 int udp_release_and_return(packet_t packet, int result); 133 134 /** @name Socket messages processing functions 135 */ 136 /*@{*/ 137 138 /** Processes the socket client messages. 139 * Runs until the client module disconnects. 140 * @param[in] callid The message identifier. 141 * @param[in] call The message parameters. 142 * @returns EOK on success. 143 * @see socket.h 144 */ 145 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call); 146 147 /** Sends data from the socket to the remote address. 148 * Binds the socket to a free port if not already connected/bound. 149 * Handles the NET_SOCKET_SENDTO message. 150 * Supports AF_INET and AF_INET6 address families. 151 * @param[in,out] local_sockets The application local sockets. 152 * @param[in] socket_id Socket identifier. 153 * @param[in] addr The destination address. 154 * @param[in] addrlen The address length. 155 * @param[in] fragments The number of data fragments. 156 * @param[out] data_fragment_size The data fragment size in bytes. 157 * @param[in] flags Various send flags. 158 * @returns EOK on success. 159 * @returns EAFNOTSUPPORT if the address family is not supported. 160 * @returns ENOTSOCK if the socket is not found. 161 * @returns EINVAL if the address is invalid. 162 * @returns ENOTCONN if the sending socket is not and cannot be bound. 163 * @returns ENOMEM if there is not enough memory left. 164 * @returns Other error codes as defined for the socket_read_packet_data() function. 165 * @returns Other error codes as defined for the ip_client_prepare_packet() function. 166 * @returns Other error codes as defined for the ip_send_msg() function. 167 */ 168 int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags); 169 170 /** Receives data to the socket. 171 * Handles the NET_SOCKET_RECVFROM message. 172 * Replies the source address as well. 173 * @param[in] local_sockets The application local sockets. 174 * @param[in] socket_id Socket identifier. 175 * @param[in] flags Various receive flags. 176 * @param[out] addrlen The source address length. 177 * @returns The number of bytes received. 178 * @returns ENOTSOCK if the socket is not found. 179 * @returns NO_DATA if there are no received packets or data. 180 * @returns ENOMEM if there is not enough memory left. 181 * @returns EINVAL if the received address is not an IP address. 182 * @returns Other error codes as defined for the packet_translate() function. 183 * @returns Other error codes as defined for the data_reply() function. 184 */ 185 int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen); 186 187 /*@}*/ 188 189 /** UDP global data. 190 */ 191 udp_globals_t udp_globals; 192 193 int udp_initialize(async_client_conn_t client_connection){ 194 ERROR_DECLARE; 195 196 measured_string_t names[] = {{str_dup("UDP_CHECKSUM_COMPUTING"), 22}, {str_dup("UDP_AUTOBINDING"), 15}}; 197 measured_string_ref configuration; 309 * 310 * Is used as an entry point from the underlying IP module. 311 * Locks the global lock and calls udp_process_packet() function. 312 * 313 * @param[in] device_id The receiving device identifier. 314 * @param[in,out] packet The received packet queue. 315 * @param receiver The target service. Ignored parameter. 316 * @param[in] error The packet error reporting service. Prefixes the 317 * received packet. 318 * @return EOK on success. 319 * @return Other error codes as defined for the 320 * udp_process_packet() function. 321 */ 322 static int udp_received_msg(device_id_t device_id, packet_t *packet, 323 services_t receiver, services_t error) 324 { 325 int result; 326 327 fibril_rwlock_write_lock(&udp_globals.lock); 328 result = udp_process_packet(device_id, packet, error); 329 if (result != EOK) 330 fibril_rwlock_write_unlock(&udp_globals.lock); 331 332 return result; 333 } 334 335 /** Process IPC messages from the IP module 336 * 337 * @param[in] iid Message identifier. 338 * @param[in,out] icall Message parameters. 339 * 340 */ 341 static void udp_receiver(ipc_callid_t iid, ipc_call_t *icall) 342 { 343 packet_t *packet; 344 int rc; 345 346 while (true) { 347 switch (IPC_GET_IMETHOD(*icall)) { 348 case NET_TL_RECEIVED: 349 rc = packet_translate_remote(udp_globals.net_phone, &packet, 350 IPC_GET_PACKET(*icall)); 351 if (rc == EOK) 352 rc = udp_received_msg(IPC_GET_DEVICE(*icall), packet, 353 SERVICE_UDP, IPC_GET_ERROR(*icall)); 354 355 async_answer_0(iid, (sysarg_t) rc); 356 break; 357 default: 358 async_answer_0(iid, (sysarg_t) ENOTSUP); 359 } 360 361 iid = async_get_call(icall); 362 } 363 } 364 365 /** Initialize the UDP module. 366 * 367 * @param[in] net_phone Network module phone. 368 * 369 * @return EOK on success. 370 * @return ENOMEM if there is not enough memory left. 371 * 372 */ 373 int tl_initialize(int net_phone) 374 { 375 measured_string_t names[] = { 376 { 377 (uint8_t *) "UDP_CHECKSUM_COMPUTING", 378 22 379 }, 380 { 381 (uint8_t *) "UDP_AUTOBINDING", 382 15 383 } 384 }; 385 measured_string_t *configuration; 198 386 size_t count = sizeof(names) / sizeof(measured_string_t); 199 char *data;200 387 uint8_t *data; 388 201 389 fibril_rwlock_initialize(&udp_globals.lock); 202 390 fibril_rwlock_write_lock(&udp_globals.lock); 203 udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT); 204 udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP, SERVICE_UDP, client_connection, udp_received_msg); 205 if(udp_globals.ip_phone < 0){ 391 392 udp_globals.net_phone = net_phone; 393 394 udp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT); 395 396 udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP, 397 SERVICE_UDP, udp_receiver); 398 if (udp_globals.ip_phone < 0) { 399 fibril_rwlock_write_unlock(&udp_globals.lock); 206 400 return udp_globals.ip_phone; 207 401 } 208 // read default packet dimensions 209 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension)); 210 ERROR_PROPAGATE(socket_ports_initialize(&udp_globals.sockets)); 211 if(ERROR_OCCURRED(packet_dimensions_initialize(&udp_globals.dimensions))){ 212 socket_ports_destroy(&udp_globals.sockets); 213 return ERROR_CODE; 214 } 402 403 /* Read default packet dimensions */ 404 int rc = ip_packet_size_req(udp_globals.ip_phone, -1, 405 &udp_globals.packet_dimension); 406 if (rc != EOK) { 407 fibril_rwlock_write_unlock(&udp_globals.lock); 408 return rc; 409 } 410 411 rc = socket_ports_initialize(&udp_globals.sockets); 412 if (rc != EOK) { 413 fibril_rwlock_write_unlock(&udp_globals.lock); 414 return rc; 415 } 416 417 rc = packet_dimensions_initialize(&udp_globals.dimensions); 418 if (rc != EOK) { 419 socket_ports_destroy(&udp_globals.sockets, free); 420 fibril_rwlock_write_unlock(&udp_globals.lock); 421 return rc; 422 } 423 215 424 udp_globals.packet_dimension.prefix += sizeof(udp_header_t); 216 425 udp_globals.packet_dimension.content -= sizeof(udp_header_t); 217 426 udp_globals.last_used_port = UDP_FREE_PORTS_START - 1; 218 // get configuration 427 219 428 udp_globals.checksum_computing = NET_DEFAULT_UDP_CHECKSUM_COMPUTING; 220 429 udp_globals.autobinding = NET_DEFAULT_UDP_AUTOBINDING; 430 431 /* Get configuration */ 221 432 configuration = &names[0]; 222 ERROR_PROPAGATE(net_get_conf_req(udp_globals.net_phone, &configuration, count, &data)); 223 if(configuration){ 224 if(configuration[0].value){ 225 udp_globals.checksum_computing = (configuration[0].value[0] == 'y'); 226 } 227 if(configuration[1].value){ 228 udp_globals.autobinding = (configuration[1].value[0] == 'y'); 229 } 433 rc = net_get_conf_req(udp_globals.net_phone, &configuration, count, 434 &data); 435 if (rc != EOK) { 436 socket_ports_destroy(&udp_globals.sockets, free); 437 fibril_rwlock_write_unlock(&udp_globals.lock); 438 return rc; 439 } 440 441 if (configuration) { 442 if (configuration[0].value) 443 udp_globals.checksum_computing = 444 (configuration[0].value[0] == 'y'); 445 446 if (configuration[1].value) 447 udp_globals.autobinding = 448 (configuration[1].value[0] == 'y'); 449 230 450 net_free_settings(configuration, data); 231 451 } 452 232 453 fibril_rwlock_write_unlock(&udp_globals.lock); 233 454 return EOK; 234 455 } 235 456 236 int udp_received_msg(device_id_t device_id, packet_t packet, services_t receiver, services_t error){ 237 int result; 238 239 fibril_rwlock_write_lock(&udp_globals.lock); 240 result = udp_process_packet(device_id, packet, error); 241 if(result != EOK){ 242 fibril_rwlock_write_unlock(&udp_globals.lock); 243 } 244 245 return result; 246 } 247 248 int udp_process_packet(device_id_t device_id, packet_t packet, services_t error){ 249 ERROR_DECLARE; 250 251 size_t length; 252 size_t offset; 253 int result; 254 udp_header_ref header; 255 socket_core_ref socket; 256 packet_t next_packet; 257 size_t total_length; 258 uint32_t checksum; 259 int fragments; 260 packet_t tmp_packet; 261 icmp_type_t type; 262 icmp_code_t code; 263 void *ip_header; 264 struct sockaddr * src; 265 struct sockaddr * dest; 266 packet_dimension_ref packet_dimension; 267 268 if(error){ 269 switch(error){ 270 case SERVICE_ICMP: 271 // ignore error 272 // length = icmp_client_header_length(packet); 273 // process error 274 result = icmp_client_process_packet(packet, &type, &code, NULL, NULL); 275 if(result < 0){ 276 return udp_release_and_return(packet, result); 277 } 278 length = (size_t) result; 279 if(ERROR_OCCURRED(packet_trim(packet, length, 0))){ 280 return udp_release_and_return(packet, ERROR_CODE); 281 } 282 break; 283 default: 284 return udp_release_and_return(packet, ENOTSUP); 285 } 286 } 287 // TODO process received ipopts? 288 result = ip_client_process_packet(packet, NULL, NULL, NULL, NULL, NULL); 289 if(result < 0){ 290 return udp_release_and_return(packet, result); 291 } 292 offset = (size_t) result; 293 294 length = packet_get_data_length(packet); 295 if(length <= 0){ 296 return udp_release_and_return(packet, EINVAL); 297 } 298 if(length < UDP_HEADER_SIZE + offset){ 299 return udp_release_and_return(packet, NO_DATA); 300 } 301 302 // trim all but UDP header 303 if(ERROR_OCCURRED(packet_trim(packet, offset, 0))){ 304 return udp_release_and_return(packet, ERROR_CODE); 305 } 306 307 // get udp header 308 header = (udp_header_ref) packet_get_data(packet); 309 if(! header){ 310 return udp_release_and_return(packet, NO_DATA); 311 } 312 // find the destination socket 313 socket = socket_port_find(&udp_globals.sockets, ntohs(header->destination_port), SOCKET_MAP_KEY_LISTENING, 0); 314 if(! socket){ 315 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){ 316 icmp_destination_unreachable_msg(udp_globals.icmp_phone, ICMP_PORT_UNREACH, 0, packet); 317 } 318 return EADDRNOTAVAIL; 319 } 320 321 // count the received packet fragments 322 next_packet = packet; 323 fragments = 0; 324 total_length = ntohs(header->total_length); 325 // compute header checksum if set 326 if(header->checksum && (! error)){ 327 result = packet_get_addr(packet, (uint8_t **) &src, (uint8_t **) &dest); 328 if(result <= 0){ 329 return udp_release_and_return(packet, result); 330 } 331 if(ERROR_OCCURRED(ip_client_get_pseudo_header(IPPROTO_UDP, src, result, dest, result, total_length, &ip_header, &length))){ 332 return udp_release_and_return(packet, ERROR_CODE); 333 }else{ 334 checksum = compute_checksum(0, ip_header, length); 335 // the udp header checksum will be added with the first fragment later 336 free(ip_header); 337 } 338 }else{ 339 header->checksum = 0; 340 checksum = 0; 341 } 342 343 do{ 344 ++ fragments; 345 length = packet_get_data_length(next_packet); 346 if(length <= 0){ 347 return udp_release_and_return(packet, NO_DATA); 348 } 349 if(total_length < length){ 350 if(ERROR_OCCURRED(packet_trim(next_packet, 0, length - total_length))){ 351 return udp_release_and_return(packet, ERROR_CODE); 352 } 353 // add partial checksum if set 354 if(header->checksum){ 355 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet)); 356 } 357 // relese the rest of the packet fragments 358 tmp_packet = pq_next(next_packet); 359 while(tmp_packet){ 360 next_packet = pq_detach(tmp_packet); 361 pq_release_remote(udp_globals.net_phone, packet_get_id(tmp_packet)); 362 tmp_packet = next_packet; 363 } 364 // exit the loop 365 break; 366 } 367 total_length -= length; 368 // add partial checksum if set 369 if(header->checksum){ 370 checksum = compute_checksum(checksum, packet_get_data(packet), packet_get_data_length(packet)); 371 } 372 }while((next_packet = pq_next(next_packet)) && (total_length > 0)); 373 374 // check checksum 375 if(header->checksum){ 376 if(flip_checksum(compact_checksum(checksum)) != IP_CHECKSUM_ZERO){ 377 if(tl_prepare_icmp_packet(udp_globals.net_phone, udp_globals.icmp_phone, packet, error) == EOK){ 378 // checksum error ICMP 379 icmp_parameter_problem_msg(udp_globals.icmp_phone, ICMP_PARAM_POINTER, ((size_t) ((void *) &header->checksum)) - ((size_t) ((void *) header)), packet); 380 } 381 return EINVAL; 382 } 383 } 384 385 // queue the received packet 386 if(ERROR_OCCURRED(dyn_fifo_push(&socket->received, packet_get_id(packet), SOCKET_MAX_RECEIVED_SIZE)) 387 || ERROR_OCCURRED(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension))){ 388 return udp_release_and_return(packet, ERROR_CODE); 389 } 390 391 // notify the destination socket 392 fibril_rwlock_write_unlock(&udp_globals.lock); 393 async_msg_5(socket->phone, NET_SOCKET_RECEIVED, (ipcarg_t) socket->socket_id, packet_dimension->content, 0, 0, (ipcarg_t) fragments); 394 return EOK; 395 } 396 397 int udp_message_standalone(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){ 398 ERROR_DECLARE; 399 400 packet_t packet; 401 402 *answer_count = 0; 403 switch(IPC_GET_METHOD(*call)){ 404 case NET_TL_RECEIVED: 405 if(! ERROR_OCCURRED(packet_translate_remote(udp_globals.net_phone, &packet, IPC_GET_PACKET(call)))){ 406 ERROR_CODE = udp_received_msg(IPC_GET_DEVICE(call), packet, SERVICE_UDP, IPC_GET_ERROR(call)); 407 } 408 return ERROR_CODE; 409 case IPC_M_CONNECT_TO_ME: 410 return udp_process_client_messages(callid, * call); 411 } 412 return ENOTSUP; 413 } 414 415 int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call){ 416 int res; 417 bool keep_on_going = true; 418 socket_cores_t local_sockets; 419 int app_phone = IPC_GET_PHONE(&call); 420 struct sockaddr * addr; 421 int socket_id; 422 size_t addrlen; 423 size_t size; 424 ipc_call_t answer; 425 int answer_count; 426 packet_dimension_ref packet_dimension; 427 428 /* 429 * Accept the connection 430 * - Answer the first IPC_M_CONNECT_TO_ME call. 431 */ 432 res = EOK; 433 answer_count = 0; 434 435 // The client connection is only in one fibril and therefore no additional locks are needed. 436 437 socket_cores_initialize(&local_sockets); 438 439 while(keep_on_going){ 440 441 // answer the call 442 answer_call(callid, res, &answer, answer_count); 443 444 // refresh data 445 refresh_answer(&answer, &answer_count); 446 447 // get the next call 448 callid = async_get_call(&call); 449 450 // process the call 451 switch(IPC_GET_METHOD(call)){ 452 case IPC_M_PHONE_HUNGUP: 453 keep_on_going = false; 454 res = EHANGUP; 455 break; 456 case NET_SOCKET: 457 socket_id = SOCKET_GET_SOCKET_ID(call); 458 res = socket_create(&local_sockets, app_phone, NULL, &socket_id); 459 SOCKET_SET_SOCKET_ID(answer, socket_id); 460 461 if(res == EOK){ 462 if (tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, DEVICE_INVALID_ID, &packet_dimension) == EOK){ 463 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, packet_dimension->content); 464 } 465 // SOCKET_SET_DATA_FRAGMENT_SIZE(answer, MAX_UDP_FRAGMENT_SIZE); 466 SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE); 467 answer_count = 3; 468 } 469 break; 470 case NET_SOCKET_BIND: 471 res = data_receive((void **) &addr, &addrlen); 472 if(res == EOK){ 473 fibril_rwlock_write_lock(&udp_globals.lock); 474 res = socket_bind(&local_sockets, &udp_globals.sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port); 475 fibril_rwlock_write_unlock(&udp_globals.lock); 476 free(addr); 477 } 478 break; 479 case NET_SOCKET_SENDTO: 480 res = data_receive((void **) &addr, &addrlen); 481 if(res == EOK){ 482 fibril_rwlock_write_lock(&udp_globals.lock); 483 res = udp_sendto_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), addr, addrlen, SOCKET_GET_DATA_FRAGMENTS(call), &size, SOCKET_GET_FLAGS(call)); 484 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size); 485 if(res != EOK){ 486 fibril_rwlock_write_unlock(&udp_globals.lock); 487 }else{ 488 answer_count = 2; 489 } 490 free(addr); 491 } 492 break; 493 case NET_SOCKET_RECVFROM: 494 fibril_rwlock_write_lock(&udp_globals.lock); 495 res = udp_recvfrom_message(&local_sockets, SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call), &addrlen); 496 fibril_rwlock_write_unlock(&udp_globals.lock); 497 if(res > 0){ 498 SOCKET_SET_READ_DATA_LENGTH(answer, res); 499 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen); 500 answer_count = 3; 501 res = EOK; 502 } 503 break; 504 case NET_SOCKET_CLOSE: 505 fibril_rwlock_write_lock(&udp_globals.lock); 506 res = socket_destroy(udp_globals.net_phone, SOCKET_GET_SOCKET_ID(call), &local_sockets, &udp_globals.sockets, NULL); 507 fibril_rwlock_write_unlock(&udp_globals.lock); 508 break; 509 case NET_SOCKET_GETSOCKOPT: 510 case NET_SOCKET_SETSOCKOPT: 511 default: 512 res = ENOTSUP; 513 break; 514 } 515 } 516 517 // release the application phone 518 ipc_hangup(app_phone); 519 520 // release all local sockets 521 socket_cores_release(udp_globals.net_phone, &local_sockets, &udp_globals.sockets, NULL); 522 523 return res; 524 } 525 526 int udp_sendto_message(socket_cores_ref local_sockets, int socket_id, const struct sockaddr * addr, socklen_t addrlen, int fragments, size_t * data_fragment_size, int flags){ 527 ERROR_DECLARE; 528 529 socket_core_ref socket; 530 packet_t packet; 531 packet_t next_packet; 532 udp_header_ref header; 457 /** Sends data from the socket to the remote address. 458 * 459 * Binds the socket to a free port if not already connected/bound. 460 * Handles the NET_SOCKET_SENDTO message. 461 * Supports AF_INET and AF_INET6 address families. 462 * 463 * @param[in,out] local_sockets The application local sockets. 464 * @param[in] socket_id Socket identifier. 465 * @param[in] addr The destination address. 466 * @param[in] addrlen The address length. 467 * @param[in] fragments The number of data fragments. 468 * @param[out] data_fragment_size The data fragment size in bytes. 469 * @param[in] flags Various send flags. 470 * @return EOK on success. 471 * @return EAFNOTSUPPORT if the address family is not supported. 472 * @return ENOTSOCK if the socket is not found. 473 * @return EINVAL if the address is invalid. 474 * @return ENOTCONN if the sending socket is not and cannot be 475 * bound. 476 * @return ENOMEM if there is not enough memory left. 477 * @return Other error codes as defined for the 478 * socket_read_packet_data() function. 479 * @return Other error codes as defined for the 480 * ip_client_prepare_packet() function. 481 * @return Other error codes as defined for the ip_send_msg() 482 * function. 483 */ 484 static int udp_sendto_message(socket_cores_t *local_sockets, int socket_id, 485 const struct sockaddr *addr, socklen_t addrlen, int fragments, 486 size_t *data_fragment_size, int flags) 487 { 488 socket_core_t *socket; 489 packet_t *packet; 490 packet_t *next_packet; 491 udp_header_t *header; 533 492 int index; 534 493 size_t total_length; … … 539 498 size_t headerlen; 540 499 device_id_t device_id; 541 packet_dimension_ref packet_dimension; 542 543 ERROR_PROPAGATE(tl_get_address_port(addr, addrlen, &dest_port)); 500 packet_dimension_t *packet_dimension; 501 size_t size; 502 int rc; 503 504 /* In case of error, do not update the data fragment size. */ 505 *data_fragment_size = 0; 506 507 rc = tl_get_address_port(addr, addrlen, &dest_port); 508 if (rc != EOK) 509 return rc; 544 510 545 511 socket = socket_cores_find(local_sockets, socket_id); 546 if (! socket){512 if (!socket) 547 513 return ENOTSOCK; 548 } 549 550 if((socket->port <= 0) && udp_globals.autobinding){ 551 // bind the socket to a random free port if not bound 552 // do{ 553 // try to find a free port 554 // fibril_rwlock_read_unlock(&udp_globals.lock); 555 // fibril_rwlock_write_lock(&udp_globals.lock); 556 // might be changed in the meantime 557 // if(socket->port <= 0){ 558 if(ERROR_OCCURRED(socket_bind_free_port(&udp_globals.sockets, socket, UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, udp_globals.last_used_port))){ 559 // fibril_rwlock_write_unlock(&udp_globals.lock); 560 // fibril_rwlock_read_lock(&udp_globals.lock); 561 return ERROR_CODE; 562 } 563 // set the next port as the search starting port number 564 udp_globals.last_used_port = socket->port; 565 // } 566 // fibril_rwlock_write_unlock(&udp_globals.lock); 567 // fibril_rwlock_read_lock(&udp_globals.lock); 568 // might be changed in the meantime 569 // }while(socket->port <= 0); 570 } 571 572 if(udp_globals.checksum_computing){ 573 if(ERROR_OCCURRED(ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr, addrlen, &device_id, &ip_header, &headerlen))){ 574 return udp_release_and_return(packet, ERROR_CODE); 575 } 576 // get the device packet dimension 577 // ERROR_PROPAGATE(tl_get_ip_packet_dimension(udp_globals.ip_phone, &udp_globals.dimensions, device_id, &packet_dimension)); 578 } 579 // }else{ 580 // do not ask all the time 581 ERROR_PROPAGATE(ip_packet_size_req(udp_globals.ip_phone, -1, &udp_globals.packet_dimension)); 514 515 if ((socket->port <= 0) && udp_globals.autobinding) { 516 /* Bind the socket to a random free port if not bound */ 517 rc = socket_bind_free_port(&udp_globals.sockets, socket, 518 UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, 519 udp_globals.last_used_port); 520 if (rc != EOK) 521 return rc; 522 /* Set the next port as the search starting port number */ 523 udp_globals.last_used_port = socket->port; 524 } 525 526 if (udp_globals.checksum_computing) { 527 rc = ip_get_route_req(udp_globals.ip_phone, IPPROTO_UDP, addr, 528 addrlen, &device_id, &ip_header, &headerlen); 529 if (rc != EOK) 530 return rc; 531 /* Get the device packet dimension */ 532 // rc = tl_get_ip_packet_dimension(udp_globals.ip_phone, 533 // &udp_globals.dimensions, device_id, &packet_dimension); 534 // if (rc != EOK) 535 // return rc; 536 } 537 // } else { 538 /* Do not ask all the time */ 539 rc = ip_packet_size_req(udp_globals.ip_phone, -1, 540 &udp_globals.packet_dimension); 541 if (rc != EOK) 542 return rc; 582 543 packet_dimension = &udp_globals.packet_dimension; 583 544 // } 584 545 585 // read the first packet fragment 586 result = tl_socket_read_packet_data(udp_globals.net_phone, &packet, UDP_HEADER_SIZE, packet_dimension, addr, addrlen); 587 if(result < 0){ 546 /* 547 * Update the data fragment size based on what the lower layers can 548 * handle without fragmentation, but not more than the maximum allowed 549 * for UDP. 550 */ 551 size = MAX_UDP_FRAGMENT_SIZE; 552 if (packet_dimension->content < size) 553 size = packet_dimension->content; 554 *data_fragment_size = size; 555 556 /* Read the first packet fragment */ 557 result = tl_socket_read_packet_data(udp_globals.net_phone, &packet, 558 UDP_HEADER_SIZE, packet_dimension, addr, addrlen); 559 if (result < 0) 588 560 return result; 589 } 561 590 562 total_length = (size_t) result; 591 if(udp_globals.checksum_computing){ 592 checksum = compute_checksum(0, packet_get_data(packet), packet_get_data_length(packet)); 593 }else{ 563 if (udp_globals.checksum_computing) 564 checksum = compute_checksum(0, packet_get_data(packet), 565 packet_get_data_length(packet)); 566 else 594 567 checksum = 0; 595 } 596 / / prefix the udp header568 569 /* Prefix the UDP header */ 597 570 header = PACKET_PREFIX(packet, udp_header_t); 598 if (! header){571 if (!header) 599 572 return udp_release_and_return(packet, ENOMEM); 600 } 573 601 574 bzero(header, sizeof(*header)); 602 // read the rest of the packet fragments 603 for(index = 1; index < fragments; ++ index){ 604 result = tl_socket_read_packet_data(udp_globals.net_phone, &next_packet, 0, packet_dimension, addr, addrlen); 605 if(result < 0){ 575 576 /* Read the rest of the packet fragments */ 577 for (index = 1; index < fragments; index++) { 578 result = tl_socket_read_packet_data(udp_globals.net_phone, 579 &next_packet, 0, packet_dimension, addr, addrlen); 580 if (result < 0) 606 581 return udp_release_and_return(packet, result); 582 583 rc = pq_add(&packet, next_packet, index, 0); 584 if (rc != EOK) 585 return udp_release_and_return(packet, rc); 586 587 total_length += (size_t) result; 588 if (udp_globals.checksum_computing) { 589 checksum = compute_checksum(checksum, 590 packet_get_data(next_packet), 591 packet_get_data_length(next_packet)); 607 592 } 608 if(ERROR_OCCURRED(pq_add(&packet, next_packet, index, 0))){ 609 return udp_release_and_return(packet, ERROR_CODE); 610 } 611 total_length += (size_t) result; 612 if(udp_globals.checksum_computing){ 613 checksum = compute_checksum(checksum, packet_get_data(next_packet), packet_get_data_length(next_packet)); 614 } 615 } 616 // set the udp header 593 } 594 595 /* Set the UDP header */ 617 596 header->source_port = htons((socket->port > 0) ? socket->port : 0); 618 597 header->destination_port = htons(dest_port); 619 598 header->total_length = htons(total_length + sizeof(*header)); 620 599 header->checksum = 0; 621 if(udp_globals.checksum_computing){ 622 // update the pseudo header 623 if(ERROR_OCCURRED(ip_client_set_pseudo_header_data_length(ip_header, headerlen, total_length + UDP_HEADER_SIZE))){ 600 601 if (udp_globals.checksum_computing) { 602 /* Update the pseudo header */ 603 rc = ip_client_set_pseudo_header_data_length(ip_header, 604 headerlen, total_length + UDP_HEADER_SIZE); 605 if (rc != EOK) { 624 606 free(ip_header); 625 return udp_release_and_return(packet, ERROR_CODE);607 return udp_release_and_return(packet, rc); 626 608 } 627 // finish the checksum computation 609 610 /* Finish the checksum computation */ 628 611 checksum = compute_checksum(checksum, ip_header, headerlen); 629 checksum = compute_checksum(checksum, (uint8_t *) header, sizeof(*header)); 630 header->checksum = htons(flip_checksum(compact_checksum(checksum))); 612 checksum = compute_checksum(checksum, (uint8_t *) header, 613 sizeof(*header)); 614 header->checksum = 615 htons(flip_checksum(compact_checksum(checksum))); 631 616 free(ip_header); 632 } else{617 } else { 633 618 device_id = DEVICE_INVALID_ID; 634 619 } 635 // prepare the first packet fragment 636 if(ERROR_OCCURRED(ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0))){ 637 return udp_release_and_return(packet, ERROR_CODE); 638 } 639 // send the packet 620 621 /* Prepare the first packet fragment */ 622 rc = ip_client_prepare_packet(packet, IPPROTO_UDP, 0, 0, 0, 0); 623 if (rc != EOK) 624 return udp_release_and_return(packet, rc); 625 626 /* Release the UDP global lock on success. */ 640 627 fibril_rwlock_write_unlock(&udp_globals.lock); 628 629 /* Send the packet */ 641 630 ip_send_msg(udp_globals.ip_phone, device_id, packet, SERVICE_UDP, 0); 631 642 632 return EOK; 643 633 } 644 634 645 int udp_recvfrom_message(socket_cores_ref local_sockets, int socket_id, int flags, size_t * addrlen){ 646 ERROR_DECLARE; 647 648 socket_core_ref socket; 635 /** Receives data to the socket. 636 * 637 * Handles the NET_SOCKET_RECVFROM message. 638 * Replies the source address as well. 639 * 640 * @param[in] local_sockets The application local sockets. 641 * @param[in] socket_id Socket identifier. 642 * @param[in] flags Various receive flags. 643 * @param[out] addrlen The source address length. 644 * @return The number of bytes received. 645 * @return ENOTSOCK if the socket is not found. 646 * @return NO_DATA if there are no received packets or data. 647 * @return ENOMEM if there is not enough memory left. 648 * @return EINVAL if the received address is not an IP address. 649 * @return Other error codes as defined for the packet_translate() 650 * function. 651 * @return Other error codes as defined for the data_reply() 652 * function. 653 */ 654 static int udp_recvfrom_message(socket_cores_t *local_sockets, int socket_id, 655 int flags, size_t *addrlen) 656 { 657 socket_core_t *socket; 649 658 int packet_id; 650 packet_t packet;651 udp_header_ refheader;652 struct sockaddr * addr;659 packet_t *packet; 660 udp_header_t *header; 661 struct sockaddr *addr; 653 662 size_t length; 654 uint8_t * data;663 uint8_t *data; 655 664 int result; 656 657 // find the socket 665 int rc; 666 667 /* Find the socket */ 658 668 socket = socket_cores_find(local_sockets, socket_id); 659 if (! socket){669 if (!socket) 660 670 return ENOTSOCK; 661 } 662 / / get the next received packet671 672 /* Get the next received packet */ 663 673 packet_id = dyn_fifo_value(&socket->received); 664 if (packet_id < 0){674 if (packet_id < 0) 665 675 return NO_DATA; 666 } 667 ERROR_PROPAGATE(packet_translate_remote(udp_globals.net_phone, &packet, packet_id)); 668 // get udp header 676 677 rc = packet_translate_remote(udp_globals.net_phone, &packet, packet_id); 678 if (rc != EOK) { 679 (void) dyn_fifo_pop(&socket->received); 680 return rc; 681 } 682 683 /* Get UDP header */ 669 684 data = packet_get_data(packet); 670 if (! data){671 pq_release_remote(udp_globals.net_phone, packet_id);672 return NO_DATA;673 } 674 header = (udp_header_ ref) data;675 676 / / set the source address port685 if (!data) { 686 (void) dyn_fifo_pop(&socket->received); 687 return udp_release_and_return(packet, NO_DATA); 688 } 689 header = (udp_header_t *) data; 690 691 /* Set the source address port */ 677 692 result = packet_get_addr(packet, (uint8_t **) &addr, NULL); 678 if(ERROR_OCCURRED(tl_set_address_port(addr, result, ntohs(header->source_port)))){ 679 pq_release_remote(udp_globals.net_phone, packet_id); 680 return ERROR_CODE; 693 rc = tl_set_address_port(addr, result, ntohs(header->source_port)); 694 if (rc != EOK) { 695 (void) dyn_fifo_pop(&socket->received); 696 return udp_release_and_return(packet, rc); 681 697 } 682 698 *addrlen = (size_t) result; 683 // send the source address 684 ERROR_PROPAGATE(data_reply(addr, * addrlen)); 685 686 // trim the header 687 ERROR_PROPAGATE(packet_trim(packet, UDP_HEADER_SIZE, 0)); 688 689 // reply the packets 690 ERROR_PROPAGATE(socket_reply_packets(packet, &length)); 691 692 // release the packet 693 dyn_fifo_pop(&socket->received); 694 pq_release_remote(udp_globals.net_phone, packet_get_id(packet)); 695 // return the total length 696 return (int) length; 697 } 698 699 int udp_release_and_return(packet_t packet, int result){ 700 pq_release_remote(udp_globals.net_phone, packet_get_id(packet)); 701 return result; 702 } 703 704 /** Default thread for new connections. 705 * 706 * @param[in] iid The initial message identifier. 707 * @param[in] icall The initial message call structure. 708 * 709 */ 710 static void tl_client_connection(ipc_callid_t iid, ipc_call_t * icall) 711 { 699 700 /* Send the source address */ 701 rc = data_reply(addr, *addrlen); 702 switch (rc) { 703 case EOK: 704 break; 705 case EOVERFLOW: 706 return rc; 707 default: 708 (void) dyn_fifo_pop(&socket->received); 709 return udp_release_and_return(packet, rc); 710 } 711 712 /* Trim the header */ 713 rc = packet_trim(packet, UDP_HEADER_SIZE, 0); 714 if (rc != EOK) { 715 (void) dyn_fifo_pop(&socket->received); 716 return udp_release_and_return(packet, rc); 717 } 718 719 /* Reply the packets */ 720 rc = socket_reply_packets(packet, &length); 721 switch (rc) { 722 case EOK: 723 break; 724 case EOVERFLOW: 725 return rc; 726 default: 727 (void) dyn_fifo_pop(&socket->received); 728 return udp_release_and_return(packet, rc); 729 } 730 731 (void) dyn_fifo_pop(&socket->received); 732 733 /* Release the packet and return the total length */ 734 return udp_release_and_return(packet, (int) length); 735 } 736 737 /** Processes the socket client messages. 738 * 739 * Runs until the client module disconnects. 740 * 741 * @param[in] callid The message identifier. 742 * @param[in] call The message parameters. 743 * @return EOK on success. 744 * 745 * @see socket.h 746 */ 747 static int udp_process_client_messages(ipc_callid_t callid, ipc_call_t call) 748 { 749 int res; 750 bool keep_on_going = true; 751 socket_cores_t local_sockets; 752 int app_phone = IPC_GET_PHONE(call); 753 struct sockaddr *addr; 754 int socket_id; 755 size_t addrlen; 756 size_t size; 757 ipc_call_t answer; 758 size_t answer_count; 759 packet_dimension_t *packet_dimension; 760 712 761 /* 713 762 * Accept the connection 714 * - Answer the first IPC_M_CONNECT_ ME_TOcall.763 * - Answer the first IPC_M_CONNECT_TO_ME call. 715 764 */ 716 ipc_answer_0(iid, EOK); 717 718 while(true) { 719 ipc_call_t answer; 720 int answer_count; 721 722 /* Clear the answer structure */ 765 res = EOK; 766 answer_count = 0; 767 768 /* 769 * The client connection is only in one fibril and therefore no 770 * additional locks are needed. 771 */ 772 773 socket_cores_initialize(&local_sockets); 774 775 while (keep_on_going) { 776 777 /* Answer the call */ 778 answer_call(callid, res, &answer, answer_count); 779 780 /* Refresh data */ 723 781 refresh_answer(&answer, &answer_count); 724 725 /* Fetch the next message */ 726 ipc_call_t call; 727 ipc_callid_t callid = async_get_call(&call); 728 729 /* Process the message */ 730 int res = tl_module_message_standalone(callid, &call, &answer, 731 &answer_count); 732 733 /* End if said to either by the message or the processing result */ 734 if ((IPC_GET_METHOD(call) == IPC_M_PHONE_HUNGUP) || (res == EHANGUP)) 735 return; 736 737 /* Answer the message */ 738 answer_call(callid, res, &answer, answer_count); 739 } 740 } 741 742 /** Starts the module. 743 * 744 * @param argc The count of the command line arguments. Ignored parameter. 745 * @param argv The command line parameters. Ignored parameter. 746 * 747 * @returns EOK on success. 748 * @returns Other error codes as defined for each specific module start function. 749 * 750 */ 782 783 /* Get the next call */ 784 callid = async_get_call(&call); 785 786 /* Process the call */ 787 switch (IPC_GET_IMETHOD(call)) { 788 case IPC_M_PHONE_HUNGUP: 789 keep_on_going = false; 790 res = EHANGUP; 791 break; 792 793 case NET_SOCKET: 794 socket_id = SOCKET_GET_SOCKET_ID(call); 795 res = socket_create(&local_sockets, app_phone, NULL, 796 &socket_id); 797 SOCKET_SET_SOCKET_ID(answer, socket_id); 798 799 if (res != EOK) 800 break; 801 802 size = MAX_UDP_FRAGMENT_SIZE; 803 if (tl_get_ip_packet_dimension(udp_globals.ip_phone, 804 &udp_globals.dimensions, DEVICE_INVALID_ID, 805 &packet_dimension) == EOK) { 806 if (packet_dimension->content < size) 807 size = packet_dimension->content; 808 } 809 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size); 810 SOCKET_SET_HEADER_SIZE(answer, UDP_HEADER_SIZE); 811 answer_count = 3; 812 break; 813 814 case NET_SOCKET_BIND: 815 res = async_data_write_accept((void **) &addr, false, 816 0, 0, 0, &addrlen); 817 if (res != EOK) 818 break; 819 fibril_rwlock_write_lock(&udp_globals.lock); 820 res = socket_bind(&local_sockets, &udp_globals.sockets, 821 SOCKET_GET_SOCKET_ID(call), addr, addrlen, 822 UDP_FREE_PORTS_START, UDP_FREE_PORTS_END, 823 udp_globals.last_used_port); 824 fibril_rwlock_write_unlock(&udp_globals.lock); 825 free(addr); 826 break; 827 828 case NET_SOCKET_SENDTO: 829 res = async_data_write_accept((void **) &addr, false, 830 0, 0, 0, &addrlen); 831 if (res != EOK) 832 break; 833 834 fibril_rwlock_write_lock(&udp_globals.lock); 835 res = udp_sendto_message(&local_sockets, 836 SOCKET_GET_SOCKET_ID(call), addr, addrlen, 837 SOCKET_GET_DATA_FRAGMENTS(call), &size, 838 SOCKET_GET_FLAGS(call)); 839 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size); 840 841 if (res != EOK) 842 fibril_rwlock_write_unlock(&udp_globals.lock); 843 else 844 answer_count = 2; 845 846 free(addr); 847 break; 848 849 case NET_SOCKET_RECVFROM: 850 fibril_rwlock_write_lock(&udp_globals.lock); 851 res = udp_recvfrom_message(&local_sockets, 852 SOCKET_GET_SOCKET_ID(call), SOCKET_GET_FLAGS(call), 853 &addrlen); 854 fibril_rwlock_write_unlock(&udp_globals.lock); 855 856 if (res <= 0) 857 break; 858 859 SOCKET_SET_READ_DATA_LENGTH(answer, res); 860 SOCKET_SET_ADDRESS_LENGTH(answer, addrlen); 861 answer_count = 3; 862 res = EOK; 863 break; 864 865 case NET_SOCKET_CLOSE: 866 fibril_rwlock_write_lock(&udp_globals.lock); 867 res = socket_destroy(udp_globals.net_phone, 868 SOCKET_GET_SOCKET_ID(call), &local_sockets, 869 &udp_globals.sockets, NULL); 870 fibril_rwlock_write_unlock(&udp_globals.lock); 871 break; 872 873 case NET_SOCKET_GETSOCKOPT: 874 case NET_SOCKET_SETSOCKOPT: 875 default: 876 res = ENOTSUP; 877 break; 878 } 879 } 880 881 /* Release the application phone */ 882 async_hangup(app_phone); 883 884 /* Release all local sockets */ 885 socket_cores_release(udp_globals.net_phone, &local_sockets, 886 &udp_globals.sockets, NULL); 887 888 return res; 889 } 890 891 /** Per-connection initialization 892 * 893 */ 894 void tl_connection(void) 895 { 896 } 897 898 /** Processes the UDP message. 899 * 900 * @param[in] callid The message identifier. 901 * @param[in] call The message parameters. 902 * @param[out] answer The message answer parameters. 903 * @param[out] answer_count The last parameter for the actual answer in the 904 * answer parameter. 905 * @return EOK on success. 906 * @return ENOTSUP if the message is not known. 907 * 908 * @see udp_interface.h 909 * @see IS_NET_UDP_MESSAGE() 910 */ 911 int tl_message(ipc_callid_t callid, ipc_call_t *call, 912 ipc_call_t *answer, size_t *answer_count) 913 { 914 *answer_count = 0; 915 916 switch (IPC_GET_IMETHOD(*call)) { 917 case IPC_M_CONNECT_TO_ME: 918 return udp_process_client_messages(callid, *call); 919 } 920 921 return ENOTSUP; 922 } 923 751 924 int main(int argc, char *argv[]) 752 925 { 753 ERROR_DECLARE;754 755 926 /* Start the module */ 756 if (ERROR_OCCURRED(tl_module_start_standalone(tl_client_connection))) 757 return ERROR_CODE; 758 759 return EOK; 927 return tl_module_start(SERVICE_UDP); 760 928 } 761 929
Note:
See TracChangeset
for help on using the changeset viewer.
