APUE Learning Example Source Code
guowenxue
2020-04-30 b0053f87034ff358b7ccadc7f2d9643e9a7767e7
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/********************************************************************************
 *      Copyright:  (C) 2020 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  socket.h
 *    Description:  This head file is for socket API
 *
 *        Version:  1.0.0(2020年04月16日)
 *         Author:  Guo Wenxue <guowenxue@gmail.com>
 *      ChangeLog:  1, Release initial version on "2020年04月16日 13时45分33秒"
 *                 
 ********************************************************************************/
#ifndef  _SOCKET_H_
#define  _SOCKET_H_
 
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/un.h>
#include <poll.h>
#include <errno.h> 
 
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
 
#include <sys/epoll.h>
#include <sys/resource.h>
 
#include "list.h"
 
#define HOSTNAME_LEN         128
 
enum
{
    SOCK_TYPE_LISTEN,  /* listen  socket */
    SOCK_TYPE_ACCEPT,  /* accept  socket */
    SOCK_TYPE_CONNECT, /* connect socket */
};
 
enum
{
    SOCK_STAT_UNINIT     = 0,  /* socket not initial */
    SOCK_STAT_INIT       = 1,  /* socket initialed */
 
    SOCK_STAT_CONNECTING = 2,  /* socket connecting in non-block mode */
 
    SOCK_STAT_CONNECTED  = 3,  /* socket connected in client mdoe */
    SOCK_STAT_LISTENED   = 3,  /* socket listened  in server mode */
    SOCK_STAT_ACCEPTED   = 3,  /* socket already accepted */
};
 
typedef struct socket_s
{
    int            fd;          /* socket fd  */ 
    uint8_t        type;        /* socket type: listen, accept or accept */
    uint8_t        status;      /* socket status: SOCK_STAT_INIT,SOCK_STAT_CONNECTED... */
    
    /* socket server/client IP address and port */
    char           raddr[HOSTNAME_LEN];  /* remote IP address or domain name */ 
    char           laddr[HOSTNAME_LEN];  /* local IP address */ 
    uint16_t       lport;                /* local listen port */ 
    uint16_t       rport;                /* remote connected port */ 
 
    /* socket heartbeat settings  */
    int            keepintvl;   /* keepalive detect interval */ 
    int            keepcnt;     /* keepalive count */ 
 
    struct sockaddr  saddr;     /* sockaddr for connect */ 
 
    struct list_head list;      /* socket server manage client link list */
} socket_t;
 
 
/*+-------------------------------------------------------------------+
 *|           client/server  socket API functions                     |
 *+-------------------------------------------------------------------+*/
 
/*  description: initialise socket context and create socket fd if sepecified
 *   input args: $sock: socket context 
 *               $type: SOCK_TYPE_LISTEN, SOCK_TYPE_ACCEPT or SOCK_TYPE_CONNEC
 *               $create: call socket() create or not
 * return value: <0: failure  0: successfully
 */                           
enum 
{
    SOCK_NOT_CREATE,
    SOCK_CREATE,
};
int socket_init(socket_t *sock, uint8_t type, int create);
 
 
/*  description: close socket and set socket status as SOCK_STAT_INIT 
 *   input args: $sock: socket context
 * return value: <0: failure  0: successfully
 */
int socket_close(socket_t *sock);
 
 
/*  description: close socket
 *   input args: $sock: socket context
 *               $lport: specify use local port $lport to connect remote server
 *               $host: IP address and port, format as "host:port", such as "127.0.0.1:8000"
 *              $block: block mode(1) or none-block(0)
 *return value:  <0: error   0: connecing in non-block mode   1:connected
 */
enum 
{
    MODE_NONBLOCK,
    MODE_BLOCK,
};
int socket_connect(socket_t *sock, int lport, char *host, int block);
 
 
/*  description: create socket and listen on port $port
 *   input args: $sock: socket context
 *                 $ip: listen IP address, NULL for any address
 *               $port: listen port
 * return value: <0: failure  0: successfully
 */
int socket_listen(socket_t *sock, char *ipaddr, int port);
 
 
/*  description: accept a new client socket
 *   input args: $sock: socket context
 *               $listenfd: listen socket fd
 * return value: <0: failure  0: successfully
 */
int socket_accept(socket_t *sock, int listenfd);
 
/*  description: send data to the socket, make sure all data send over. 
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 * return value: <0: failure  0: successfully
 */
int socket_send(socket_t *sock, char *data, int bytes);
 
 
/*  description: receive data from the socket in some time
 *   input args: $sock: socket context
 *               $data: send data
 *               $bytes: data size
 *               $timeout: receive data time, <=0 will don't timeout
 * return value: <0: error  >=0: receive data bytes;
 */
int socket_recv(socket_t *sock, char *buf, int size, int timeout);
 
 
/*  description: create epoll for socket server and add listenfd into it
 *   input args: $max_evts:  max events for epoll_create()
 *               $listenfd:  listen socket fd
 * return value: <0: failure  >=0: epollfd
 */ 
int epoll_init(int max_evts, int listenfd);
 
/*  description: add new fd into epoll to monitor
 *   input args: $epollfd:  epoll fd
 *               $fd:       socket fd need added into epoll
 * return value: <0: failure  0: successfully
 */ 
inline int epoll_add(int epollfd, int fd);
 
static inline int epoll_del(int epollfd, int fd)
{
    return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
}
 
/*+-------------------------------------------------------------------+
 *|                socket utils function                              |
 *+-------------------------------------------------------------------+*/
 
/*  description: parser hostname and port from $host and set it into $sock 
 *   input args: $sock: socket context
 *               $host: connect hostname, format as "hostname:port"
 */
int parser_host_port(socket_t *sock, char *host);
 
 
/* description: set socket listen port as reusable, fix port already used bug  */
int socket_set_reuseaddr(int sockfd);
 
/* set socket as non-block mode, common socket default work as block mode */
int socket_set_nonblock(int sockfd);
 
/* set socket receive and send buffer size in linux kernel space */
int socket_set_buffer(int sockfd, int rsize, int ssize);
 
/* set heartbeat keepalive  */
int socket_set_keepalive(int sockfd, int keepintvl, int keepcnt);
 
/*  Set open file description count to max */
void set_socket_rlimit(void);
 
#endif   /* ----- #ifndef _SOCKET_H_  ----- */