Line No. | Rev | Author | Line |
---|---|---|---|
1 | 32 | kaklik | /********************************************************************* |
2 | * |
||
3 | * Berekely Socket Distribution API Source File |
||
4 | * |
||
5 | ********************************************************************* |
||
6 | * FileName: BerkeleyAPI.c |
||
7 | * Description: Berkeley Socket Distribution(BSD) APIs for Microchip TCPIP Stack |
||
8 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32 |
||
9 | * Compiler: Microchip C32 v1.05 or higher |
||
10 | * Microchip C30 v3.12 or higher |
||
11 | * Microchip C18 v3.30 or higher |
||
12 | * HI-TECH PICC-18 PRO 9.63PL2 or higher |
||
13 | * Company: Microchip Technology, Inc. |
||
14 | * |
||
15 | * Software License Agreement |
||
16 | * |
||
17 | * Copyright (C) 2002-2009 Microchip Technology Inc. All rights |
||
18 | * reserved. |
||
19 | * |
||
20 | * Microchip licenses to you the right to use, modify, copy, and |
||
21 | * distribute: |
||
22 | * (i) the Software when embedded on a Microchip microcontroller or |
||
23 | * digital signal controller product ("Device") which is |
||
24 | * integrated into Licensee's product; or |
||
25 | * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h, |
||
26 | * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device |
||
27 | * used in conjunction with a Microchip ethernet controller for |
||
28 | * the sole purpose of interfacing with the ethernet controller. |
||
29 | * |
||
30 | * You should refer to the license agreement accompanying this |
||
31 | * Software for additional information regarding your rights and |
||
32 | * obligations. |
||
33 | * |
||
34 | * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT |
||
35 | * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT |
||
36 | * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
||
37 | * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
38 | * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR |
||
39 | * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF |
||
40 | * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS |
||
41 | * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE |
||
42 | * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER |
||
43 | * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT |
||
44 | * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. |
||
45 | * |
||
46 | * Author Date Comment |
||
47 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
48 | * Aseem Swalah 4/3/08 Original |
||
49 | ********************************************************************/ |
||
50 | |||
51 | #include "TCPIPConfig.h" |
||
52 | |||
53 | #if defined(STACK_USE_BERKELEY_API) |
||
54 | |||
55 | #include "TCPIP Stack/TCPIP.h" |
||
56 | |||
57 | static BOOL HandlePossibleTCPDisconnection(SOCKET s); |
||
58 | |||
59 | |||
60 | #if defined(__18CXX) && !defined(HI_TECH_C) |
||
61 | #pragma udata BSD_uRAM |
||
62 | #endif |
||
63 | static struct BSDSocket BSDSocketArray[BSD_SOCKET_COUNT]; |
||
64 | #if defined(__18CXX) && !defined(HI_TECH_C) |
||
65 | #pragma udata |
||
66 | #endif |
||
67 | |||
68 | static WORD gAutoPortNumber = 1024; |
||
69 | |||
70 | |||
71 | /***************************************************************************** |
||
72 | Function: |
||
73 | void BerkeleySocketInit(void) |
||
74 | |||
75 | Summary: |
||
76 | Initializes the Berkeley socket structure array. |
||
77 | |||
78 | Description: |
||
79 | This function initializes the Berkeley socket array. This function should |
||
80 | be called before any BSD socket call. |
||
81 | |||
82 | Precondition: |
||
83 | None. |
||
84 | |||
85 | Parameters: |
||
86 | None. |
||
87 | |||
88 | Returns: |
||
89 | None |
||
90 | |||
91 | Remarks: |
||
92 | None. |
||
93 | ***************************************************************************/ |
||
94 | void BerkeleySocketInit(void) |
||
95 | { |
||
96 | unsigned int s; |
||
97 | struct BSDSocket *socket; |
||
98 | |||
99 | for ( s = 0; s < BSD_SOCKET_COUNT; s++ ) |
||
100 | { |
||
101 | socket = (struct BSDSocket *)&BSDSocketArray[s]; |
||
102 | socket->bsdState = SKT_CLOSED; |
||
103 | } |
||
104 | } |
||
105 | |||
106 | /***************************************************************************** |
||
107 | Function: |
||
108 | SOCKET socket( int af, int type, int protocol ) |
||
109 | |||
110 | Summary: |
||
111 | This function creates a new Berkeley socket. |
||
112 | |||
113 | Description: |
||
114 | This function creates a new BSD socket for the microchip |
||
115 | TCPIP stack. The return socket descriptor is used for the subsequent |
||
116 | BSD operations. |
||
117 | |||
118 | Precondition: |
||
119 | BerkeleySocketInit function should be called. |
||
120 | |||
121 | Parameters: |
||
122 | af - address family - AF_INET. |
||
123 | type - socket type SOCK_DGRAM or SOCK_STREAM. |
||
124 | protocol - IP protocol IPPROTO_UDP or IPPROTO_TCP. |
||
125 | |||
126 | Returns: |
||
127 | New socket descriptor. INVALID_SOCKET in case of error. |
||
128 | |||
129 | Remarks: |
||
130 | None. |
||
131 | ***************************************************************************/ |
||
132 | SOCKET socket( int af, int type, int protocol ) |
||
133 | { |
||
134 | struct BSDSocket *socket = BSDSocketArray; |
||
135 | SOCKET s; |
||
136 | |||
137 | if( af != AF_INET ) |
||
138 | return INVALID_SOCKET; |
||
139 | |||
140 | for( s = 0; s < BSD_SOCKET_COUNT; s++,socket++ ) |
||
141 | { |
||
142 | if( socket->bsdState != SKT_CLOSED ) //socket in use |
||
143 | continue; |
||
144 | |||
145 | socket->SocketType = type; |
||
146 | |||
147 | if( type == SOCK_DGRAM && protocol == IPPROTO_UDP ) |
||
148 | { |
||
149 | socket->bsdState = SKT_CREATED; |
||
150 | return s; |
||
151 | } |
||
152 | else if( type == SOCK_STREAM && protocol == IPPROTO_TCP ) |
||
153 | { |
||
154 | socket->bsdState = SKT_CREATED; |
||
155 | return s; |
||
156 | } |
||
157 | else |
||
158 | return INVALID_SOCKET; |
||
159 | } |
||
160 | |||
161 | return INVALID_SOCKET; |
||
162 | } |
||
163 | |||
164 | /***************************************************************************** |
||
165 | Function: |
||
166 | int bind( SOCKET s, const struct sockaddr* name, int namelen ) |
||
167 | |||
168 | Summary: |
||
169 | This function assigns a name to the socket descriptor. |
||
170 | |||
171 | Description: |
||
172 | The bind function assigns a name to an unnamed socket. The |
||
173 | name represents the local address of the communication |
||
174 | endpoint. For sockets of type SOCK_STREAM, the name of the |
||
175 | remote endpoint is assigned when a connect or accept function |
||
176 | is executed. |
||
177 | |||
178 | Precondition: |
||
179 | socket function should be called. |
||
180 | |||
181 | Parameters: |
||
182 | s - Socket descriptor returned from a previous call to socket. |
||
183 | name - pointer to the sockaddr structure containing the |
||
184 | local address of the socket. |
||
185 | namelen - length of the sockaddr structure. |
||
186 | |||
187 | Returns: |
||
188 | If bind is successful, a value of 0 is returned. A return |
||
189 | value of SOCKET_ERROR indicates an error. |
||
190 | |||
191 | Remarks: |
||
192 | None. |
||
193 | ***************************************************************************/ |
||
194 | int bind( SOCKET s, const struct sockaddr* name, int namelen ) |
||
195 | { |
||
196 | struct BSDSocket *socket; |
||
197 | struct sockaddr_in *local_addr; |
||
198 | WORD lPort; |
||
199 | |||
200 | if( s >= BSD_SOCKET_COUNT ) |
||
201 | return SOCKET_ERROR; |
||
202 | |||
203 | socket = &BSDSocketArray[s]; |
||
204 | |||
205 | if( socket->bsdState != SKT_CREATED ) //only work with recently created socket |
||
206 | return SOCKET_ERROR; |
||
207 | |||
208 | if( (unsigned int)namelen < sizeof(struct sockaddr_in) ) |
||
209 | return SOCKET_ERROR; |
||
210 | |||
211 | local_addr = (struct sockaddr_in *)name; |
||
212 | |||
213 | lPort = local_addr->sin_port; |
||
214 | if( lPort == 0u ) //pick a port |
||
215 | { |
||
216 | lPort = gAutoPortNumber++; |
||
217 | if(gAutoPortNumber > 5000u) // reset the port numbers |
||
218 | gAutoPortNumber = 1024; |
||
219 | } |
||
220 | |||
221 | if(socket->SocketType == SOCK_DGRAM) |
||
222 | { |
||
223 | socket->SocketID = UDPOpen(lPort, NULL, 0); |
||
224 | if(socket->SocketID == INVALID_UDP_SOCKET) |
||
225 | return SOCKET_ERROR; |
||
226 | } |
||
227 | |||
228 | socket->localPort = lPort; |
||
229 | socket->bsdState = SKT_BOUND; |
||
230 | return 0; //success |
||
231 | } |
||
232 | |||
233 | /***************************************************************************** |
||
234 | Function: |
||
235 | int listen( SOCKET s, int backlog ) |
||
236 | |||
237 | Summary: |
||
238 | The listen function sets the specified socket in a listen mode |
||
239 | |||
240 | Description: |
||
241 | This function sets the specified socket in a listen |
||
242 | mode. Calling the listen function indicates that the |
||
243 | application is ready to accept connection requests arriving |
||
244 | at a socket of type SOCK_STREAM. The connection request is |
||
245 | queued (if possible) until accepted with an accept function. |
||
246 | The backlog parameter defines the maximum number of pending |
||
247 | connections that may be queued. |
||
248 | |||
249 | Precondition: |
||
250 | bind() must have been called on the s socket first. |
||
251 | |||
252 | Parameters: |
||
253 | s - Socket identifier returned from a prior socket() call. |
||
254 | backlog - Maximum number of connection requests that can be queued. Note |
||
255 | that each backlog requires a TCP_PURPOSE_BERKELEY_SERVER type TCP |
||
256 | socket to be allocated in the TCPSocketInitializer[] in TCPIPConfig.h. |
||
257 | Also, ensure that BSD_SOCKET_COUNT (also in TCPIPConfig.h) is greater |
||
258 | than the backlog by at least 1 (more if you have other BSD sockets in |
||
259 | use). |
||
260 | |||
261 | Returns: |
||
262 | Returns 0 on success, else return SOCKET_ERROR. |
||
263 | |||
264 | Remarks: |
||
265 | None |
||
266 | ***************************************************************************/ |
||
267 | int listen( SOCKET s, int backlog ) |
||
268 | { |
||
269 | struct BSDSocket *ps; |
||
270 | SOCKET clientSockID; |
||
271 | unsigned int socketcount; |
||
272 | unsigned char assigned; |
||
273 | |||
274 | if( s >= BSD_SOCKET_COUNT ) |
||
275 | return SOCKET_ERROR; |
||
276 | |||
277 | ps = &BSDSocketArray[s]; |
||
278 | |||
279 | if(ps->SocketType != SOCK_STREAM) |
||
280 | return SOCKET_ERROR; |
||
281 | |||
282 | if(ps->bsdState == SKT_BSD_LISTEN) |
||
283 | backlog = ps->backlog; |
||
284 | |||
285 | if((ps->bsdState != SKT_BOUND) && (ps->bsdState != SKT_BSD_LISTEN)) |
||
286 | return SOCKET_ERROR; |
||
287 | |||
288 | while(backlog--) |
||
289 | { |
||
290 | assigned = 0; |
||
291 | for(socketcount = 0; socketcount < BSD_SOCKET_COUNT; socketcount++) |
||
292 | { |
||
293 | if(BSDSocketArray[socketcount].bsdState != SKT_CLOSED) |
||
294 | continue; |
||
295 | |||
296 | clientSockID = TCPOpen(0, TCP_OPEN_SERVER, ps->localPort, TCP_PURPOSE_BERKELEY_SERVER); |
||
297 | if(clientSockID == INVALID_SOCKET) |
||
298 | return SOCKET_ERROR; |
||
299 | |||
300 | // Clear the first reset flag |
||
301 | TCPWasReset(clientSockID); |
||
302 | |||
303 | assigned = 1; |
||
304 | ps->bsdState = SKT_BSD_LISTEN; |
||
305 | ps->backlog = backlog; |
||
306 | |||
307 | BSDSocketArray[socketcount].SocketID = clientSockID; |
||
308 | BSDSocketArray[socketcount].bsdState = SKT_LISTEN; |
||
309 | BSDSocketArray[socketcount].isServer = TRUE; |
||
310 | BSDSocketArray[socketcount].localPort = ps->localPort; |
||
311 | BSDSocketArray[socketcount].SocketType = SOCK_STREAM; |
||
312 | break; |
||
313 | } |
||
314 | if(!assigned) |
||
315 | return SOCKET_ERROR; |
||
316 | } |
||
317 | return 0; //Success |
||
318 | } |
||
319 | |||
320 | |||
321 | /***************************************************************************** |
||
322 | Function: |
||
323 | SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) |
||
324 | |||
325 | Summary: |
||
326 | This function accepts connection requests queued for a listening socket. |
||
327 | |||
328 | Description: |
||
329 | The accept function is used to accept connection requests |
||
330 | queued for a listening socket. If a connection request is |
||
331 | pending, accept removes the request from the queue, and a new |
||
332 | socket is created for the connection. The original listening |
||
333 | socket remains open and continues to queue new connection |
||
334 | requests. The socket must be a SOCK_STREAM type socket. |
||
335 | |||
336 | Precondition: |
||
337 | listen function should be called. |
||
338 | |||
339 | Parameters: |
||
340 | s - Socket descriptor returned from a previous call to |
||
341 | socket. must be bound to a local name and in listening mode. |
||
342 | addr - Optional pointer to a buffer that receives the address |
||
343 | of the connecting entity. |
||
344 | addrlen - Optional pointer to an integer that contains the |
||
345 | length of the address addr |
||
346 | |||
347 | Returns: |
||
348 | If the accept function succeeds, it returns a non-negative |
||
349 | integer that is a descriptor for the accepted socket. |
||
350 | Otherwise, the value INVALID_SOCKET is returned. |
||
351 | |||
352 | Remarks: |
||
353 | None. |
||
354 | ***************************************************************************/ |
||
355 | SOCKET accept(SOCKET s, struct sockaddr* addr, int* addrlen) |
||
356 | { |
||
357 | struct BSDSocket *pListenSock; |
||
358 | SOCKET_INFO *remoteSockInfo; |
||
359 | struct sockaddr_in *addrRemote; |
||
360 | unsigned int sockCount; |
||
361 | TCP_SOCKET hTCP; |
||
362 | |||
363 | if( s >= BSD_SOCKET_COUNT ) |
||
364 | return INVALID_SOCKET; |
||
365 | |||
366 | pListenSock = &BSDSocketArray[s]; /* Get the pointer to listening server socket */ |
||
367 | |||
368 | if ( pListenSock->bsdState != SKT_BSD_LISTEN ) |
||
369 | return INVALID_SOCKET; |
||
370 | if ( pListenSock->SocketType != SOCK_STREAM ) |
||
371 | return INVALID_SOCKET; |
||
372 | |||
373 | for(sockCount = 0; sockCount < BSD_SOCKET_COUNT; sockCount++) |
||
374 | { |
||
375 | if(BSDSocketArray[sockCount].bsdState != SKT_LISTEN) |
||
376 | continue; |
||
377 | |||
378 | if(BSDSocketArray[sockCount].localPort != pListenSock->localPort) |
||
379 | continue; |
||
380 | |||
381 | hTCP = BSDSocketArray[sockCount].SocketID; |
||
382 | |||
383 | // We don't care about connections and disconnections before we can |
||
384 | // process them, so clear the reset flag |
||
385 | TCPWasReset(hTCP); |
||
386 | |||
387 | if(TCPIsConnected(hTCP)) |
||
388 | { |
||
389 | remoteSockInfo = TCPGetRemoteInfo(hTCP); |
||
390 | if(addr) |
||
391 | { |
||
392 | if(addrlen) |
||
393 | { |
||
394 | if((unsigned int)*addrlen < sizeof(struct sockaddr_in)) |
||
395 | return INVALID_SOCKET; |
||
396 | addrRemote = (struct sockaddr_in *)addr; |
||
397 | addrRemote->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; |
||
398 | addrRemote->sin_port = remoteSockInfo->remotePort.Val; |
||
399 | *addrlen = sizeof(struct sockaddr_in); |
||
400 | } |
||
401 | } |
||
402 | BSDSocketArray[sockCount].remotePort = remoteSockInfo->remotePort.Val; |
||
403 | BSDSocketArray[sockCount].remoteIP = remoteSockInfo->remote.IPAddr.Val; |
||
404 | BSDSocketArray[sockCount].bsdState = SKT_EST; |
||
405 | return sockCount; |
||
406 | } |
||
407 | } |
||
408 | |||
409 | return INVALID_SOCKET; |
||
410 | } |
||
411 | |||
412 | /***************************************************************************** |
||
413 | Function: |
||
414 | int connect( SOCKET s, struct sockaddr* name, int namelen ) |
||
415 | |||
416 | Summary: |
||
417 | This function connects to the peer communications end point. |
||
418 | |||
419 | Description: |
||
420 | The connect function assigns the address of the peer |
||
421 | communications endpoint. For stream sockets, connection is |
||
422 | established between the endpoints. For datagram sockets, an |
||
423 | address filter is established between the endpoints until |
||
424 | changed with another connect() function. |
||
425 | |||
426 | Precondition: |
||
427 | socket function should be called. |
||
428 | |||
429 | Parameters: |
||
430 | s - Socket descriptor returned from a previous call to socket. |
||
431 | name - pointer to the sockaddr structure containing the |
||
432 | peer address and port number. |
||
433 | namelen - length of the sockaddr structure. |
||
434 | |||
435 | Returns: |
||
436 | If the connect() function succeeds, it returns 0. Otherwise, |
||
437 | the value SOCKET_ERROR is returned to indicate an error |
||
438 | condition. For stream based socket, if the connection is not |
||
439 | established yet, connect returns SOCKET_CNXN_IN_PROGRESS. |
||
440 | |||
441 | Remarks: |
||
442 | None. |
||
443 | ***************************************************************************/ |
||
444 | int connect( SOCKET s, struct sockaddr* name, int namelen ) |
||
445 | { |
||
446 | struct BSDSocket *socket; |
||
447 | struct sockaddr_in *addr; |
||
448 | DWORD remoteIP; |
||
449 | WORD remotePort; |
||
450 | WORD localPort; |
||
451 | |||
452 | if( s >= BSD_SOCKET_COUNT ) |
||
453 | return SOCKET_ERROR; |
||
454 | |||
455 | socket = &BSDSocketArray[s]; |
||
456 | |||
457 | if( socket->bsdState < SKT_CREATED ) |
||
458 | return SOCKET_ERROR; |
||
459 | |||
460 | if( (unsigned int)namelen < sizeof(struct sockaddr_in)) |
||
461 | return SOCKET_ERROR; |
||
462 | |||
463 | addr = (struct sockaddr_in *)name; |
||
464 | remotePort = addr->sin_port; |
||
465 | remoteIP = addr->sin_addr.S_un.S_addr; |
||
466 | |||
467 | if( remoteIP == 0u || remotePort == 0u ) |
||
468 | return SOCKET_ERROR; |
||
469 | |||
470 | if( socket->SocketType == SOCK_STREAM ) |
||
471 | { |
||
472 | switch(socket->bsdState) |
||
473 | { |
||
474 | case SKT_EST: |
||
475 | return 0; // already established |
||
476 | |||
477 | case SKT_IN_PROGRESS: |
||
478 | if(HandlePossibleTCPDisconnection(s)) |
||
479 | return SOCKET_ERROR; |
||
480 | |||
481 | if(!TCPIsConnected(socket->SocketID)) |
||
482 | return SOCKET_CNXN_IN_PROGRESS; |
||
483 | |||
484 | socket->bsdState = SKT_EST; |
||
485 | return 0; //success |
||
486 | |||
487 | case SKT_CREATED: |
||
488 | case SKT_BOUND: |
||
489 | socket->SocketID = TCPOpen(remoteIP, TCP_OPEN_IP_ADDRESS, remotePort, TCP_PURPOSE_BERKELEY_CLIENT); |
||
490 | if(socket->SocketID == INVALID_SOCKET) |
||
491 | return SOCKET_ERROR; |
||
492 | |||
493 | // Clear the first reset flag |
||
494 | TCPWasReset(socket->SocketID); |
||
495 | |||
496 | socket->isServer = FALSE; |
||
497 | socket->bsdState = SKT_IN_PROGRESS; |
||
498 | return SOCKET_CNXN_IN_PROGRESS; |
||
499 | |||
500 | default: |
||
501 | return SOCKET_ERROR; |
||
502 | } |
||
503 | } |
||
504 | else |
||
505 | { |
||
506 | // If not explicitly bound to a local port, implicitly do the binding |
||
507 | if(socket->bsdState == SKT_CREATED) |
||
508 | { |
||
509 | localPort = gAutoPortNumber++; |
||
510 | if(gAutoPortNumber > 5000u) // reset the port numbers |
||
511 | gAutoPortNumber = 1024; |
||
512 | |||
513 | socket->SocketID = UDPOpen(localPort, NULL, remotePort); |
||
514 | if(socket->SocketID == INVALID_UDP_SOCKET) |
||
515 | return SOCKET_ERROR; |
||
516 | socket->bsdState = SKT_BOUND; |
||
517 | } |
||
518 | if(socket->bsdState != SKT_BOUND) |
||
519 | return SOCKET_ERROR; |
||
520 | |||
521 | // UDP: remote port is used as a filter. Need to call connect when using |
||
522 | // send/recv calls. No need to call 'connect' if using sendto/recvfrom |
||
523 | // calls. |
||
524 | socket->remotePort = remotePort; |
||
525 | socket->remoteIP = remoteIP; |
||
526 | return 0; //success |
||
527 | } |
||
528 | return SOCKET_ERROR; |
||
529 | } |
||
530 | |||
531 | /***************************************************************************** |
||
532 | Function: |
||
533 | int send( SOCKET s, const char* buf, int len, int flags ) |
||
534 | |||
535 | Summary: |
||
536 | The send function is used to send outgoing data on an already |
||
537 | connected socket. |
||
538 | |||
539 | Description: |
||
540 | The send function is used to send outgoing data on an already |
||
541 | connected socket. This function is used to send a reliable, |
||
542 | ordered stream of data bytes on a socket of type SOCK_STREAM |
||
543 | but can also be used to send datagrams on a socket of type SOCK_DGRAM. |
||
544 | |||
545 | Precondition: |
||
546 | connect function should be called for TCP and UDP sockets. |
||
547 | Server side, accept function should be called. |
||
548 | |||
549 | Parameters: |
||
550 | s - Socket descriptor returned from a previous call to socket. |
||
551 | buf - application data buffer containing data to transmit. |
||
552 | len - length of data in bytes. |
||
553 | flags - message flags. Currently this field is not supported. |
||
554 | |||
555 | Returns: |
||
556 | On success, send returns number of bytes sent. In case of |
||
557 | error, returns SOCKET_ERROR. a zero indicates no data send. |
||
558 | |||
559 | Remarks: |
||
560 | None. |
||
561 | ***************************************************************************/ |
||
562 | int send( SOCKET s, const char* buf, int len, int flags ) |
||
563 | { |
||
564 | return sendto(s, buf, len, flags, NULL, 0); |
||
565 | } |
||
566 | |||
567 | /***************************************************************************** |
||
568 | Function: |
||
569 | int sendto(SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen) |
||
570 | |||
571 | Summary: |
||
572 | This function used to send the data for both connection oriented and connection-less |
||
573 | sockets. |
||
574 | |||
575 | Description: |
||
576 | The sendto function is used to send outgoing data on a socket. |
||
577 | The destination address is given by to and tolen. Both |
||
578 | Datagram and stream sockets are supported. |
||
579 | |||
580 | Precondition: |
||
581 | socket function should be called. |
||
582 | |||
583 | Parameters: |
||
584 | s - Socket descriptor returned from a previous call to socket. |
||
585 | buf - application data buffer containing data to transmit. |
||
586 | len - length of data in bytes. |
||
587 | flags - message flags. Currently this field is not supported. |
||
588 | to - Optional pointer to the the sockaddr structure containing the |
||
589 | destination address. If NULL, the currently bound remote port and IP |
||
590 | address are used as the destination. |
||
591 | tolen - length of the sockaddr structure. |
||
592 | |||
593 | Returns: |
||
594 | On success, sendto returns number of bytes sent. In case of |
||
595 | error returns SOCKET_ERROR |
||
596 | |||
597 | Remarks: |
||
598 | None. |
||
599 | ***************************************************************************/ |
||
600 | int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen ) |
||
601 | { |
||
602 | struct BSDSocket *socket; |
||
603 | int size = SOCKET_ERROR; |
||
604 | NODE_INFO remoteInfo; |
||
605 | static DWORD startTick; // NOTE: startTick really should be a per socket BSDSocket structure member since other BSD calls can interfere with the ARP cycles |
||
606 | WORD wRemotePort; |
||
607 | struct sockaddr_in local; |
||
608 | |||
609 | if( s >= BSD_SOCKET_COUNT ) |
||
610 | return SOCKET_ERROR; |
||
611 | |||
612 | socket = &BSDSocketArray[s]; |
||
613 | |||
614 | if(socket->bsdState == SKT_CLOSED) |
||
615 | return SOCKET_ERROR; |
||
616 | |||
617 | if(socket->SocketType == SOCK_DGRAM) //UDP |
||
618 | { |
||
619 | // Decide the destination IP address and port |
||
620 | remoteInfo.IPAddr.Val = socket->remoteIP; |
||
621 | wRemotePort = socket->remotePort; |
||
622 | if(to) |
||
623 | { |
||
624 | if((unsigned int)tolen != sizeof(struct sockaddr_in)) |
||
625 | return SOCKET_ERROR; |
||
626 | wRemotePort = ((struct sockaddr_in*)to)->sin_port; |
||
627 | remoteInfo.IPAddr.Val = ((struct sockaddr_in*)to)->sin_addr.s_addr; |
||
628 | |||
629 | // Implicitly bind the socket if it isn't already |
||
630 | if(socket->bsdState == SKT_CREATED) |
||
631 | { |
||
632 | memset(&local, 0x00, sizeof(local)); |
||
633 | if(bind(s, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR) |
||
634 | return SOCKET_ERROR; |
||
635 | } |
||
636 | } |
||
637 | if(remoteInfo.IPAddr.Val == IP_ADDR_ANY) |
||
638 | remoteInfo.IPAddr.Val = 0xFFFFFFFFu; |
||
639 | |||
640 | // Set the remote IP and MAC address if it is different from what we already have stored in the UDP socket |
||
641 | if(UDPSocketInfo[socket->SocketID].remoteNode.IPAddr.Val != remoteInfo.IPAddr.Val) |
||
642 | { |
||
643 | if(ARPIsResolved(&remoteInfo.IPAddr, &remoteInfo.MACAddr)) |
||
644 | { |
||
645 | memcpy((void*)&UDPSocketInfo[socket->SocketID].remoteNode, (void*)&remoteInfo, sizeof(remoteInfo)); |
||
646 | } |
||
647 | else |
||
648 | { |
||
649 | if(TickGet() - startTick > 1*TICK_SECOND) |
||
650 | { |
||
651 | ARPResolve(&remoteInfo.IPAddr); |
||
652 | startTick = TickGet(); |
||
653 | } |
||
654 | return SOCKET_ERROR; |
||
655 | } |
||
656 | } |
||
657 | |||
658 | // Select the UDP socket and see if we can write to it |
||
659 | if(UDPIsPutReady(socket->SocketID)) |
||
660 | { |
||
661 | // Set the proper remote port |
||
662 | UDPSocketInfo[socket->SocketID].remotePort = wRemotePort; |
||
663 | |||
664 | // Write data and send UDP datagram |
||
665 | size = UDPPutArray((BYTE*)buf, len); |
||
666 | UDPFlush(); |
||
667 | return size; |
||
668 | } |
||
669 | } |
||
670 | else if(socket->SocketType == SOCK_STREAM) //TCP will only send to the already established socket. |
||
671 | { |
||
672 | if(socket->bsdState != SKT_EST) |
||
673 | return SOCKET_ERROR; |
||
674 | |||
675 | if(HandlePossibleTCPDisconnection(s)) |
||
676 | return SOCKET_ERROR; |
||
677 | |||
678 | // Handle special case were 0 return value is okay |
||
679 | if(len == 0) |
||
680 | return 0; |
||
681 | |||
682 | // Write data to the socket. If one or more bytes were written, then |
||
683 | // return this value. Otherwise, fail and return SOCKET_ERROR. |
||
684 | size = TCPPutArray(socket->SocketID, (BYTE*)buf, len); |
||
685 | if(size) |
||
686 | return size; |
||
687 | } |
||
688 | return SOCKET_ERROR; |
||
689 | } |
||
690 | |||
691 | /***************************************************************************** |
||
692 | Function: |
||
693 | int recv( SOCKET s, char* buf, int len, int flags ) |
||
694 | |||
695 | Summary: |
||
696 | The recv() function is used to receive incoming data that has |
||
697 | been queued for a socket. |
||
698 | |||
699 | Description: |
||
700 | The recv() function is used to receive incoming data that has |
||
701 | been queued for a socket. This function can be used with both |
||
702 | datagram and stream socket. If the available data |
||
703 | is too large to fit in the supplied application buffer buf, |
||
704 | excess bytes are discarded in case of SOCK_DGRAM type |
||
705 | sockets. For SOCK_STREAM types, the data is buffered |
||
706 | internally so the application can retreive all data by |
||
707 | multiple calls of recvfrom. |
||
708 | |||
709 | Precondition: |
||
710 | connect function should be called for TCP and UDP sockets. |
||
711 | Server side, accept function should be called. |
||
712 | |||
713 | Parameters: |
||
714 | s - Socket descriptor returned from a previous call to socket. |
||
715 | buf - application data receive buffer. |
||
716 | len - buffer length in bytes. |
||
717 | flags - no significance in this implementation |
||
718 | |||
719 | Returns: |
||
720 | If recv is successful, the number of bytes copied to |
||
721 | application buffer buf is returned. A value of zero indicates |
||
722 | no data available. A return value of SOCKET_ERROR (-1) |
||
723 | indicates an error condition. A return value of SOCKET_DISCONNECTED |
||
724 | indicates the connection no longer exists. |
||
725 | |||
726 | Remarks: |
||
727 | None. |
||
728 | ***************************************************************************/ |
||
729 | int recv( SOCKET s, char* buf, int len, int flags ) |
||
730 | { |
||
731 | struct BSDSocket *socket; |
||
732 | |||
733 | if( s >= BSD_SOCKET_COUNT ) |
||
734 | return SOCKET_ERROR; |
||
735 | |||
736 | socket = &BSDSocketArray[s]; |
||
737 | |||
738 | if(socket->SocketType == SOCK_STREAM) //TCP |
||
739 | { |
||
740 | if(socket->bsdState != SKT_EST) |
||
741 | return SOCKET_ERROR; |
||
742 | |||
743 | if(HandlePossibleTCPDisconnection(s)) |
||
744 | return SOCKET_ERROR; |
||
745 | |||
746 | return TCPGetArray(socket->SocketID, (BYTE*)buf, len); |
||
747 | } |
||
748 | else if(socket->SocketType == SOCK_DGRAM) //UDP |
||
749 | { |
||
750 | if(socket->bsdState != SKT_BOUND) |
||
751 | return SOCKET_ERROR; |
||
752 | |||
753 | if(UDPIsGetReady(socket->SocketID)) |
||
754 | return UDPGetArray((BYTE*)buf, len); |
||
755 | } |
||
756 | |||
757 | return 0; |
||
758 | } |
||
759 | |||
760 | /***************************************************************************** |
||
761 | Function: |
||
762 | int recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen) |
||
763 | |||
764 | Summary: |
||
765 | The recvfrom() function is used to receive incoming data that |
||
766 | has been queued for a socket. |
||
767 | |||
768 | Description: |
||
769 | The recvfrom() function is used to receive incoming data that |
||
770 | has been queued for a socket. This function can be used with |
||
771 | both datagram and stream type sockets. If the available data |
||
772 | is too large to fit in the supplied application buffer buf, |
||
773 | excess bytes are discarded in case of SOCK_DGRAM type |
||
774 | sockets. For SOCK_STREAM types, the data is buffered |
||
775 | internally so the application can retreive all data by |
||
776 | multiple calls of recvfrom. |
||
777 | |||
778 | Precondition: |
||
779 | socket function should be called. |
||
780 | |||
781 | Parameters: |
||
782 | s - Socket descriptor returned from a previous call to socket. |
||
783 | buf - application data receive buffer. |
||
784 | len - buffer length in bytes. |
||
785 | flags - message flags. Currently this is not supported. |
||
786 | from - pointer to the sockaddr structure that will be |
||
787 | filled in with the destination address. |
||
788 | fromlen - size of buffer pointed by from. |
||
789 | |||
790 | Returns: |
||
791 | If recvfrom is successful, the number of bytes copied to |
||
792 | application buffer buf is returned. A value of zero indicates |
||
793 | no data available. A return value of SOCKET_ERROR (-1) |
||
794 | indicates an error condition. |
||
795 | |||
796 | Remarks: |
||
797 | None. |
||
798 | ***************************************************************************/ |
||
799 | int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen ) |
||
800 | { |
||
801 | struct BSDSocket *socket; |
||
802 | struct sockaddr_in *rem_addr; |
||
803 | SOCKET_INFO *remoteSockInfo; |
||
804 | |||
805 | socket = &BSDSocketArray[s]; |
||
806 | rem_addr = (struct sockaddr_in *)from; |
||
807 | |||
808 | if(socket->SocketType == SOCK_DGRAM) //UDP |
||
809 | { |
||
810 | // If this BSD socket doesn't have a Microchip UDP socket associated |
||
811 | // with it yet, then no data can be received and we must not use the |
||
812 | // socket->SocketID parameter, which isn't set yet. |
||
813 | if(socket->bsdState != SKT_BOUND) |
||
814 | return 0; |
||
815 | |||
816 | if(UDPIsGetReady(socket->SocketID)) |
||
817 | { |
||
818 | // Capture sender information (can change packet to packet) |
||
819 | if(from && fromlen) |
||
820 | { |
||
821 | if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) |
||
822 | { |
||
823 | rem_addr->sin_addr.S_un.S_addr = UDPSocketInfo[socket->SocketID].remoteNode.IPAddr.Val; |
||
824 | rem_addr->sin_port = UDPSocketInfo[socket->SocketID].remotePort; |
||
825 | *fromlen = sizeof(struct sockaddr_in); |
||
826 | } |
||
827 | } |
||
828 | |||
829 | return UDPGetArray((BYTE*)buf, len); |
||
830 | } |
||
831 | } |
||
832 | else //TCP recieve from already connected socket. |
||
833 | { |
||
834 | if(from && fromlen) |
||
835 | { |
||
836 | // Capture sender information (will always match socket connection information) |
||
837 | if((unsigned int)*fromlen >= sizeof(struct sockaddr_in)) |
||
838 | { |
||
839 | remoteSockInfo = TCPGetRemoteInfo(socket->SocketID); |
||
840 | rem_addr->sin_addr.S_un.S_addr = remoteSockInfo->remote.IPAddr.Val; |
||
841 | rem_addr->sin_port = remoteSockInfo->remotePort.Val; |
||
842 | *fromlen = sizeof(struct sockaddr_in); |
||
843 | } |
||
844 | } |
||
845 | return recv(s, buf, len, 0); |
||
846 | } |
||
847 | return 0; |
||
848 | } |
||
849 | |||
850 | /***************************************************************************** |
||
851 | Function: |
||
852 | int gethostname(char* name, int namelen ) |
||
853 | |||
854 | Summary: |
||
855 | Returns the standard host name for the system. |
||
856 | |||
857 | Description: |
||
858 | This function returns the standard host name of the system which is |
||
859 | calling this function. The returned name is null-terminated. |
||
860 | |||
861 | Precondition: |
||
862 | None. |
||
863 | |||
864 | Parameters: |
||
865 | name - Pointer to a buffer that receives the local host name. |
||
866 | namelen - size of the name array. |
||
867 | |||
868 | Returns: |
||
869 | Success will return a value of 0. |
||
870 | If name is too short to hold the host name or any other error occurs, |
||
871 | SOCKET_ERROR (-1) will be returned. On error, *name will be unmodified |
||
872 | and no null terminator will be generated. |
||
873 | |||
874 | Remarks: |
||
875 | None. |
||
876 | ***************************************************************************/ |
||
877 | int gethostname(char* name, int namelen) |
||
878 | { |
||
879 | WORD wSourceLen; |
||
880 | WORD w; |
||
881 | BYTE v; |
||
882 | |||
883 | wSourceLen = sizeof(AppConfig.NetBIOSName); |
||
884 | for(w = 0; w < wSourceLen; w++) |
||
885 | { |
||
886 | v = AppConfig.NetBIOSName[w]; |
||
887 | if((v == ' ') || (v == 0u)) |
||
888 | break; |
||
889 | } |
||
890 | wSourceLen = w; |
||
891 | if(namelen < (int)wSourceLen + 1) |
||
892 | return SOCKET_ERROR; |
||
893 | |||
894 | memcpy((void*)name, (void*)AppConfig.NetBIOSName, wSourceLen); |
||
895 | name[wSourceLen] = 0; |
||
896 | |||
897 | return 0; |
||
898 | } |
||
899 | |||
900 | /***************************************************************************** |
||
901 | Function: |
||
902 | int closesocket( SOCKET s ) |
||
903 | |||
904 | Summary: |
||
905 | The closesocket function closes an existing socket. |
||
906 | |||
907 | Description: |
||
908 | The closesocket function closes an existing socket. |
||
909 | This function releases the socket descriptor s. |
||
910 | Any data buffered at the socket is discarded. If the |
||
911 | socket s is no longer needed, closesocket() must be |
||
912 | called in order to release all resources associated with s. |
||
913 | |||
914 | Precondition: |
||
915 | None. |
||
916 | |||
917 | Parameters: |
||
918 | s - Socket descriptor returned from a previous call to socket |
||
919 | |||
920 | Returns: |
||
921 | If closesocket is successful, a value of 0 is returned. |
||
922 | A return value of SOCKET_ERROR (-1) indicates an error. |
||
923 | |||
924 | Remarks: |
||
925 | None. |
||
926 | ***************************************************************************/ |
||
927 | int closesocket( SOCKET s ) |
||
928 | { |
||
929 | BYTE i; |
||
930 | struct BSDSocket *socket; |
||
931 | |||
932 | if( s >= BSD_SOCKET_COUNT ) |
||
933 | return SOCKET_ERROR; |
||
934 | |||
935 | socket = &BSDSocketArray[s]; |
||
936 | |||
937 | if(socket->bsdState == SKT_CLOSED) |
||
938 | return 0; // Nothing to do, so return success |
||
939 | |||
940 | if(socket->SocketType == SOCK_STREAM) |
||
941 | { |
||
942 | if(socket->bsdState == SKT_BSD_LISTEN) |
||
943 | { |
||
944 | // This is a listerner handle, so when we close it we also should |
||
945 | // close all TCP sockets that were opened for backlog processing |
||
946 | // but didn't actually get connected |
||
947 | for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++) |
||
948 | { |
||
949 | if(BSDSocketArray[i].bsdState != SKT_LISTEN) |
||
950 | continue; |
||
951 | if(BSDSocketArray[i].localPort == socket->localPort) |
||
952 | { |
||
953 | TCPClose(BSDSocketArray[i].SocketID); |
||
954 | BSDSocketArray[i].bsdState = SKT_CLOSED; |
||
955 | } |
||
956 | } |
||
957 | } |
||
958 | else if(socket->bsdState >= SKT_LISTEN) |
||
959 | { |
||
960 | // For server sockets, if the parent listening socket is still open, |
||
961 | // then return this socket to the queue for future backlog processing. |
||
962 | if(socket->isServer) |
||
963 | { |
||
964 | for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++) |
||
965 | { |
||
966 | if(BSDSocketArray[i].bsdState != SKT_BSD_LISTEN) |
||
967 | continue; |
||
968 | if(BSDSocketArray[i].localPort == socket->localPort) |
||
969 | { |
||
970 | TCPDisconnect(socket->SocketID); |
||
971 | |||
972 | // Listener socket is still open, so just return to the |
||
973 | // listening state so that the user must call accept() again to |
||
974 | // reuse this BSD socket |
||
975 | socket->bsdState = SKT_LISTEN; |
||
976 | return 0; |
||
977 | } |
||
978 | } |
||
979 | // If we get down here, then the parent listener socket has |
||
980 | // apparently already been closed, so this socket can not be |
||
981 | // reused. Close it complete. |
||
982 | TCPClose(socket->SocketID); |
||
983 | } |
||
984 | else if(socket->bsdState != SKT_DISCONNECTED) // this is a client socket that isn't already disconnected |
||
985 | { |
||
986 | TCPClose(socket->SocketID); |
||
987 | } |
||
988 | } |
||
989 | } |
||
990 | else //udp sockets |
||
991 | { |
||
992 | if(socket->bsdState == SKT_BOUND) |
||
993 | UDPClose(socket->SocketID); |
||
994 | } |
||
995 | |||
996 | socket->bsdState = SKT_CLOSED; |
||
997 | return 0; //success |
||
998 | } |
||
999 | |||
1000 | |||
1001 | /***************************************************************************** |
||
1002 | Function: |
||
1003 | static BOOL HandlePossibleTCPDisconnection(SOCKET s) |
||
1004 | |||
1005 | Summary: |
||
1006 | Internal function that checks for asynchronous TCP connection state |
||
1007 | changes and resynchs the BSD socket descriptor state to match. |
||
1008 | |||
1009 | Description: |
||
1010 | Internal function that checks for asynchronous TCP connection state |
||
1011 | changes and resynchs the BSD socket descriptor state to match. |
||
1012 | |||
1013 | Precondition: |
||
1014 | None |
||
1015 | |||
1016 | Parameters: |
||
1017 | s - TCP type socket descriptor returned from a previous call to socket. |
||
1018 | This socket must be in the SKT_LISTEN, SKT_IN_PROGRESS, SKT_EST, or |
||
1019 | SKT_DISCONNECTED states. |
||
1020 | |||
1021 | Returns: |
||
1022 | TRUE - Socket is disconnected |
||
1023 | FALSE - Socket is |
||
1024 | |||
1025 | ***************************************************************************/ |
||
1026 | static BOOL HandlePossibleTCPDisconnection(SOCKET s) |
||
1027 | { |
||
1028 | struct BSDSocket *socket; |
||
1029 | BYTE i; |
||
1030 | BOOL bSocketWasReset; |
||
1031 | |||
1032 | socket = &BSDSocketArray[s]; |
||
1033 | |||
1034 | // Nothing to do if disconnection has already been handled |
||
1035 | if(socket->bsdState == SKT_DISCONNECTED) |
||
1036 | return TRUE; |
||
1037 | |||
1038 | // Find out if a disconnect has occurred |
||
1039 | bSocketWasReset = TCPWasReset(socket->SocketID); |
||
1040 | |||
1041 | // For server sockets, if the parent listening socket is still open, |
||
1042 | // then return this socket to the queue for future backlog processing. |
||
1043 | if(socket->isServer) |
||
1044 | { |
||
1045 | for(i = 0; i < sizeof(BSDSocketArray)/sizeof(BSDSocketArray[0]); i++) |
||
1046 | { |
||
1047 | if(BSDSocketArray[i].bsdState != SKT_BSD_LISTEN) |
||
1048 | continue; |
||
1049 | if(BSDSocketArray[i].localPort == socket->localPort) |
||
1050 | { |
||
1051 | // Nothing to do if a disconnect has not occurred |
||
1052 | if(!bSocketWasReset) |
||
1053 | return FALSE; |
||
1054 | |||
1055 | // Listener socket is still open, so just return to the |
||
1056 | // listening state so that the user must call accept() again to |
||
1057 | // reuse this BSD socket |
||
1058 | socket->bsdState = SKT_LISTEN; |
||
1059 | return TRUE; |
||
1060 | } |
||
1061 | } |
||
1062 | } |
||
1063 | |||
1064 | // If we get down here and the socket was reset, then this socket |
||
1065 | // should be closed so that no more clients can connect to it. However, |
||
1066 | // we can't go to the BSD SKT_CLOSED state directly since the user still |
||
1067 | // has to call closesocket() with this s SOCKET descriptor first. |
||
1068 | if(bSocketWasReset) |
||
1069 | { |
||
1070 | TCPClose(socket->SocketID); |
||
1071 | socket->bsdState = SKT_DISCONNECTED; |
||
1072 | return TRUE; |
||
1073 | } |
||
1074 | |||
1075 | return FALSE; |
||
1076 | } |
||
1077 | |||
1078 | #endif //STACK_USE_BERKELEY_API |
||
1079 |
Powered by WebSVN v2.8.3