udp.c revision 47461
147061Sbrian/*- 247061Sbrian * Copyright (c) 1999 Brian Somers <brian@Awfulhak.org> 347061Sbrian * All rights reserved. 447061Sbrian * 547061Sbrian * Redistribution and use in source and binary forms, with or without 647061Sbrian * modification, are permitted provided that the following conditions 747061Sbrian * are met: 847061Sbrian * 1. Redistributions of source code must retain the above copyright 947061Sbrian * notice, this list of conditions and the following disclaimer. 1047061Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1147061Sbrian * notice, this list of conditions and the following disclaimer in the 1247061Sbrian * documentation and/or other materials provided with the distribution. 1347061Sbrian * 1447061Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1547061Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1647061Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1747061Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1847061Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1947061Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2047061Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2147061Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2247061Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2347061Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2447061Sbrian * SUCH DAMAGE. 2547061Sbrian * 2647461Sbrian * $Id: udp.c,v 1.1 1999/05/12 09:49:09 brian Exp $ 2747061Sbrian */ 2847061Sbrian 2947061Sbrian#include <sys/types.h> 3047061Sbrian#include <sys/socket.h> 3147061Sbrian#include <netinet/in.h> 3247061Sbrian#include <arpa/inet.h> 3347061Sbrian#include <netdb.h> 3447061Sbrian 3547061Sbrian#include <errno.h> 3647061Sbrian#include <stdio.h> 3747061Sbrian#include <stdlib.h> 3847061Sbrian#include <string.h> 3947061Sbrian#include <sys/uio.h> 4047061Sbrian#include <termios.h> 4147061Sbrian#include <unistd.h> 4247061Sbrian 4347061Sbrian#include "layer.h" 4447061Sbrian#include "defs.h" 4547061Sbrian#include "mbuf.h" 4647061Sbrian#include "log.h" 4747061Sbrian#include "sync.h" 4847061Sbrian#include "timer.h" 4947061Sbrian#include "lqr.h" 5047061Sbrian#include "hdlc.h" 5147061Sbrian#include "throughput.h" 5247061Sbrian#include "fsm.h" 5347061Sbrian#include "lcp.h" 5447061Sbrian#include "ccp.h" 5547061Sbrian#include "link.h" 5647061Sbrian#include "async.h" 5747061Sbrian#include "descriptor.h" 5847061Sbrian#include "physical.h" 5947061Sbrian#include "udp.h" 6047061Sbrian 6147061Sbrianstruct udpdevice { 6247061Sbrian struct device dev; /* What struct physical knows about */ 6347061Sbrian struct sockaddr_in sock; /* peer address */ 6447061Sbrian unsigned connected : 1; /* Have we connect()d ? */ 6547061Sbrian}; 6647061Sbrian 6747061Sbrian#define device2udp(d) ((d)->type == UDP_DEVICE ? (struct udpdevice *)d : NULL) 6847061Sbrian 6947061Sbrianstatic ssize_t 7047061Sbrianudp_Sendto(struct physical *p, const void *v, size_t n) 7147061Sbrian{ 7247061Sbrian struct udpdevice *dev = device2udp(p->handler); 7347061Sbrian 7447061Sbrian if (dev->connected) 7547061Sbrian return write(p->fd, v, n); 7647061Sbrian 7747061Sbrian return sendto(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, 7847061Sbrian sizeof dev->sock); 7947061Sbrian} 8047061Sbrian 8147061Sbrianstatic ssize_t 8247061Sbrianudp_Recvfrom(struct physical *p, void *v, size_t n) 8347061Sbrian{ 8447061Sbrian struct udpdevice *dev = device2udp(p->handler); 8547061Sbrian int sz, ret; 8647061Sbrian 8747061Sbrian if (dev->connected) 8847061Sbrian return read(p->fd, v, n); 8947061Sbrian 9047061Sbrian sz = sizeof dev->sock; 9147061Sbrian ret = recvfrom(p->fd, v, n, 0, (struct sockaddr *)&dev->sock, &sz); 9247061Sbrian 9347061Sbrian if (*p->name.full == '\0') { 9447061Sbrian snprintf(p->name.full, sizeof p->name.full, "%s:%d/udp", 9547061Sbrian inet_ntoa(dev->sock.sin_addr), ntohs(dev->sock.sin_port)); 9647061Sbrian p->name.base = p->name.full; 9747061Sbrian } 9847061Sbrian 9947061Sbrian return ret; 10047061Sbrian} 10147061Sbrian 10247061Sbrianstatic void 10347061Sbrianudp_Free(struct physical *p) 10447061Sbrian{ 10547061Sbrian struct udpdevice *dev = device2udp(p->handler); 10647061Sbrian 10747061Sbrian free(dev); 10847061Sbrian} 10947061Sbrian 11047061Sbrianstatic void 11147061Sbrianudp_device2iov(struct physical *p, struct iovec *iov, int *niov, 11247061Sbrian int maxiov, pid_t newpid) 11347061Sbrian{ 11447061Sbrian iov[*niov].iov_base = p ? p->handler : malloc(sizeof(struct udpdevice)); 11547061Sbrian iov[*niov].iov_len = sizeof(struct udpdevice); 11647061Sbrian (*niov)++; 11747061Sbrian} 11847061Sbrian 11947061Sbrianstatic const struct device baseudpdevice = { 12047061Sbrian UDP_DEVICE, 12147061Sbrian "udp", 12247061Sbrian NULL, 12347061Sbrian NULL, 12447061Sbrian NULL, 12547061Sbrian NULL, 12647061Sbrian udp_Free, 12747061Sbrian udp_Recvfrom, 12847061Sbrian udp_Sendto, 12947061Sbrian udp_device2iov, 13047061Sbrian NULL, 13147061Sbrian NULL 13247061Sbrian}; 13347061Sbrian 13447061Sbrianstruct device * 13547061Sbrianudp_iov2device(int type, struct physical *p, struct iovec *iov, int *niov, 13647061Sbrian int maxiov) 13747061Sbrian{ 13847061Sbrian if (type == UDP_DEVICE) { 13947461Sbrian struct udpdevice *dev = (struct udpdevice *)iov[(*niov)++].iov_base; 14047061Sbrian 14147061Sbrian /* Refresh function pointers etc */ 14247461Sbrian memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 14347061Sbrian 14447461Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 14547461Sbrian return &dev->dev; 14647461Sbrian } 14747061Sbrian 14847461Sbrian return NULL; 14947061Sbrian} 15047061Sbrian 15147061Sbrianstatic struct udpdevice * 15247061Sbrianudp_CreateDevice(struct physical *p, char *host, char *port) 15347061Sbrian{ 15447061Sbrian struct udpdevice *dev; 15547061Sbrian struct servent *sp; 15647061Sbrian 15747061Sbrian if ((dev = malloc(sizeof *dev)) == NULL) { 15847061Sbrian log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 15947061Sbrian p->link.name, strerror(errno)); 16047061Sbrian return NULL; 16147061Sbrian } 16247061Sbrian 16347061Sbrian dev->sock.sin_family = AF_INET; 16447061Sbrian dev->sock.sin_addr.s_addr = inet_addr(host); 16547061Sbrian dev->sock.sin_addr = GetIpAddr(host); 16647061Sbrian if (dev->sock.sin_addr.s_addr == INADDR_NONE) { 16747061Sbrian log_Printf(LogWARN, "%s: %s: unknown host\n", p->link.name, host); 16847061Sbrian free(dev); 16947061Sbrian return NULL; 17047061Sbrian } 17147061Sbrian dev->sock.sin_port = htons(atoi(port)); 17247061Sbrian if (dev->sock.sin_port == 0) { 17347061Sbrian sp = getservbyname(port, "udp"); 17447061Sbrian if (sp) 17547061Sbrian dev->sock.sin_port = sp->s_port; 17647061Sbrian else { 17747061Sbrian log_Printf(LogWARN, "%s: %s: unknown service\n", p->link.name, port); 17847061Sbrian free(dev); 17947061Sbrian return NULL; 18047061Sbrian } 18147061Sbrian } 18247061Sbrian 18347061Sbrian log_Printf(LogPHASE, "%s: Connecting to %s:%s/udp\n", p->link.name, 18447061Sbrian host, port); 18547061Sbrian 18647061Sbrian p->fd = socket(PF_INET, SOCK_DGRAM, 0); 18747061Sbrian if (p->fd >= 0) { 18847061Sbrian log_Printf(LogDEBUG, "%s: Opened udp socket %s\n", p->link.name, 18947061Sbrian p->name.full); 19047061Sbrian if (connect(p->fd, (struct sockaddr *)&dev->sock, sizeof dev->sock) == 0) { 19147061Sbrian dev->connected = 1; 19247061Sbrian return dev; 19347061Sbrian } else 19447061Sbrian log_Printf(LogWARN, "%s: connect: %s\n", p->name.full, strerror(errno)); 19547061Sbrian } else 19647061Sbrian log_Printf(LogWARN, "%s: socket: %s\n", p->name.full, strerror(errno)); 19747061Sbrian 19847061Sbrian close(p->fd); 19947061Sbrian p->fd = -1; 20047061Sbrian free(dev); 20147061Sbrian 20247061Sbrian return NULL; 20347061Sbrian} 20447061Sbrian 20547061Sbrianstruct device * 20647061Sbrianudp_Create(struct physical *p) 20747061Sbrian{ 20847061Sbrian char *cp, *host, *port, *svc; 20947061Sbrian struct udpdevice *dev; 21047061Sbrian 21147061Sbrian dev = NULL; 21247061Sbrian if (p->fd < 0) { 21347061Sbrian if ((cp = strchr(p->name.full, ':')) != NULL) { 21447061Sbrian *cp = '\0'; 21547061Sbrian host = p->name.full; 21647061Sbrian port = cp + 1; 21747061Sbrian svc = strchr(port, '/'); 21847061Sbrian if (svc && strcasecmp(svc, "/udp")) { 21947061Sbrian *cp = ':'; 22047061Sbrian return NULL; 22147061Sbrian } 22247061Sbrian if (svc) 22347061Sbrian *svc = '\0'; 22447061Sbrian 22547061Sbrian if (*host && *port) 22647061Sbrian dev = udp_CreateDevice(p, host, port); 22747061Sbrian 22847061Sbrian *cp = ':'; 22947061Sbrian if (svc) 23047061Sbrian *svc = '/'; 23147061Sbrian } 23247061Sbrian } else { 23347061Sbrian /* See if we're a connected udp socket */ 23447061Sbrian int type, sz, err; 23547061Sbrian 23647061Sbrian sz = sizeof type; 23747061Sbrian if ((err = getsockopt(p->fd, SOL_SOCKET, SO_TYPE, &type, &sz)) == 0 && 23847061Sbrian sz == sizeof type && type == SOCK_DGRAM) { 23947061Sbrian if ((dev = malloc(sizeof *dev)) == NULL) { 24047061Sbrian log_Printf(LogWARN, "%s: Cannot allocate a udp device: %s\n", 24147061Sbrian p->link.name, strerror(errno)); 24247061Sbrian return NULL; 24347061Sbrian } 24447061Sbrian 24547061Sbrian /* We can't getpeername().... hence we stay un-connect()ed */ 24647061Sbrian dev->connected = 0; 24747061Sbrian 24847061Sbrian log_Printf(LogPHASE, "%s: Link is a udp socket\n", p->link.name); 24947061Sbrian 25047061Sbrian if (p->link.lcp.cfg.openmode != OPEN_PASSIVE) { 25147061Sbrian log_Printf(LogPHASE, "%s: Changing openmode to PASSIVE\n", 25247061Sbrian p->link.name); 25347061Sbrian p->link.lcp.cfg.openmode = OPEN_PASSIVE; 25447061Sbrian } 25547061Sbrian } 25647061Sbrian } 25747061Sbrian 25847061Sbrian if (dev) { 25947061Sbrian memcpy(&dev->dev, &baseudpdevice, sizeof dev->dev); 26047461Sbrian physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNC); 26147061Sbrian return &dev->dev; 26247061Sbrian } 26347061Sbrian 26447061Sbrian return NULL; 26547061Sbrian} 266