v0.3.4 - add to socket protocol keys with optional number arguments like key[1]=value

This commit is contained in:
Edward Emelianov 2025-11-06 15:31:59 +03:00
parent 9e285bbe34
commit 56ee64dd78
7 changed files with 143 additions and 20 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 4.0) cmake_minimum_required(VERSION 4.0)
set(PROJ usefull_macros) set(PROJ usefull_macros)
set(MINOR_VERSION "3") set(MINOR_VERSION "4")
set(MID_VERSION "3") set(MID_VERSION "3")
set(MAJOR_VERSION "0") set(MAJOR_VERSION "0")
set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}")

View File

@ -1,3 +1,12 @@
Thu Nov 6 11:25:07 MSK 2025
VERSION 0.3.4:
add data type:
- sl_sock_keyno_t - number of key (like key[keyno] = val) using in sl_sock_hitem_t.data
add functions:
- sl_sock_keyno_init - init keyno (or use macro SL_SOCK_KEYNO_DEFAUL in assignment)
- sl_sock_keyno_check - return -1 if there's no keyno, else return its value
New functional listed in examples/clientserver.c introducing key `flags` that allows to work with bit flags as a whole or by bits like flags[1]=1, flags21=0, flags{31} or flags(14)...
Wed Sep 10 14:19:24 MSK 2025 Wed Sep 10 14:19:24 MSK 2025
(still version 0.3.3: I forgot to add changelog last commits) (still version 0.3.3: I forgot to add changelog last commits)
- fixed minor bugs and memory leaks - fixed minor bugs and memory leaks

View File

