File: socketSample.ec

package info (click to toggle)
ecere-sdk 0.44.15-1
  • links: PTS
  • area: main
  • in suites: sid, stretch
  • size: 97,712 kB
  • ctags: 54,695
  • sloc: ansic: 593,042; makefile: 12,250; yacc: 4,955; lex: 707; objc: 259; python: 252; xml: 102
file content (170 lines) | stat: -rw-r--r-- 6,041 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import "ecere"

// We'll use TCP/IP port 5623 for this sample
define samplePort = 5623;

// We will use this simple structure for our messages
struct SamplePacket
{
   int stringLen;
   // stringLen + 1 bytes are actually used (variable size depending on string)
   char string[1];
};

class SampleService : Service
{
   void OnAccept()
   {
      // When we get an incoming connection to our service, we spawn a SampleSocket (Can only serve one right now)
      if(!servingSocket)
      {
         servingSocket = SampleSocket { this };
         form.UpdateButtonStates();
      }
   }
}

class SampleSocket : Socket
{
   void OnConnect()
   {
      // We want a non blocking Connect() call, so we define an OnConnect() that simply updates the button disabled states
      form.UpdateButtonStates();
   }

   void OnDisconnect(int code)
   {
      // On disconnection we need to null the socket pointers, and update the buttons
      if(connectedSocket == this)
         connectedSocket = null;
      else if(servingSocket == this)
         servingSocket = null;

      form.UpdateButtonStates();
   }

   unsigned int OnReceive(const unsigned char * buffer, unsigned int count)
   {
      // We only process the data if we've received enough bytes to make up the message
      // This first if just checks if we have reveived enough bytes for the header
      if(count >= sizeof(SamplePacket))
      {
         SamplePacket * packet = (SamplePacket *) buffer;
         uint size = sizeof(SamplePacket) + packet->stringLen;
         // Here we check if we've actually received the entire message
         if(count >= size)
         {
            // We've received a complete message, so we change the contents of the recvString EditBox
            form.recvString.contents = packet->string;
            // and we return the size of the message we've processed.
            // If more data is already buffered, this method will be called again right away.
            return size;
         }
      }
      // We haven't received enough data to process this message yet: return 0 bytes processed
      // This method will be called again once more data has been received.
      return 0;
   }
}

class SocketSample : Window
{
   text = "Socket Sample";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   tabCycle = true;
   size = { 416, 176 };
   nativeDecorations = true;

   // Service is missing a property to tell us if it's listening or not already, so we keep track of it in this variable
   bool listening;

   void UpdateButtonStates()
   {
      bool connected = (connectedSocket && connectedSocket.connected) || (servingSocket && servingSocket.connected);

      // The Send button is disabled if we're not connected
      btnSend.disabled = !connected;
      // The Connect button is disabled if we've already defined a connectedSocket
      btnConnect.disabled = connectedSocket != null;
      // The Listen button is disabled if we're already listening
      btnListen.disabled = listening;
   }

   Button btnSend
   {
      this, text = "Send", position = { 344, 64 }, disabled = true;

      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         // We build up a SamplePacket here with our message from the sentString EditBox
         const String string = sentString.contents;
         int len = strlen(string);
         int size = sizeof(SamplePacket) + len;
         SamplePacket * packet = (SamplePacket *)new byte[size];
         packet->stringLen = len;
         memcpy(packet->string, string, len+1);
         // If we've connected to another server, we use the connectedSocket, otherwise we use the servingSocket (Send back to whom connected to us)
         (connectedSocket ? connectedSocket : servingSocket).Send(packet, size);
         // Make sure to free memory allocated with 'new'
         delete packet;
         return true;
      }
   };
   EditBox serverAddress { this, text = "Server Address", size = { 174, 19 }, position = { 8, 40 }, contents = "localhost" };
   Label lblServerAddress { this, position = { 8, 16 }, labeledWindow = serverAddress };
   Button btnListen
   {
      this, text = "Listen", position = { 144, 104 };

      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         // Start listening here
         if(service.Start())
         {
            listening = true;
            UpdateButtonStates();
         }
         return true;
      }
   };
   EditBox sentString { this, text = "Sent String", size = { 166, 19 }, position = { 224, 40 } };
   Label lblSentString { this, position = { 224, 16 }, labeledWindow = sentString };
   EditBox recvString { this, text = "Received String", size = { 166, 19 }, position = { 224, 104 } };
   Label label1 { this, position = { 224, 80 }, labeledWindow = recvString };
   Button btnConnect
   {
      this, text = "Connect", position = { 8, 72 };

      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         btnConnect.disabled = true;
         // Create a socket and attempt a connection to the address specified in the serverAddress EditBox
         connectedSocket = SampleSocket { };
         // Connect is a blocking call if no OnConnect method is defined in the Socket, a non-blocking call otherwise
         connectedSocket.Connect(serverAddress.contents, samplePort);
         return true;
      }
   };

   void OnDestroy()
   {
      // We need to disconnect the socket and stop the service before destroying the application,
      // otherwise we'll get a crash with the SampleSocket accessing the form that is already destroyed
      if(connectedSocket)
         connectedSocket.Disconnect(0);
      service.Stop();
   }
}

// The form
SocketSample form {};

// The service
SampleService service { port = samplePort };

// We use 2 sockets: one for when we connect to a server, one for the incoming connections to our SampleService
SampleSocket connectedSocket, servingSocket;