diff options
author | Kozlov Dmitry <dima@server> | 2010-08-03 13:28:53 +0400 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-08-03 13:28:53 +0400 |
commit | 5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f (patch) | |
tree | e72134e47e1491580af15e3eccbba451f13fdd42 /accel-pptpd | |
parent | ba8e1a64e75930a161afac9048e7d03b7f880644 (diff) | |
download | accel-ppp-5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f.tar.gz accel-ppp-5a2d6079eba1c7e2a9479cb10d714b5a97bbfe4f.zip |
initiating work on accel-pptpd, replacement of modified poptop
Diffstat (limited to 'accel-pptpd')
-rw-r--r-- | accel-pptpd/CMakeLists.txt | 16 | ||||
-rw-r--r-- | accel-pptpd/ctrl.c | 380 | ||||
-rw-r--r-- | accel-pptpd/events.h | 18 | ||||
-rw-r--r-- | accel-pptpd/if_pppox.h | 227 | ||||
-rw-r--r-- | accel-pptpd/list.h | 252 | ||||
-rw-r--r-- | accel-pptpd/log.c | 111 | ||||
-rw-r--r-- | accel-pptpd/log.h | 25 | ||||
-rw-r--r-- | accel-pptpd/ppp.c | 174 | ||||
-rw-r--r-- | accel-pptpd/ppp.h | 125 | ||||
-rw-r--r-- | accel-pptpd/ppp_fsm.c | 477 | ||||
-rw-r--r-- | accel-pptpd/ppp_fsm.h | 91 | ||||
-rw-r--r-- | accel-pptpd/ppp_lcp.c | 229 | ||||
-rw-r--r-- | accel-pptpd/pptp_prot.h | 297 | ||||
-rw-r--r-- | accel-pptpd/pptpd.c | 134 | ||||
-rw-r--r-- | accel-pptpd/pptpd.h | 26 | ||||
-rw-r--r-- | accel-pptpd/triton/CMakeLists.txt | 13 | ||||
-rw-r--r-- | accel-pptpd/triton/conf_file.c | 185 | ||||
-rw-r--r-- | accel-pptpd/triton/conf_file.h | 16 | ||||
-rw-r--r-- | accel-pptpd/triton/coroutine.c | 153 | ||||
-rw-r--r-- | accel-pptpd/triton/event.c | 155 | ||||
-rw-r--r-- | accel-pptpd/triton/list.h | 249 | ||||
-rw-r--r-- | accel-pptpd/triton/loader.c | 55 | ||||
-rw-r--r-- | accel-pptpd/triton/md.c | 342 | ||||
-rw-r--r-- | accel-pptpd/triton/options.c | 46 | ||||
-rw-r--r-- | accel-pptpd/triton/timer.c | 244 | ||||
-rw-r--r-- | accel-pptpd/triton/triton.h | 78 | ||||
-rw-r--r-- | accel-pptpd/triton/triton_p.h | 140 |
27 files changed, 4258 insertions, 0 deletions
diff --git a/accel-pptpd/CMakeLists.txt b/accel-pptpd/CMakeLists.txt new file mode 100644 index 00000000..5ee16fd2 --- /dev/null +++ b/accel-pptpd/CMakeLists.txt @@ -0,0 +1,16 @@ +PROJECT (pptpd) +cmake_minimum_required(VERSION 2.6) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") + +ADD_SUBDIRECTORY(triton) + +ADD_EXECUTABLE(pptpd + pptpd.c + ctrl.c + log.c + ppp.c + ppp_fsm.c + ppp_lcp.c +) +TARGET_LINK_LIBRARIES(pptpd pthread triton)
\ No newline at end of file diff --git a/accel-pptpd/ctrl.c b/accel-pptpd/ctrl.c new file mode 100644 index 00000000..3fbc6e82 --- /dev/null +++ b/accel-pptpd/ctrl.c @@ -0,0 +1,380 @@ +/* +* C Implementation: ctrl +* +* Description: +* +* +* Author: <xeb@mail.ru>, (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +#include "if_pppox.h" + +#include "list.h" +#include "pptp_prot.h" +#include "triton/triton.h" +#include "pptpd.h" +#include "log.h" +#include "ppp.h" + + +#define TIMEOUT 10000 + +#define STATE_IDLE 0 +#define STATE_ESTB 1 +#define STATE_FIN 10 + +struct pptp_conn_t +{ + struct triton_md_handler_t *h; + int state; + + u_int8_t *in_buf; + int in_size; + u_int8_t *out_buf; + int out_size; + int out_pos; + + struct ppp_t *ppp; +}; + +static void pptp_read(struct triton_md_handler_t *h); +static void pptp_write(struct triton_md_handler_t *h); +static void pptp_timeout(struct triton_md_handler_t *h); + +static void ctrl_read(struct triton_md_handler_t *h) +{ + struct triton_md_handler_t *hc; + struct pptp_conn_t *conn; + + int fd; + int n=read(h->fd,&fd,sizeof(fd)); + if (n!=4) + { + log_error("too short message from controlling thread\n"); + return; + } + + conn=malloc(sizeof(*conn)); + memset(conn,0,sizeof(*conn)); + conn->in_buf=malloc(PPTP_CTRL_SIZE_MAX); + conn->out_buf=malloc(PPTP_CTRL_SIZE_MAX); + + hc=malloc(sizeof(*hc)); + memset(hc,0,sizeof(*hc)); + hc->fd=fd; + hc->twait=TIMEOUT; + hc->read=pptp_read; + hc->write=pptp_write; + hc->timeout=pptp_timeout; + + hc->pd=conn; + conn->h=hc; + + conn->ppp=alloc_ppp(); + + triton_md_register_handler(hc); + triton_md_enable_handler(hc,MD_MODE_READ); +} + +int ctrl_init(struct ctrl_thread_t*ctrl) +{ + struct triton_md_handler_t *h=malloc(sizeof(*h)); + memset(h,0,sizeof(*h)); + h->fd=ctrl->pipe_fd[0]; + h->twait=-1; + h->read=ctrl_read; + triton_md_register_handler(h); + triton_md_enable_handler(h,MD_MODE_READ); + + return 0; +} + +static void disconnect(struct pptp_conn_t *conn) +{ + close(conn->h->fd); + triton_md_unregister_handler(conn->h); + free(conn->h); + free(conn); +} + +static int post_msg(struct pptp_conn_t *conn,void *buf,int size) +{ + int n; + if (conn->out_size) + { + log_debug("post_msg: buffer is not empty\n"); + return -1; + } + + n=write(conn->h->fd,buf,size); + if (n<0) + { + if (errno==EINTR) n=0; + else + { + log_debug("post_msg: failed to write socket %i\n",errno); + return -1; + } + } + + if (n<size) + { + memcpy(conn->out_buf,buf+n,size-n); + triton_md_enable_handler(conn->h,MD_MODE_WRITE); + } + + return 0; +} + +static int send_pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn,int reason,int err_code) +{ + struct pptp_stop_ctrl_conn msg={ + .header=PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), + .reason_result=hton8(reason), + .error_code=hton8(err_code), + }; + + return post_msg(conn,&msg,sizeof(msg)); +} + +static int send_pptp_stop_ctrl_conn_rply(struct pptp_conn_t *conn,int reason,int err_code) +{ + struct pptp_stop_ctrl_conn msg={ + .header=PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), + .reason_result=hton8(reason), + .error_code=hton8(err_code), + }; + + return post_msg(conn,&msg,sizeof(msg)); +} +static int pptp_stop_ctrl_conn_rqst(struct pptp_conn_t *conn) +{ + struct pptp_stop_ctrl_conn *msg=(struct pptp_stop_ctrl_conn *)conn->in_buf; + log_info("PPTP_STOP_CTRL_CONN_RQST reason=%i error_code=%i\n",msg->reason_result,msg->error_code); + + conn->state=STATE_FIN; + conn->h->twait=1000; + + return send_pptp_stop_ctrl_conn_rply(conn,PPTP_CONN_STOP_OK,0); +} + +static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn,int res_code,int err_code) +{ + struct pptp_start_ctrl_conn msg={ + .header=PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY), + .version=htons(PPTP_VERSION), + .result_code=res_code, + .error_code=err_code, + .framing_cap=htonl(PPTP_FRAME_SYNC), + .bearer_cap=htonl(0), + .max_channels=htons(1), + .firmware_rev=htons(PPTP_FIRMWARE_VERSION), + }; + + memset(msg.hostname,0,sizeof(msg.hostname)); + strcpy((char*)msg.hostname,PPTP_HOSTNAME); + + memset(msg.vendor,0,sizeof(msg.vendor)); + strcpy((char*)msg.vendor,PPTP_VENDOR); + + return post_msg(conn,&msg,sizeof(msg)); +} +static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn) +{ + struct pptp_start_ctrl_conn *msg=(struct pptp_start_ctrl_conn *)conn->in_buf; + + if (conn->state!=STATE_IDLE) + { + log_info("unexpected PPTP_START_CTRL_CONN_RQST\n"); + if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_EXISTS,0)) + return -1; + return 0; + } + + if (msg->version!=htons(PPTP_VERSION)) + { + log_info("PPTP version mismatch: expecting %x, received %s\n",PPTP_VERSION,msg->version); + if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_PROTOCOL,0)) + return -1; + return 0; + } + if (!(ntohl(msg->framing_cap)&PPTP_FRAME_SYNC)) + { + log_info("connection does not supports sync mode\n"); + if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_GE,0)) + return -1; + return 0; + } + if (send_pptp_start_ctrl_conn_rply(conn,PPTP_CONN_RES_SUCCESS,0)) + return -1; + + conn->state=STATE_ESTB; + + return 0; +} + +static int send_pptp_out_call_rply(struct pptp_conn_t *conn,struct pptp_out_call_rqst *rqst,int call_id,int res_code,int err_code) +{ + struct pptp_out_call_rply msg={ + .header=PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY), + .call_id=htons(call_id), + .call_id_peer=rqst->call_id, + .result_code=res_code, + .error_code=err_code, + .cause_code=0, + .speed=rqst->bps_max, + .recv_size=rqst->recv_size, + .delay=0, + .channel=0, + }; + + return post_msg(conn,&msg,sizeof(msg)); +} + +static int pptp_out_call_rqst(struct pptp_conn_t *conn) +{ + struct pptp_out_call_rqst *msg=(struct pptp_out_call_rqst *)conn->in_buf; + struct sockaddr_pppox src_addr,dst_addr; + struct sockaddr_in addr; + socklen_t addrlen; + int pptp_sock; + + if (conn->state!=STATE_ESTB) + { + log_info("unexpected PPTP_OUT_CALL_RQST\n"); + if (send_pptp_out_call_rply(conn,msg,0,PPTP_CALL_RES_GE,PPTP_GE_NOCONN)) + return -1; + return 0; + } + + src_addr.sa_family=AF_PPPOX; + src_addr.sa_protocol=PX_PROTO_PPTP; + src_addr.sa_addr.pptp.call_id=0; + addrlen=sizeof(addr); getsockname(conn->h->fd,(struct sockaddr*)&addr,&addrlen); + src_addr.sa_addr.pptp.sin_addr=addr.sin_addr; + + dst_addr.sa_family=AF_PPPOX; + dst_addr.sa_protocol=PX_PROTO_PPTP; + dst_addr.sa_addr.pptp.call_id=htons(msg->call_id); + addrlen=sizeof(addr); getpeername(conn->h->fd,(struct sockaddr*)&addr,&addrlen); + dst_addr.sa_addr.pptp.sin_addr=addr.sin_addr; + + pptp_sock=socket(AF_PPPOX,SOCK_STREAM,PX_PROTO_PPTP); + if (pptp_sock<0) + { + log_error("failed to create PPTP socket (%s)\n",strerror(errno)); + return -1; + } + if (bind(pptp_sock,(struct sockaddr*)&src_addr,sizeof(src_addr))) + { + log_error("failed to bind PPTP socket (%s)\n",strerror(errno)); + close(pptp_sock); + return -1; + } + addrlen=sizeof(src_addr); + getsockname(pptp_sock,(struct sockaddr*)&src_addr,&addrlen); + + if (connect(pptp_sock,(struct sockaddr*)&dst_addr,sizeof(dst_addr))) + { + log_error("failed to connect PPTP socket (%s)\n",strerror(errno)); + close(pptp_sock); + return -1; + } + + if (send_pptp_out_call_rply(conn,msg,src_addr.sa_addr.pptp.call_id,PPTP_CALL_RES_OK,0)) + return -1; + + conn->ppp->fd=pptp_sock; + conn->ppp->chan_name=strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr)); + establish_ppp(conn->ppp); + + return 0; +} + +static int process_packet(struct pptp_conn_t *conn) +{ + struct pptp_header *hdr=(struct pptp_header *)conn->in_buf; + switch(ntohs(hdr->ctrl_type)) + { + case PPTP_START_CTRL_CONN_RQST: + return pptp_start_ctrl_conn_rqst(conn); + case PPTP_STOP_CTRL_CONN_RQST: + return pptp_stop_ctrl_conn_rqst(conn); + case PPTP_OUT_CALL_RQST: + return pptp_out_call_rqst(conn); + } + return 0; +} + +static void pptp_read(struct triton_md_handler_t *h) +{ + struct pptp_conn_t *conn=(struct pptp_conn_t *)h->pd; + struct pptp_header *hdr=(struct pptp_header *)conn->in_buf; + int n; + + n=read(h->fd,conn->in_buf,PPTP_CTRL_SIZE_MAX-conn->in_size); + if (n<=0) + { + if (errno==EINTR) return; + disconnect(conn); + return; + } + conn->in_size+=n; + if (conn->in_size>=sizeof(*hdr)) + { + if (hdr->magic!=htonl(PPTP_MAGIC)) goto drop; + if (ntohs(hdr->length)>=PPTP_CTRL_SIZE_MAX) goto drop; + if (ntohs(hdr->length)>conn->in_size) goto drop; + if (ntohs(hdr->length)==conn->in_size) + { + if (ntohs(hdr->length)!=PPTP_CTRL_SIZE(ntohs(hdr->ctrl_type))) goto drop; + if (process_packet(conn)) goto drop; + conn->in_size=0; + } + } + h->twait=TIMEOUT; + return; +drop: + disconnect(conn); + return; +} +static void pptp_write(struct triton_md_handler_t *h) +{ + struct pptp_conn_t *conn=(struct pptp_conn_t *)h->pd; + int n=write(h->fd,conn->out_buf+conn->out_pos,conn->out_size-conn->out_pos); + + if (n<0) + { + if (errno==EINTR) n=0; + else + { + log_debug("post_msg: failed to write socket %i\n",errno); + disconnect(conn); + return; + } + } + + conn->out_pos+=n; + if (conn->out_pos==conn->out_size) + { + conn->out_pos=0; + conn->out_size=0; + triton_md_disable_handler(h,MD_MODE_WRITE); + } + h->twait=TIMEOUT; +} +static void pptp_timeout(struct triton_md_handler_t *h) +{ +} diff --git a/accel-pptpd/events.h b/accel-pptpd/events.h new file mode 100644 index 00000000..15704a7a --- /dev/null +++ b/accel-pptpd/events.h @@ -0,0 +1,18 @@ +// +// C++ Interface: events +// +// Description: +// +// +// Author: <xeb@mail.ru>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef EVENTS_H +#define EVENTS_H + +#define EV_PPP_PACKET 1 + +#endif diff --git a/accel-pptpd/if_pppox.h b/accel-pptpd/if_pppox.h new file mode 100644 index 00000000..da327a1c --- /dev/null +++ b/accel-pptpd/if_pppox.h @@ -0,0 +1,227 @@ +/*************************************************************************** + * Linux PPP over X - Generic PPP transport layer sockets + * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) + * + * This file supplies definitions required by the PPP over Ethernet driver + * (pppox.c). All version information wrt this file is located in pppox.c + * + * License: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#ifndef __LINUX_IF_PPPOX_H +#define __LINUX_IF_PPPOX_H + + +#include <asm/types.h> +#include <asm/byteorder.h> +#include <linux/version.h> + +#ifdef __KERNEL__ +#include <linux/in.h> +#include <linux/if_ether.h> +#include <linux/if.h> +#include <linux/netdevice.h> +#include <linux/ppp_channel.h> +#endif /* __KERNEL__ */ + +/* For user-space programs to pick up these definitions + * which they wouldn't get otherwise without defining __KERNEL__ + */ +#ifndef AF_PPPOX +#define AF_PPPOX 24 +#define PF_PPPOX AF_PPPOX +#endif /* !(AF_PPPOX) */ + +struct pptp_addr{ + __u16 call_id; + struct in_addr sin_addr; +}; +/************************************************************************ + * Protocols supported by AF_PPPOX + */ +#define PX_PROTO_OE 0 /* Currently just PPPoE */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,22) +#define PX_PROTO_PPTP 1 +#define PX_MAX_PROTO 2 +#else +#define PX_PROTO_PPTP 2 +#define PX_MAX_PROTO 3 +#endif + +struct sockaddr_pppox { + sa_family_t sa_family; /* address family, AF_PPPOX */ + unsigned int sa_protocol; /* protocol identifier */ + union{ + struct pptp_addr pptp; + }sa_addr; +}__attribute__ ((packed)); + + +/********************************************************************* + * + * ioctl interface for defining forwarding of connections + * + ********************************************************************/ + +#define PPPOEIOCSFWD _IOW(0xB1 ,0, size_t) +#define PPPOEIOCDFWD _IO(0xB1 ,1) +/*#define PPPOEIOCGFWD _IOWR(0xB1,2, size_t)*/ + +/* Codes to identify message types */ +#define PADI_CODE 0x09 +#define PADO_CODE 0x07 +#define PADR_CODE 0x19 +#define PADS_CODE 0x65 +#define PADT_CODE 0xa7 +struct pppoe_tag { + __u16 tag_type; + __u16 tag_len; + char tag_data[0]; +} __attribute ((packed)); + +/* Tag identifiers */ +#define PTT_EOL __constant_htons(0x0000) +#define PTT_SRV_NAME __constant_htons(0x0101) +#define PTT_AC_NAME __constant_htons(0x0102) +#define PTT_HOST_UNIQ __constant_htons(0x0103) +#define PTT_AC_COOKIE __constant_htons(0x0104) +#define PTT_VENDOR __constant_htons(0x0105) +#define PTT_RELAY_SID __constant_htons(0x0110) +#define PTT_SRV_ERR __constant_htons(0x0201) +#define PTT_SYS_ERR __constant_htons(0x0202) +#define PTT_GEN_ERR __constant_htons(0x0203) + +struct pppoe_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 ver : 4; + __u8 type : 4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 type : 4; + __u8 ver : 4; +#else +#error "Please fix <asm/byteorder.h>" +#endif + __u8 code; + __u16 sid; + __u16 length; + struct pppoe_tag tag[0]; +} __attribute__ ((packed)); + + +/* Socket options */ +#define PPTP_SO_TIMEOUT 1 + + +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,0) +struct pppoe_opt { + struct net_device *dev; /* device associated with socket*/ + struct pppoe_addr pa; /* what this socket is bound to*/ + struct sockaddr_pppox relay; /* what socket data will be + relayed to (PPPoE relaying) */ +}; +#endif +struct pptp_opt { + struct pptp_addr src_addr; + struct pptp_addr dst_addr; + int timeout; + __u32 ack_sent, ack_recv; + __u32 seq_sent, seq_recv; + int ppp_flags; + int flags; + struct sk_buff_head skb_buf; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + struct tq_struct buf_work; //check bufferd packets work + struct timer_list buf_timer; + #else + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + struct delayed_work buf_work; //check bufferd packets work + #else + struct work_struct buf_work; //check bufferd packets work + #endif + #endif + struct gre_statistics *stat; + spinlock_t xmit_lock; + spinlock_t rcv_lock; +}; +#define PPTP_FLAG_PAUSE 0 +#define PPTP_FLAG_PROC 1 + +#include <net/sock.h> + +struct pppox_sock { + /* struct sock must be the first member of pppox_sock */ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + struct ppp_channel chan; + struct sock *sk; + #else + struct sock sk; + struct ppp_channel chan; + #endif + struct pppox_sock *next; /* for hash table */ + union { + struct pppoe_opt pppoe; + struct pptp_opt pptp; + } proto; + unsigned short num; +}; +#define pppoe_dev proto.pppoe.dev +#define pppoe_pa proto.pppoe.pa +#define pppoe_relay proto.pppoe.relay + +static inline struct pppox_sock *pppox_sk(struct sock *sk) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + return (struct pppox_sock *)sk->protinfo.pppox; + #else + return (struct pppox_sock *)sk; + #endif +} + +static inline struct sock *sk_pppox(struct pppox_sock *po) +{ + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) + return po->sk; + #else + return (struct sock *)po; + #endif +} + +struct module; + +struct pppox_proto { + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + int (*create)(struct socket *sock); + #else + int (*create)(struct net *net, struct socket *sock); + #endif + int (*ioctl)(struct socket *sock, unsigned int cmd, + unsigned long arg); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) + struct module *owner; + #endif +}; + +extern int register_pppox_proto(int proto_num, struct pppox_proto *pp); +extern void unregister_pppox_proto(int proto_num); +extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */ +extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); + +/* PPPoX socket states */ +enum { + PPPOX_NONE = 0, /* initial state */ + PPPOX_CONNECTED = 1, /* connection established ==TCP_ESTABLISHED */ + PPPOX_BOUND = 2, /* bound to ppp device */ + PPPOX_RELAY = 4, /* forwarding is enabled */ + PPPOX_ZOMBIE = 8, /* dead, but still bound to ppp device */ + PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/ +}; + +#endif /* __KERNEL__ */ + +#endif /* !(__LINUX_IF_PPPOX_H) */ diff --git a/accel-pptpd/list.h b/accel-pptpd/list.h new file mode 100644 index 00000000..49045b7e --- /dev/null +++ b/accel-pptpd/list.h @@ -0,0 +1,252 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE) + +//#include <linux/prefetch.h> + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#ifndef NULL +#define NULL 0 +#endif + +void static inline prefetch(void* p){} + +typedef struct list_head { + struct list_head *next, *prev; +} list_t; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a _new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *_new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = _new; + _new->next = next; + _new->prev = prev; + prev->next = _new; +} + +/** + * list_add - add a _new entry + * @_new: _new entry to be added + * @head: list head to add it after + * + * Insert a _new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head, head->next); +} + +/** + * list_add_tail - add a _new entry + * @_new: _new entry to be added + * @head: list head to add it before + * + * Insert a _new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ + __list_add(_new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL;//(void *) 0; + entry->prev = NULL;//(void *) 0; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the _new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the _new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +//#endif /* __KERNEL__ || _LVM_H_INCLUDE */ + +#endif diff --git a/accel-pptpd/log.c b/accel-pptpd/log.c new file mode 100644 index 00000000..454e9975 --- /dev/null +++ b/accel-pptpd/log.c @@ -0,0 +1,111 @@ +/* +* C Implementation: log +* +* Description: +* +* +* Author: <xeb@mail.ru>, (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include <sys/time.h> + +#include "log.h" + +#define RED_COLOR "\033[1;31m" +#define GREEN_COLOR "\033[1;32m" +#define YELLOW_COLOR "\033[1;33m" +#define BLUE_COLOR "\033[1;34m" +#define NORMAL_COLOR "\033[0;39m" + +#define LOG_ERROR 0 +#define LOG_WARN 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 + +static FILE *log_file=NULL; +static int log_level=1; +static int log_color=1; +static const char* level_name[]={"error","warning","info","debug"}; +static const char* level_color[]={RED_COLOR,YELLOW_COLOR,GREEN_COLOR,BLUE_COLOR}; +static pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER; + +static int msg_completed=1; + +static void do_log(int level,const char *fmt,va_list ap) +{ + struct timeval tv; + + pthread_mutex_lock(&lock); + gettimeofday(&tv,NULL); + if (log_color) fprintf(log_file,"[%s%li.%03li] [%s]%s ",level_color[level],tv.tv_sec,tv.tv_usec/1000,NORMAL_COLOR,level_name[level]); + else fprintf(log_file,"[%li.%03li] [%s] ",tv.tv_sec,tv.tv_usec/1000,level_name[level]); + + vfprintf(log_file,fmt,ap); + + msg_completed=fmt[strlen(fmt)-1]=='\n'; + if (msg_completed) pthread_mutex_unlock(&lock); +} +void log_error(const char *fmt,...) +{ + if (log_level>=1) + { + va_list ap; + va_start(ap,fmt); + do_log(LOG_ERROR,fmt,ap); + } +} +void log_warn(const char *fmt,...) +{ + if (log_level>=2) + { + va_list ap; + va_start(ap,fmt); + do_log(LOG_WARN,fmt,ap); + } +} +void log_info(const char *fmt,...) +{ + if (log_level>=3) + { + va_list ap; + va_start(ap,fmt); + do_log(LOG_INFO,fmt,ap); + } +} +void log_debug(const char *fmt,...) +{ + if (log_level>=4) + { + va_list ap; + va_start(ap,fmt); + do_log(LOG_DEBUG,fmt,ap); + } +} + +void log_msg(const char *fmt,...) +{ + va_list ap; + if (msg_completed) return; + va_start(ap,fmt); + vfprintf(log_file,fmt,ap); + msg_completed=fmt[strlen(fmt)-1]=='\n'; + if (msg_completed) pthread_mutex_unlock(&lock); +} + +void log_init(FILE *f,int level,int color) +{ + log_file=f; + log_level=level; + log_color=color; +} diff --git a/accel-pptpd/log.h b/accel-pptpd/log.h new file mode 100644 index 00000000..25f9f976 --- /dev/null +++ b/accel-pptpd/log.h @@ -0,0 +1,25 @@ +// +// C++ Interface: log +// +// Description: +// +// +// Author: <xeb@mail.ru>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef LOG_H +#define LOG_H + +#include <stdio.h> + +void log_init(FILE *f,int level,int color); +void log_error(const char *fmt,...); +void log_warn(const char *fmt,...); +void log_info(const char *fmt,...); +void log_debug(const char *fmt,...); +void log_msg(const char *fmt,...); + +#endif diff --git a/accel-pptpd/ppp.c b/accel-pptpd/ppp.c new file mode 100644 index 00000000..c24987fa --- /dev/null +++ b/accel-pptpd/ppp.c @@ -0,0 +1,174 @@ + +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> + +#include "triton/triton.h" + +#include "ppp.h" +#include "ppp_fsm.h" +#include "log.h" +#include "events.h" + +static void ppp_read(struct triton_md_handler_t*); +static void ppp_write(struct triton_md_handler_t*); +static void ppp_timeout(struct triton_md_handler_t*); + +struct ppp_t *alloc_ppp(void) +{ + struct ppp_t *ppp=malloc(sizeof(*ppp)); + memset(ppp,0,sizeof(*ppp)); + ppp->out_buf=malloc(PPP_MTU+PPP_HDRLEN); + ppp->in_buf=malloc(PPP_MRU+PPP_HDRLEN); + ppp->mtu=PPP_MTU; + ppp->mru=PPP_MRU; + return ppp; +} + +int establish_ppp(struct ppp_t *ppp) +{ + /* Open an instance of /dev/ppp and connect the channel to it */ + if (ioctl(ppp->fd, PPPIOCGCHAN, &ppp->chan_idx)==-1) + { + log_error("Couldn't get channel number\n"); + return -1; + } + + ppp->chan_fd=open("/dev/ppp", O_RDWR); + if (ppp->chan_fd<0) + { + log_error("Couldn't reopen /dev/ppp\n"); + return -1; + } + + if (ioctl(ppp->chan_fd, PPPIOCATTCHAN, &ppp->chan_idx)<0) + { + log_error("Couldn't attach to channel %d\n", ppp->chan_idx); + goto exit_close_chan; + } + + ppp->unit_fd=open("/dev/ppp", O_RDWR); + if (ppp->unit_fd<0) + { + log_error("Couldn't reopen /dev/ppp\n"); + goto exit_close_chan; + } + + ppp->unit_idx=-1; + if (ioctl(ppp->unit_fd, PPPIOCNEWUNIT, &ppp->unit_idx)<0) + { + log_error("Couldn't create new ppp unit\n"); + goto exit_clodse_unit; + } + + if (ioctl(ppp->chan_fd, PPPIOCCONNECT, &ppp->unit_idx)<0) + { + log_error("Couldn't attach to PPP unit %d\n", ppp->unit_idx); + goto exit_clodse_unit; + } + + log_info("connect: ppp%i <--> pptp(%s)\n",ppp->unit_idx,ppp->chan_name); + + ppp->h=malloc(sizeof(*ppp->h)); + memset(ppp->h,0,sizeof(*ppp->h)); + ppp->h->pd=ppp; + ppp->h->fd=ppp->chan_fd; + ppp->h->read=ppp_read; + ppp->h->write=ppp_write; + ppp->h->timeout=ppp_timeout; + ppp->h->twait=-1; + triton_md_register_handler(ppp->h); + triton_md_enable_handler(ppp->h,MD_MODE_READ); + INIT_LIST_HEAD(&ppp->layers); + + ppp->lcp_layer=ppp_lcp_init(ppp); + ppp_fsm_open(ppp->lcp_layer); + ppp_fsm_lower_up(ppp->lcp_layer); + + return 0; + +exit_clodse_unit: + close(ppp->unit_fd); +exit_close_chan: + close(ppp->chan_fd); + return -1; +} + +int ppp_send(struct ppp_t *ppp, void *data, int size) +{ + int n; + + if (ppp->out_buf_size) return -1; + if (size>PPP_MTU+PPP_HDRLEN) return -1; + + n=write(ppp->unit_fd,data,size); + if (n>=0) + { + if (n!=ppp->out_buf_size-ppp->out_buf_pos) + { + ppp->out_buf_pos+=n; + triton_md_enable_handler(ppp->h,MD_MODE_WRITE); + } + } + return n; +} + +static void ppp_read(struct triton_md_handler_t*h) +{ + struct ppp_t *ppp=(struct ppp_t *)h->pd; + struct ppp_hdr_t *hdr=(struct ppp_hdr_t *)(ppp->in_buf+2); + u_int16_t proto; + + ppp->in_buf_size=read(h->fd,ppp->in_buf,PPP_MRU+PPP_HDRLEN); + //if (ppp->in_buf_size==0) + if (ppp->in_buf_size<PPP_HDRLEN+2 || ppp->in_buf_size<ntohs(hdr->len)+2) + { + log_warn("discarding short packet\n"); + return; + } + + proto=ntohs(*(u_int16_t*)ppp->in_buf); + if (proto==PPP_LCP) ppp->lcp_layer->recv(ppp->lcp_layer,hdr); + else if (ppp->lcp_layer->fsm_state!=FSM_Opened) + { + log_warn("discarding non-LCP packet when LCP is not opened\n"); + return; + }else + { + struct ppp_layer_t *l=NULL; + list_for_each_entry(l,&ppp->layers,entry) + { + if (l->proto==proto) l->recv(l,hdr); + } + + if (!l) + { + log_warn("discarding unknown packet %x\n",proto); + } + } +} +static void ppp_write(struct triton_md_handler_t*h) +{ + struct ppp_t *ppp=(struct ppp_t *)h->pd; + + int n=write(ppp->unit_fd,ppp->out_buf+ppp->out_buf_pos,ppp->out_buf_size-ppp->out_buf_pos); + if (n>=0) + { + ppp->out_buf_pos+=n; + if (ppp->out_buf_pos==ppp->out_buf_size) + { + triton_md_disable_handler(ppp->h,MD_MODE_WRITE); + ppp->out_buf_pos=0; + ppp->out_buf_size=0; + } + } +} +static void ppp_timeout(struct triton_md_handler_t*h) +{ + +} diff --git a/accel-pptpd/ppp.h b/accel-pptpd/ppp.h new file mode 100644 index 00000000..e640229f --- /dev/null +++ b/accel-pptpd/ppp.h @@ -0,0 +1,125 @@ +#ifndef PPP_H +#define PPP_H + +#include <sys/types.h> +#include "ppp_fsm.h" + +/* + * Packet header = Code, id, length. + */ +#define PPP_HEADERLEN 4 +#define PPP_MTU 1500 + +/* + * Timeouts. + */ +#define DEFTIMEOUT 3 /* Timeout time in seconds */ +#define DEFMAXTERMREQS 2 /* Maximum Terminate-Request transmissions */ +#define DEFMAXCONFREQS 10 /* Maximum Configure-Request transmissions */ +#define DEFMAXNAKLOOPS 5 /* Maximum number of nak loops */ + +/* + * Protocol field values. + */ +#define PPP_IP 0x21 /* Internet Protocol */ +#define PPP_AT 0x29 /* AppleTalk Protocol */ +#define PPP_IPX 0x2b /* IPX protocol */ +#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ +#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ +#define PPP_COMP 0xfd /* compressed packet */ +#define PPP_IPCP 0x8021 /* IP Control Protocol */ +#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ +#define PPP_IPXCP 0x802b /* IPX Control Protocol */ +#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ +#define PPP_CCP 0x80fd /* Compression Control Protocol */ +#define PPP_ECP 0x8053 /* Encryption Control Protocol */ +#define PPP_LCP 0xc021 /* Link Control Protocol */ +#define PPP_PAP 0xc023 /* Password Authentication Protocol */ +#define PPP_LQR 0xc025 /* Link Quality Report protocol */ +#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP 0xc029 /* Callback Control Protocol */ +#define PPP_EAP 0xc227 /* Extensible Authentication Protocol */ + + +struct ppp_t +{ + struct triton_md_handler_t *h; + int fd; + int chan_fd; + int unit_fd; + + int chan_idx; + int unit_idx; + + char *chan_name; + + int mtu,mru; + int require_mppe:1; + int require_pap:1; + int require_chap:1; + int require_mschap:1; + int require_mschap_v2:1; + + int allow_mppe:1; + int allow_pap:1; + int allow_chap:1; + int allow_mschap:1; + int allow_mschap_v2:1; + + int log:1; + + void *out_buf; + int out_buf_size; + int out_buf_pos; + + void *in_buf; + int in_buf_size; + + struct ppp_layer_t *lcp_layer; + struct list_head layers; +}; + +struct ppp_fsm_handler_t +{ + void (*reset_conf)(struct ppp_t *ppp); /* Reset our Configuration Information */ + int (*conf_length)(struct ppp_t *ppp); /* Length of our Configuration Information */ + void (*add_conf)(struct ppp_t *ppp, unsigned char *, int *); /* Add our Configuration Information */ + int (*ack_conf)(struct ppp_t *ppp, unsigned char *,int); /* ACK our Configuration Information */ + int (*nak_conf)(struct ppp_t *ppp, unsigned char *,int,int); /* NAK our Configuration Information */ + int (*rej_conf)(struct ppp_t *ppp, unsigned char *,int); /* Reject our Configuration Information */ + int (*req_conf)(struct ppp_t *ppp, unsigned char *,int *,int); /* Request peer's Configuration Information */ + void (*opened)(struct ppp_t *ppp); /* Called when fsm reaches OPENED state */ + void (*down)(struct ppp_t *ppp); /* Called when fsm leaves OPENED state */ + void (*starting)(struct ppp_t *ppp); /* Called when we want the lower layer */ + void (*finished)(struct ppp_t *ppp); /* Called when we don't want the lower layer */ + void (*protreject)(struct ppp_t *ppp,int); /* Called when Protocol-Reject received */ + void (*retransmit)(struct ppp_t *ppp); /* Retransmission is necessary */ + int (*extcode)(struct ppp_t *ppp, int, int, unsigned char *, int); /* Called when unknown code received */ + char *proto_name; /* String name for protocol (for messages) */ +}; + +struct ppp_hdr_t +{ + u_int8_t code; + u_int8_t id; + u_int16_t len; + u_int8_t data[100]; +}__attribute__((packed)); + +struct ppp_opt_t +{ + u_int8_t type; + u_int16_t len; + u_int8_t data[100]; +}__attribute__((packed)); + +struct ppp_t *alloc_ppp(void); +int establish_ppp(struct ppp_t *ppp); +int ppp_send(struct ppp_t *ppp, void *data, int size); + +void ppp_init(void); + +struct ppp_layer_t* ppp_lcp_init(struct ppp_t *ppp); + +#endif diff --git a/accel-pptpd/ppp_fsm.c b/accel-pptpd/ppp_fsm.c new file mode 100644 index 00000000..f966cd07 --- /dev/null +++ b/accel-pptpd/ppp_fsm.c @@ -0,0 +1,477 @@ +/* +* C Implementation: ppp_fsm +* +* Description: +* +* +* Author: <xeb@mail.ru>, (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include "triton/triton.h" +#include "ppp.h" +#include "ppp_fsm.h" + +void send_term_req(struct ppp_layer_t *layer); +void send_term_ack(struct ppp_layer_t *layer); +void send_echo_reply(struct ppp_layer_t *layer); + +static void init_req_counter(struct ppp_layer_t *layer,int timeout); +static void zero_req_counter(struct ppp_layer_t *layer); +static int restart_timer_func(struct triton_timer_t*t); + +void ppp_fsm_init(struct ppp_layer_t *layer) +{ + layer->fsm_state=FSM_Initial; + layer->restart_timer.active=0; + layer->restart_timer.pd=layer; + layer->restart_timer.expire=restart_timer_func; + layer->restart_timer.period=3000; + layer->restart_counter=0; + layer->max_terminate=2; + layer->max_configure=10; + layer->max_failure=5; + layer->seq=0; +} + +void ppp_fsm_lower_up(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Initial: + layer->fsm_state=FSM_Closed; + break; + case FSM_Starting: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_lower_down(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Closing: + layer->fsm_state=FSM_Initial; + break; + case FSM_Stopped: + if (layer->layer_started) layer->layer_started(layer); + layer->fsm_state=FSM_Starting; + break; + case FSM_Stopping: + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + layer->fsm_state=FSM_Starting; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + layer->fsm_state=FSM_Starting; + break; + default: + break; + } +} + +void ppp_fsm_open(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Initial: + if (layer->layer_started) layer->layer_started(layer); + layer->fsm_state=FSM_Starting; + break; + case FSM_Starting: + break; + case FSM_Closed: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Closing: + case FSM_Stopping: + layer->fsm_state=FSM_Stopping; + case FSM_Stopped: + case FSM_Opened: + if (layer->opt_restart) + { + ppp_fsm_lower_down(layer); + ppp_fsm_lower_up(layer); + } + break; + default: + break; + } +} + +void ppp_fsm_close(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Starting: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Initial; + break; + case FSM_Stopped: + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + layer->fsm_state=FSM_Closing; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_terminate); + send_term_req(layer); + layer->fsm_state=FSM_Closing; + break; + default: + break; + } +} + +void ppp_fsm_timeout0(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + case FSM_Stopping: + send_term_req(layer); + break; + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + case FSM_Req_Sent: + case FSM_Ack_Sent: + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + default: + break; + } +} + +void ppp_fsm_timeout1(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + case FSM_Ack_Rcvd: + case FSM_Req_Sent: + case FSM_Ack_Sent: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + layer->opt_passive=1; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_req_good(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + send_term_ack(layer); + break; + case FSM_Stopped: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + case FSM_Req_Sent: + case FSM_Ack_Sent: + if (layer->send_conf_ack) layer->send_conf_ack(layer); + layer->fsm_state=FSM_Ack_Sent; + break; + case FSM_Ack_Rcvd: + if (layer->send_conf_ack) layer->send_conf_ack(layer); + //tlu + if (layer->layer_up) layer->layer_up(layer); + layer->fsm_state=FSM_Opened; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + if (layer->send_conf_req) layer->send_conf_req(layer); + if (layer->send_conf_ack) layer->send_conf_ack(layer); + layer->fsm_state=FSM_Ack_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_req_bad(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + send_term_ack(layer); + break; + case FSM_Stopped: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + case FSM_Ack_Sent: + if (layer->send_conf_rej) layer->send_conf_rej(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + if (layer->send_conf_rej) layer->send_conf_rej(layer); + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + if (layer->send_conf_req) layer->send_conf_req(layer); + if (layer->send_conf_rej) layer->send_conf_rej(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_conf_ack(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Stopped: + send_term_ack(layer); + break; + case FSM_Req_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + layer->fsm_state=FSM_Ack_Rcvd; + break; + case FSM_Ack_Rcvd: + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + //tlu + if (layer->layer_up) layer->layer_up(layer); + layer->fsm_state=FSM_Opened; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + default: + break; + } +} + +void ppp_fsm_recv_conf_rej(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closed: + case FSM_Stopped: + send_term_ack(layer); + break; + case FSM_Req_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_failure); + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + case FSM_Ack_Rcvd: + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Ack_Sent: + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_term_req(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + send_term_req(layer); + //if (layer->zero_req_cnt) layer->zero_req_cnt(layer); + zero_req_counter(layer); + layer->fsm_state=FSM_Stopping; + break; + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + send_term_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + send_term_req(layer); + break; + } +} + +void ppp_fsm_recv_term_ack(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Closing: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + break; + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_unk(struct ppp_layer_t *layer) +{ + if (layer->send_conf_rej) layer->send_conf_rej(layer); +} + +void ppp_fsm_recv_code_rej_perm(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Ack_Rcvd: + layer->fsm_state=FSM_Req_Sent; + break; + default: + break; + } +} + +void ppp_fsm_recv_code_rej_bad(struct ppp_layer_t *layer) +{ + switch(layer->fsm_state) + { + case FSM_Opened: + if (layer->layer_down) layer->layer_down(layer); + //if (layer->init_req_cnt) layer->init_req_cnt(layer); + init_req_counter(layer,layer->max_configure); + if (layer->send_conf_req) layer->send_conf_req(layer); + layer->fsm_state=FSM_Stopping; + break; + case FSM_Closing: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Closed; + break; + case FSM_Stopping: + case FSM_Req_Sent: + case FSM_Ack_Rcvd: + case FSM_Ack_Sent: + if (layer->layer_finished) layer->layer_finished(layer); + layer->fsm_state=FSM_Stopped; + break; + default: + break; + } +} + +void ppp_fsm_recv_echo(struct ppp_layer_t *layer) +{ + if (layer->fsm_state==FSM_Opened) + send_echo_reply(layer); +} + +void send_term_req(struct ppp_layer_t *layer) +{ + struct ppp_hdr_t hdr={ + .code=TERMREQ, + .id=++layer->seq, + .len=4, + }; + + ppp_send(layer->ppp,&hdr,hdr.len); +} +void send_term_ack(struct ppp_layer_t *layer) +{ + struct ppp_hdr_t hdr={ + .code=TERMACK, + .id=layer->recv_id, + .len=4, + }; + + ppp_send(layer->ppp,&hdr,hdr.len); +} +void send_echo_reply(struct ppp_layer_t *layer) +{ + struct ppp_hdr_t hdr={ + .code=ECHOREP, + .id=layer->recv_id, + .len=8, + }; + + *(int*)hdr.data=layer->magic_num; + + ppp_send(layer->ppp,&hdr,hdr.len); +} + +void ppp_fsm_recv(struct ppp_layer_t *layer) +{ +} + +static void init_req_counter(struct ppp_layer_t *layer,int timeout) +{ + triton_timer_del(&layer->restart_timer); + triton_timer_add(&layer->restart_timer); + layer->restart_counter=timeout; +} +static void zero_req_counter(struct ppp_layer_t *layer) +{ + triton_timer_del(&layer->restart_timer); + triton_timer_add(&layer->restart_timer); + layer->restart_counter=0; +} + +static int restart_timer_func(struct triton_timer_t*t) +{ + struct ppp_layer_t *layer=(struct ppp_layer_t *)t->pd; + + if (layer->restart_counter) + { + ppp_fsm_timeout0(layer); + layer->restart_counter--; + return 1; + } + + ppp_fsm_timeout1(layer); + return 0; +} diff --git a/accel-pptpd/ppp_fsm.h b/accel-pptpd/ppp_fsm.h new file mode 100644 index 00000000..f07735d1 --- /dev/null +++ b/accel-pptpd/ppp_fsm.h @@ -0,0 +1,91 @@ +#ifndef PPP_FSM_H +#define PPP_FSM_H + +#include "list.h" + +typedef enum {FSM_Initial=0,FSM_Starting,FSM_Closed,FSM_Stopped,FSM_Closing,FSM_Stopping,FSM_Req_Sent,FSM_Ack_Rcvd,FSM_Ack_Sent,FSM_Opened} FSM_STATE; +/* + * CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ 1 /* Configuration Request */ +#define CONFACK 2 /* Configuration Ack */ +#define CONFNAK 3 /* Configuration Nak */ +#define CONFREJ 4 /* Configuration Reject */ +#define TERMREQ 5 /* Termination Request */ +#define TERMACK 6 /* Termination Ack */ +#define CODEREJ 7 /* Code Reject */ +#define ECHOREQ 9 /* Echo Request */ +#define ECHOREP 10 /* Echo Reply */ + +struct ppp_hdr_t; + +struct lcp_options_t +{ + int mru; + int auth; + int magic; + int accomp; + int pcomp; +}; + +struct ppp_layer_t +{ + struct list_head entry; + struct ppp_layer_t *lower; + struct ppp_layer_t *upper; + + int proto; + struct ppp_t *ppp; + FSM_STATE fsm_state; + + union + { + struct lcp_options_t lcp; + }options; + + struct triton_timer_t restart_timer; + int restart_counter; + int max_terminate; + int max_configure; + int max_failure; + + int seq; + int recv_id; + int magic_num; + + int opt_restart:1; + int opt_passive:1; + + //fsm handling + void (*layer_up)(struct ppp_layer_t*); + void (*layer_down)(struct ppp_layer_t*); + void (*layer_started)(struct ppp_layer_t*); + void (*layer_finished)(struct ppp_layer_t*); + void (*send_conf_req)(struct ppp_layer_t*); + void (*send_conf_ack)(struct ppp_layer_t*); + void (*send_conf_nak)(struct ppp_layer_t*); + void (*send_conf_rej)(struct ppp_layer_t*); + + void (*recv)(struct ppp_layer_t*,struct ppp_hdr_t*); +}; + +void ppp_fsm_init(struct ppp_layer_t*); +void ppp_fsm_recv(struct ppp_layer_t*); + +void ppp_fsm_lower_up(struct ppp_layer_t *layer); +void ppp_fsm_lower_down(struct ppp_layer_t *layer); +void ppp_fsm_open(struct ppp_layer_t *layer); +void ppp_fsm_close(struct ppp_layer_t *layer); +void ppp_fsm_timeout0(struct ppp_layer_t *layer); +void ppp_fsm_timeout1(struct ppp_layer_t *layer); +void ppp_fsm_recv_conf_req_good(struct ppp_layer_t *layer); +void ppp_fsm_recv_conf_req_bad(struct ppp_layer_t *layer); +void ppp_fsm_recv_conf_ack(struct ppp_layer_t *layer); +void ppp_fsm_recv_conf_rej(struct ppp_layer_t *layer); +void ppp_fsm_recv_term_req(struct ppp_layer_t *layer); +void ppp_fsm_recv_term_ack(struct ppp_layer_t *layer); +void ppp_fsm_recv_unk(struct ppp_layer_t *layer); +void ppp_fsm_recv_code_rej_bad(struct ppp_layer_t *layer); +void ppp_fsm_recv_echo(struct ppp_layer_t *layer); + +#endif diff --git a/accel-pptpd/ppp_lcp.c b/accel-pptpd/ppp_lcp.c new file mode 100644 index 00000000..8f9c88b9 --- /dev/null +++ b/accel-pptpd/ppp_lcp.c @@ -0,0 +1,229 @@ +#include <stdlib.h> +#include <string.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <arpa/inet.h> + +#include "triton/triton.h" + +#include "ppp.h" +#include "ppp_fsm.h" +#include "events.h" +#include "log.h" + +char* accomp="allow,disabled"; +char* pcomp="allow,disabled"; +char* auth="pap,mschap-v2"; +char* mppe="allow,disabled"; +char* pwdb="radius"; + +/* + * Options. + */ +#define CI_VENDOR 0 /* Vendor Specific */ +#define CI_MRU 1 /* Maximum Receive Unit */ +#define CI_ASYNCMAP 2 /* Async Control Character Map */ +#define CI_AUTHTYPE 3 /* Authentication Type */ +#define CI_QUALITY 4 /* Quality Protocol */ +#define CI_MAGICNUMBER 5 /* Magic Number */ +#define CI_PCOMPRESSION 7 /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */ +#define CI_FCSALTERN 9 /* FCS-Alternatives */ +#define CI_SDP 10 /* Self-Describing-Pad */ +#define CI_NUMBERED 11 /* Numbered-Mode */ +#define CI_CALLBACK 13 /* callback */ +#define CI_MRRU 17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF 18 /* short sequence numbers for multilink */ +#define CI_EPDISC 19 /* endpoint discriminator */ +#define CI_MPPLUS 22 /* Multi-Link-Plus-Procedure */ +#define CI_LDISC 23 /* Link-Discriminator */ +#define CI_LCPAUTH 24 /* LCP Authentication */ +#define CI_COBS 25 /* Consistent Overhead Byte Stuffing */ +#define CI_PREFELIS 26 /* Prefix Elision */ +#define CI_MPHDRFMT 27 /* MP Header Format */ +#define CI_I18N 28 /* Internationalization */ +#define CI_SDL 29 /* Simple Data Link */ + +/*static void layer_up(struct ppp_layer_t*); +static void layer_down(struct ppp_layer_t*); +static void layer_started(struct ppp_layer_t*); +static void layer_finished(struct ppp_layer_t*);*/ +static void send_conf_req(struct ppp_layer_t*); +static void send_conf_ack(struct ppp_layer_t*); +static void send_conf_nak(struct ppp_layer_t*); +static void send_conf_rej(struct ppp_layer_t*); +static void lcp_recv(struct ppp_layer_t*`); + +struct ppp_layer_t* ppp_lcp_init(struct ppp_t *ppp) +{ + struct ppp_layer_t *layer=malloc(sizeof(*layer)); + memset(layer,0,sizeof(*layer)); + + layer->proto=PPP_PROTO_LCP; + layer->ppp=ppp; + ppp_fsm_init(layer); + + layer->recv=lcp_recv; + layer->send_conf_req=send_conf_req; + layer->send_conf_ack=send_conf_ack; + layer->send_conf_nak=send_conf_nak; + layer->send_conf_rej=send_conf_rej; + + ppp_fsm_init(layer); + + return layer; +} + +/*void ev_ppp_packet(int proto,struct ppp_t *ppp) +{ + struct ppp_hdr_t *hdr; + + if (proto!=PPP_LCP) return; + if (ppp->in_buf_size-2<PPP_HEADERLEN) + { + log_debug("LCP: short packet received\n"); + return; + } + + hdr=(struct ppp_hdr_t *)(ppp->in_buf+2); + if (hdr->len<PPP_HEADERLEN) + { + log_debug("LCP: short packet received\n"); + return; + } + + //ppp_fsm_recv(); +}*/ + +/*static void layer_up(struct ppp_layer_t*) +{ +} +static void layer_down(struct ppp_layer_t*) +{ +} +static void layer_started(struct ppp_layer_t*) +{ +} +static void layer_finished(struct ppp_layer_t*) +{ +}*/ +static void send_conf_req(struct ppp_layer_t*l) +{ +} +static void send_conf_ack(struct ppp_layer_t*l) +{ +} +static void send_conf_nak(struct ppp_layer_t*l) +{ +} +static void send_conf_rej(struct ppp_layer_t*l) +{ +} + +static int lcp_recv_conf_req(struct ppp_layer_t*l,u_int8_t *data,int size) +{ + struct ppp_opt_t *opt; + while(size) + { + opt=(struct ppp_opt_t *)data; + switch(opt->type) + { + case CI_MRU: + l->options.lcp.mru=*(u_int16_t*)data; + break; + case CI_ASYNCMAP: + break; + case CI_AUTHTYPE: + if (l->ppp->log) log_msg("<auth "); + switch(*(u_int16_t*)data) + { + case PPP_PAP: + if (l->ppp->log) log_msg("pap"); + break; + case PPP_EAP: + if (l->ppp->log) log_msg("eap"); + break; + case PPP_CHAP: + if (l->ppp->log) log_msg("chap"); + break; + /*switch(data[4]) + { + case + }*/ + default: + if (l->ppp->log) log_msg("unknown"); + return -1; + } + if (l->ppp->log) log_msg(" auth>"); + case CI_MAGICNUMBER: + if (*(u_int32_t*)data==l->magic_num) + { + log_error("loop detected\n"); + return -1; + } + break; + case CI_PCOMPRESSION: + case CI_ACCOMPRESSION: + } + } + return 0; +} + +static void lcp_recv(struct ppp_layer_t*l) +{ + struct ppp_hdr_t *hdr; + + if (l->ppp->in_buf_size-2<PPP_HEADERLEN) + { + log_debug("LCP: short packet received\n"); + return; + } + + hdr=(struct ppp_hdr_t *)(l->ppp->in_buf+2); + if (hdr->len<PPP_HEADERLEN) + { + log_debug("LCP: short packet received\n"); + return; + } + + l->recv_id=hdr->id; + switch(hdr->code) + { + case CONFREQ: + if (lcp_recv_conf_req(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN)) + ppp_fsm_recv_conf_req_bad(l); + else + ppp_fsm_recv_conf_req_good(l); + break; + case CONFACK: + lcp_recv_conf_ack(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_ack(l); + break; + case CONFNAK: + lcp_recv_conf_nak(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_nak(l); + break; + case CONFREJ: + lcp_recv_conf_rej(l,hdr->data,ntohs(hdr->len)-PPP_HDRLEN); + ppp_fsm_recv_conf_rej(l); + break; + case TERMREQ: + ppp_fsm_recv_term_req(l); + break; + case TERMACK: + ppp_fsm_recv_term_ack(l); + break; + case CODEREJ: + ppp_fsm_recv_code_rej_bad(l); + break; + case ECHOREQ: + ppp_fsm_recv_echo_req(l); + break; + case ECHOREP: + lcp_recv_echo_rep(l); + break; + default: + ppp_fsm_recv_unk(l); + break; + } +} diff --git a/accel-pptpd/pptp_prot.h b/accel-pptpd/pptp_prot.h new file mode 100644 index 00000000..cee250b3 --- /dev/null +++ b/accel-pptpd/pptp_prot.h @@ -0,0 +1,297 @@ +#ifndef PPTP_PROT_H +#define PPTP_PROT_H + +#include <sys/types.h> + +#define hton8(x) (x) +#define ntoh8(x) (x) +#define hton16(x) htons(x) +#define ntoh16(x) ntohs(x) +#define hton32(x) htonl(x) +#define ntoh32(x) ntohl(x) + +/* PPTP magic numbers: ----------------------------------------- */ + +#define PPTP_MAGIC 0x1A2B3C4D /* Magic cookie for PPTP datagrams */ +#define PPTP_PORT 1723 /* PPTP TCP port number */ +#define PPTP_PROTO 47 /* PPTP IP protocol number */ + +/* PPTP result codes:---------------------------------------- */ +#define PPTP_CONN_RES_SUCCESS 1 +#define PPTP_CONN_RES_GE 2 +#define PPTP_CONN_RES_EXISTS 3 +#define PPTP_CONN_RES_AUTH 4 +#define PPTP_CONN_RES_PROTOCOL 5 + +#define PPTP_CONN_STOP_OK 1 +#define PPTP_CONN_STOP_GE 2 + +#define PPTP_CALL_RES_OK 1 +#define PPTP_CALL_RES_GE 2 + +#define PPTP_GE_NOCONN 1 + +/* Control Connection Message Types: --------------------------- */ + +#define PPTP_MESSAGE_CONTROL 1 +#define PPTP_MESSAGE_MANAGE 2 + +/* Control Message Types: -------------------------------------- */ + +/* (Control Connection Management) */ +#define PPTP_START_CTRL_CONN_RQST 1 +#define PPTP_START_CTRL_CONN_RPLY 2 +#define PPTP_STOP_CTRL_CONN_RQST 3 +#define PPTP_STOP_CTRL_CONN_RPLY 4 +#define PPTP_ECHO_RQST 5 +#define PPTP_ECHO_RPLY 6 + +/* (Call Management) */ +#define PPTP_OUT_CALL_RQST 7 +#define PPTP_OUT_CALL_RPLY 8 +#define PPTP_IN_CALL_RQST 9 +#define PPTP_IN_CALL_RPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_RQST 12 +#define PPTP_CALL_CLEAR_NTFY 13 + +/* (Error Reporting) */ +#define PPTP_WAN_ERR_NTFY 14 + +/* (PPP Session Control) */ +#define PPTP_SET_LINK_INFO 15 + +/* PPTP version information: --------------------------------------*/ +#define PPTP_VERSION_STRING "1.00" +#define PPTP_VERSION 0x100 +#define PPTP_FIRMWARE_STRING "0.01" +#define PPTP_FIRMWARE_VERSION 0x001 + +#define PPTP_HOSTNAME "local" +#define PPTP_VENDOR "cananian" + +/* PPTP capabilities: ---------------------------------------------*/ + +/* (Framing capabilities for msg sender) */ +#define PPTP_FRAME_ASYNC 1 +#define PPTP_FRAME_SYNC 2 +#define PPTP_FRAME_ANY 3 + +/* (Bearer capabilities for msg sender) */ +#define PPTP_BEARER_ANALOG 1 +#define PPTP_BEARER_DIGITAL 2 +#define PPTP_BEARER_ANY 3 + +#define PPTP_RESULT_GENERAL_ERROR 2 + +/* (Reasons to close a connection) */ +#define PPTP_STOP_NONE 1 /* no good reason */ +#define PPTP_STOP_PROTOCOL 2 /* can't support peer's protocol version */ +#define PPTP_STOP_LOCAL_SHUTDOWN 3 /* requester is being shut down */ + +/* PPTP datagram structures (all data in network byte order): ----------*/ + +struct pptp_header +{ + u_int16_t length; /* message length in octets, including header */ + u_int16_t pptp_type; /* PPTP message type. 1 for control message. */ + u_int32_t magic; /* this should be PPTP_MAGIC. */ + u_int16_t ctrl_type; /* Control message type (0-15) */ + u_int16_t reserved0; /* reserved. MUST BE ZERO. */ +}__attribute__((packed)); + +struct pptp_start_ctrl_conn /* for control message types 1 and 2 */ +{ + struct pptp_header header; + + u_int16_t version; /* PPTP protocol version. = PPTP_VERSION */ + u_int8_t result_code; /* these two fields should be zero on rqst msg*/ + u_int8_t error_code; /* 0 unless result_code==2 (General Error) */ + u_int32_t framing_cap; /* Framing capabilities */ + u_int32_t bearer_cap; /* Bearer Capabilities */ + u_int16_t max_channels; /* Maximum Channels (=0 for PNS, PAC ignores) */ + u_int16_t firmware_rev; /* Firmware or Software Revision */ + u_int8_t hostname[64]; /* Host Name (64 octets, zero terminated) */ + u_int8_t vendor[64]; /* Vendor string (64 octets, zero term.) */ +}__attribute__((packed)); + +struct pptp_stop_ctrl_conn /* for control message types 3 and 4 */ +{ + struct pptp_header header; + + u_int8_t reason_result; /* reason for rqst, result for rply */ + u_int8_t error_code; /* MUST be 0, unless rply result==2 (general err)*/ + u_int16_t reserved1; /* MUST be 0 */ +}__attribute__((packed)); + +struct pptp_echo_rqst /* for control message type 5 */ +{ + struct pptp_header header; + u_int32_t identifier; /* arbitrary value set by sender which is used */ + /* to match up reply and request */ +}__attribute__((packed)); + +struct pptp_echo_rply /* for control message type 6 */ +{ + struct pptp_header header; + u_int32_t identifier; /* should correspond to id of rqst */ + u_int8_t result_code; + u_int8_t error_code; /* =0, unless result_code==2 (general error) */ + u_int16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_out_call_rqst /* for control message type 7 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ + u_int16_t call_sernum; /* Call Serial Number (used for logging) */ + u_int32_t bps_min; /* Minimum BPS (lowest acceptable line speed) */ + u_int32_t bps_max; /* Maximum BPS (highest acceptable line speed) */ + u_int32_t bearer; /* Bearer type */ + u_int32_t framing; /* Framing type */ + u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + u_int16_t phone_len; /* Phone Number Length (num. of valid digits) */ + u_int16_t reserved1; /* MUST BE ZERO */ + u_int8_t phone_num[64]; /* Phone Number (64 octets, null term.) */ + u_int8_t subaddress[64]; /* Subaddress (64 octets, null term.) */ +}__attribute__((packed)); + +struct pptp_out_call_rply /* for control message type 8 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + u_int8_t result_code; /* Result Code (1 is no errors) */ + u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ + u_int16_t cause_code; /* Cause Code (addt'l failure information) */ + u_int32_t speed; /* Connect Speed (in BPS) */ + u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + u_int32_t channel; /* Physical Channel ID (for logging) */ +}__attribute__((packed)); + +struct pptp_in_call_rqst /* for control message type 9 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (unique id used to multiplex data) */ + u_int16_t call_sernum; /* Call Serial Number (used for logging) */ + u_int32_t bearer; /* Bearer type */ + u_int32_t channel; /* Physical Channel ID (for logging) */ + u_int16_t dialed_len; /* Dialed Number Length (# of valid digits) */ + u_int16_t dialing_len; /* Dialing Number Length (# of valid digits) */ + u_int8_t dialed_num[64]; /* Dialed Number (64 octets, zero term.) */ + u_int8_t dialing_num[64]; /* Dialing Number (64 octets, zero term.) */ + u_int8_t subaddress[64]; /* Subaddress (64 octets, zero term.) */ +}__attribute__((packed)); + +struct pptp_in_call_rply /* for control message type 10 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + u_int8_t result_code; /* Result Code (1 is no errors) */ + u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ + u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + u_int16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_in_call_connect /* for control message type 11 */ +{ + struct pptp_header header; + u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + u_int16_t reserved1; /* MUST BE ZERO */ + u_int32_t speed; /* Connect Speed (in BPS) */ + u_int16_t recv_size; /* Recv. Window Size (no. of buffered packets) */ + u_int16_t delay; /* Packet Processing Delay (in 1/10 sec) */ + u_int32_t framing; /* Framing type */ +}__attribute__((packed)); + +struct pptp_call_clear_rqst /* for control message type 12 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + u_int16_t reserved1; /* MUST BE ZERO */ +}__attribute__((packed)); + +struct pptp_call_clear_ntfy /* for control message type 13 */ +{ + struct pptp_header header; + u_int16_t call_id; /* Call ID (used to multiplex data over tunnel)*/ + u_int8_t result_code; /* Result Code */ + u_int8_t error_code; /* Error Code (=0 unless result_code==2) */ + u_int16_t cause_code; /* Cause Code (for ISDN, is Q.931 cause code) */ + u_int16_t reserved1; /* MUST BE ZERO */ + u_int8_t call_stats[128]; /* Call Statistics: 128 octets, ascii, 0-term */ +}__attribute__((packed)); + +struct pptp_wan_err_ntfy /* for control message type 14 */ +{ + struct pptp_header header; + u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst)*/ + u_int16_t reserved1; /* MUST BE ZERO */ + u_int32_t crc_errors; /* CRC errors */ + u_int32_t frame_errors; /* Framing errors */ + u_int32_t hard_errors; /* Hardware overruns */ + u_int32_t buff_errors; /* Buffer overruns */ + u_int32_t time_errors; /* Time-out errors */ + u_int32_t align_errors; /* Alignment errors */ +}__attribute__((packed)); + +struct pptp_set_link_info /* for control message type 15 */ +{ + struct pptp_header header; + u_int16_t call_id_peer; /* Peer's Call ID (call_id of pptp_out_call_rqst) */ + u_int16_t reserved1; /* MUST BE ZERO */ + u_int32_t send_accm; /* Send ACCM (for PPP packets; default 0xFFFFFFFF)*/ + u_int32_t recv_accm; /* Receive ACCM (for PPP pack.;default 0xFFFFFFFF)*/ +}__attribute__((packed)); + +/* helpful #defines: -------------------------------------------- */ +#define pptp_isvalid_ctrl(header, type, length) \ + (!( ( ntoh16(((struct pptp_header *)header)->length) < (length) ) || \ + ( ntoh16(((struct pptp_header *)header)->pptp_type) !=(type) ) || \ + ( ntoh32(((struct pptp_header *)header)->magic) !=PPTP_MAGIC) || \ + ( ntoh16(((struct pptp_header *)header)->ctrl_type) > PPTP_SET_LINK_INFO) || \ + ( ntoh16(((struct pptp_header *)header)->reserved0) !=0 ) )) + +#define PPTP_HEADER_CTRL(type) \ +{ hton16(PPTP_CTRL_SIZE(type)), \ + hton16(PPTP_MESSAGE_CONTROL), \ + hton32(PPTP_MAGIC), \ + hton16(type), 0 } + +#define PPTP_CTRL_SIZE(type) ( \ +(type==PPTP_START_CTRL_CONN_RQST)?sizeof(struct pptp_start_ctrl_conn): \ +(type==PPTP_START_CTRL_CONN_RPLY)?sizeof(struct pptp_start_ctrl_conn): \ +(type==PPTP_STOP_CTRL_CONN_RQST )?sizeof(struct pptp_stop_ctrl_conn): \ +(type==PPTP_STOP_CTRL_CONN_RPLY )?sizeof(struct pptp_stop_ctrl_conn): \ +(type==PPTP_ECHO_RQST )?sizeof(struct pptp_echo_rqst): \ +(type==PPTP_ECHO_RPLY )?sizeof(struct pptp_echo_rply): \ +(type==PPTP_OUT_CALL_RQST )?sizeof(struct pptp_out_call_rqst): \ +(type==PPTP_OUT_CALL_RPLY )?sizeof(struct pptp_out_call_rply): \ +(type==PPTP_IN_CALL_RQST )?sizeof(struct pptp_in_call_rqst): \ +(type==PPTP_IN_CALL_RPLY )?sizeof(struct pptp_in_call_rply): \ +(type==PPTP_IN_CALL_CONNECT )?sizeof(struct pptp_in_call_connect): \ +(type==PPTP_CALL_CLEAR_RQST )?sizeof(struct pptp_call_clear_rqst): \ +(type==PPTP_CALL_CLEAR_NTFY )?sizeof(struct pptp_call_clear_ntfy): \ +(type==PPTP_WAN_ERR_NTFY )?sizeof(struct pptp_wan_err_ntfy): \ +(type==PPTP_SET_LINK_INFO )?sizeof(struct pptp_set_link_info): \ +0) +#define max(a,b) (((a)>(b))?(a):(b)) +#define PPTP_CTRL_SIZE_MAX ( \ +max(sizeof(struct pptp_start_ctrl_conn), \ +max(sizeof(struct pptp_echo_rqst), \ +max(sizeof(struct pptp_echo_rply), \ +max(sizeof(struct pptp_out_call_rqst), \ +max(sizeof(struct pptp_out_call_rply), \ +max(sizeof(struct pptp_in_call_rqst), \ +max(sizeof(struct pptp_in_call_rply), \ +max(sizeof(struct pptp_in_call_connect), \ +max(sizeof(struct pptp_call_clear_rqst), \ +max(sizeof(struct pptp_call_clear_ntfy), \ +max(sizeof(struct pptp_wan_err_ntfy), \ +max(sizeof(struct pptp_set_link_info), 0))))))))))))) + +#endif diff --git a/accel-pptpd/pptpd.c b/accel-pptpd/pptpd.c new file mode 100644 index 00000000..e29e61fc --- /dev/null +++ b/accel-pptpd/pptpd.c @@ -0,0 +1,134 @@ +/* +* C Implementation: pptpd +* +* Description: +* +* +* Author: <xeb@mail.ru>, (C) 2009 +* +* Copyright: See COPYING file that comes with this distribution +* +*/ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <pthread.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> + +#include <sys/poll.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <netinet/in.h> + +#include "list.h" +#include "pptp_prot.h" +#include "triton/triton.h" +#include "pptpd.h" +#include "log.h" + +static struct ctrl_thread_t *threads=NULL; +static int threads_count=0; + +int start_server(void) +{ + int sock,c_sock; + int r,min_thr,min_cnt; + struct pollfd pfd; + struct sockaddr_in addr; + socklen_t size; + + sock=socket (PF_INET, SOCK_STREAM, 0); + if (sock<0) + { + log_error("failed to create socket\n"); + return -1; + } + addr.sin_family = AF_INET; + addr.sin_port = htons (PPTP_PORT); + addr.sin_addr.s_addr = htonl (INADDR_ANY); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &sock, sizeof(sock)); + if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) < 0) + { + perror("bind"); + log_error("failed to bind socket\n"); + return -1; + } + + if (listen (sock, 1000)<0) + { + log_error("failed to listen socket\n"); + return -1; + } + + pfd.fd=sock; + pfd.events=POLLIN; + + while(1) + { + r=poll(&pfd,1,-1); + if (r<0 && errno!=EINTR) + { + log_error("poll failed\n"); + return -2; + } + if (r<=0) continue; + if (!(pfd.revents&POLLIN)) continue; + + size=sizeof(addr); + c_sock=accept(sock,(struct sockaddr *)&addr,&size); + if (c_sock<0) + { + log_error("client accept failed\n"); + continue; + } + + min_thr=0; min_cnt=65536; + for(r=0; r<threads_count; r++) + { + pthread_mutex_lock(&threads[r].lock); + if (threads[r].count<min_cnt) + { + min_cnt=threads[r].count; + min_thr=r; + } + pthread_mutex_unlock(&threads[r].lock); + } + write(threads[min_thr].pipe_fd[1],&c_sock,sizeof(c_sock)); + } +} + +int start_threads(int cnt) +{ + int i; + if (!cnt) cnt=sysconf(_SC_NPROCESSORS_CONF); + threads=malloc(cnt*sizeof(*threads)); + memset(threads,0,cnt*sizeof(*threads)); + + for(i=0; i<cnt; i++) + { + //threads[i].lock=PTHREAD_MUTEX_INITIALIZER; + if (pipe(threads[i].pipe_fd)) + { + log_error("failed to create pipe\n"); + return -1; + } + if (triton_run((int(*)(void*))ctrl_init,&threads[i])) + { + log_error("triton_run failed\n"); + return -1; + } + } + threads_count=cnt; + return 0; +} + +int main(int argc,char **argv) +{ + log_init(stdout,4,0); + start_threads(0); + start_server(); + return EXIT_SUCCESS; +} diff --git a/accel-pptpd/pptpd.h b/accel-pptpd/pptpd.h new file mode 100644 index 00000000..d98978e5 --- /dev/null +++ b/accel-pptpd/pptpd.h @@ -0,0 +1,26 @@ +// +// C++ Interface: pptpd +// +// Description: +// +// +// Author: <xeb@mail.ru>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// + +#ifndef PPTPD_H +#define PPTPD_H + +struct ctrl_thread_t +{ + pthread_t thr; + pthread_mutex_t lock; + int count; + int pipe_fd[2]; +}; + +int ctrl_init(struct ctrl_thread_t*); + +#endif diff --git a/accel-pptpd/triton/CMakeLists.txt b/accel-pptpd/triton/CMakeLists.txt new file mode 100644 index 00000000..868c3eb1 --- /dev/null +++ b/accel-pptpd/triton/CMakeLists.txt @@ -0,0 +1,13 @@ +SET(target triton) +SET(sources_c + md.c + conf_file.c + coroutine.c + event.c + timer.c + options.c + loader.c +) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +ADD_LIBRARY(${target} STATIC ${sources_c}) diff --git a/accel-pptpd/triton/conf_file.c b/accel-pptpd/triton/conf_file.c new file mode 100644 index 00000000..3ddb649e --- /dev/null +++ b/accel-pptpd/triton/conf_file.c @@ -0,0 +1,185 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> + +#include "conf_file.h" +#include "triton_p.h" + +struct sect_t +{ + struct list_head entry; + + struct conf_file_sect_t *sect; +}; + +static LIST_HEAD(sections); + +static char* skip_space(char *str); +static char* skip_word(char *str); + +static struct conf_file_sect_t *find_sect(const char *name); +static struct conf_file_sect_t *create_sect(const char *name); +static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val); +static struct option_t *find_item(struct conf_file_sect_t *,const char *name); + +void conf_file_load(const char *fname) +{ + char *buf,*str,*str2; + char *path0,*path; + int cur_line=0; + static struct conf_file_sect_t *cur_sect=NULL; + FILE *f=fopen(fname,"r"); + if (!f) + { + perror("triton: open conf file"); + return; + } + + buf=(char*)malloc(1024); + path0=(char*)malloc(4096); + path=(char*)malloc(4096); + + getcwd(path0,1024); + + while(!feof(f)) + { + buf=fgets(buf,1024,f); + if (!buf) break; + ++cur_line; + if (buf[strlen(buf)-1]=='\n') + buf[strlen(buf)-1]=0; + + str=skip_space(buf); + if (*str=='#' || *str==0) continue; + if (strncmp(str,"$include",8)==0) + { + str=skip_word(str); + str=skip_space(str); + /*if (*str=='.') + { + strcpy(path,path0); + strcat(path,str+1); + str=path; + }*/ + conf_file_load(str); + continue; + } + if (*str=='[') + { + for (str2=++str; *str2 && *str2!=']'; str2++); + if (*str2!=']') + { +//L1: + printf("triton: sintax error in conf file %s line %i\n",fname,cur_line); + return; + } + *str2=0; + cur_sect=find_sect(str); + if (!cur_sect) cur_sect=create_sect(str); + continue; + } + if (!cur_sect) + { + printf("triton: no section opened in conf file %s line %i\n",fname,cur_line); + return; + } + str2=skip_word(str); + if (*str2==' ') + { + *str2=0; + ++str2; + } + str2=skip_space(str2); + if (*str2=='=' || *str2==',') + { + *str2=0; + str2=skip_space(str2+1); + if (*str2 && *(str2+1) && *str2=='$' && *(str2+1)=='{') + { + char *s; + struct option_t *opt; + for (s=str2+2; *s && *s!='}'; s++); + if (*s=='}') + { + *s=0; + str2+=2; + } + opt=find_item(cur_sect,str2); + if (!opt) + { + printf("triton: parent option not found int conf file %s line %i\n",fname,cur_line); + return; + } + str2=opt->val; + } + }else str2=NULL; + sect_add_item(cur_sect,str,str2); + } + + free(buf); + free(path); + free(path0); + fclose(f); +} + +static char* skip_space(char *str) +{ + for (; *str && *str==' '; str++); + return str; +} +static char* skip_word(char *str) +{ + for (; *str && (*str!=' ' && *str!='='); str++); + return str; +} + +static struct conf_file_sect_t *find_sect(const char *name) +{ + struct sect_t *s; + list_for_each_entry(s,§ions,entry) + { + if (strcmp(s->sect->name,name)==0) return s->sect; + } + return NULL; +} + +static struct conf_file_sect_t *create_sect(const char *name) +{ + struct sect_t *s=(struct sect_t *)malloc(sizeof(struct sect_t)); + + s->sect=(struct conf_file_sect_t*)malloc(sizeof(struct conf_file_sect_t)); + s->sect->name=(char*)strdup(name); + INIT_LIST_HEAD(&s->sect->items); + + list_add_tail(&s->entry,§ions); + + return s->sect; +} + +static void sect_add_item(struct conf_file_sect_t *sect,const char *name,const char *val) +{ + struct option_t *opt=(struct option_t *)malloc(sizeof(struct option_t)); + + opt->name=(char*)strdup(name); + opt->val=val?(char*)strdup(val):NULL; + + list_add_tail(&opt->entry,§->items); +} + +static struct option_t *find_item(struct conf_file_sect_t *sect,const char *name) +{ + struct option_t *opt; + list_for_each_entry(opt,§->items,entry) + { + if (strcmp(opt->name,name)==0) + return opt; + } + + return NULL; +} + +struct conf_file_sect_t *conf_file_get_section(const char *name) +{ + return find_sect(name); +} diff --git a/accel-pptpd/triton/conf_file.h b/accel-pptpd/triton/conf_file.h new file mode 100644 index 00000000..47ade313 --- /dev/null +++ b/accel-pptpd/triton/conf_file.h @@ -0,0 +1,16 @@ +#ifndef CONF_FILE_H +#define CONF_FILE_H + +#include "list.h" + +struct conf_file_sect_t +{ + const char *name; + + struct list_head items; +}; + +void conf_file_load(const char *fname); +struct conf_file_sect_t *conf_file_get_section(const char *name); + +#endif diff --git a/accel-pptpd/triton/coroutine.c b/accel-pptpd/triton/coroutine.c new file mode 100644 index 00000000..b2866d0f --- /dev/null +++ b/accel-pptpd/triton/coroutine.c @@ -0,0 +1,153 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <signal.h> +#include <string.h> + +#include "triton_p.h" + +#ifdef USE_CORO + +static LIST_HEAD(coroutines); +asm(".hidden current_coro"); +struct coroutine_t *current_coro=NULL; +//asm(".hidden sched_uc"); +static ucontext_t sched_uc; + +asm(".hidden schedule"); +void schedule(void) +{ + struct coroutine_t *coro; + struct list_head *p; + while(1) + { + current_coro=NULL; + for(p=coroutines.next; p!=&coroutines; p=p->next) + { + coro=list_entry(p,typeof(*current_coro),entry); + if (coro->time.tv_sec) + { + if (!current_coro) current_coro=coro; + else if (coro->time.tv_sec<current_coro->time.tv_sec) continue; + else if (coro->time.tv_sec>current_coro->time.tv_sec || coro->time.tv_usec>current_coro->time.tv_usec) current_coro=coro; + } + } + if (current_coro) + { + get_time(¤t_coro->time); + swapcontext(&sched_uc,¤t_coro->uc); + //break; + }else + { + printf("triton: coroutine: bug: no current coro !!!\n"); + exit(-1); + } + } +} + +void coroutine_init(void) +{ + getcontext(&sched_uc); + sched_uc.uc_stack.ss_sp=malloc(DEF_COROUTINE_STACK); + sched_uc.uc_stack.ss_size=DEF_COROUTINE_STACK; + makecontext(&sched_uc,schedule,0); +} + +void triton_coroutine_schedule() +{ + memset(¤t_coro->time,0,sizeof(current_coro->time)); + memset(¤t_coro->timeout,0,sizeof(current_coro->timeout)); + swapcontext(¤t_coro->uc,&sched_uc); +} + +long int triton_coroutine_create(int stack_size,triton_coroutine_func func,void *arg,int run) +{ + struct coroutine_t *coro=malloc(sizeof(*coro)); + memset(coro,0,sizeof(*coro)); + + if (!stack_size) stack_size=DEF_COROUTINE_STACK;//+SIGSTKSZ; + + getcontext(&coro->uc); + coro->uc.uc_link=&sched_uc; + coro->uc.uc_stack.ss_sp=malloc(stack_size); + coro->uc.uc_stack.ss_size=stack_size; + makecontext(&coro->uc,(void (*)(void))func,1,arg); + + if (run) coro->time.tv_sec=1; + + list_add(&coro->entry,&coroutines); + + return (long int)coro; +} +void triton_coroutine_delete(long int id) +{ + struct coroutine_t *coro=(struct coroutine_t *)id; + + list_del(&coro->entry); + free(coro->uc.uc_stack.ss_sp); +} +int triton_coroutine_schedule_timeout(int msec) +{ + //current_coro->msleep=msec; + struct timeval tv; + int t; + get_time(¤t_coro->timeout); + current_coro->timeout.tv_sec+=msec/1000; + current_coro->timeout.tv_usec+=(msec%1000)*1000; + if (current_coro->timeout.tv_usec>=1000000) + { + current_coro->timeout.tv_sec++; + current_coro->timeout.tv_usec-=1000000; + } + //triton_coroutine_schedule(); + memset(¤t_coro->time,0,sizeof(current_coro->time)); + //memset(¤t_coro->timeout,0,sizeof(current_coro->timeout)); + swapcontext(¤t_coro->uc,&sched_uc); + get_time(&tv); + t=(current_coro->timeout.tv_sec-tv.tv_sec)*1000+(current_coro->timeout.tv_usec-tv.tv_usec)/1000; + if (t<0) t=0; + return t; +} +void triton_coroutine_wakeup(long int id) +{ + struct coroutine_t *coro=(struct coroutine_t *)id; + struct coroutine_t *cur_coro=current_coro; + get_time(¤t_coro->time); + current_coro=coro; + swapcontext(&cur_coro->uc,&coro->uc); +} + +asm(".hidden coroutine_get_timeout"); +int coroutine_get_timeout(struct timeval *tv) +{ + struct coroutine_t *coro; + struct list_head *p; + int twait,t=-1; + for(p=coroutines.next; p!=&coroutines; p=p->next) + { + coro=list_entry(p,typeof(*coro),entry); + if (coro->timeout.tv_sec) + { + twait=(coro->timeout.tv_sec-tv->tv_sec)*1000+(coro->timeout.tv_usec-tv->tv_usec)/1000; + if (t==-1 || twait<t) t=twait; + } + } + return t; +} +asm(".hidden coroutine_check_timeout"); +void coroutine_check_timeout(struct timeval *tv) +{ + struct coroutine_t *coro; + struct list_head *p; + for(p=coroutines.next; p!=&coroutines;) + { + coro=list_entry(p,typeof(*coro),entry); + p=p->next; + if (coro->timeout.tv_sec && (tv->tv_sec>coro->timeout.tv_sec || (tv->tv_sec==coro->timeout.tv_sec && tv->tv_usec>=coro->timeout.tv_usec))) + { + triton_coroutine_wakeup((long int)coro); + } + } +} + +#endif diff --git a/accel-pptpd/triton/event.c b/accel-pptpd/triton/event.c new file mode 100644 index 00000000..9daa226b --- /dev/null +++ b/accel-pptpd/triton/event.c @@ -0,0 +1,155 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> + +#include "triton_p.h" + +#define EVENTS1_SIZE 1024 + +static __thread struct list_head events2; +static __thread struct event_t *events1; +static __thread long *args; + +asm(".hidden event_init"); + +static struct event_t *find_event(int ev_id); +static struct event_t *create_event(int ev_id); + +void event_init(void) +{ + int i; + args=malloc(MAX_ARGS*sizeof(long)); + events1=(struct event_t *)malloc(EVENTS1_SIZE*sizeof(struct event_t)); + + for (i=0; i<EVENTS1_SIZE; i++) + { + events1[i].ev_id=i; + INIT_LIST_HEAD(&events1[i].handlers); + } + + INIT_LIST_HEAD(&events2); +} + +void triton_event_register_handler(int ev_id,triton_event_func func,int arg_cnt,...) +{ + struct event_t *ev; + struct event_handler_t *ev_h; + + ev=find_event(ev_id); + if (!ev) + ev=create_event(ev_id); + + ev_h=(struct event_handler_t*)malloc(sizeof(struct event_handler_t)); + memset(ev_h,0,sizeof(*ev_h)); + ev_h->event_func=func; + if (arg_cnt) + { + va_list p; + va_start(p,arg_cnt); + ev_h->arg_cnt=arg_cnt; + ev_h->args=malloc(arg_cnt*sizeof(long)); + #ifdef BROKEN_GCC + for(i=0; i<arg_cnt; i++) + *((int*)ev_h->args+i)=va_arg(p,long); + #else + memcpy(ev_h->args,p,arg_cnt*sizeof(long)); + #endif + va_end(p); + } + + list_add_tail(&ev_h->entry,&ev->handlers); +} +void triton_event_unregister_handler(int ev_id,triton_event_func func) +{ + struct event_t *ev; + struct event_handler_t *ev_h; + + ev=find_event(ev_id); + if (!ev) + return; + + list_for_each_entry(ev_h,&ev->handlers,entry) + { + if (ev_h->event_func==func) + { + list_del(&ev_h->entry); + if (ev_h->args) free(ev_h->args); + free(ev_h); + + if (list_empty(&ev->handlers) && ev_id>=EVENTS1_SIZE) + { + list_del(&ev->entry); + free(ev); + } + return; + } + } +} + +/*#define dyn_call(func,arg_cnt,args)\ + asm("movl %%esp,%%edi;\n\ + movl %0,%%esi;\n\ + movl %1,%%ecx;\n\ + cld;\n\ + rep movsl;\n\ + call *%2;\n"::"m" (args),"m" (arg_cnt),"m" (func):"%edi","%esi","%ecx");*/ + +void triton_event_fire(int ev_id,int arg_cnt,...) +{ + struct event_t *ev; + struct event_handler_t *ev_h; + struct list_head *p1,*p2; + va_list p; + //void *args_p=&args; + //char pp[ARG_OFFSET+MAX_ARGS*sizeof(int)]; + //memcpy(pp,__builtin_apply_args(),ARG_OFFSET); + + ev=find_event(ev_id); + if (!ev) + return; + + list_for_each_safe(p1,p2,&ev->handlers) + { + ev_h=list_entry(p1,struct event_handler_t,entry); + if (ev_h->arg_cnt) memcpy(args,ev_h->args,ev_h->arg_cnt*sizeof(long)); + va_start(p,arg_cnt); + #ifdef BROKEN_GCC + for(i=0; i<arg_cnt; i++) + args[ev_h->arg_cnt+i]=va_arg(p,long); + #else + memcpy(args+ev_h->arg_cnt,p,arg_cnt*sizeof(long)); + #endif + //memcpy(pp+ARG_OFFSET,args,(ev_h->arg_cnt+arg_cnt)*sizeof(int)); + //__builtin_apply(ev_h->event_func,pp,ARG_OFFSET+(ev_h->arg_cnt+arg_cnt)*sizeof(int)); + //ev_h->event_func(ev_id,arg); + //__builtin_apply(ev_h->event_func,args_p,(ev_h->arg_cnt+arg_cnt)*sizeof(int)); + dyn_call(ev_h->event_func,ev_h->arg_cnt+arg_cnt,args); + } + + va_end(p); +} + +static struct event_t *find_event(int ev_id) +{ + struct event_t *ev; + if (ev_id<EVENTS1_SIZE) + return events1+ev_id; + + list_for_each_entry(ev,&events2,entry) + { + if (ev->ev_id==ev_id) + return ev; + } + return NULL; +} +static struct event_t *create_event(int ev_id) +{ + struct event_t *ev=(struct event_t *)malloc(sizeof(struct event_t)); + + INIT_LIST_HEAD(&ev->handlers); + + list_add_tail(&ev->entry,&events2); + + return ev; +} diff --git a/accel-pptpd/triton/list.h b/accel-pptpd/triton/list.h new file mode 100644 index 00000000..d95dd714 --- /dev/null +++ b/accel-pptpd/triton/list.h @@ -0,0 +1,249 @@ +#ifndef _LINUX_LIST_H +#define _LINUX_LIST_H + +//#if defined(__KERNEL__) || defined(_LVM_H_INCLUDE) + +//#include <linux/prefetch.h> + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +typedef struct list_head { + struct list_head *next, *prev; +} list_t; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +#define INIT_LIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ + +static void inline prefetch(void *p){} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty on entry does not return true after this, the entry is in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = (void *) 0; + entry->prev = (void *) 0; +} + +/** + * list_del_init - deletes entry from list and reinitialize it. + * @entry: the element to delete from the list. + */ +static inline void list_del_init(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + INIT_LIST_HEAD(entry); +} + +/** + * list_move - delete from one list and add as another's head + * @list: the entry to move + * @head: the head that will precede our entry + */ +static inline void list_move(struct list_head *list, struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add(list, head); +} + +/** + * list_move_tail - delete from one list and add as another's tail + * @list: the entry to move + * @head: the head that will follow our entry + */ +static inline void list_move_tail(struct list_head *list, + struct list_head *head) +{ + __list_del(list->prev, list->next); + list_add_tail(list, head); +} + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(struct list_head *head) +{ + return head->next == head; +} + +static inline void __list_splice(struct list_head *list, + struct list_head *head) +{ + struct list_head *first = list->next; + struct list_head *last = list->prev; + struct list_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; +} + +/** + * list_splice - join two lists + * @list: the new list to add. + * @head: the place to add it in the first list. + */ +static inline void list_splice(struct list_head *list, struct list_head *head) +{ + if (!list_empty(list)) + __list_splice(list, head); +} + +/** + * list_splice_init - join two lists and reinitialise the emptied list. + * @list: the new list to add. + * @head: the place to add it in the first list. + * + * The list at @list is reinitialised + */ +static inline void list_splice_init(struct list_head *list, + struct list_head *head) +{ + if (!list_empty(list)) { + __list_splice(list, head); + INIT_LIST_HEAD(list); + } +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next, prefetch(pos->next); pos != (head); \ + pos = pos->next, prefetch(pos->next)) + +/** + * __list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + * + * This variant differs from list_for_each() in that it's the + * simplest possible list iteration code, no prefetching is done. + * Use this for code that knows the list to be very short (empty + * or 1 entry) most of the time. + */ +#define __list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_prev - iterate over a list backwards + * @pos: the &struct list_head to use as a loop counter. + * @head: the head for your list. + */ +#define list_for_each_prev(pos, head) \ + for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \ + pos = pos->prev, prefetch(pos->prev)) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +/** + * list_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + prefetch(pos->member.next); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member), \ + prefetch(pos->member.next)) + +//#endif /* __KERNEL__ || _LVM_H_INCLUDE */ + +#endif diff --git a/accel-pptpd/triton/loader.c b/accel-pptpd/triton/loader.c new file mode 100644 index 00000000..33d48315 --- /dev/null +++ b/accel-pptpd/triton/loader.c @@ -0,0 +1,55 @@ +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdio.h> +#include <pthread.h> + +#include "conf_file.h" +#include "triton_p.h" + +void md_init(void); +void event_init(void); +void timer_init(void); + +struct thread_arg_t +{ + int (*post_init)(void*); + void *arg; +}; + +void *thread(struct thread_arg_t *arg) +{ + printf("triton: starting new thread\n"); + #ifdef USE_CORO + coroutine_init(); + #endif + md_init(); + event_init(); + timer_init(); + + arg->post_init(arg->arg); + + free(arg); + + //conf_file_load(cf_name); + #ifdef USE_CORO + schedule(); + #else + md_run(); + #endif + + return NULL; +} + +int triton_init(const char *conf_file) +{ + return 0; +} +int triton_run(int (*post_init)(void*),void *arg) +{ + pthread_t thr; + struct thread_arg_t *thr_arg=malloc(sizeof(*thr_arg)); + thr_arg->post_init=post_init; + thr_arg->arg=arg; + return pthread_create(&thr,NULL,(void*(*)(void*))thread,thr_arg); +} diff --git a/accel-pptpd/triton/md.c b/accel-pptpd/triton/md.c new file mode 100644 index 00000000..a0d2fabb --- /dev/null +++ b/accel-pptpd/triton/md.c @@ -0,0 +1,342 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <signal.h> +#include <string.h> + +#include "triton_p.h" + +#define USE_GET_TIME + +static __thread struct list_head handlers; +static __thread fd_set read_fds; +static __thread fd_set write_fds; +static __thread fd_set read_fds0; +static __thread fd_set write_fds0; +static __thread int md_term; + +asm(".hidden md_init"); +asm(".hidden md_run"); +asm(".hidden md_terminate"); + +static void _triton_process_events(int wait); + +void md_init() +{ + INIT_LIST_HEAD(&handlers); + + FD_ZERO(&read_fds); + FD_ZERO(&write_fds); + + signal(SIGPIPE,SIG_IGN); + + #ifdef USE_CORO + triton_coroutine_create(0,md_run,0,1); + #endif +} +void md_run() +{ + md_term=0; + + while(!md_term) + { + _triton_process_events(1); + } +} + + +#ifdef USE_CORO +asm(".hidden cur_uc"); +ucontext_t cur_uc; +#endif + +static void _triton_process_events(int wait) +{ + int max_fd=0,t; + struct md_handler_t *md_h; + struct timeval tv1,tv2,twait0; + struct list_head *p1,*p2; + int twait,n; + int _break=0; + + gettimeofday(&tv1,NULL); + _break=0; + + if (wait) + { + twait=timer_prepare(&tv1); + #ifdef USE_CORO + t=coroutine_get_timeout(&tv1); + #else + t=-1; + #endif + if (t>=0 && (twait==-1 || t<twait)) twait=t; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->in_handler) continue; + if (md_h->handler->twait>=0 && (twait==-1 || md_h->handler->twait<twait)) twait=md_h->handler->twait; + } + }else + { + twait=0; + } + + read_fds0=read_fds; write_fds0=write_fds; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->in_handler) + { + FD_CLR(md_h->fd,&read_fds0); + FD_CLR(md_h->fd,&write_fds0); + }else + { + if (md_h->fd>max_fd) max_fd=md_h->fd; + } + } + + twait0=(struct timeval){twait/1000,(twait%1000)*1000}; + n=select(max_fd+1,&read_fds0,&write_fds0,NULL,twait>=0?&twait0:NULL); + + gettimeofday(&tv2,NULL); + twait=(tv2.tv_sec-tv1.tv_sec)*1000+(tv2.tv_usec-tv1.tv_usec)/1000; + + list_for_each_safe(p1,p2,&handlers) + { + md_h=list_entry(p1,struct md_handler_t,entry); + //if (!md_h->del) + { + if (md_h->handler->twait>=0) + { + md_h->handler->twait-=twait; + if (md_h->handler->twait<=0) md_h->timeout=1; + } + } + } + + timer_check(&tv2); + gettimeofday(&tv2,NULL); + #ifdef USE_CORO + coroutine_check_timeout(&tv2); + #endif + + list_for_each_safe(p1,p2,&handlers) + { + md_h=list_entry(p1,struct md_handler_t,entry); + if (md_h->in_handler) continue; + if (!md_h->del) + { + if (md_h->timeout) + { + md_h->timeout=0; + #ifdef USE_CORO + md_h->in_handler=1; + if (md_h->coro) + { + long int id=(long int)md_h->coro; + md_h->coro=NULL; + triton_coroutine_wakeup(id); + }else + #endif + { + md_h->handler->timeout(md_h->handler); + } + md_h->in_handler=0; + if (_break) return; + } + } + } + + if (n<0) + { + perror("triton: md(select)"); + //goto check_timeout; + } + if (n>0) + { + list_for_each_safe(p1,p2,&handlers) + { + md_h=list_entry(p1,struct md_handler_t,entry); + if (md_h->in_handler) continue; + if (md_h->del) continue; + md_h->in_handler=1; + if (FD_ISSET(md_h->fd,&read_fds0)) + { + if (md_h->handler->read==md_h->handler->write) + FD_CLR(md_h->fd,&write_fds0); + + #ifdef USE_CORO + if (md_h->coro) + { + long int id=(long int)md_h->coro; + md_h->coro=NULL; + triton_coroutine_wakeup(id); + }else + #endif + { + md_h->handler->read(md_h->handler); + } + } + if (!md_h->del && FD_ISSET(md_h->fd,&write_fds0) && md_h->handler->write) + { + #ifdef USE_CORO + if (md_h->coro) + { + long int id=(long int)md_h->coro; + md_h->coro=NULL; + triton_coroutine_wakeup(id); + }else + #endif + { + md_h->handler->write(md_h->handler); + } + } + md_h->in_handler=0; + if (_break) return; + } + } +//check_timeout: + + for(p1=handlers.next; p1!=&handlers;) + { + md_h=list_entry(p1,struct md_handler_t,entry); + p1=p1->next; + if (md_h->del) + { + list_del(&md_h->entry); + free(md_h); + } + } + + if (!wait) _break=1; +} + +void triton_process_events(void) +{ + _triton_process_events(0); +} + +void md_terminate() +{ + md_term=1; +} + +void triton_md_register_handler(struct triton_md_handler_t *h) +{ + struct md_handler_t *md_h; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->handler==h) + { + if (!md_h->del) + { + printf("triton: bug: double triton_md_register_handler\n"); + abort(); + } + md_h->del=0; + md_h->in_handler=0; + md_h->coro=0; + md_h->fd=0; + return; + } + } + + md_h=(struct md_handler_t *)malloc(sizeof(struct md_handler_t)); + memset(md_h,0,sizeof(*md_h)); + md_h->handler=h; + + list_add_tail(&md_h->entry,&handlers); +} +void triton_md_unregister_handler(struct triton_md_handler_t *h) +{ + struct md_handler_t *md_h; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->handler==h) + { + triton_md_disable_handler(h,0); + /*list_del(&md_h->entry); + free(md_h); + return;*/ + md_h->del=1; + return; + } + } +} +void triton_md_enable_handler(struct triton_md_handler_t *h, int mode) +{ + struct md_handler_t *md_h; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->handler==h) + { + md_h->fd=h->fd; + break; + } + } + if (mode) + { + if (mode&MD_MODE_READ) + FD_SET(h->fd,&read_fds); + if (mode&MD_MODE_WRITE) + FD_SET(h->fd,&write_fds); + }else + { + FD_SET(h->fd,&read_fds); + FD_SET(h->fd,&write_fds); + } +} +void triton_md_disable_handler(struct triton_md_handler_t *h,int mode) +{ + if (mode) + { + if (mode&MD_MODE_READ) + FD_CLR(h->fd,&read_fds); + if (mode&MD_MODE_WRITE) + FD_CLR(h->fd,&write_fds); + }else + { + FD_CLR(h->fd,&read_fds); + FD_CLR(h->fd,&write_fds); + } +} + +#ifdef USE_CORO +int triton_md_wait(struct triton_md_handler_t *h) +{ + struct md_handler_t *md_h; + int res=0; + + list_for_each_entry(md_h,&handlers,entry) + { + if (md_h->handler==h) break; + } + + md_h->in_handler=0; + + md_h->coro=current_coro; + triton_coroutine_schedule(); + + if (FD_ISSET(md_h->fd,&read_fds0)) res|=MD_MODE_READ; + if (FD_ISSET(md_h->fd,&write_fds0)) res|=MD_MODE_WRITE; + return res; +} +int triton_md_wait2(int fd,int mode,int timeout) +{ + int r; + struct triton_md_handler_t h= + { + .fd=fd, + .twait=timeout, + }; + triton_md_register_handler(&h); + triton_md_enable_handler(&h,mode); + r=triton_md_wait(&h); + triton_md_unregister_handler(&h); + return r; +} +#endif diff --git a/accel-pptpd/triton/options.c b/accel-pptpd/triton/options.c new file mode 100644 index 00000000..ba7fc564 --- /dev/null +++ b/accel-pptpd/triton/options.c @@ -0,0 +1,46 @@ +#include <stdlib.h> +#include <string.h> + +#include "triton_p.h" +#include "conf_file.h" + +static struct conf_file_sect_t *sect=NULL; + +static const char* find_option(const char *name) +{ + struct option_t *opt; + + if (!sect) + { + sect=conf_file_get_section("options"); + if (!sect) return 0; + } + + list_for_each_entry(opt,§->items,entry) + { + if (strcmp(opt->name,name)==0) + return opt->val; + } + + return NULL; +} +int triton_get_int_option(const char *str) +{ + const char *val=find_option(str); + if (!val) return 0; + + return atoi(val); +} +const char* triton_get_str_option(const char *str) +{ + const char *val=find_option(str); + + return val; +} +double triton_get_double_option(const char *str) +{ + const char *val=find_option(str); + if (!val) return 0; + + return atof(val); +} diff --git a/accel-pptpd/triton/timer.c b/accel-pptpd/triton/timer.c new file mode 100644 index 00000000..2ea36cb0 --- /dev/null +++ b/accel-pptpd/triton/timer.c @@ -0,0 +1,244 @@ +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <string.h> + +#include "triton_p.h" + +static __thread struct list_head timers; +static __thread struct list_head timers_ss; +static __thread int in_timer; + +asm(".hidden timer_prepare"); +asm(".hidden timer_check"); +asm(".hidden timer_init"); + +static void tv_add(struct timeval *tv,int msec); + + +void timer_init(void) +{ + INIT_LIST_HEAD(&timers); + INIT_LIST_HEAD(&timers_ss); + in_timer=0; +} + +void triton_timer_add(struct triton_timer_t*tt) +{ + struct timer_t *t=(struct timer_t *)malloc(sizeof(struct timer_t)); + + t->del=0; + t->timer=tt; + tt->active=1; + + list_add_tail(&t->entry,&timers); +} +void triton_timer_del(struct triton_timer_t*tt) +{ + struct timer_t *t; + + list_for_each_entry(t,&timers,entry) + { + if (t->timer==tt) + { + tt->active=0; + if (in_timer) + { + t->del=1; + }else + { + list_del(&t->entry); + free(t); + } + return; + } + } +} +void triton_timer_single_shot1(int twait,triton_ss_func func,int arg_cnt,...) +{ + struct timeval tv; + struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t)); + + memset(t,0,sizeof(*t)); + + gettimeofday(&tv,NULL); + + tv_add(&tv,twait); + + t->ss_func=func; + t->expire_tv=tv;//(struct timeval){tv.tv_sec+twait/1000,tv.tv_usec+(twait%1000)*1000000}; + if (arg_cnt) + { + va_list p; + va_start(p,arg_cnt); + t->arg_cnt=arg_cnt; + t->args=malloc(arg_cnt*sizeof(long)); + #ifdef BROKEN_GCC + for(i=0; i<arg_cnt; i++) + *((long*)t->args+i)=va_arg(p,long); + #else + memcpy(t->args,p,arg_cnt*sizeof(long)); + #endif + va_end(p); + } + + list_add_tail(&t->entry,&timers_ss); +} +void triton_timer_single_shot2(struct timeval *tv,triton_ss_func func,int arg_cnt,...) +{ + struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t)); + + memset(t,0,sizeof(*t)); + + t->ss_func=func; + t->expire_tv=*tv;//(struct timeval){tv.tv_sec+twait/1000,tv.tv_usec+(twait%1000)*1000000}; + if (arg_cnt) + { + va_list p; + va_start(p,arg_cnt); + t->arg_cnt=arg_cnt; + t->args=malloc(arg_cnt*sizeof(long)); + #ifdef BROKEN_GCC + for(i=0; i<arg_cnt; i++) + *((long*)t->args+i)=va_arg(p,long); + #else + memcpy(t->args,p,arg_cnt*sizeof(long)); + #endif + va_end(p); + } + + list_add_tail(&t->entry,&timers_ss); +} +void triton_timer_single_shot3(int tv_sec,int tv_usec,triton_ss_func func,int arg_cnt,...) +{ + struct timer_single_shot_t *t=(struct timer_single_shot_t *)malloc(sizeof(struct timer_single_shot_t)); + + memset(t,0,sizeof(*t)); + + t->ss_func=func; + t->expire_tv.tv_sec=tv_sec; + t->expire_tv.tv_usec=tv_usec; + if (arg_cnt) + { + va_list p; + va_start(p,arg_cnt); + t->arg_cnt=arg_cnt; + t->args=malloc(arg_cnt*sizeof(long)); + #ifdef BROKEN_GCC + for(i=0; i<arg_cnt; i++) + *((int*)t->args+i)=va_arg(p,long); + #else + memcpy(t->args,p,arg_cnt*sizeof(long)); + #endif + va_end(p); + } + + list_add_tail(&t->entry,&timers_ss); +} + +int timer_prepare(struct timeval *tv) +{ + struct timer_t *t; + struct timer_single_shot_t *ss_t; + + int twait=-1,twait0; + + list_for_each_entry(t,&timers,entry) + { + twait0=(t->timer->expire_tv.tv_sec-tv->tv_sec)*1000+ + (t->timer->expire_tv.tv_usec-tv->tv_usec)/1000; + if (twait0<0) twait0=0; + if (twait0>=0 && (twait==-1 || twait0<twait)) + twait=twait0; + } + + if (twait) + { + list_for_each_entry(ss_t,&timers_ss,entry) + { + twait0=(ss_t->expire_tv.tv_sec-tv->tv_sec)*1000+ + (ss_t->expire_tv.tv_usec-tv->tv_usec)/1000; + if (twait0<0) twait0=0; + if (twait0>=0 && (twait==-1 || twait0<twait)) + twait=twait0; + } + } + + return twait; +} + + +void timer_check(struct timeval *tv) +{ + struct timer_t *t; + struct timer_single_shot_t *ss_t; + struct list_head *p1,*p2; + int twait0; + + in_timer=1; + + list_for_each_safe(p1,p2,&timers) + { + t=list_entry(p1,struct timer_t,entry); + if (t->del) continue; + twait0=(t->timer->expire_tv.tv_sec-tv->tv_sec)*1000+ + (t->timer->expire_tv.tv_usec-tv->tv_usec)/1000; + if (twait0<=0) + { + if (!t->timer->expire(t->timer)) + { + t->timer->active=0; + list_del(&t->entry); + free(t); + continue; + } + if (t->timer->period) + { + tv_add(&t->timer->expire_tv,t->timer->period); + } + } + } + + list_for_each_safe(p1,p2,&timers_ss) + { + ss_t=list_entry(p1,struct timer_single_shot_t,entry); + twait0=(ss_t->expire_tv.tv_sec-tv->tv_sec)*1000+ + (ss_t->expire_tv.tv_usec-tv->tv_usec)/1000; + if (twait0<=0) + { + list_del(&ss_t->entry); + if (ss_t->arg_cnt) + { + //args_p=&ss_t->args; + //memcpy(pp+ARG_OFFSET,ss_t->args,ss_t->arg_cnt*sizeof(int)); + //__builtin_apply(ss_t->ss_func,pp,ARG_OFFSET+ss_t->arg_cnt*sizeof(int)); + dyn_call(ss_t->ss_func,ss_t->arg_cnt,ss_t->args); + free(ss_t->args); + }else ss_t->ss_func(); + free(ss_t); + } + } + + list_for_each_safe(p1,p2,&timers) + { + t=list_entry(p1,struct timer_t,entry); + if (t->del) + { + list_del(&t->entry); + t->timer->active=0; + free(t); + } + } + in_timer=0; +} + +static void tv_add(struct timeval *tv,int msec) +{ + tv->tv_sec+=msec/1000; + tv->tv_usec+=(msec%1000)*1000; + if (tv->tv_usec>=1000000) + { + tv->tv_sec++; + tv->tv_usec-=1000000; + } +} diff --git a/accel-pptpd/triton/triton.h b/accel-pptpd/triton/triton.h new file mode 100644 index 00000000..b726076e --- /dev/null +++ b/accel-pptpd/triton/triton.h @@ -0,0 +1,78 @@ +#ifndef TRITON_H +#define TRITON_H + +#include <sys/time.h> + +struct triton_md_handler_t +{ + int fd; + int twait; + void *pd; + + void (*read)(struct triton_md_handler_t *h); + void (*write)(struct triton_md_handler_t *h); + void (*timeout)(struct triton_md_handler_t *h); +}; + +#define MD_MODE_READ 1 +#define MD_MODE_WRITE 2 +void triton_md_register_handler(struct triton_md_handler_t *h); +void triton_md_unregister_handler(struct triton_md_handler_t *h); +void triton_md_enable_handler(struct triton_md_handler_t *h, int mode); +void triton_md_disable_handler(struct triton_md_handler_t *h,int mode); +int triton_md_wait(struct triton_md_handler_t *h); +int triton_md_wait2(int fd,int mode,int timeout); + +struct triton_timer_t +{ + struct timeval expire_tv; + int period; + void *pd; + int active; + + int (*expire)(struct triton_timer_t*); +}; + +void triton_timer_add(struct triton_timer_t*); +void triton_timer_del(struct triton_timer_t*); + +typedef void (*triton_ss_func)(void); +void triton_timer_single_shot1(int twait,triton_ss_func,int argc,...); +void triton_timer_single_shot2(struct timeval *shot_tv,triton_ss_func,int argc,...); +void triton_timer_single_shot3(int tv_sec,int tv_usec,triton_ss_func,int argc,...); + +typedef void (*triton_event_func)(void); +void triton_event_register_handler(int ev_id,triton_event_func,int argc,...); +void triton_event_unregister_handler(int ev_id,triton_event_func); +void triton_event_fire(int ev_id,int argc,...); + +int triton_get_int_option(const char *str); +const char* triton_get_str_option(const char *str); +double triton_get_double_option(const char *str); + +void triton_terminate(void); +void triton_process_events(void); + +#ifdef USE_CORO +#define DEF_COROUTINE_STACK 64*1024 +typedef void (*triton_coroutine_func)(void*); +long int triton_coroutine_create(int stack_size,triton_coroutine_func func,void *arg,int run); +void triton_coroutine_delete(long int id); +void triton_coroutine_wakeup(long int id); +void triton_coroutine_schedule(); +int triton_coroutine_schedule_timeout(int msec); +#endif + +#define TRITON_OK 0 +#define TRITON_ERR_NOCOMP -1 +#define TRITON_ERR_NOSUPP -2 +#define TRITON_ERR_NOINTF -3 +#define TRITON_ERR_EXISTS -4 +#define TRITON_ERR_NOCHAN -5 +#define TRITON_ERR_NOMSG -6 +#define TRITON_ERR_BUSY -5 + +int triton_init(const char *conf_file); +int triton_run(int (*post_init)(void*),void *arg); + +#endif diff --git a/accel-pptpd/triton/triton_p.h b/accel-pptpd/triton/triton_p.h new file mode 100644 index 00000000..0602bfa0 --- /dev/null +++ b/accel-pptpd/triton/triton_p.h @@ -0,0 +1,140 @@ +#ifndef TRITON_P_H +#define TRITON_P_H + +#include "triton.h" +#include "list.h" + +#include <stdarg.h> +#include <ucontext.h> + +#define MAX_ARGS 32 + +struct option_t +{ + struct list_head entry; + + char *name; + char *val; +}; + +struct md_handler_t +{ + struct list_head entry; + + int fd; + int del; + int timeout; + int volatile in_handler; + + struct coroutine_t *coro; + + struct triton_md_handler_t *handler; +}; + +struct timer_t +{ + struct list_head entry; + int del; + struct triton_timer_t *timer; +}; + +struct timer_single_shot_t +{ + struct list_head entry; + + struct timeval expire_tv; + int arg_cnt; + void *args; + triton_ss_func ss_func; +}; + +struct event_handler_t +{ + struct list_head entry; + + int arg_cnt; + void *args; + triton_event_func event_func; +}; +struct event_t +{ + struct list_head entry; + + int ev_id; + struct list_head handlers; +}; + +struct coroutine_t +{ + struct list_head entry; + ucontext_t uc; + struct timeval timeout; + struct timeval time; +}; + + +extern struct list_head components; +extern void md_run(); +extern void md_terminate(); +extern int timer_prepare(struct timeval *tv); +extern void timer_check(struct timeval *tv); +extern int coroutine_get_timeout(struct timeval *tv); +extern void coroutine_check_timeout(struct timeval *tv); +extern void event_init(); +extern struct coroutine_t *current_coro; +void schedule(void); + +//#define BROKEN_GCC + +#ifdef BROKEN_GCC +#define dyn_call(func,arg_cnt,args)\ +{\ + switch(arg_cnt)\ + {\ + case 0: \ + {\ + typedef void (*func0)(void);\ + ((func0)func)();\ + break;\ + }\ + case 1: \ + {\ + typedef void (*func0)(long);\ + ((func0)func)(*((long*)args+0));\ + break;\ + }\ + case 2: \ + {\ + typedef void (*func0)(long,long);\ + ((func0)func)(*((long*)args+0),*((long*)args+1));\ + break;\ + }\ + case 3: \ + {\ + typedef void (*func0)(long,long,long);\ + ((func0)func)(*((long*)args+0),*((long*)args+1),*((long*)args+2));\ + break;\ + }\ + case 4: \ + {\ + typedef void (*func0)(long,long,long,long);\ + ((func0)func)(*((long*)args+0),*((long*)args+1),*((long*)args+2),*((long*)args+3));\ + break;\ + }\ + }\ +} +#else +#define dyn_call(func,arg_cnt,args)\ +{\ + int aaa=arg_cnt*sizeof(long);\ + asm("subl %2,%%esp; \n\ + movl %%esp,%%edi;\n\ + movl %0,%%esi;\n\ + cld;\n\ + rep movsl;\n\ + call *%1;\n\ + addl %2,%%esp\n"::"m" (args),"m" (func),"g" (aaa),"c"(arg_cnt):"%edi","%esi","%esp");\ +} +#endif + +#endif |