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 + -
显示快捷键?