| 1 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
| 2 |
<!-- saved from url=(0068)http://www.interlog.com/~calex/software/source/lib/libgpl/udp_util.c --> |
| 3 |
<HTML><HEAD> |
| 4 |
<META content="text/html; charset=windows-1252" http-equiv=Content-Type> |
| 5 |
<META content="MSHTML 5.00.3105.105" name=GENERATOR></HEAD> |
| 6 |
<BODY><XMP>/************************************************************************ |
| 7 |
* Copyright (c) 1996 by Charles A. Measday * |
| 8 |
* * |
| 9 |
* Permission to use, copy, modify, and distribute this software * |
| 10 |
* and its documentation for any purpose and without fee is hereby * |
| 11 |
* granted, provided that the above copyright notice appear in all * |
| 12 |
* copies. The author makes no representations about the suitability * |
| 13 |
* of this software for any purpose. It is provided "as is" without * |
| 14 |
* express or implied warranty. * |
| 15 |
************************************************************************/ |
| 16 |
|
| 17 |
/* |
| 18 |
@(#) FILE: udp_util.c RELEASE: 1.9 DATE: 09/10/96, 10:40:50 |
| 19 |
*/ |
| 20 |
/******************************************************************************* |
| 21 |
|
| 22 |
File: |
| 23 |
|
| 24 |
udp_util.c |
| 25 |
|
| 26 |
UDP Networking Utilities. |
| 27 |
|
| 28 |
|
| 29 |
Author: Alex Measday, ISI |
| 30 |
|
| 31 |
|
| 32 |
Purpose: |
| 33 |
|
| 34 |
The UDP_UTIL package implements a high-level interface to UDP/IP |
| 35 |
network communications. Under the UDP protocol, processes send |
| 36 |
"datagrams" to each other. Unlike TCP, UDP has no concept of a |
| 37 |
"connection"; messages are individually routed to one or more |
| 38 |
destination endpoints through a single socket. Also unlike TCP, |
| 39 |
UDP does not guarantee reliable transmission; messages may be |
| 40 |
lost or sent out of order. |
| 41 |
|
| 42 |
In the UDP_UTIL package, the endpoints of a connection-less UDP |
| 43 |
"connection" are called, well, "endpoints". A given program may |
| 44 |
create an anonymous UDP endpoint bound to a system-assigned network |
| 45 |
port: |
| 46 |
|
| 47 |
udpCreate (NULL, NULL, &endpoint) ; |
| 48 |
|
| 49 |
or it may create a UDP endpoint bound to a predetermined network |
| 50 |
port (specified by name or port number): |
| 51 |
|
| 52 |
udpCreate ("<name>", NULL, &endpoint) ; |
| 53 |
|
| 54 |
Client processes generally create anonymous UDP endpoints for the |
| 55 |
purpose of sending messages to a server process at a predetermined |
| 56 |
network port. With an anonymous endpoint, a client must let the |
| 57 |
server(s) know its port number before the client can receive messages |
| 58 |
from the server(s). The act of sending a datagram to the server(s) |
| 59 |
automatically supplies the server(s) with the client's port number |
| 60 |
and IP address. |
| 61 |
|
| 62 |
By creating a UDP endpoint bound to a predetermined network port, a |
| 63 |
server is immediately ready to receive datagrams sent by clients to |
| 64 |
that port; the clients already know the port number, so there is no |
| 65 |
need for the server to send messages first. |
| 66 |
|
| 67 |
To send a datagram from one endpoint to another, you must specify the |
| 68 |
network address of the destination endpoint. Since the destination |
| 69 |
endpoint probably belongs to another process, possibly on a remote host, |
| 70 |
the UDP_UTIL package requires you to create a "proxy" endpoint for the |
| 71 |
destination endpoint: |
| 72 |
|
| 73 |
udpCreate ("<name>[@<host>]", source, &destination) ; |
| 74 |
|
| 75 |
A proxy endpoint simply specifies the network address of the destination |
| 76 |
endpoint; the proxy endpoint is not bound to a network port and it has |
| 77 |
no operating system socket associated with it. The proxy endpoint is |
| 78 |
internally linked with its source endpoint, so, when a datagram is sent |
| 79 |
to the proxy, udpWrite() automatically sends the datagram through the |
| 80 |
source endpoint to the destination. A source endpoint may have many |
| 81 |
proxy endpoints, but a given proxy endpoint is only linked to a single |
| 82 |
source. (If you have multiple source endpoints, you can create multiple |
| 83 |
proxy endpoints for the same destination.) |
| 84 |
|
| 85 |
When a datagram is read from an anonymous or predetermined endpoint, |
| 86 |
udpRead() returns the text of the datagram and a proxy endpoint for |
| 87 |
the sender of the datagram. The proxy endpoint can be used to return |
| 88 |
a response to the sender: |
| 89 |
|
| 90 |
char message[64], response[32] ; |
| 91 |
UdpEndpoint me, you ; |
| 92 |
... |
| 93 |
-- Read message. |
| 94 |
udpRead (me, -1.0, sizeof message, message, NULL, &you) ; |
| 95 |
-- Send response. |
| 96 |
udpWrite (you, -1.0, sizeof response, response) ; |
| 97 |
|
| 98 |
Although there is no harm in doing so, there is no need to delete proxy |
| 99 |
endpoints; they are automatically garbage-collected when their source |
| 100 |
endpoint is deleted. |
| 101 |
|
| 102 |
The following is a very simple server process that creates a UDP |
| 103 |
endpoint bound to a predetermined network port and then reads and |
| 104 |
displays messages received from clients: |
| 105 |
|
| 106 |
#include <stdio.h> -- Standard I/O definitions. |
| 107 |
#include "udp_util.h" -- UDP utilities. |
| 108 |
|
| 109 |
main (int argc, char *argv[]) |
| 110 |
{ |
| 111 |
char buffer[128] ; |
| 112 |
UdpEndpoint client, server ; |
| 113 |
-- Create UDP endpoint. |
| 114 |
udpCreate ("<name>", NULL, &server) ; |
| 115 |
|
| 116 |
for ( ; ; ) { -- Read and display messages. |
| 117 |
udpRead (server, -1.0, 128, buffer, NULL, &client) ; |
| 118 |
printf ("From %s: %s\n", udpName (client), buffer) ; |
| 119 |
} |
| 120 |
|
| 121 |
} |
| 122 |
|
| 123 |
The following client process creates an anonymous UDP endpoint and |
| 124 |
sends 16 messages through that endpoint to the server: |
| 125 |
|
| 126 |
#include <stdio.h> -- Standard I/O definitions. |
| 127 |
#include "udp_util.h" -- UDP utilities. |
| 128 |
|
| 129 |
main (int argc, char *argv[]) |
| 130 |
{ |
| 131 |
char buffer[128] ; |
| 132 |
int i ; |
| 133 |
UdpEndpoint client, server ; |
| 134 |
|
| 135 |
udpCreate (NULL, NULL, &client) ; -- Create client and target. |
| 136 |
udpCreate ("<name>[@<host>]", client, &server) ; |
| 137 |
|
| 138 |
for (i = 0 ; i < 16 ; i++) { -- Send messages. |
| 139 |
sprintf (buffer, "Hello for the %dth time!", i) ; |
| 140 |
udpWrite (server, -1.0, strlen (buffer) + 1, buffer) ; |
| 141 |
} |
| 142 |
|
| 143 |
udpDestroy (client) ; -- Deletes client and target. |
| 144 |
|
| 145 |
} |
| 146 |
|
| 147 |
Note that "client" is the anonymous endpoint and "server" is a proxy |
| 148 |
for the destination endpoint. |
| 149 |
|
| 150 |
|
| 151 |
Notes: |
| 152 |
|
| 153 |
These functions are reentrant under VxWorks (except for the global |
| 154 |
debug flag). |
| 155 |
|
| 156 |
|
| 157 |
Public Procedures (* defined as macros): |
| 158 |
|
| 159 |
udpCreate() - creates a UDP endpoint. |
| 160 |
udpDestroy() - destroys a UDP endpoint. |
| 161 |
udpFd() - returns the file descriptor for an endpoint's socket. |
| 162 |
udpIsReadable() - checks if a datagram is waiting to be read. |
| 163 |
udpIsUp() - checks if an endpoint is up. |
| 164 |
udpIsWriteable() - checks if a datagram can be written. |
| 165 |
udpName() - returns the name of an endpoint. |
| 166 |
udpRead() - reads a datagram. |
| 167 |
* udpSetBuf() - changes the sizes of an endpoint's receive and send buffers. |
| 168 |
udpWrite() - sends a datagram. |
| 169 |
|
| 170 |
*******************************************************************************/ |
| 171 |
|
| 172 |
#define _BSD_SOURCE 1 |
| 173 |
|
| 174 |
#include <ctype.h> /* Standard character functions. */ |
| 175 |
#include <errno.h> /* System error definitions. */ |
| 176 |
#include <limits.h> /* Maximum/minimum value definitions. */ |
| 177 |
#ifndef PATH_MAX |
| 178 |
# include <sys/param.h> /* System parameters. */ |
| 179 |
# define PATH_MAX MAXPATHLEN |
| 180 |
#endif |
| 181 |
#include <stdio.h> /* Standard I/O definitions. */ |
| 182 |
#include <stdlib.h> /* Standard C Library definitions. */ |
| 183 |
#include <string.h> /* C Library string functions. */ |
| 184 |
|
| 185 |
#if defined(VMS) |
| 186 |
# include <socket.h> /* Socket-related definitions. */ |
| 187 |
# include <ucx$inetdef.h> /* VMS/Ultrix network definitions. */ |
| 188 |
# include <unixio.h> /* VMS-emulation of UNIX I/O. */ |
| 189 |
# include "fd.h" /* File descriptor set definitions. */ |
| 190 |
# define MAXHOSTNAMELEN 64 |
| 191 |
#elif defined(VXWORKS) |
| 192 |
# include <hostLib.h> /* Host library definitions. */ |
| 193 |
# include <ioLib.h> /* I/O library definitions. */ |
| 194 |
# include <selectLib.h> /* SELECT(2) definitions. */ |
| 195 |
# include <socket.h> /* Socket-related definitions. */ |
| 196 |
# include <sockLib.h> /* Socket library definitions. */ |
| 197 |
# include <types.h> /* System type definitions. */ |
| 198 |
# include <unistd.h> /* UNIX I/O definitions. */ |
| 199 |
# include <sys/times.h> /* System time definitions. */ |
| 200 |
#else |
| 201 |
# include <netdb.h> /* Network database definitions. */ |
| 202 |
# include <unistd.h> /* UNIX I/O definitions. */ |
| 203 |
# include <sys/param.h> /* System parameters. */ |
| 204 |
# include <sys/socket.h> /* Socket-related definitions. */ |
| 205 |
# include <sys/time.h> /* System time definitions. */ |
| 206 |
# include <sys/types.h> /* System type definitions. */ |
| 207 |
#endif |
| 208 |
|
| 209 |
#include <netinet/in.h> /* Internet IPC domain definitions. */ |
| 210 |
|
| 211 |
#include "meo_util.h" /* Memory operations. */ |
| 212 |
#include "net_util.h" /* Networking utilities. */ |
| 213 |
#include "skt_util.h" /* Socket support functions. */ |
| 214 |
#include "tv_util.h" /* "timeval" manipulation functions. */ |
| 215 |
#include "vperror.h" /* VPERROR() definitions. */ |
| 216 |
#include "udp_util.h" /* UDP networking utilities. */ |
| 217 |
|
| 218 |
|
| 219 |
/******************************************************************************* |
| 220 |
UDP Endpoints - contain information about local and remote UDP sockets. |
| 221 |
A "local" (to the application) endpoint represents a UDP socket on |
| 222 |
which the application can receive UDP datagrams. A "remote" (to |
| 223 |
the application) endpoint has no socket and simply specifies the |
| 224 |
source address of a datagram received by the application or the |
| 225 |
destination address of a datagram being sent by the application. |
| 226 |
Socket-less remote endpoints are linked to their "parent" local |
| 227 |
endpoint; when the parent is deleted, the children are automatically |
| 228 |
deleted. |
| 229 |
*******************************************************************************/ |
| 230 |
|
| 231 |
typedef struct _UdpEndpoint { |
| 232 |
char *name ; /* "<port>[@<host>]" */ |
| 233 |
struct sockaddr address ; /* Network address and port number. */ |
| 234 |
int addressLength ; /* Length (in bytes) of address. */ |
| 235 |
int fd ; /* UDP socket. */ |
| 236 |
struct _UdpEndpoint *parent ; /* Local parent of remote endpoint. */ |
| 237 |
struct _UdpEndpoint *next ; /* Link to first child or next sibling. */ |
| 238 |
} _UdpEndpoint ; |
| 239 |
|
| 240 |
|
| 241 |
int udp_util_debug = 0 ; /* Global debug switch (1/0 = yes/no). */ |
| 242 |
|
| 243 |
/******************************************************************************* |
| 244 |
|
| 245 |
Procedure: |
| 246 |
|
| 247 |
udpCreate () |
| 248 |
|
| 249 |
Create a UDP Endpoint. |
| 250 |
|
| 251 |
|
| 252 |
Purpose: |
| 253 |
|
| 254 |
The udpCreate() function creates any one of three types of UDP endpoints: |
| 255 |
|
| 256 |
(1) a UDP socket bound to a system-chosen network port, |
| 257 |
|
| 258 |
(2) a UDP socket bound to a predetermined network port |
| 259 |
(identified by port name or number), and |
| 260 |
|
| 261 |
(3) a socket-less UDP endpoint used to specify the target |
| 262 |
of a datagram being sent. |
| 263 |
|
| 264 |
The anonymous and predetermined endpoints (#'s 1 and 2 above) should |
| 265 |
be closed by a call to udpDestroy() when they are no longer needed. |
| 266 |
Proxy endpoints (#3 above) are linked upon creation to an existing |
| 267 |
anonymous or predetermined endpoint (i.e., its "parent"). When a |
| 268 |
parent endpoint is closed, all of its "children" (i.e., the associated |
| 269 |
proxy endpoints) are automatically deleted. |
| 270 |
|
| 271 |
|
| 272 |
Invocation (anonymous endpoint): |
| 273 |
|
| 274 |
status = udpCreate (NULL, NULL, &endpoint) ; |
| 275 |
|
| 276 |
Invocation (predetermined endpoint): |
| 277 |
|
| 278 |
status = udpCreate (serverName, NULL, &endpoint) ; |
| 279 |
|
| 280 |
Invocation (proxy endpoint): |
| 281 |
|
| 282 |
status = udpCreate (targetName, parent, &endpoint) ; |
| 283 |
|
| 284 |
where |
| 285 |
|
| 286 |
<serverName> - I |
| 287 |
is the server's name. This is used for determining the port |
| 288 |
associated with the server (via the system's name/port mappings). |
| 289 |
You can side-step the system maps and explicitly specify a |
| 290 |
particular port by passing in a decimal number encoded in ASCII |
| 291 |
(e.g., "1234" for port 1234). |
| 292 |
<targetName> - I |
| 293 |
is the target's name: "<server>[@<host>]". The server can be |
| 294 |
specified as a name or as a port number; see the "serverName" |
| 295 |
argument description above. The host, if given, can be |
| 296 |
specified as a name or as a dotted Internet address. |
| 297 |
<endpoint> - O |
| 298 |
returns a handle for the UDP endpoint. |
| 299 |
<status> - O |
| 300 |
returns the status of creating the UDP endpoint, zero if |
| 301 |
there were no errors and ERRNO otherwise. |
| 302 |
|
| 303 |
*******************************************************************************/ |
| 304 |
|
| 305 |
|
| 306 |
int udpCreate ( |
| 307 |
|
| 308 |
# if __STDC__ |
| 309 |
const char *name, |
| 310 |
UdpEndpoint parent, |
| 311 |
UdpEndpoint *endpoint) |
| 312 |
# else |
| 313 |
name, parent, endpoint) |
| 314 |
|
| 315 |
char *name ; |
| 316 |
UdpEndpoint parent ; |
| 317 |
UdpEndpoint *endpoint ; |
| 318 |
# endif |
| 319 |
|
| 320 |
{ /* Local variables. */ |
| 321 |
char *s, hostName[MAXHOSTNAMELEN+1], serverName[MAXHOSTNAMELEN+1] ; |
| 322 |
int length, portNumber ; |
| 323 |
struct sockaddr_in socketName ; |
| 324 |
|
| 325 |
|
| 326 |
|
| 327 |
|
| 328 |
|
| 329 |
/******************************************************************************* |
| 330 |
Construct the endpoint's network address. |
| 331 |
*******************************************************************************/ |
| 332 |
|
| 333 |
/* Parse the host and server names. If the host name is not defined |
| 334 |
explicitly, it defaults to the local host. */ |
| 335 |
|
| 336 |
s = netHostOf (netAddrOf (NULL)) ; |
| 337 |
if (s == NULL) { |
| 338 |
vperror ("(udpCreate) Error getting local host name.\nnetHostOf: ") ; |
| 339 |
return (errno) ; |
| 340 |
} |
| 341 |
strcpy (hostName, s) ; |
| 342 |
|
| 343 |
if (name == NULL) { /* Let system choose port #? */ |
| 344 |
strcpy (serverName, "0") ; |
| 345 |
} else { /* User-specified port #. */ |
| 346 |
s = strchr (name, '@') ; |
| 347 |
if (s == NULL) { /* "<server>" */ |
| 348 |
strcpy (serverName, name) ; |
| 349 |
} else { /* "<server>@<host>" */ |
| 350 |
length = s - name ; |
| 351 |
strncpy (serverName, name, length) ; |
| 352 |
serverName[length] = '\0' ; |
| 353 |
strcpy (hostName, ++s) ; |
| 354 |
} |
| 355 |
} |
| 356 |
|
| 357 |
/* Lookup the port number bound to the server name. */ |
| 358 |
|
| 359 |
portNumber = netPortOf (serverName, "udp") ; |
| 360 |
if (portNumber == -1) { |
| 361 |
vperror ("(udpCreate) Error getting server entry for %s.\nnetPortOf: ", |
| 362 |
serverName) ; |
| 363 |
return (errno) ; |
| 364 |
} |
| 365 |
|
| 366 |
/* Set up the network address for the endpoint. */ |
| 367 |
|
| 368 |
memset (&socketName, '\0', sizeof socketName) ; |
| 369 |
socketName.sin_family = AF_INET ; |
| 370 |
socketName.sin_port = htons (portNumber) ; |
| 371 |
|
| 372 |
socketName.sin_addr.s_addr = netAddrOf (hostName) ; |
| 373 |
if ((long) socketName.sin_addr.s_addr == -1) { |
| 374 |
vperror ("(udpCreate) Error getting host entry for %s.\nnetAddrOf: ", |
| 375 |
hostName) ; |
| 376 |
return (errno) ; |
| 377 |
} |
| 378 |
|
| 379 |
|
| 380 |
/******************************************************************************* |
| 381 |
Create a UDP endpoint structure. |
| 382 |
*******************************************************************************/ |
| 383 |
|
| 384 |
*endpoint = (UdpEndpoint) malloc (sizeof (_UdpEndpoint)) ; |
| 385 |
if (*endpoint == NULL) { |
| 386 |
vperror ("(udpCreate) Error allocating endpoint structure for %s.\nmalloc: ", |
| 387 |
serverName) ; |
| 388 |
return (errno) ; |
| 389 |
} |
| 390 |
|
| 391 |
(*endpoint)->name = NULL ; |
| 392 |
*((struct sockaddr_in *) &(*endpoint)->address) = socketName ; |
| 393 |
(*endpoint)->addressLength = sizeof socketName ; |
| 394 |
(*endpoint)->fd = -1 ; |
| 395 |
(*endpoint)->parent = parent ; |
| 396 |
(*endpoint)->next = NULL ; |
| 397 |
|
| 398 |
|
| 399 |
/******************************************************************************* |
| 400 |
If a UDP socket is to be created, then create the socket and bind it to |
| 401 |
the specified port number. |
| 402 |
*******************************************************************************/ |
| 403 |
|
| 404 |
if (parent == NULL) { |
| 405 |
|
| 406 |
/* Create a socket for the endpoint. */ |
| 407 |
|
| 408 |
(*endpoint)->fd = socket (AF_INET, SOCK_DGRAM, 0) ; |
| 409 |
if ((*endpoint)->fd < 0) { |
| 410 |
vperror ("(udpCreate) Error creating socket for %s.\nsocket: ", |
| 411 |
serverName) ; |
| 412 |
udpDestroy (*endpoint) ; *endpoint = NULL ; |
| 413 |
return (errno) ; |
| 414 |
} |
| 415 |
|
| 416 |
/* Bind the network address to the socket. */ |
| 417 |
|
| 418 |
if (bind ((*endpoint)->fd, |
| 419 |
&(*endpoint)->address, (*endpoint)->addressLength)) { |
| 420 |
vperror ("(udpCreate) Error binding %s's socket name.\nbind: ", |
| 421 |
serverName) ; |
| 422 |
udpDestroy (*endpoint) ; *endpoint = NULL ; |
| 423 |
return (errno) ; |
| 424 |
} |
| 425 |
|
| 426 |
sprintf (serverName, "%d", |
| 427 |
sktPort ((*endpoint)->name, (*endpoint)->fd)) ; |
| 428 |
|
| 429 |
} |
| 430 |
|
| 431 |
|
| 432 |
/******************************************************************************* |
| 433 |
Otherwise, if a socket-less, proxy endpoint is being created, then |
| 434 |
simply link it to its parent endpoint. |
| 435 |
*******************************************************************************/ |
| 436 |
|
| 437 |
else { |
| 438 |
|
| 439 |
(*endpoint)->next = parent->next ; |
| 440 |
parent->next = *endpoint ; |
| 441 |
|
| 442 |
} |
| 443 |
|
| 444 |
|
| 445 |
/******************************************************************************* |
| 446 |
Construct the endpoint's name. |
| 447 |
*******************************************************************************/ |
| 448 |
|
| 449 |
(*endpoint)->name = malloc (strlen (serverName) + 1 + |
| 450 |
strlen (hostName) + 1) ; |
| 451 |
if ((*endpoint)->name == NULL) { |
| 452 |
vperror ("(udpCreate) Error duplicating server name: %s%c%s\nmalloc: ", |
| 453 |
serverName, (parent == NULL) ? '#' : '@', hostName) ; |
| 454 |
udpDestroy (*endpoint) ; *endpoint = NULL ; |
| 455 |
return (errno) ; |
| 456 |
} |
| 457 |
sprintf ((*endpoint)->name, "%s%c%s", |
| 458 |
serverName, (parent == NULL) ? '#' : '@', hostName) ; |
| 459 |
|
| 460 |
|
| 461 |
if (udp_util_debug) printf ("(udpCreate) Created %s, socket %d.\n", |
| 462 |
(*endpoint)->name, (*endpoint)->fd) ; |
| 463 |
|
| 464 |
return (0) ; /* Successful completion. */ |
| 465 |
|
| 466 |
} |
| 467 |
|
| 468 |
/******************************************************************************* |
| 469 |
|
| 470 |
Procedure: |
| 471 |
|
| 472 |
udpDestroy () |
| 473 |
|
| 474 |
Destroy a UDP Endpoint. |
| 475 |
|
| 476 |
|
| 477 |
Purpose: |
| 478 |
|
| 479 |
The udpDestroy() function destroys a UDP endpoint. If the endpoint |
| 480 |
is a socket bound to a network port, the socket is closed. If the |
| 481 |
endpoint is a socket-less, proxy endpoint, the endpoint is simply |
| 482 |
unlinked from the socket endpoint (i.e., its "parent") with which |
| 483 |
it is associated. |
| 484 |
|
| 485 |
|
| 486 |
Invocation: |
| 487 |
|
| 488 |
status = udpDestroy (endpoint) ; |
| 489 |
|
| 490 |
where |
| 491 |
|
| 492 |
<endpoint> - I |
| 493 |
is the endpoint handle returned by udpCreate() or udpRead(). |
| 494 |
<status> - O |
| 495 |
returns the status of destroying the endpoint, zero if there |
| 496 |
were no errors and ERRNO otherwise. |
| 497 |
|
| 498 |
*******************************************************************************/ |
| 499 |
|
| 500 |
|
| 501 |
int udpDestroy ( |
| 502 |
|
| 503 |
# if __STDC__ |
| 504 |
UdpEndpoint endpoint) |
| 505 |
# else |
| 506 |
endpoint) |
| 507 |
|
| 508 |
UdpEndpoint endpoint ; |
| 509 |
# endif |
| 510 |
|
| 511 |
{ /* Local variables. */ |
| 512 |
UdpEndpoint prev ; |
| 513 |
|
| 514 |
|
| 515 |
|
| 516 |
|
| 517 |
if (endpoint == NULL) return (0) ; |
| 518 |
|
| 519 |
if (udp_util_debug) printf ("(udpDestroy) Destroying %s, socket %d ...\n", |
| 520 |
endpoint->name, endpoint->fd) ; |
| 521 |
|
| 522 |
/* If this is a socket endpoint, then delete all of the socket-less proxy |
| 523 |
endpoints associated with the endpoint. */ |
| 524 |
|
| 525 |
if (endpoint->parent == NULL) { |
| 526 |
while (endpoint->next != NULL) |
| 527 |
udpDestroy (endpoint->next) ; |
| 528 |
close (endpoint->fd) ; |
| 529 |
endpoint->fd = -1 ; |
| 530 |
} |
| 531 |
|
| 532 |
/* Otherwise, if this is a socket-less proxy, then unlink the proxy endpoint |
| 533 |
from its socket endpoint (i.e., its "parent"). */ |
| 534 |
|
| 535 |
else { |
| 536 |
for (prev = endpoint->parent ; prev != NULL ; prev = prev->next) |
| 537 |
if (prev->next == endpoint) break ; |
| 538 |
if (prev != NULL) prev->next = endpoint->next ; |
| 539 |
} |
| 540 |
|
| 541 |
/* Deallocate the endpoint structure. */ |
| 542 |
|
| 543 |
if (endpoint->name != NULL) { |
| 544 |
free (endpoint->name) ; endpoint->name = NULL ; |
| 545 |
} |
| 546 |
free (endpoint) ; |
| 547 |
|
| 548 |
return (0) ; |
| 549 |
|
| 550 |
} |
| 551 |
|
| 552 |
/******************************************************************************* |
| 553 |
|
| 554 |
Procedure: |
| 555 |
|
| 556 |
udpFd () |
| 557 |
|
| 558 |
Get a UDP Endpoint's Socket. |
| 559 |
|
| 560 |
|
| 561 |
Purpose: |
| 562 |
|
| 563 |
Function udpFd() returns a UDP endpoint's socket. |
| 564 |
|
| 565 |
|
| 566 |
Invocation: |
| 567 |
|
| 568 |
fd = udpFd (endpoint) ; |
| 569 |
|
| 570 |
where |
| 571 |
|
| 572 |
<endpoint> - I |
| 573 |
is the endpoint handle returned by udpCreate() or udpRead(). |
| 574 |
<fd> - O |
| 575 |
returns the UNIX file descriptor for the endpoint's socket. |
| 576 |
|
| 577 |
*******************************************************************************/ |
| 578 |
|
| 579 |
|
| 580 |
int udpFd ( |
| 581 |
|
| 582 |
# if __STDC__ |
| 583 |
UdpEndpoint endpoint) |
| 584 |
# else |
| 585 |
endpoint) |
| 586 |
|
| 587 |
UdpEndpoint endpoint ; |
| 588 |
# endif |
| 589 |
|
| 590 |
{ |
| 591 |
return ((endpoint == NULL) ? -1 : endpoint->fd) ; |
| 592 |
} |
| 593 |
|
| 594 |
/******************************************************************************* |
| 595 |
|
| 596 |
Procedure: |
| 597 |
|
| 598 |
udpIsReadable () |
| 599 |
|
| 600 |
Check if Data is Waiting to be Read. |
| 601 |
|
| 602 |
|
| 603 |
Purpose: |
| 604 |
|
| 605 |
The udpIsReadable() function checks to see if data is waiting to |
| 606 |
be read from a UDP endpoint. |
| 607 |
|
| 608 |
|
| 609 |
Invocation: |
| 610 |
|
| 611 |
isReadable = udpIsReadable (endpoint) ; |
| 612 |
|
| 613 |
where |
| 614 |
|
| 615 |
<endpoint> - I |
| 616 |
is the endpoint handle returned by udpCreate(). |
| 617 |
<isReadable> - O |
| 618 |
returns true (a non-zero value) if data is available for |
| 619 |
reading and false (zero) otherwise. |
| 620 |
|
| 621 |
*******************************************************************************/ |
| 622 |
|
| 623 |
|
| 624 |
int udpIsReadable ( |
| 625 |
|
| 626 |
# if __STDC__ |
| 627 |
UdpEndpoint endpoint) |
| 628 |
# else |
| 629 |
endpoint) |
| 630 |
|
| 631 |
UdpEndpoint endpoint ; |
| 632 |
# endif |
| 633 |
|
| 634 |
{ |
| 635 |
|
| 636 |
if (endpoint == NULL) |
| 637 |
return (0) ; |
| 638 |
else if (endpoint->parent == NULL) |
| 639 |
return (sktIsReadable (endpoint->name, endpoint->fd)) ; |
| 640 |
else |
| 641 |
return (sktIsReadable (endpoint->name, (endpoint->parent)->fd)) ; |
| 642 |
|
| 643 |
} |
| 644 |
|
| 645 |
/******************************************************************************* |
| 646 |
|
| 647 |
Procedure: |
| 648 |
|
| 649 |
udpIsUp () |
| 650 |
|
| 651 |
Check if a UDP Endpoint is Up. |
| 652 |
|
| 653 |
|
| 654 |
Purpose: |
| 655 |
|
| 656 |
The udpIsUp() function checks to see if a UDP endpoint is still up. |
| 657 |
|
| 658 |
|
| 659 |
Invocation: |
| 660 |
|
| 661 |
isUp = udpIsUp (endpoint) ; |
| 662 |
|
| 663 |
where |
| 664 |
|
| 665 |
<endpoint> - I |
| 666 |
is the endpoint handle returned by udpCreate(). |
| 667 |
<isUp> - O |
| 668 |
returns true (a non-zero value) if the endpoint is up and |
| 669 |
false (zero) otherwise. |
| 670 |
|
| 671 |
*******************************************************************************/ |
| 672 |
|
| 673 |
|
| 674 |
int udpIsUp ( |
| 675 |
|
| 676 |
# if __STDC__ |
| 677 |
UdpEndpoint endpoint) |
| 678 |
# else |
| 679 |
endpoint) |
| 680 |
|
| 681 |
UdpEndpoint endpoint ; |
| 682 |
# endif |
| 683 |
|
| 684 |
{ |
| 685 |
|
| 686 |
if (endpoint == NULL) |
| 687 |
return (0) ; |
| 688 |
else if (endpoint->parent == NULL) |
| 689 |
return (sktIsUp (endpoint->name, endpoint->fd)) ; |
| 690 |
else |
| 691 |
return (sktIsUp (endpoint->name, (endpoint->parent)->fd)) ; |
| 692 |
|
| 693 |
} |
| 694 |
|
| 695 |
/******************************************************************************* |
| 696 |
|
| 697 |
Procedure: |
| 698 |
|
| 699 |
udpIsWriteable () |
| 700 |
|
| 701 |
Check if Data can be Written. |
| 702 |
|
| 703 |
|
| 704 |
Purpose: |
| 705 |
|
| 706 |
The udpIsWriteable() function checks to see if data can be written |
| 707 |
to a UDP endpoint. |
| 708 |
|
| 709 |
|
| 710 |
Invocation: |
| 711 |
|
| 712 |
isWriteable = udpIsWriteable (endpoint) ; |
| 713 |
|
| 714 |
where |
| 715 |
|
| 716 |
<endpoint> - I |
| 717 |
is the endpoint handle returned by udpCreate(). |
| 718 |
<isWriteable> - O |
| 719 |
returns true (a non-zero value) if the endpoint is ready |
| 720 |
for writing and false (zero) otherwise. |
| 721 |
|
| 722 |
*******************************************************************************/ |
| 723 |
|
| 724 |
|
| 725 |
int udpIsWriteable ( |
| 726 |
|
| 727 |
# if __STDC__ |
| 728 |
UdpEndpoint endpoint) |
| 729 |
# else |
| 730 |
endpoint) |
| 731 |
|
| 732 |
UdpEndpoint endpoint ; |
| 733 |
# endif |
| 734 |
|
| 735 |
{ |
| 736 |
|
| 737 |
if (endpoint == NULL) |
| 738 |
return (0) ; |
| 739 |
else if (endpoint->parent == NULL) |
| 740 |
return (sktIsWriteable (endpoint->name, endpoint->fd)) ; |
| 741 |
else |
| 742 |
return (sktIsWriteable (endpoint->name, (endpoint->parent)->fd)) ; |
| 743 |
|
| 744 |
} |
| 745 |
|
| 746 |
/******************************************************************************* |
| 747 |
|
| 748 |
Procedure: |
| 749 |
|
| 750 |
udpName () |
| 751 |
|
| 752 |
Get a UDP Endpoint's Name. |
| 753 |
|
| 754 |
|
| 755 |
Purpose: |
| 756 |
|
| 757 |
Function udpName() returns a UDP endpoint's name. |
| 758 |
|
| 759 |
|
| 760 |
Invocation: |
| 761 |
|
| 762 |
name = udpName (endpoint) ; |
| 763 |
|
| 764 |
where |
| 765 |
|
| 766 |
<endpoint> - I |
| 767 |
is the endpoint handle returned by udpCreate() or udpRead(). |
| 768 |
<name> - O |
| 769 |
returns the endpoint's name. The name is stored in memory |
| 770 |
local to the UDP utilities and it should not be modified or |
| 771 |
freed by the caller. |
| 772 |
|
| 773 |
*******************************************************************************/ |
| 774 |
|
| 775 |
|
| 776 |
char *udpName ( |
| 777 |
|
| 778 |
# if __STDC__ |
| 779 |
UdpEndpoint endpoint) |
| 780 |
# else |
| 781 |
endpoint) |
| 782 |
|
| 783 |
UdpEndpoint endpoint ; |
| 784 |
# endif |
| 785 |
|
| 786 |
{ |
| 787 |
if (endpoint == NULL) return ("") ; |
| 788 |
if (endpoint->name == NULL) return ("") ; |
| 789 |
return (endpoint->name) ; |
| 790 |
} |
| 791 |
|
| 792 |
/******************************************************************************* |
| 793 |
|
| 794 |
Procedure: |
| 795 |
|
| 796 |
udpRead () |
| 797 |
|
| 798 |
Read Data from a UDP Endpoint. |
| 799 |
|
| 800 |
|
| 801 |
Purpose: |
| 802 |
|
| 803 |
Function udpRead() reads the next message on a UDP endpoint. A timeout |
| 804 |
can be specified that limits how long udpRead() waits for the message |
| 805 |
to be received. |
| 806 |
|
| 807 |
|
| 808 |
Invocation: |
| 809 |
|
| 810 |
status = udpRead (endpoint, timeout, maxBytesToRead, |
| 811 |
buffer, &numBytesRead, &source) ; |
| 812 |
|
| 813 |
where |
| 814 |
|
| 815 |
<endpoint> - I |
| 816 |
is the endpoint handle returned by udpCreate(). |
| 817 |
<timeout> - I |
| 818 |
specifies the maximum amount of time (in seconds) that the caller |
| 819 |
wishes to wait for the next message to be received. A fractional |
| 820 |
time can be specified; e.g., 2.5 seconds. A negative timeout |
| 821 |
(e.g., -1.0) causes an infinite wait; a zero timeout (0.0) allows |
| 822 |
a read only if message is immediately available. |
| 823 |
<maxBytesToRead> - I |
| 824 |
specifies the maximum number of bytes to read; i.e., the size of |
| 825 |
the message buffer. |
| 826 |
<buffer> - O |
| 827 |
receives the input data. This buffer should be at least |
| 828 |
maxBytesToRead in size. |
| 829 |
<numBytesRead> - O |
| 830 |
returns the actual number of bytes read. |
| 831 |
<source> - O |
| 832 |
returns an endpoint handle for the source of the message. |
| 833 |
<status> - O |
| 834 |
returns the status of reading from the endpoint: zero if no |
| 835 |
errors occurred, EWOULDBLOCK if the timeout interval expired |
| 836 |
before a message was received, and ERRNO otherwise. |
| 837 |
|
| 838 |
*******************************************************************************/ |
| 839 |
|
| 840 |
|
| 841 |
int udpRead ( |
| 842 |
|
| 843 |
# if __STDC__ |
| 844 |
UdpEndpoint endpoint, |
| 845 |
double timeout, |
| 846 |
int maxBytesToRead, |
| 847 |
char *buffer, |
| 848 |
int *numBytesRead, |
| 849 |
UdpEndpoint *source) |
| 850 |
# else |
| 851 |
endpoint, timeout, maxBytesToRead, buffer, numBytesRead, source) |
| 852 |
|
| 853 |
UdpEndpoint endpoint ; |
| 854 |
double timeout ; |
| 855 |
int maxBytesToRead ; |
| 856 |
char *buffer ; |
| 857 |
int *numBytesRead ; |
| 858 |
UdpEndpoint *source ; |
| 859 |
# endif |
| 860 |
|
| 861 |
{ /* Local variables. */ |
| 862 |
char *hostName ; |
| 863 |
char sourceName[PATH_MAX+1] ; |
| 864 |
fd_set readMask ; |
| 865 |
int addressLength, fd, length, numActive ; |
| 866 |
struct sockaddr address ; |
| 867 |
struct timeval deltaTime, expirationTime ; |
| 868 |
UdpEndpoint ep, sourcePoint ; |
| 869 |
|
| 870 |
|
| 871 |
|
| 872 |
|
| 873 |
|
| 874 |
if (endpoint == NULL) { |
| 875 |
errno = EINVAL ; |
| 876 |
vperror ("(udpRead) NULL endpoint handle: ") ; |
| 877 |
return (errno) ; |
| 878 |
} |
| 879 |
|
| 880 |
fd = endpoint->fd ; |
| 881 |
if (fd < 0) { |
| 882 |
errno = EINVAL ; |
| 883 |
vperror ("(udpRead) %d file descriptor: ", fd) ; |
| 884 |
return (errno) ; |
| 885 |
} |
| 886 |
|
| 887 |
|
| 888 |
/******************************************************************************* |
| 889 |
If a timeout interval was specified, then wait until the expiration of |
| 890 |
the interval for a message to be received. |
| 891 |
*******************************************************************************/ |
| 892 |
|
| 893 |
if (timeout >= 0.0) { |
| 894 |
|
| 895 |
/* Compute the expiration time as the current time plus the interval. */ |
| 896 |
|
| 897 |
expirationTime = tvAdd (tvTOD (), tvCreateF (timeout)) ; |
| 898 |
|
| 899 |
/* Wait for the next message to arrive. */ |
| 900 |
|
| 901 |
for ( ; ; ) { |
| 902 |
deltaTime = tvSubtract (expirationTime, tvTOD ()) ; |
| 903 |
FD_ZERO (&readMask) ; FD_SET (fd, &readMask) ; |
| 904 |
numActive = select (fd+1, &readMask, NULL, NULL, &deltaTime) ; |
| 905 |
if (numActive >= 0) break ; |
| 906 |
if (errno == EINTR) continue ; |
| 907 |
vperror ("(udpRead) Error waiting for input on %s.\nselect: ", |
| 908 |
endpoint->name) ; |
| 909 |
return (errno) ; |
| 910 |
} |
| 911 |
|
| 912 |
if (numActive == 0) { |
| 913 |
errno = EWOULDBLOCK ; |
| 914 |
vperror ("(udpRead) Timeout while waiting for input on %s.\n", |
| 915 |
endpoint->name) ; |
| 916 |
return (errno) ; |
| 917 |
} |
| 918 |
|
| 919 |
} |
| 920 |
|
| 921 |
|
| 922 |
/******************************************************************************* |
| 923 |
Read the message. |
| 924 |
*******************************************************************************/ |
| 925 |
|
| 926 |
addressLength = sizeof address ; |
| 927 |
length = recvfrom (fd, buffer, maxBytesToRead, 0, &address, &addressLength) ; |
| 928 |
if (length < 0) { |
| 929 |
vperror ("(udpRead) Error reading from %s.\nrecvfrom: ", |
| 930 |
endpoint->name) ; |
| 931 |
return (errno) ; |
| 932 |
} else if (length == 0) { |
| 933 |
errno = EPIPE ; |
| 934 |
vperror ("(udpRead) Broken connection on %s.\nrecvfrom: ", |
| 935 |
endpoint->name) ; |
| 936 |
return (errno) ; |
| 937 |
} |
| 938 |
|
| 939 |
if (numBytesRead != NULL) *numBytesRead = length ; |
| 940 |
|
| 941 |
|
| 942 |
/******************************************************************************* |
| 943 |
Create a UDP endpoint for the source of the message. |
| 944 |
*******************************************************************************/ |
| 945 |
|
| 946 |
/* Check to see if an endpoint already exists for this particular source. */ |
| 947 |
|
| 948 |
for (ep = endpoint->next ; ep != NULL ; ep = ep->next) { |
| 949 |
if ((addressLength == ep->addressLength) && |
| 950 |
(memcmp (&address, &ep->address, addressLength) == 0)) break ; |
| 951 |
} |
| 952 |
|
| 953 |
/* If not, create a brand new endpoint. If so, then use the existing one. */ |
| 954 |
|
| 955 |
if (ep == NULL) { |
| 956 |
hostName = netHostOf ( |
| 957 |
((struct sockaddr_in *) &address)->sin_addr.s_addr) ; |
| 958 |
sprintf (sourceName, "%d@%s", |
| 959 |
ntohs (((struct sockaddr_in *) &address)->sin_port), |
| 960 |
hostName) ; |
| 961 |
if (udpCreate (sourceName, endpoint, &sourcePoint)) { |
| 962 |
vperror ("(udpRead) Error creating source endpoint: %s\nudpCreate: ", |
| 963 |
sourceName) ; |
| 964 |
return (errno) ; |
| 965 |
} |
| 966 |
} else { |
| 967 |
sourcePoint = ep ; |
| 968 |
} |
| 969 |
|
| 970 |
if (source != NULL) *source = sourcePoint ; |
| 971 |
|
| 972 |
|
| 973 |
if (udp_util_debug) { |
| 974 |
printf ("(udpRead) Read %d bytes from %s on %s, socket %d.\n", |
| 975 |
length, sourcePoint->name, endpoint->name, endpoint->fd) ; |
| 976 |
meoDumpX (stdout, " ", 0, buffer, length) ; |
| 977 |
} |
| 978 |
|
| 979 |
return (0) ; |
| 980 |
|
| 981 |
} |
| 982 |
|
| 983 |
/******************************************************************************* |
| 984 |
|
| 985 |
Procedure: |
| 986 |
|
| 987 |
Write () |
| 988 |
|
| 989 |
Write Data to a UDP Endpoint. |
| 990 |
|
| 991 |
|
| 992 |
Purpose: |
| 993 |
|
| 994 |
Function udpWrite() writes a message to a destination UDP endpoint. |
| 995 |
A timeout interval can be specified that limits how long udpWrite() |
| 996 |
waits to output the message. |
| 997 |
|
| 998 |
Note that a message is written through a local source endpoint to the |
| 999 |
remote destination endpoint. Only the destination endpoint is passed |
| 1000 |
to udpWrite(); udpWrite() will use the destination's "parent" as the |
| 1001 |
source endpoint. |
| 1002 |
|
| 1003 |
|
| 1004 |
Invocation: |
| 1005 |
|
| 1006 |
status = udpWrite (destination, timeout, numBytesToWrite, buffer) ; |
| 1007 |
|
| 1008 |
where |
| 1009 |
|
| 1010 |
<destination> - I |
| 1011 |
is the destination endpoint handle returned by udpCreate() |
| 1012 |
or udpRead(). |
| 1013 |
<timeout> - I |
| 1014 |
specifies the maximum amount of time (in seconds) that the |
| 1015 |
caller wishes to wait for the data to be output. A fractional |
| 1016 |
time can be specified; e.g., 2.5 seconds. A negative timeout |
| 1017 |
(e.g., -1.0) causes an infinite wait; udpWrite() will wait as |
| 1018 |
long as necessary to output all of the data. A zero timeout |
| 1019 |
(0.0) specifies no wait: if the socket is not ready for writing, |
| 1020 |
udpWrite() returns immediately. |
| 1021 |
<numBytesToWrite> - I |
| 1022 |
is the number of bytes to write. |
| 1023 |
<buffer> - O |
| 1024 |
is the data to be output. |
| 1025 |
<status> - O |
| 1026 |
returns the status of sending the message: zero if no errors |
| 1027 |
occurred, EWOULDBLOCK if the timeout interval expired before |
| 1028 |
the message could be sent, and ERRNO otherwise. |
| 1029 |
|
| 1030 |
*******************************************************************************/ |
| 1031 |
|
| 1032 |
|
| 1033 |
int udpWrite ( |
| 1034 |
|
| 1035 |
# if __STDC__ |
| 1036 |
UdpEndpoint destination, |
| 1037 |
double timeout, |
| 1038 |
int numBytesToWrite, |
| 1039 |
const char *buffer) |
| 1040 |
# else |
| 1041 |
destination, timeout, numBytesToWrite, buffer) |
| 1042 |
|
| 1043 |
UdpEndpoint destination ; |
| 1044 |
double timeout ; |
| 1045 |
int numBytesToWrite ; |
| 1046 |
const char *buffer ; |
| 1047 |
# endif |
| 1048 |
|
| 1049 |
{ /* Local variables. */ |
| 1050 |
fd_set writeMask ; |
| 1051 |
int fd, length, numActive ; |
| 1052 |
struct timeval deltaTime, expirationTime ; |
| 1053 |
|
| 1054 |
|
| 1055 |
|
| 1056 |
|
| 1057 |
|
| 1058 |
if (destination == NULL) { |
| 1059 |
errno = EINVAL ; |
| 1060 |
vperror ("(udpWrite) NULL destination handle: ") ; |
| 1061 |
return (errno) ; |
| 1062 |
} |
| 1063 |
|
| 1064 |
fd = (destination->parent == NULL) ? destination->fd |
| 1065 |
: (destination->parent)->fd ; |
| 1066 |
if (fd < 0) { |
| 1067 |
errno = EINVAL ; |
| 1068 |
vperror ("(udpWrite) %d file descriptor: ", fd) ; |
| 1069 |
return (errno) ; |
| 1070 |
} |
| 1071 |
|
| 1072 |
|
| 1073 |
/******************************************************************************* |
| 1074 |
If a timeout interval was specified, then wait until the expiration |
| 1075 |
of the interval for the endpoint's socket to be ready for writing. |
| 1076 |
*******************************************************************************/ |
| 1077 |
|
| 1078 |
if (timeout >= 0.0) { |
| 1079 |
|
| 1080 |
/* Compute the expiration time as the current time plus the interval. */ |
| 1081 |
|
| 1082 |
expirationTime = tvAdd (tvTOD (), tvCreateF (timeout)) ; |
| 1083 |
|
| 1084 |
/* Wait for the endpoint to be ready for writing. */ |
| 1085 |
|
| 1086 |
for ( ; ; ) { |
| 1087 |
deltaTime = tvSubtract (expirationTime, tvTOD ()) ; |
| 1088 |
FD_ZERO (&writeMask) ; FD_SET (fd, &writeMask) ; |
| 1089 |
numActive = select (fd+1, NULL, &writeMask, NULL, &deltaTime) ; |
| 1090 |
if (numActive >= 0) break ; |
| 1091 |
if (errno == EINTR) continue ; |
| 1092 |
vperror ("(udpWrite) Error waiting to write to %s.\nselect: ", |
| 1093 |
destination->name) ; |
| 1094 |
return (errno) ; |
| 1095 |
} |
| 1096 |
|
| 1097 |
if (numActive == 0) { |
| 1098 |
errno = EWOULDBLOCK ; |
| 1099 |
vperror ("(udpWrite) Timeout while waiting to write data to %s.\n", |
| 1100 |
destination->name) ; |
| 1101 |
return (errno) ; |
| 1102 |
} |
| 1103 |
|
| 1104 |
} |
| 1105 |
|
| 1106 |
|
| 1107 |
/******************************************************************************* |
| 1108 |
Send the message to the destination endpoint. |
| 1109 |
*******************************************************************************/ |
| 1110 |
|
| 1111 |
length = sendto (fd, (char *) buffer, numBytesToWrite, 0, |
| 1112 |
&destination->address, destination->addressLength) ; |
| 1113 |
if (length < 0) { |
| 1114 |
vperror ("(udpWrite) Error sending %d-byte message to %s.\nsendto: ", |
| 1115 |
numBytesToWrite, destination->name) ; |
| 1116 |
return (errno) ; |
| 1117 |
} |
| 1118 |
|
| 1119 |
if (udp_util_debug) { |
| 1120 |
printf ("(udpWrite) Wrote %d bytes to %s, socket %d.\n", |
| 1121 |
length, destination->name, fd) ; |
| 1122 |
meoDumpX (stdout, " ", 0, buffer, length) ; |
| 1123 |
} |
| 1124 |
|
| 1125 |
|
| 1126 |
return (0) ; |
| 1127 |
|
| 1128 |
} |
| 1129 |
</XMP></BODY></HTML> |