1 #include <stdio.h>
2 #include "erl_driver.h"
3 #include <errno.h>
4 
5 
6 
7 /* -------------------------------------------------------------------------
8 ** Data types
9 **/
10 
11 enum e_heavy {
12     heavy_off, heavy_set, heavy_reset
13 };
14 
15 typedef struct _erl_drv_data {
16     ErlDrvPort   erlang_port;
17     enum e_heavy heavy;
18     int crash;
19 } EchoDrvData;
20 
21 static EchoDrvData echo_drv_data, *echo_drv_data_p;
22 
23 
24 
25 /* -------------------------------------------------------------------------
26 ** Entry struct
27 **/
28 
29 static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command);
30 static void         echo_drv_stop(ErlDrvData drv_data);
31 static void         echo_drv_output(ErlDrvData drv_data, char *buf,
32 				    ErlDrvSizeT len);
33 static void         echo_drv_finish(void);
34 static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
35 				     unsigned int command,
36 				     char *buf,  ErlDrvSizeT len,
37 				     char **rbuf, ErlDrvSizeT rlen);
38 
39 static ErlDrvEntry echo_drv_entry = {
40     NULL, /* init */
41     echo_drv_start,
42     echo_drv_stop,
43     echo_drv_output,
44     NULL, /* ready_input */
45     NULL, /* ready_output */
46     "echo_drv",
47     echo_drv_finish,
48     NULL, /* handle */
49     echo_drv_control,
50     NULL, /* timeout */
51     NULL, /* outputv */
52     NULL, /* ready_async */
53     NULL,
54     NULL,
55     NULL,
56     ERL_DRV_EXTENDED_MARKER,
57     ERL_DRV_EXTENDED_MAJOR_VERSION,
58     ERL_DRV_EXTENDED_MINOR_VERSION,
59     0,
60     NULL,
61     NULL,
62     NULL
63 };
64 
65 /* -------------------------------------------------------------------------
66 ** Entry functions
67 **/
68 
DRIVER_INIT(echo_drv)69 DRIVER_INIT(echo_drv)
70 {
71     echo_drv_data_p = NULL;
72     return &echo_drv_entry;
73 }
74 
echo_drv_start(ErlDrvPort port,char * command)75 static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command)
76 {
77     if (echo_drv_data_p != NULL) {
78 	return ERL_DRV_ERROR_GENERAL;
79     }
80     echo_drv_data_p = &echo_drv_data;
81     echo_drv_data_p->erlang_port = port;
82     echo_drv_data_p->heavy = heavy_off;
83     echo_drv_data_p->crash = 0;
84     return echo_drv_data_p;
85 }
86 
echo_drv_stop(EchoDrvData * data_p)87 static void echo_drv_stop(EchoDrvData *data_p) {
88     echo_drv_data_p = NULL;
89 }
90 
echo_drv_output(ErlDrvData drv_data,char * buf,ErlDrvSizeT len)91 static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
92     EchoDrvData* data_p = (EchoDrvData *) drv_data;
93 
94     if (data_p->crash) {
95 	driver_failure_posix(data_p->erlang_port, EINTR);
96 	return;
97     }
98 
99     driver_output(data_p->erlang_port, buf, len);
100     switch (data_p->heavy) {
101     case heavy_off:
102 	break;
103     case heavy_set:
104 	set_port_control_flags(data_p->erlang_port, PORT_CONTROL_FLAG_HEAVY);
105 	data_p->heavy = heavy_reset;
106 	break;
107     case heavy_reset:
108 	set_port_control_flags(data_p->erlang_port, 0);
109 	data_p->heavy = heavy_off;
110 	break;
111     }
112 
113 }
114 
echo_drv_finish()115 static void echo_drv_finish() {
116     echo_drv_data_p = NULL;
117 }
118 
echo_drv_control(ErlDrvData drv_data,unsigned int command,char * buf,ErlDrvSizeT len,char ** rbuf,ErlDrvSizeT rlen)119 static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
120 				     unsigned int command,
121 				     char *buf, ErlDrvSizeT len,
122 				     char **rbuf, ErlDrvSizeT rlen) {
123     EchoDrvData* data_p = (EchoDrvData *) drv_data;
124     switch (command) {
125     case 'h':
126 	data_p->heavy = heavy_set;
127 	break;
128     case 'c':
129 	data_p->crash = 1;
130     }
131     return 0;
132 }
133