udp.c revision 47461
1/*- 2 * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: udp.c,v 1.1 1999/05/12 09:49:09 brian Exp $ 27 */ 28 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <netinet/in.h> 32#include <arpa/inet.h> 33#include <netdb.h> 34 35#include <errno.h> 36#include <stdio.h> 37#include <stdlib.h> 38#include <string.h> 39#include <sys/uio.h> 40#include <termios.h> 41#include <unistd.h> 42 43#include "layer.h" 44#include "defs.h" 45#include "mbuf.h" 46#include "log.h" 47#include "sync.h" 48#include "timer.h" 49#include "lqr.h" 50#include "hdlc.h" 51#include "throughput.h" 52#include "fsm.h" 53#include "lcp.h" 54#include "ccp.h" 55#include "link.h" 56#include "async.h" 57#include "descriptor.h" 58#include "physical.h" 59#include "udp.h" 60 61struct udpdevice { 62 struct device dev; /* What struct physical knows about */ 63 struct sockaddr_in sock; /* peer address */ 64 unsigned connected : 1; /* Have we connect()d ? */ 65}; 66 67#define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 68 69static ssize_t 70udp_Sendto(struct physical *p, const void *v, size_t n) 71{ 72 struct udpdevice *dev = device2udp(p->handler); 73 74 if (dev->connected) 75 return write(p->fd, v, n); 76 77 return sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 78 sizeof dev->sock); 79} 80 81static ssize_t 82udp_Recvfrom(struct physical *p, void *v, size_t n) 83{ 84 struct udpdevice *dev = device2udp(p->handler); 85 int sz, ret; 86 87 if (dev->connected) 88 return read(p->fd, v, n); 89 90 sz = sizeof dev->sock; 91 ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 92 93 if (*p->name.full == '\0') { 94 snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 95 inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 96 p->name.base = p->name.full; 97 } 98 99 return ret; 100} 101 102static void 103udp_Free(struct physical *p) 104{ 105 struct udpdevice *dev = device2udp(p->handler); 106 107 free(dev); 108} 109 110static void 111udp_device2iov(struct physical *p, struct iovec *iov, int *niov, 112 int maxiov, pid_t newpid) 113{ 114 iov[*niov].iov_base = p ? p->handler : malloc(sizeof(struct udpdevice)); 115 iov[*niov].iov_len = sizeof(struct udpdevice); 116 (*niov)++; 117} 118 119static const struct device baseudpdevice = { 120 UDP_DEVICE, 121 "udp", 122 NULL, 123 NULL, 124 NULL, 125 NULL, 126 udp_Free, 127 udp_Recvfrom, 128 udp_Sendto, 129 udp_device2iov, 130 NULL, 131 NULL 132}; 133 134struct device * 135udp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 136 int maxiov) 137{ 138 if (type == UDP_DEVICE) { 139 struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 140 141 /* Refresh function pointers etc */ 142 memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 143 144 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 145 return &dev->dev; 146 } 147 148 return NULL; 149} 150 151static struct udpdevice * 152udp_CreateDevice(struct physical *p, char *host, char *port) 153{ 154 struct udpdevice *dev; 155 struct servent *sp; 156 157 if ((dev = malloc(sizeof *dev)) == NULL) { 158 log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 159 p->link.name, strerror(errno)); 160 return NULL; 161 } 162 163 dev->sock.sin_family = AF_INET; 164 dev->sock.sin_addr.s_addr = inet_addr(host); 165 dev->sock.sin_addr = GetIpAddr(host); 166 if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 167 log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 168 free(dev); 169 return NULL; 170 } 171 dev->sock.sin_port = htons(atoi(port)); 172 if (dev->sock.sin_port == 0) { 173 sp = getservbyname(port, "udp"); 174 if (sp) 175 dev->sock.sin_port = sp->s_port; 176 else { 177 log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 178 free(dev); 179 return NULL; 180 } 181 } 182 183 log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 184 host, port); 185 186 p->fd = socket(PF_INET, SOCK_DGRAM, 0); 187 if (p->fd >= 0) { 188 log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 189 p->name.full); 190 if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 191 dev->connected = 1; 192 return dev; 193 } else 194 log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 195 } else 196 log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 197 198 close(p->fd); 199 p->fd = -1; 200 free(dev); 201 202 return NULL; 203} 204 205struct device * 206udp_Create(struct physical *p) 207{ 208 char *cp, *host, *port, *svc; 209 struct udpdevice *dev; 210 211 dev = NULL; 212 if (p->fd < 0) { 213 if ((cp = strchr(p->name.full, ':')) != NULL) { 214 *cp = '\0'; 215 host = p->name.full; 216 port = cp + 1; 217 svc = strchr(port, '/'); 218 if (svc && strcasecmp(svc, "/udp")) { 219 *cp = ':'; 220 return NULL; 221 } 222 if (svc) 223 *svc = '\0'; 224 225 if (*host && *port) 226 dev = udp_CreateDevice(p, host, port); 227 228 *cp = ':'; 229 if (svc) 230 *svc = '/'; 231 } 232 } else { 233 /* See if we're a connected udp socket */ 234 int type, sz, err; 235 236 sz = sizeof type; 237 if ((err = getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz)) == 0 && 238 sz == sizeof type && type == SOCK_DGRAM) { 239 if ((dev = malloc(sizeof *dev)) == NULL) { 240 log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 241 p->link.name, strerror(errno)); 242 return NULL; 243 } 244 245 /* We can't getpeername().... hence we stay un-connect()ed */ 246 dev->connected = 0; 247 248 log_Printf(LogPHASE, "%s: Link is a udp socket\n", p->link.name); 249 250 if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 251 log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 252 p->link.name); 253 p->link.lcp.cfg.openmode = OPEN_PASSIVE; 254 } 255 } 256 } 257 258 if (dev) { 259 memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 260 physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 261 return &dev->dev; 262 } 263 264 return NULL; 265} 266