ose_inet_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 689 行 · 第 1/2 页
C
689 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ */#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#undef WANT_NONBLOCKING#undef ERL_SYS_DRV#include "erl_driver.h"#include "inet.h"#include "inet.sig"#include "nameser.h" #include "resolv.h"#include "netdb.h"#include "efs.h"#include "sys.h"#include "ose_inet_drv.h"#include "erl_inet.sig"#define INET_SIG_TIMEOUT 60000union SIGNAL { SIGSELECT sig_no;};static int ose_inet_init(void);static ErlDrvData ose_inet_start(ErlDrvPort, char*);static void ose_inet_stop(ErlDrvData);static void ose_inet_command(ErlDrvData, char*, int);static void ose_inet_input(ErlDrvData, ErlDrvEvent);struct erl_drv_entry ose_inet_driver_entry = { ose_inet_init, ose_inet_start, /* start */ ose_inet_stop, /* port closed */ ose_inet_command, /* data from erlang */ ose_inet_input, /* data in message queue */ NULL, /* output, not used */ "ose_inet", NULL, NULL, NULL, NULL, NULL};static int ose_tcp_inet_init(void);static void ose_tcp_inet_stop(ErlDrvData);static void ose_tcp_inet_command(ErlDrvData, char*, int);static void ose_tcp_inet_commandv(ErlDrvData, ErlIOVec*);static void ose_tcp_inet_drv_input(ErlDrvData, ErlDrvEvent);static ErlDrvData ose_tcp_inet_start(ErlDrvPort, char* command);static int ose_tcp_inet_ctl(ErlDrvData, unsigned int, char*, int, char**, int);static void ose_tcp_inet_timeout(ErlDrvData);static struct erl_drv_entry ose_tcp_inet_driver_entry = { ose_tcp_inet_init, ose_tcp_inet_start, ose_tcp_inet_stop, ose_tcp_inet_command, NULL, /* tcp input function called from ose_inet_input */ NULL, /* ready_output not used (this driver never does driver_select(DO_WRITE) */ "tcp_inet", NULL, NULL, ose_tcp_inet_ctl, ose_tcp_inet_timeout, ose_tcp_inet_commandv};static int ose_udp_inet_init(void);static void ose_udp_inet_stop(ErlDrvData);static void ose_udp_inet_command(ErlDrvData, char*, int);static void ose_udp_inet_drv_input(ErlDrvData, ErlDrvEvent);static ErlDrvData ose_udp_inet_start(ErlDrvPort, char*);static int ose_udp_inet_ctl(ErlDrvData, unsigned int, char*, int, char**, int);static void ose_udp_inet_timeout(ErlDrvData);static struct erl_drv_entry ose_udp_inet_driver_entry = { ose_udp_inet_init, ose_udp_inet_start, ose_udp_inet_stop, ose_udp_inet_command, NULL, /* udp input function called from ose_inet_input */ NULL, /* ready_output not used (this driver never does driver_select(DO_WRITE) */ "udp_inet", NULL, NULL, ose_udp_inet_ctl, ose_udp_inet_timeout, NULL};/* pointers to the inet_drv entries */static struct erl_drv_entry *tcp_inet_driver_entry;static struct erl_drv_entry *udp_inet_driver_entry;#define SELECTED 0#define NOT_SELECTED 1struct sockState { int read; /* indicates if driver has selected socket for input */ int write; /* indicates if driver has selected socket for output */};typedef struct inet_drv_data { struct erl_drv_entry *entry; void* erl_drv_data;} InetDrvData;extern Uint erts_max_ports;static PROCESS inet_, erl_sock_select_;static ErlDrvPort reserved_port;static InetDrvData **driver_data; /* port -> driver data (array of size erts_max_ports) */static ErlDrvPort ports[MAX_SOCKS]; /* socket -> port */static struct sockState* sock_status[MAX_SOCKS];union eventSig { SIGSELECT sig_no; struct SockSelect sock_select; struct InetEventRead inet_ev_read; struct InetEventWrite inet_ev_write; struct SockSelectError sock_select_error; struct InetEventAck inet_ev_ack;};union iSIGNAL { SIGSELECT sig_no; struct InetIfUp up; struct InetRouteAdd route;};extern PROCESS start_sock_select();extern void stop_sock_select(PROCESS);extern void select_release(void);/* forward declarations */static void send_sock_select(int, int, int);static void send_event_ack(PROCESS, int);/************************** GEN FUNCS ***************************/void add_ose_inet_drv_entry() { add_driver_entry(&ose_inet_driver_entry);}static int ose_inet_init(void) { printf("ose inet drv init (max sockets = %d, max ports = %d)\n", MAX_SOCKS, erts_max_ports); driver_data = (InetDrvData **)driver_alloc(erts_max_ports*sizeof(InetDrvData *)); memset((void*)driver_data, 0, erts_max_ports*sizeof(InetDrvData *)); memset((void*)ports, 0, MAX_SOCKS*sizeof(ErlDrvPort)); return 0;}/* setup default erlang port for inet signals */static ErlDrvData ose_inet_start(ErlDrvPort res_port, char* command) {#ifdef DEBUG printf("ose_inet starts! port: %d\n", (int)res_port);#endif /* "hunt" for ose_inet (i.e. find pid given name */ if(hunt("ose_inet", 0, &inet_, NULL)) { reserved_port = res_port; /* make sure any signals from ose_inet is handled by this driver */ driver_select(res_port, (ErlDrvEvent)inet_, DO_START, 1); driver_select(res_port, (ErlDrvEvent)inet_, DO_READ, 1); /* find or start sock_select process */ if (hunt("erl_sock_select", 0, &erl_sock_select_, NULL)) stop_sock_select(erl_sock_select_); erl_sock_select_ = start_sock_select(); /* register port with rescheduler process and get ready to receive */ driver_select(res_port, (ErlDrvEvent)erl_sock_select_, DO_START, 1); driver_select(res_port, (ErlDrvEvent)erl_sock_select_, DO_READ, 1); /* make it possible for the inet driver to send signals to itself */ driver_select(res_port, (ErlDrvEvent)current_process(), DO_START, 1); driver_select(res_port, (ErlDrvEvent)current_process(), DO_READ, 1); return (ErlDrvData)NULL; } else return ERL_DRV_ERROR_GENERAL;}static void ose_inet_stop(ErlDrvData e) { int i; InetDrvData *dd;#ifdef DEBUG printf("ose_inet stopped!\n");#endif /* unregister port processes */ driver_select(reserved_port, (ErlDrvEvent)erl_sock_select_, DO_STOP, 1); driver_select(reserved_port, (ErlDrvEvent)inet_, DO_STOP, 1); /* clear memory */ for(i = 0; i < erts_max_ports; i++) { if((dd = driver_data[i]) != NULL) driver_free(dd); } kill_proc(erl_sock_select_);}/* called from erlang to send data on socket (not used) */static void ose_inet_command(ErlDrvData e, char *buf, int len) { fprintf(stderr, "ose_inet command called!\n");}/* driver receives event signal (from inet or erl_sock_select) */static void ose_inet_input(ErlDrvData empty, ErlDrvEvent sig) { union eventSig *inet_sig = (union eventSig *)sig; InetDrvData *dd; int sock; struct sockState *ss; switch(inet_sig->sig_no) { /* data available on socket */ case INET_EVENT_READ: sock = inet_sig->inet_ev_read.sock; if((ss = sock_status[sock]) == NULL) { /* socket has been closed, discard signal */ fprintf(stderr, "Data on socket %d (unknown socket, port %d)\n", sock, ports[sock]); send_sock_select(sock, DO_READ, 0); } else /* check sock status if driver is ready to receive, else ignore indication */ if(ss->read == SELECTED) { /* note: sock->port has been registered, since read == SELECTED */ dd = driver_data[(int)(ports[sock])];#ifdef DEBUG printf("Port %d has data on socket %d (read)\n", ports[sock], sock);#endif (*((dd->entry)->ready_input))((ErlDrvData)(dd->erl_drv_data), (ErlDrvEvent)sock); } send_event_ack(sender((union SIGNAL **)&inet_sig), sock); ose_sig_free_buf((union SIGNAL **)&inet_sig); return; case INET_EVENT_WRITE: sock = inet_sig->inet_ev_write.sock; if((ss = sock_status[sock]) == NULL) { /* socket has been closed, discard signal */ fprintf(stderr, "Output ready on socket %d (unknown socket, port %d)\n", sock, ports[sock]); send_sock_select(sock, DO_WRITE, 0); } else /* check sock status if driver wants to write, else ignore indication */ if(ss->write == SELECTED) { /* note: sock->port has been registered, since write == SELECTED */ dd = driver_data[(int)(ports[sock])];#ifdef DEBUG printf("Port %d ready to write on socket %d\n", ports[sock], sock);#endif (*((dd->entry)->ready_output))((ErlDrvData)(dd->erl_drv_data), (ErlDrvEvent)sock); } send_event_ack(sender((union SIGNAL **)&inet_sig), sock); ose_sig_free_buf((union SIGNAL **)&inet_sig); return; case SOCK_SELECT_ERROR: sock = inet_sig->sock_select_error.sock; fprintf(stderr, "Select error %d! Bad socket: %d (port %d)\n", sock, inet_sig->sock_select_error.error, ports[sock]); /* what to do here? exit!? */ send_event_ack(sender((union SIGNAL **)&inet_sig), sock); ose_sig_free_buf((union SIGNAL **)&inet_sig); return; default: sock = inet_sig->sock_select_error.sock; fprintf(stderr, "Unknown signal %li from process: %li\n", inet_sig->sig_no, sender((union SIGNAL **)&inet_sig)); send_event_ack(sender((union SIGNAL **)&inet_sig), sock); ose_sig_free_buf((union SIGNAL **)&inet_sig); }}int ose_inet_select(ErlDrvPort ix, ErlDrvEvent e, int mode, int on){ /* extern void send_error(int sock, int error); */ extern void send_write_event(int s); extern void send_read_event(int s); int sock = (int)e; ports[sock] = ix; if (mode & DO_READ) { if(on) sock_status[sock]->read = SELECTED; else sock_status[sock]->read = NOT_SELECTED; } else if (mode & DO_WRITE) { if(on) sock_status[sock]->write = SELECTED; else sock_status[sock]->write = NOT_SELECTED; } send_sock_select(sock, mode, on); return 0;}int ose_inet_socket(int domain, int type, int protocol) { int sock; struct sockState *ss; if((sock = socket(domain, type, protocol)) >= 0) { ss = driver_alloc(sizeof(struct sockState)); ss->read = ss->write = NOT_SELECTED; sock_status[sock] = ss; } return sock;}int ose_inet_close(int sock) { int res;#ifdef DEBUG printf("\nClosing socket %d (port %d)\n", sock, ports[sock]);#endif send_sock_select(sock, (DO_READ | DO_WRITE), 0); driver_free(sock_status[sock]); sock_status[sock] = NULL; ports[sock] = 0; if((res = close(sock)) == -1)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?