00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00028 #include "dnxUdp.h"
00029 #include "dnxTSPI.h"
00030
00031 #include "dnxTransport.h"
00032 #include "dnxError.h"
00033 #include "dnxDebug.h"
00034 #include "dnxLogging.h"
00035
00036 #include "dnxProtocol.h"
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <stddef.h>
00041 #include <string.h>
00042 #include <errno.h>
00043 #include <assert.h>
00044 #include <sys/types.h>
00045 #include <sys/time.h>
00046 #include <sys/socket.h>
00047 #include <sys/select.h>
00048 #include <netinet/in.h>
00049 #include <netdb.h>
00050 #include <unistd.h>
00051 #include <pthread.h>
00052 #include <limits.h>
00053
00054 #ifndef HOST_NAME_MAX
00055 # define HOST_NAME_MAX 256
00056 #endif
00057
00059 typedef struct iDnxUdpChannel_
00060 {
00061 char * host;
00062 int port;
00063 int socket;
00064 DnxTransStats stats;
00065 iDnxChannel ichan;
00066 } iDnxUdpChannel;
00067
00070 static pthread_mutex_t udpMutex;
00071
00072
00073
00074
00075
00098 static int dnxUdpOpen(iDnxChannel * icp, int mode)
00099 {
00100 iDnxUdpChannel * iucp = (iDnxUdpChannel *)
00101 ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00102 struct hostent * he;
00103 struct sockaddr_in inaddr;
00104 int sd;
00105
00106 assert(icp && iucp->port > 0);
00107
00108 inaddr.sin_family = AF_INET;
00109 inaddr.sin_port = htons((in_port_t)iucp->port);
00110
00111
00112 if (!strcmp(iucp->host, "INADDR_ANY")
00113 || !strcmp(iucp->host, "0.0.0.0")
00114 || !strcmp(iucp->host, "0"))
00115 {
00116
00117 if (mode == DNX_MODE_ACTIVE) return DNX_ERR_ADDRESS;
00118 inaddr.sin_addr.s_addr = INADDR_ANY;
00119 }
00120 else
00121 {
00122 DNX_PT_MUTEX_LOCK(&udpMutex);
00123 if ((he = gethostbyname(iucp->host)) != 0)
00124 memcpy(&inaddr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
00125 DNX_PT_MUTEX_UNLOCK(&udpMutex);
00126
00127 if (!he) return DNX_ERR_ADDRESS;
00128 }
00129
00130 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00131 {
00132 dnxLog("dnxUdpOpen: socket failed: %s.", strerror(errno));
00133 return DNX_ERR_OPEN;
00134 }
00135
00136
00137 if (mode == DNX_MODE_ACTIVE)
00138 {
00139 struct sockaddr_in inaddr_any;
00140
00141
00142
00143
00144 memset(&inaddr_any, 0, sizeof inaddr_any);
00145 inaddr_any.sin_family = AF_INET;
00146 inaddr_any.sin_addr.s_addr = htonl(INADDR_ANY);
00147 if (bind(sd, (struct sockaddr *)&inaddr_any, sizeof inaddr_any) != 0)
00148 {
00149 close(sd);
00150 dnxLog("dnxUdpOpen: bind(any) failed: %s.", strerror(errno));
00151 return DNX_ERR_OPEN;
00152 }
00153
00154
00155
00156
00157
00158 if (connect(sd, (struct sockaddr *)&inaddr, sizeof inaddr) != 0)
00159 {
00160 dnxLog("dnxUdpOpen: connect(%lx) failed: %s.",
00161 (unsigned long)inaddr.sin_addr.s_addr, strerror(errno));
00162 close(sd);
00163 return DNX_ERR_OPEN;
00164 }
00165 }
00166 else
00167 {
00168 struct linger lopt;
00169 int reuse = 1;
00170
00171 lopt.l_onoff = 0;
00172 lopt.l_linger = 0;
00173
00174
00175 setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof reuse);
00176 setsockopt(sd, SOL_SOCKET, SO_LINGER, &lopt, sizeof lopt);
00177
00178
00179
00180 if (bind(sd, (struct sockaddr *)&inaddr, sizeof inaddr) != 0)
00181 {
00182 close(sd);
00183 dnxLog("dnxUdpOpen: bind(%lx) failed: %s.",
00184 (unsigned long)inaddr.sin_addr.s_addr, strerror(errno));
00185 return DNX_ERR_OPEN;
00186 }
00187 }
00188
00189 iucp->socket = sd;
00190
00191 return DNX_OK;
00192 }
00193
00194
00195
00202 static int dnxUdpClose(iDnxChannel * icp)
00203 {
00204 iDnxUdpChannel * iucp = (iDnxUdpChannel *)
00205 ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00206
00207 assert(icp && iucp->socket);
00208
00209 close(iucp->socket);
00210 iucp->socket = 0;
00211
00212 return DNX_OK;
00213 }
00214
00215
00216
00248 static int dnxUdpRead(iDnxChannel * icp, char * buf, int * size, int timeout, char * src)
00249 {
00250 iDnxUdpChannel * iucp = (iDnxUdpChannel *)((char *)icp - offsetof(iDnxUdpChannel, ichan));
00251 socklen_t slen = sizeof(struct sockaddr_storage);
00252 ssize_t mlen;
00253
00254 assert(icp && iucp->socket && buf && size && *size > 0);
00255
00256
00257 if (timeout > 0)
00258 {
00259 struct timeval tv;
00260 fd_set fd_rds;
00261 int nsd;
00262
00263 FD_ZERO(&fd_rds);
00264 FD_SET(iucp->socket, &fd_rds);
00265
00266 tv.tv_usec = 0L;
00267 tv.tv_sec = timeout;
00268
00269 if ((nsd = select(iucp->socket + 1, &fd_rds, 0, 0, &tv)) == 0)
00270 return DNX_ERR_TIMEOUT;
00271
00272 if (nsd < 0)
00273 {
00274 if (errno != EINTR)
00275 {
00276 dnxLog("UDP receive - select failed: %s.", strerror(errno));
00277 return DNX_ERR_RECEIVE;
00278 }
00279 return DNX_ERR_TIMEOUT;
00280 }
00281 }
00282
00283
00284 if (src)
00285 mlen = recvfrom(iucp->socket, buf, *size, 0, (struct sockaddr *)src, &slen);
00286 else
00287 mlen = read(iucp->socket, buf, *size);
00288
00289 if (mlen < 0)
00290 {
00291 iucp->stats.rderrs++;
00292
00293
00294
00295 if (errno == ECONNREFUSED) return DNX_ERR_ADDRESS;
00296
00297 dnxDebug(2, "UDP receive - %s socket failed: %s.",
00298 src? "recvfrom unconnected": "read connected", strerror(errno));
00299
00300 return DNX_ERR_RECEIVE;
00301 }
00302
00303 iucp->stats.reads++;
00304 *size = (int)mlen;
00305
00306 return DNX_OK;
00307 }
00308
00309
00310
00342 static int dnxUdpWrite(iDnxChannel * icp, char * buf, int size, int timeout, char * dst)
00343 {
00344 iDnxUdpChannel * iucp = (iDnxUdpChannel *) ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00345 ssize_t mlen;
00346
00347 assert(icp && iucp->socket && buf && size);
00348
00349
00350 if (timeout > 0)
00351 {
00352 struct timeval tv;
00353 fd_set fd_wrs;
00354 int nsd;
00355
00356 FD_ZERO(&fd_wrs);
00357 FD_SET(iucp->socket, &fd_wrs);
00358
00359 tv.tv_usec = 0L;
00360 tv.tv_sec = timeout;
00361
00362 if ((nsd = select(iucp->socket + 1, 0, &fd_wrs, 0, &tv)) == 0)
00363 return DNX_ERR_TIMEOUT;
00364 if (nsd < 0)
00365 {
00366 if (errno != EINTR)
00367 {
00368 dnxLog("UDP send - select failed: %s.", strerror(errno));
00369 return DNX_ERR_SEND;
00370 }
00371 return DNX_ERR_TIMEOUT;
00372 }
00373 }
00374
00375
00376 if (dst)
00377 {
00378 struct sockaddr * sa = (struct sockaddr *)dst;
00379 mlen = sendto(iucp->socket, buf, size, 0, sa, sa->sa_family == AF_INET?
00380 sizeof(struct sockaddr_in): sizeof(struct sockaddr_in6));
00381 }
00382 else
00383 mlen = write(iucp->socket, buf, size);
00384
00385 if (mlen < 0)
00386 {
00387 iucp->stats.wrerrs++;
00388 dnxDebug(2, "UDP send - %s socket failed: %s.",
00389 dst? "sendto unconnected": "write connected", strerror(errno));
00390 return DNX_ERR_SEND;
00391 }
00392
00393 iucp->stats.writes++;
00394
00395 return DNX_OK;
00396 }
00397
00398
00399
00404 static void dnxUdpDelete(iDnxChannel * icp)
00405 {
00406 iDnxUdpChannel * iucp = (iDnxUdpChannel *)
00407 ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00408
00409 assert(icp && iucp->socket == 0);
00410
00411 xfree(iucp->host);
00412 xfree(iucp);
00413 }
00414
00415
00416
00422 static void dnxUdpGetStats(iDnxChannel * icp, DnxTransStats * tsp)
00423 {
00424 iDnxUdpChannel * iucp = (iDnxUdpChannel *)
00425 ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00426
00427 assert(icp && tsp);
00428
00429 *tsp = iucp->stats;
00430 }
00431
00432
00433
00438 static void dnxUdpResetStats(iDnxChannel * icp)
00439 {
00440 iDnxUdpChannel * iucp = (iDnxUdpChannel *)
00441 ((char *)icp - offsetof(iDnxUdpChannel, ichan));
00442
00443 assert(icp);
00444
00445 memset(&iucp->stats, 0, sizeof iucp->stats);
00446 }
00447
00448
00449
00458 static int dnxUdpNew(char * url, iDnxChannel ** icpp)
00459 {
00460 char * cp, * ep, * lastchar;
00461 iDnxUdpChannel * iucp = NULL;
00462 long port;
00463
00464 assert(icpp && url && *url);
00465
00466
00467 if ((cp = strstr(url, "://")) == 0)
00468 return DNX_ERR_BADURL;
00469 cp += 3;
00470
00471
00472 if ((ep = strchr(cp, ':')) == 0 || ep == cp || ep - cp > HOST_NAME_MAX)
00473 return DNX_ERR_BADURL;
00474
00475
00476 if ((port = strtol(ep + 1, &lastchar, 0)) < 1 || port > 65535
00477 || (*lastchar && *lastchar != '/'))
00478 return DNX_ERR_BADURL;
00479
00480 if(iucp)
00481 xfree(iucp);
00482
00483
00484 if ((iucp = (iDnxUdpChannel *)xcalloc(1,sizeof *iucp)) == 0)
00485 {
00486 return DNX_ERR_MEMORY;
00487 }
00488
00489
00490
00491 if ((iucp->host = (char *)xmalloc(ep - cp + 1)) == 0)
00492 {
00493 xfree(iucp);
00494 return DNX_ERR_MEMORY;
00495 }
00496 memcpy(iucp->host, cp, ep - cp);
00497 iucp->host[ep - cp] = 0;
00498 iucp->port = (int)port;
00499
00500
00501 iucp->ichan.txOpen = dnxUdpOpen;
00502 iucp->ichan.txClose = dnxUdpClose;
00503 iucp->ichan.txRead = dnxUdpRead;
00504 iucp->ichan.txWrite = dnxUdpWrite;
00505 iucp->ichan.txDelete = dnxUdpDelete;
00506 iucp->ichan.txGetStats = dnxUdpGetStats;
00507 iucp->ichan.txResetStats = dnxUdpResetStats;
00508 *icpp = &iucp->ichan;
00509
00510 return DNX_OK;
00511 }
00512
00513
00514
00515
00516
00524 int dnxUdpInit(int (**ptxAlloc)(char * url, iDnxChannel ** icpp))
00525 {
00526 DNX_PT_MUTEX_INIT(&udpMutex);
00527
00528 *ptxAlloc = dnxUdpNew;
00529
00530 return DNX_OK;
00531 }
00532
00533
00534
00537 void dnxUdpDeInit(void)
00538 {
00539 DNX_PT_MUTEX_DESTROY(&udpMutex);
00540 }
00541
00542
00543