1 |
ab11 |
1.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> |