@ -122,6 +122,7 @@ static void runclient(sl_sock_t *s){
static sl_sock_int_t iflag = {0}; static sl_sock_int_t iflag = {0};
static sl_sock_double_t dflag = {0}; static sl_sock_double_t dflag = {0};
static sl_sock_string_t sflag = {0}; static sl_sock_string_t sflag = {0};
static uint32_t bitflags = 0;
static sl_sock_hresult_e dtimeh(sl_sock_t _U_ *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){ static sl_sock_hresult_e dtimeh(sl_sock_t _U_ *client, _U_ sl_sock_hitem_t *item, _U_ const char *req){
char buf[32]; char buf[32];
@ -169,6 +170,7 @@ static void disconnected(sl_sock_t *c){
if(c->type == SOCKT_UNIX) LOGMSG("Disconnected client fd=%d", c->fd); if(c->type == SOCKT_UNIX) LOGMSG("Disconnected client fd=%d", c->fd);
else LOGMSG("Disconnected client fd=%d, IP=%s", c->fd, c->IP); else LOGMSG("Disconnected client fd=%d, IP=%s", c->fd, c->IP);
} }
// default (unknown key) handler
static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){ static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){
if(!s || !str) return RESULT_FAIL; if(!s || !str) return RESULT_FAIL;
sl_sock_sendstrmessage(s, "You entered wrong command:\n```\n"); sl_sock_sendstrmessage(s, "You entered wrong command:\n```\n");
@ -176,6 +178,33 @@ static sl_sock_hresult_e defhandler(struct sl_sock *s, const char *str){
sl_sock_sendstrmessage(s, "\n```\nTry \"help\"\n"); sl_sock_sendstrmessage(s, "\n```\nTry \"help\"\n");
return RESULT_SILENCE; return RESULT_SILENCE;
} }
// if we use this macro, there's no need to run `sl_sock_keyno_init` later
static sl_sock_keyno_t kph_number = SL_SOCK_KEYNO_DEFAULT;
// handler for key with optional parameter number
static sl_sock_hresult_e keyparhandler(struct sl_sock *s, sl_sock_hitem_t *item, const char *req){
if(!item->data) return RESULT_FAIL;
char buf[1024];
int no = sl_sock_keyno_check((sl_sock_keyno_t*)item->data);
long long newval = -1;
if(req){
if(!sl_str2ll(&newval, req) || newval < 0 || newval > 0xffffffff) return RESULT_BADVAL;
}
printf("no = %d\n", no);
if(no < 0){ // flags as a whole
if(req) bitflags = (uint32_t)newval;
snprintf(buf, 1023, "flags = 0x%08X\n", bitflags);
sl_sock_sendstrmessage(s, buf);
}else if(no < 32){ // bit access
int bitmask = 1 << no;
if(req){
if(newval) bitflags |= bitmask;
else bitflags &= ~bitmask;
}
snprintf(buf, 1023, "flags[%d] = %d\n", no, bitflags & bitmask ? 1 : 0);
sl_sock_sendstrmessage(s, buf);
}else return RESULT_BADKEY;
return RESULT_SILENCE;
}
static sl_sock_hitem_t handlers[] = { static sl_sock_hitem_t handlers[] = {
{sl_sock_inthandler, "int", "set/get integer flag", (void*)&iflag}, {sl_sock_inthandler, "int", "set/get integer flag", (void*)&iflag},
@ -183,6 +212,7 @@ static sl_sock_hitem_t handlers[] = {
{sl_sock_strhandler, "str", "set/get string variable", (void*)&sflag}, {sl_sock_strhandler, "str", "set/get string variable", (void*)&sflag},
{show, "show", "show current flags @ server console", NULL}, {show, "show", "show current flags @ server console", NULL},
{dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL}, {dtimeh, "dtime", "get server's UNIX time for all clients connected", NULL},
{keyparhandler, "flags", "set/get bit flags as whole (flags=val) or by bits (flags[bit]=val)", (void*)&kph_number},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -193,6 +223,7 @@ int main(int argc, char **argv){
if(!G.node) ERRX("Point node"); if(!G.node) ERRX("Point node");
sl_socktype_e type = (G.isunix) ? SOCKT_UNIX : SOCKT_NET; sl_socktype_e type = (G.isunix) ? SOCKT_UNIX : SOCKT_NET;
if(G.isserver){ if(G.isserver){
//sl_sock_keyno_init(&kph_number); // don't forget to init first or use macro in initialisation
s = sl_sock_run_server(type, G.node, -1, handlers); s = sl_sock_run_server(type, G.node, -1, handlers);
} else { } else {
sl_setup_con(); sl_setup_con();

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 12:08+0300\n" "POT-Creation-Date: 2025-11-06 15:03+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -121,35 +121,35 @@ msgstr ""
msgid "Server disconnected" msgid "Server disconnected"
msgstr "" msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:385 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:434
msgid "Can't start server handlers thread" msgid "Can't start server handlers thread"
msgstr "" msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:454 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:503
msgid "Limit of connections reached" msgid "Limit of connections reached"
msgstr "" msgstr ""
#. check for RB overflow #. check for RB overflow
#. -1 - buffer empty (can't be), -2 - buffer overflow #. -1 - buffer empty (can't be), -2 - buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:498 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:547
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:499 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:548
#, c-format #, c-format
msgid "Server thread: ring buffer overflow for fd=%d" msgid "Server thread: ring buffer overflow for fd=%d"
msgstr "" msgstr ""
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:513 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:562
#, c-format #, c-format
msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d" msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d"
msgstr "" msgstr ""
#. buffer overflow #. buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:525 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:574
#, c-format #, c-format
msgid "Server thread: buffer overflow from fd=%d" msgid "Server thread: buffer overflow from fd=%d"
msgstr "" msgstr ""
#. never reached #. never reached
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:615 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:664
#, c-format #, c-format
msgid "Unsupported socket type %d" msgid "Unsupported socket type %d"
msgstr "" msgstr ""

View File

@ -7,7 +7,7 @@
msgid "" msgid ""
msgstr "Project-Id-Version: PACKAGE VERSION\n" msgstr "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-09-10 12:08+0300\n" "POT-Creation-Date: 2025-11-06 14:57+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -33,7 +33,7 @@ msgstr "sl_conf_showhelp():
#: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:322 #: /home/eddy/Docs/SAO/C_diff/snippets_library/config.c:322
#, c-format #, c-format
msgid "Configuration file options (format: key=value):\n" msgid "Configuration file options (format: key=value):\n"
msgstr "" msgstr "ïÐÃÉÉ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÏÇÏ ÆÁÊÌÁ (ÆÏÒÍÁÔ: ËÌÀÞ=ÚÎÁÞÅÎÉÅ):\n"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:69 #: /home/eddy/Docs/SAO/C_diff/snippets_library/daemon.c:69
#, c-format #, c-format
@ -120,36 +120,36 @@ msgstr "
msgid "Server disconnected" msgid "Server disconnected"
msgstr "óÅÒ×ÅÒ ÏÔËÌÀÞÅÎ" msgstr "óÅÒ×ÅÒ ÏÔËÌÀÞÅÎ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:385 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:434
msgid "Can't start server handlers thread" msgid "Can't start server handlers thread"
msgstr "îÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ ÐÏÔÏË-ÏÂÒÁÂÏÔÞÉË ÓÅÒ×ÅÒÁ" msgstr "îÅ ÍÏÇÕ ÚÁÐÕÓÔÉÔØ ÐÏÔÏË-ÏÂÒÁÂÏÔÞÉË ÓÅÒ×ÅÒÁ"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:454 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:503
msgid "Limit of connections reached" msgid "Limit of connections reached"
msgstr "äÏÓÔÉÇÎÕÔ ÐÒÅÄÅÌ ÓÏÅÄÉÎÅÎÉÊ" msgstr "äÏÓÔÉÇÎÕÔ ÐÒÅÄÅÌ ÓÏÅÄÉÎÅÎÉÊ"
#. check for RB overflow #. check for RB overflow
#. -1 - buffer empty (can't be), -2 - buffer overflow #. -1 - buffer empty (can't be), -2 - buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:498 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:547
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:499 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:548
#, c-format #, c-format
msgid "Server thread: ring buffer overflow for fd=%d" msgid "Server thread: ring buffer overflow for fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d" msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d"
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:513 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:562
#, c-format #, c-format
msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d" msgid "Server thread: can't write data to ringbuffer: overflow from fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÎÅ ÍÏÇÕ ÓÏÈÒÁÎÉÔØ ÄÁÎÎÙÅ × ËÏÌØÃÅ×ÏÍ ÂÕÆÅÒÅ, " msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÎÅ ÍÏÇÕ ÓÏÈÒÁÎÉÔØ ÄÁÎÎÙÅ × ËÏÌØÃÅ×ÏÍ ÂÕÆÅÒÅ, "
"ÐÅÒÅÐÏÌÎÅÎÉÅ ÏÔ fd=%d" "ÐÅÒÅÐÏÌÎÅÎÉÅ ÏÔ fd=%d"
#. buffer overflow #. buffer overflow
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:525 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:574
#, c-format #, c-format
msgid "Server thread: buffer overflow from fd=%d" msgid "Server thread: buffer overflow from fd=%d"
msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d" msgstr "ðÏÔÏË ÓÅÒ×ÅÒÁ: ÐÅÒÅÐÏÌÎÅÎÉÅ ÂÕÆÅÒÁ ÏÔ fd=%d"
#. never reached #. never reached
#: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:615 #: /home/eddy/Docs/SAO/C_diff/snippets_library/socket.c:664
#, c-format #, c-format
msgid "Unsupported socket type %d" msgid "Unsupported socket type %d"
msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÓÏËÅÔÁ %d" msgstr "îÅÐÏÄÄÅÒÖÉ×ÁÅÍÙÊ ÔÉÐ ÓÏËÅÔÁ %d"

View File

@ -16,8 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ctype.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <ctype.h>
#include <inttypes.h>
#include <netdb.h> #include <netdb.h>
#include <poll.h> #include <poll.h>
#include <stdio.h> #include <stdio.h>
@ -25,7 +26,6 @@
#include <strings.h> #include <strings.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/un.h> // unix socket #include <sys/un.h> // unix socket
#include <inttypes.h>
#include <unistd.h> #include <unistd.h>
#include "usefull_macros.h" #include "usefull_macros.h"
@ -345,10 +345,59 @@ static sl_sock_hresult_e msgparser(sl_sock_t *client, char *str){
sl_sock_sendbyte(client, '\n'); sl_sock_sendbyte(client, '\n');
return RESULT_SILENCE; return RESULT_SILENCE;
} }
// check for strict params like `key=val`
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){ for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
if(strcmp(h->key, key)) continue; if(strcmp(h->key, key)) continue;
if(h->data){
sl_sock_keyno_t *kn = (sl_sock_keyno_t*)h->data;
if(-1 == isinf(kn->magick)) kn->n = -1; // no value number
}
return h->handler(client, h, valptr); return h->handler(client, h, valptr);
} }
// now check for optional key's number like key0=val, key[1]=val, key(2)=val or key{3}=val
int keylen = strlen(key);
char *numstart = NULL;
const char *bra = "([{", *ket = ")]}";
char *found = strchr(ket, key[keylen - 1]);
DBG("found=%s", found);
if(found){
char *keyend = strchr(key, bra[found - ket]); // find starting bracket
DBG("keyend=%s", keyend);
if(keyend){
numstart = keyend + 1;
keylen = keyend - key;
}
}else{ // maybe this is key123=val ?
numstart = &key[keylen-1];
while(numstart > key && isdigit(*numstart)) --numstart;
if(numstart == &key[keylen-1]) numstart = NULL;
else{
keylen = (++numstart) - key;
DBG("numstart=%s", numstart);
}
}
if(numstart){
char *eptr;
long long LL = strtoll(numstart, &eptr, 0);
DBG("LL=%lld, len=%d", LL, keylen);
if(eptr != numstart && LL >= 0 && LL <= INT_MAX){
int parno = (int)LL;
for(sl_sock_hitem_t *h = client->handlers; h->handler; ++h){
if(strncmp(h->key, key, keylen)) continue; // now search only in first `keylen` bytes
DBG("found %s", h->key);
if(h->data){
sl_sock_keyno_t *kn = (sl_sock_keyno_t*)h->data;
if(-1 == isinf(kn->magick)){
kn->n = parno;
DBG("run handler, parno=%d", parno);
return h->handler(client, h, valptr);
}
}
DBG("NO data");
break;
}
}
}
if(client->defmsg_handler) return client->defmsg_handler(client, str); if(client->defmsg_handler) return client->defmsg_handler(client, str);
return RESULT_BADKEY; return RESULT_BADKEY;
} }
@ -826,6 +875,7 @@ ssize_t sl_sock_readline(sl_sock_t *sock, char *str, size_t len){
sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){ sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
char buf[128]; char buf[128];
sl_sock_int_t *i = (sl_sock_int_t *)hitem->data; sl_sock_int_t *i = (sl_sock_int_t *)hitem->data;
if(!i) return RESULT_FAIL;
if(!str){ // getter if(!str){ // getter
snprintf(buf, 127, "%s=%" PRId64 "\n", hitem->key, i->val); snprintf(buf, 127, "%s=%" PRId64 "\n", hitem->key, i->val);
sl_sock_sendstrmessage(client, buf); sl_sock_sendstrmessage(client, buf);
@ -841,6 +891,7 @@ sl_sock_hresult_e sl_sock_inthandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){ sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
char buf[128]; char buf[128];
sl_sock_double_t *d = (sl_sock_double_t *)hitem->data; sl_sock_double_t *d = (sl_sock_double_t *)hitem->data;
if(!d) return RESULT_FAIL;
if(!str){ // getter if(!str){ // getter
snprintf(buf, 127, "%s=%g\n", hitem->key, d->val); snprintf(buf, 127, "%s=%g\n", hitem->key, d->val);
sl_sock_sendstrmessage(client, buf); sl_sock_sendstrmessage(client, buf);
@ -855,6 +906,7 @@ sl_sock_hresult_e sl_sock_dblhandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){ sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem, const char *str){
char buf[SL_VAL_LEN + SL_KEY_LEN + 3]; char buf[SL_VAL_LEN + SL_KEY_LEN + 3];
sl_sock_string_t *s = (sl_sock_string_t*) hitem->data; sl_sock_string_t *s = (sl_sock_string_t*) hitem->data;
if(!s) return RESULT_FAIL;
if(!str){ // getter if(!str){ // getter
snprintf(buf, SL_VAL_LEN + SL_KEY_LEN + 2, "%s=%s\n", hitem->key, s->val); snprintf(buf, SL_VAL_LEN + SL_KEY_LEN + 2, "%s=%s\n", hitem->key, s->val);
sl_sock_sendstrmessage(client, buf); sl_sock_sendstrmessage(client, buf);
@ -868,3 +920,24 @@ sl_sock_hresult_e sl_sock_strhandler(sl_sock_t *client, sl_sock_hitem_t *hitem,
s->val[l] = 0; s->val[l] = 0;
return RESULT_OK; return RESULT_OK;
} }
/**
* @brief sl_sock_keyno_init - init k->magick and k-> to default values
* @param k - key's number value
*/
void sl_sock_keyno_init(sl_sock_keyno_t* k){
if(!k) return;
k->magick = -INFINITY;
k->n = -1;
}
/**
* @brief sl_sock_keyno_check - check if this is a really `sl_sock_keyno_t`
* @param k - pointer to check
* @return k.n or -1 if failed
*/
int sl_sock_keyno_check(sl_sock_keyno_t* k){
DBG("magick=%g (%d)", k->magick, isinf(k->magick));
if(!k || -1 != isinf(k->magick)) return -1;
DBG("k->n=%d", k->n);
return k->n;
}

View File

@ -36,6 +36,7 @@
#include <unistd.h> // pid_t #include <unistd.h> // pid_t
// just for different purposes // just for different purposes
#include <limits.h> #include <limits.h>
#include <math.h> // inf/isinf
#include <stdint.h> #include <stdint.h>
#if defined GETTEXT #if defined GETTEXT
@ -445,6 +446,15 @@ typedef struct{
int len; // strlen of `val` int len; // strlen of `val`
} sl_sock_string_t; } sl_sock_string_t;
// optional keyword number like key[12] = 500
typedef struct{
double magick; // Inf - to distinguish it from sl_sock_*_t
int n; // if n < 0 there was no any number in `key`
} sl_sock_keyno_t;
#define SL_SOCK_KEYNO_DEFAULT (sl_sock_keyno_t){.magick = -INFINITY, .n = -1}
void sl_sock_keyno_init(sl_sock_keyno_t*);
int sl_sock_keyno_check(sl_sock_keyno_t*);
struct sl_sock_hitem; struct sl_sock_hitem;
struct sl_sock; struct sl_sock;