├── README.md ├── .gitignore ├── pico_osal.h ├── pico_osal_pthread.c ├── pico_osal_noos.c ├── pico_osal_freertos.c ├── pico_bsd_syscalls.h ├── pico_bsd_sockets.h ├── pico_posix_wrapper.c ├── LICENSE └── pico_bsd_sockets.c /README.md: -------------------------------------------------------------------------------- 1 | picotcp-bsd 2 | =========== 3 | 4 | BSD POSIX-compliant socket support for PicoTCP running on any OS. 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | 25 | *.swp 26 | 27 | -------------------------------------------------------------------------------- /pico_osal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pico_osal.h 3 | * 4 | * Created on: December 2013 5 | * Author: Maxime Vincent 6 | * Description: OS Abstraction Layer between PicoTCP and FreeRTOS 7 | * 8 | */ 9 | 10 | #ifndef _PICO_OSAL_H_ 11 | #define _PICO_OSAL_H_ 12 | 13 | /***************************************************************************** 14 | * Public types/enumerations/variables 15 | ****************************************************************************/ 16 | 17 | /* Queue implementation API is: */ 18 | 19 | 20 | /* Posix version of thread */ 21 | typedef void* pico_thread_t; 22 | typedef void *(*pico_thread_fn)(void *); 23 | 24 | void * pico_mutex_init(void); 25 | void pico_mutex_deinit(void * mutex); 26 | void pico_mutex_lock(void * mutex); 27 | int pico_mutex_lock_timeout(void * mutex, int timeout); 28 | void pico_mutex_unlock(void * mutex); 29 | void pico_mutex_unlock_ISR(void * mutex); 30 | 31 | void * pico_signal_init(void); 32 | void pico_signal_deinit(void * signal); 33 | void pico_signal_wait(void * signal); 34 | int pico_signal_wait_timeout(void * signal, int timeout); 35 | void pico_signal_send(void * signal); 36 | void pico_signal_send_ISR(void * signal); 37 | 38 | pico_thread_t pico_thread_create(pico_thread_fn thread, void *arg, int stack_size, int prio); 39 | void pico_thread_destroy(pico_thread_t t); 40 | void pico_msleep(int ms); 41 | 42 | void pico_threads_schedule(void); 43 | 44 | #endif /* _PICO_OSAL_H_ */ 45 | 46 | -------------------------------------------------------------------------------- /pico_osal_pthread.c: -------------------------------------------------------------------------------- 1 | /* Pthread osal implementation, for testing purposes */ 2 | #include 3 | #include "pico_defines.h" 4 | #include "pico_stack.h" 5 | #include "pico_osal.h" 6 | #include 7 | #include 8 | 9 | #define BILLION 1000000000 10 | 11 | void * pico_mutex_init(void) { 12 | pthread_mutex_t *mutex = pico_zalloc(sizeof(pthread_mutex_t)); 13 | if (!mutex) 14 | return NULL; 15 | if (pthread_mutex_init(mutex, NULL) == 0 ) 16 | return mutex; 17 | pico_free(mutex); 18 | return NULL; 19 | } 20 | void pico_mutex_deinit(void * mutex) 21 | { 22 | pthread_mutex_destroy((pthread_mutex_t *)mutex); 23 | pico_free(mutex); 24 | } 25 | 26 | void pico_mutex_lock(void * mutex) 27 | { 28 | pthread_mutex_lock((pthread_mutex_t *)mutex); 29 | } 30 | 31 | int pico_mutex_lock_timeout(void *mutex, int timeout) 32 | { 33 | if (timeout < 0) { 34 | return pthread_mutex_lock((pthread_mutex_t *)mutex); 35 | 36 | } else { 37 | struct timespec ts = { timeout / 1000, (timeout % 1000) * 1000000 }; 38 | return pthread_mutex_timedlock((pthread_mutex_t *)mutex, &ts); 39 | } 40 | 41 | } 42 | 43 | void pico_mutex_unlock(void * mutex) 44 | { 45 | pthread_mutex_unlock((pthread_mutex_t *)mutex); 46 | } 47 | 48 | 49 | void * pico_signal_init(void) 50 | { 51 | sem_t *sem = pico_zalloc(sizeof(pthread_mutex_t)); 52 | if (!sem) 53 | return NULL; 54 | if (sem_init(sem, 0, 0) == 0) 55 | return sem; 56 | pico_free(sem); 57 | return NULL; 58 | } 59 | 60 | void pico_signal_deinit(void * signal) 61 | { 62 | sem_destroy((sem_t *) signal); 63 | } 64 | 65 | void pico_signal_wait(void * signal) 66 | { 67 | sem_wait((sem_t *) signal); 68 | } 69 | 70 | int pico_signal_wait_timeout(void * signal, int timeout) 71 | { 72 | if (timeout < 0) { 73 | return sem_wait((sem_t *) signal); 74 | } else { 75 | struct timespec ts; 76 | clock_gettime(CLOCK_REALTIME, &ts); 77 | ts.tv_sec += (timeout / 1000); 78 | ts.tv_nsec += ((timeout % 1000) * 1000000); 79 | if (ts.tv_nsec >= BILLION) { 80 | ts.tv_nsec -= BILLION; 81 | ts.tv_sec++; 82 | } 83 | return sem_timedwait((sem_t *) signal, &ts); 84 | } 85 | } 86 | 87 | void pico_signal_send(void * signal) 88 | { 89 | sem_post((sem_t *) signal); 90 | } 91 | 92 | pico_thread_t pico_thread_create(pico_thread_fn thread, void *arg, int stack_size, int prio) 93 | { 94 | pico_thread_t t = PICO_ZALLOC(sizeof(pthread_t)); 95 | if (!t) 96 | return NULL; 97 | (void)stack_size; 98 | (void)prio; 99 | pthread_create((pthread_t *)t, NULL, thread, arg); 100 | pthread_detach(*((pthread_t *)t)); 101 | } 102 | 103 | void pico_thread_destroy(pico_thread_t t) 104 | { 105 | pthread_cancel(*((pthread_t *)t)); 106 | PICO_FREE(t); 107 | } 108 | 109 | void pico_msleep(int ms) 110 | { 111 | struct timespec ts = { ms / 1000, (ms % 1000) * 1000000 }; 112 | nanosleep(&ts, NULL); 113 | } 114 | 115 | void pico_threads_schedule(void) 116 | { 117 | while (1 < 2) 118 | pico_msleep(1000); 119 | } 120 | -------------------------------------------------------------------------------- /pico_osal_noos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pico_osal.h 3 | * 4 | * Created on: December 2014 5 | * Author: Maxime Vincent 6 | * Description: OS Abstraction Layer between PicoTCP and No Operating System 7 | * 8 | */ 9 | 10 | /* PicoTCP includes */ 11 | #include "pico_defines.h" 12 | #include "pico_config.h" 13 | #include "pico_stack.h" 14 | #include "pico_osal.h" 15 | 16 | #define osal_dbg(...) 17 | //#define osal_dbg(...) printf(__VA_ARGS__) 18 | 19 | /***************************************************************************** 20 | * Public functions 21 | ****************************************************************************/ 22 | 23 | /* ============= */ 24 | /* == MUTEXES == */ 25 | /* ============= */ 26 | 27 | struct osal_mutex { 28 | volatile int want_to_take; /* for ISR safety, basically a mutex for the mutex */ 29 | volatile int mutex; 30 | int idx; /* only to keep track of the amount/idx, no real function .. */ 31 | }; 32 | 33 | static uint8_t mtx_number = 0; 34 | 35 | void * pico_mutex_init(void) 36 | { 37 | struct osal_mutex * mutex; 38 | mutex = pico_zalloc(sizeof(struct osal_mutex)); 39 | osal_dbg("mi: %p for %p\n", mutex, __builtin_return_address(0)); 40 | if (!mutex) 41 | return NULL; 42 | mutex->mutex = 1; 43 | mutex->idx = mtx_number++; 44 | return mutex; 45 | } 46 | 47 | void pico_mutex_deinit(void * mutex) 48 | { 49 | struct osal_mutex * mtx = mutex; 50 | pico_free(mutex); 51 | } 52 | 53 | int pico_mutex_lock_timeout(void * mutex, int timeout) 54 | { 55 | int retval = 0; 56 | if(mutex != NULL) 57 | { 58 | struct osal_mutex * mtx = mutex; 59 | pico_time timestamp = PICO_TIME_MS(); 60 | while (mtx->mutex == 0) 61 | { 62 | pico_stack_tick(); 63 | #ifdef _POSIX_VERSION 64 | usleep(500); 65 | #endif 66 | 67 | /* break on timeout unless infinite timeout */ 68 | if ((timeout != -1) && (PICO_TIME_MS() > (timestamp + timeout))) 69 | break; 70 | } 71 | if (mtx->mutex == 1) 72 | { 73 | mtx->mutex = 0; /* take the mutex */ 74 | } 75 | else 76 | { 77 | retval = -1; /* timeout */ 78 | } 79 | } 80 | return retval; 81 | } 82 | 83 | void pico_mutex_lock(void * mutex) 84 | { 85 | pico_mutex_lock_timeout(mutex, -1); 86 | } 87 | 88 | void pico_mutex_unlock(void * mutex) 89 | { 90 | if(mutex != NULL) 91 | { 92 | struct osal_mutex * mtx = mutex; 93 | mtx->mutex = 1; 94 | } 95 | } 96 | 97 | void pico_mutex_unlock_ISR(void * mutex) 98 | { 99 | if(mutex != NULL) 100 | { 101 | struct osal_mutex * mtx = mutex; 102 | // tricky stuff needed or not? 103 | mtx->mutex = 1; 104 | } 105 | } 106 | 107 | /* ============= */ 108 | /* == SIGNALS == */ 109 | /* ============= */ 110 | 111 | void * pico_signal_init(void) 112 | { 113 | void * signal = pico_mutex_init(); 114 | pico_mutex_lock(signal); 115 | return signal; 116 | } 117 | 118 | void pico_signal_deinit(void * signal) 119 | { 120 | pico_mutex_deinit(signal); 121 | } 122 | 123 | void pico_signal_wait(void * signal) 124 | { 125 | pico_signal_wait_timeout(signal, -1); 126 | } 127 | 128 | int pico_signal_wait_timeout(void * signal, int timeout) 129 | { 130 | return pico_mutex_lock_timeout(signal, timeout); 131 | } 132 | 133 | void pico_signal_send(void * signal) 134 | { 135 | pico_mutex_unlock(signal); 136 | } 137 | 138 | void pico_signal_send_ISR(void * signal) 139 | { 140 | pico_mutex_unlock_ISR(signal); 141 | } 142 | 143 | 144 | /* ============= */ 145 | /* == THREADS == */ 146 | /* ============= */ 147 | 148 | pico_thread_t pico_thread_create(pico_thread_fn thread, void *arg, int stack_size, int prio) 149 | { 150 | (void)thread; 151 | (void)arg; 152 | (void)stack_size; 153 | (void)prio; 154 | return NULL; 155 | } 156 | 157 | void pico_thread_destroy(pico_thread_t t) 158 | { 159 | return; 160 | } 161 | 162 | void pico_msleep(int ms) 163 | { 164 | pico_time now = PICO_TIME_MS(); 165 | while ((pico_time)(now + ms) < PICO_TIME_MS()); 166 | } 167 | -------------------------------------------------------------------------------- /pico_osal_freertos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pico_osal.h 3 | * 4 | * Created on: December 2013 5 | * Author: Maxime Vincent 6 | * Description: OS Abstraction Layer between PicoTCP and FreeRTOS 7 | * 8 | */ 9 | /* FreeRTOS includes */ 10 | #include "FreeRTOS.h" 11 | #include "task.h" 12 | #include "semphr.h" 13 | #include "portmacro.h" 14 | 15 | 16 | /* PicoTCP includes */ 17 | #include "pico_defines.h" 18 | #include "pico_config.h" 19 | #include "pico_osal.h" 20 | 21 | #define osal_dbg(...) 22 | //#define osal_dbg(...) printf(__VA_ARGS__) 23 | 24 | /***************************************************************************** 25 | * Public functions 26 | ****************************************************************************/ 27 | 28 | struct osal_mutex { 29 | void * mutex; 30 | uint8_t idx; /* only to keep track of the amount/idx, no real function .. */ 31 | }; 32 | static uint8_t mtx_number = 0; 33 | 34 | 35 | /* ============= */ 36 | /* == SIGNALS == */ 37 | /* ============= */ 38 | 39 | void * pico_signal_init(void) 40 | { 41 | struct osal_mutex *signal; 42 | signal = pico_zalloc(sizeof(struct osal_mutex)); 43 | osal_dbg("mi: %p for %p\n", signal, __builtin_return_address(0)); 44 | if (!signal) 45 | return NULL; 46 | signal->mutex= xSemaphoreCreateBinary(); 47 | signal->idx = mtx_number++; 48 | return signal; 49 | } 50 | 51 | void pico_signal_deinit(void * signal) 52 | { 53 | struct osal_mutex * mtx = signal; 54 | vSemaphoreDelete(mtx->mutex); 55 | pico_free(signal); 56 | } 57 | 58 | void pico_signal_wait(void * signal) 59 | { 60 | pico_signal_wait_timeout(signal, (int)portMAX_DELAY); 61 | } 62 | 63 | int pico_signal_wait_timeout(void * signal, int timeout) 64 | { 65 | int retval = 0; 66 | if(signal != NULL) 67 | { 68 | struct osal_mutex * mtx = signal; 69 | if (timeout == portMAX_DELAY) { 70 | while (xSemaphoreTake(mtx->mutex, portMAX_DELAY) == pdFALSE); 71 | } else { 72 | retval = xSemaphoreTake(mtx->mutex, timeout); 73 | } 74 | } 75 | if (retval) { 76 | return 0; /* Success */ 77 | } else { 78 | return -1; /* Timeout */ 79 | } 80 | } 81 | 82 | void pico_signal_send(void * signal) 83 | { 84 | if(signal != NULL) 85 | { 86 | struct osal_mutex * mtx = signal; 87 | xSemaphoreGive(mtx->mutex); 88 | } 89 | } 90 | 91 | void pico_signal_send_ISR(void * signal) 92 | { 93 | if(signal != NULL) 94 | { 95 | struct osal_mutex * mtx = signal; 96 | long task_switch_needed = 0; 97 | xSemaphoreGiveFromISR(mtx->mutex, &task_switch_needed); 98 | portYIELD_FROM_ISR(task_switch_needed); 99 | } 100 | } 101 | 102 | /* ============= */ 103 | /* == MUTEXES == */ 104 | /* ============= */ 105 | 106 | 107 | void *pico_mutex_init(void) 108 | { 109 | struct osal_mutex *mutex; 110 | mutex = pico_zalloc(sizeof(struct osal_mutex)); 111 | osal_dbg("mi: %p for %p\n", mutex, __builtin_return_address(0)); 112 | if (!mutex) 113 | return NULL; 114 | mutex->mutex = xSemaphoreCreateMutex(); 115 | mutex->idx = mtx_number++; 116 | return mutex; 117 | } 118 | 119 | void pico_mutex_deinit(void * mutex) 120 | { 121 | pico_signal_deinit(mutex); 122 | } 123 | 124 | int pico_mutex_lock_timeout(void * mutex, int timeout) 125 | { 126 | return pico_signal_wait_timeout(mutex, timeout); 127 | } 128 | 129 | void pico_mutex_lock(void * mutex) 130 | { 131 | pico_signal_wait_timeout(mutex, (int)portMAX_DELAY); 132 | } 133 | 134 | void pico_mutex_unlock(void * mutex) 135 | { 136 | pico_signal_send(mutex); 137 | } 138 | 139 | void pico_mutex_unlock_ISR(void * mutex) 140 | { 141 | pico_signal_send_ISR(mutex); 142 | } 143 | 144 | 145 | /* ============= */ 146 | /* == THREADS == */ 147 | /* ============= */ 148 | static char thread_name[4] = "T"; 149 | static int thread_n = 0; 150 | 151 | pico_thread_t pico_thread_create(pico_thread_fn thread, void *arg, int stack_size, int prio) 152 | { 153 | pico_thread_t t = PICO_ZALLOC(sizeof(TaskHandle_t)); 154 | if (!t) 155 | return NULL; 156 | thread_name[2] = (thread_n++) % 10; 157 | thread_name[3] = 0; 158 | xTaskCreate((TaskFunction_t)thread, thread_name, stack_size, arg, prio, t); 159 | return t; 160 | } 161 | 162 | void pico_thread_destroy(pico_thread_t t) 163 | { 164 | vTaskDelete((TaskHandle_t)t); 165 | PICO_FREE(t); 166 | } 167 | 168 | void pico_msleep(int ms) 169 | { 170 | vTaskDelay(ms); 171 | } 172 | 173 | void pico_threads_schedule(void) 174 | { 175 | vTaskStartScheduler(); 176 | } 177 | -------------------------------------------------------------------------------- /pico_bsd_syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef PICO_BSD_SYSCALLS_H_ 2 | #define PICO_BSD_SYSCALLS_H_ 3 | 4 | #include "pico_bsd_sockets.h" 5 | 6 | /* Cannot be included directly, expect from pico_bsd_sockets.h */ 7 | 8 | #if !defined (__socklen_t_defined) && defined (REPLACE_STDCALLS) 9 | 10 | /* For systems that have the syscalls already defined */ 11 | #ifdef socket 12 | #undef socket 13 | #endif 14 | #define socket pico_newsocket 15 | 16 | #ifdef bind 17 | #undef bind 18 | #endif 19 | #define bind pico_bind 20 | 21 | #ifdef listen 22 | #undef listen 23 | #endif 24 | #define listen pico_listen 25 | 26 | #ifdef connect 27 | #undef connect 28 | #endif 29 | #define connect pico_connect 30 | 31 | #ifdef accept 32 | #undef accept 33 | #endif 34 | #define accept pico_accept 35 | 36 | #ifdef sendto 37 | #undef sendto 38 | #endif 39 | #define sendto pico_sendto 40 | 41 | #ifdef recvfrom 42 | #undef recvfrom 43 | #endif 44 | #define recvfrom pico_recvfrom 45 | 46 | #ifdef write 47 | #undef write 48 | #endif 49 | #define write pico_write 50 | 51 | #ifdef read 52 | #undef read 53 | #endif 54 | #define read pico_read 55 | 56 | #ifdef send 57 | #undef send 58 | #endif 59 | #define send pico_send 60 | 61 | #ifdef recv 62 | #undef recv 63 | #endif 64 | #define recv pico_recv 65 | 66 | #ifdef close 67 | #undef close 68 | #endif 69 | #define close pico_close 70 | 71 | #ifdef shutdown 72 | #undef shutdown 73 | #endif 74 | #define shutdown pico_shutdown 75 | 76 | #ifdef getsockname 77 | #undef getsockname 78 | #endif 79 | #define getsockname pico_getsockname 80 | 81 | #ifdef getpeername 82 | #undef getpeername 83 | #endif 84 | #define getpeername pico_getpeername 85 | 86 | #ifdef setsockopt 87 | #undef setsockopt 88 | #endif 89 | #define setsockopt pico_setsockopt 90 | 91 | #ifdef getsockopt 92 | #undef getsockopt 93 | #endif 94 | #define getsockopt pico_getsockopt 95 | 96 | #ifdef gettimeofday 97 | #undef gettimeofday 98 | #endif 99 | #define gettimeofday pico_gettimeofday 100 | 101 | #ifdef gethostbyname 102 | #undef gethostbyname 103 | #endif 104 | #define gethostbyname pico_gethostbyname 105 | 106 | #ifdef getaddrinfo 107 | #undef getaddrinfo 108 | #endif 109 | #define getaddrinfo pico_getaddrinfo 110 | 111 | #ifdef freeaddrinfo 112 | #undef freeaddrinfo 113 | #endif 114 | #define freeaddrinfo pico_freeaddrinfo 115 | 116 | #ifdef htons 117 | #undef htons 118 | #endif 119 | #define htons short_be 120 | 121 | #ifdef htonl 122 | #undef htonl 123 | #endif 124 | #define htonl long_be 125 | 126 | #ifdef ntohs 127 | #undef ntohs 128 | #endif 129 | #define ntohs short_be 130 | 131 | #ifdef ntohl 132 | #undef ntohl 133 | #endif 134 | #define ntohl long_be 135 | 136 | #ifdef inet_ntoa 137 | #undef inet_ntoa 138 | #endif 139 | #define inet_ntoa pico_inet_ntoa 140 | 141 | #ifdef inet_ntop 142 | #undef inet_ntop 143 | #endif 144 | #define inet_ntop pico_inet_ntop 145 | 146 | #ifdef select 147 | #undef select 148 | #endif 149 | #define select pico_select 150 | 151 | #ifdef pselect 152 | #undef pselect 153 | #endif 154 | #define pselect pico_pselect 155 | 156 | #ifdef poll 157 | #undef poll 158 | #endif 159 | #define poll pico_poll 160 | 161 | #ifdef ppoll 162 | #undef ppoll 163 | #endif 164 | #define ppoll pico_ppoll 165 | 166 | #ifdef fcntl 167 | #undef fcntl 168 | #endif 169 | #define fcntl pico_fcntl 170 | #else 171 | 172 | static inline int socket(int domain, int type, int proto) 173 | { 174 | return pico_newsocket(domain, type, proto); 175 | } 176 | 177 | static inline int bind(int sd, struct sockaddr * local_addr, socklen_t socklen) 178 | { 179 | return pico_bind(sd, local_addr, socklen); 180 | } 181 | 182 | static inline int listen(int sd, int backlog) 183 | { 184 | return pico_listen(sd, backlog); 185 | } 186 | 187 | static inline int connect(int sd, struct sockaddr *_saddr, socklen_t socklen) 188 | { 189 | return pico_connect(sd, _saddr, socklen); 190 | } 191 | 192 | static inline int accept(int sd, struct sockaddr *_orig, socklen_t *socklen) 193 | { 194 | return pico_accept(sd, _orig, socklen); 195 | } 196 | 197 | static inline int sendto(int sd, void * buf, int len, int flags, struct sockaddr *_dst, socklen_t socklen) 198 | { 199 | return pico_sendto(sd, buf, len, flags, _dst, socklen); 200 | } 201 | 202 | static inline int recvfrom(int sd, void * buf, int len, int flags, struct sockaddr *_addr, socklen_t *socklen) 203 | { 204 | return pico_recvfrom(sd, buf, len, flags, _addr, socklen); 205 | } 206 | 207 | static inline int write(int sd, void * buf, int len) 208 | { 209 | return pico_write(sd, buf, len); 210 | } 211 | 212 | static inline int send(int sd, void * buf, int len, int flags) 213 | { 214 | return pico_send(sd, buf, len, flags); 215 | } 216 | 217 | static inline int read(int sd, void * buf, int len) 218 | { 219 | return pico_read(sd, buf, len); 220 | } 221 | 222 | static inline int recv(int sd, void * buf, int len, int flags) 223 | { 224 | return pico_recv(sd, buf, len, flags); 225 | } 226 | 227 | static inline int close(int sd) 228 | { 229 | return pico_close(sd); 230 | } 231 | 232 | static inline int shutdown(int sd, int how) 233 | { 234 | return pico_shutdown(sd, how); 235 | } 236 | 237 | static inline int getsockname(int sd, struct sockaddr * local_addr, socklen_t *socklen) 238 | { 239 | return pico_getsockname(sd, local_addr, socklen); 240 | } 241 | 242 | static inline int getpeername(int sd, struct sockaddr * remote_addr, socklen_t *socklen) 243 | { 244 | return pico_getpeername(sd, remote_addr, socklen); 245 | } 246 | 247 | static inline int fcntl(int sd, int cmd, int arg) 248 | { 249 | return pico_fcntl(sd, cmd, arg); 250 | } 251 | 252 | #ifdef PICO_SUPPORT_DNS_CLIENT 253 | static inline struct hostent *gethostbyname(const char *name) 254 | { 255 | return pico_gethostbyname(name); 256 | } 257 | 258 | static inline int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) 259 | { 260 | return pico_getaddrinfo(node, service, hints, res); 261 | } 262 | 263 | static inline void freeaddrinfo(struct addrinfo *res) 264 | { 265 | return pico_freeaddrinfo(res); 266 | } 267 | #endif 268 | 269 | static inline int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) 270 | { 271 | return pico_setsockopt(sockfd, level, optname, optval, optlen); 272 | } 273 | 274 | static inline int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) 275 | { 276 | return pico_getsockopt(sockfd, level, optname, optval, optlen); 277 | } 278 | 279 | static inline int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 280 | { 281 | return pico_select(nfds, readfds, writefds, exceptfds, timeout); 282 | } 283 | 284 | static inline int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) 285 | { 286 | return pico_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask); 287 | } 288 | 289 | static inline int poll(struct pollfd *pfd, nfds_t npfd, int timeout) 290 | { 291 | return pico_poll(pfd, npfd, timeout); 292 | } 293 | 294 | static inline int ppoll(struct pollfd *pfd, nfds_t npfd, const struct timespec *timeout_ts, const sigset_t *sigmask) 295 | { 296 | return pico_ppoll(pfd, npfd, timeout_ts, sigmask); 297 | } 298 | 299 | static int gettimeofday(struct timeval *tv, struct timezone *tz) 300 | { 301 | return pico_gettimeofday(tv, tz); 302 | } 303 | 304 | static int settimeofday(struct timeval *tv, struct timezone *tz) 305 | { 306 | return pico_settimeofday(tv, tz); 307 | } 308 | 309 | static inline const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) 310 | { 311 | return pico_inet_ntop(af, src, dst, size); 312 | } 313 | 314 | static inline char *inet_ntoa(struct in_addr in) 315 | { 316 | return pico_inet_ntoa(in); 317 | } 318 | 319 | static inline uint32_t htonl(uint32_t le) 320 | { 321 | return long_be(le); 322 | } 323 | 324 | static inline uint32_t ntohl(uint32_t le) 325 | { 326 | return long_be(le); 327 | } 328 | 329 | static inline uint16_t htons(uint16_t le) 330 | { 331 | return short_be(le); 332 | } 333 | 334 | static inline uint16_t ntohs(uint16_t le) 335 | { 336 | return short_be(le); 337 | } 338 | 339 | #endif 340 | 341 | #endif /* PICO_BSD_SYSCALLS_H_ */ 342 | -------------------------------------------------------------------------------- /pico_bsd_sockets.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | PicoTCP. Copyright (c) 2013 TASS Belgium NV. Some rights reserved. 3 | See LICENSE and COPYING for usage. 4 | Do not redistribute without a written permission by the Copyright 5 | holders. 6 | 7 | Author: Maxime Vincent, Daniele Lacamera 8 | *********************************************************************/ 9 | #ifndef PICO_BSD_SOCKETS_H_ 10 | #define PICO_BSD_SOCKETS_H_ 11 | 12 | #include 13 | #include 14 | #include "pico_defines.h" 15 | #include "pico_constants.h" 16 | #include "pico_config.h" 17 | #include "pico_stack.h" 18 | #include "pico_icmp4.h" 19 | #include "pico_stack.h" 20 | #include "pico_ipv4.h" 21 | #include "pico_ipv6.h" 22 | #include "pico_dns_client.h" 23 | #include "pico_socket.h" 24 | 25 | #define SOCKSIZE 16 26 | #define SOCKSIZE6 28 27 | 28 | struct pico_bsd_endpoint; 29 | extern void *picoLock; 30 | extern void *pico_signal_tick; 31 | 32 | #if defined STDSOCKET || defined __socklen_t_defined 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #ifdef __linux__ 41 | #include 42 | #endif 43 | 44 | static inline int sockopt_get_name(int posix_name) 45 | { 46 | switch (posix_name) { 47 | case IP_MULTICAST_LOOP: return PICO_IP_MULTICAST_LOOP; 48 | case IP_MULTICAST_TTL: return PICO_IP_MULTICAST_TTL; 49 | case IP_MULTICAST_IF: return PICO_IP_MULTICAST_IF; 50 | case IP_ADD_MEMBERSHIP: return PICO_IP_ADD_MEMBERSHIP; 51 | case IP_DROP_MEMBERSHIP: return PICO_IP_DROP_MEMBERSHIP; 52 | case SO_RCVBUF : return PICO_SOCKET_OPT_RCVBUF; 53 | case SO_SNDBUF : return PICO_SOCKET_OPT_SNDBUF; 54 | case TCP_NODELAY : return PICO_TCP_NODELAY; 55 | case TCP_KEEPCNT : return PICO_SOCKET_OPT_KEEPCNT; 56 | case TCP_KEEPIDLE : return PICO_SOCKET_OPT_KEEPIDLE; 57 | case TCP_KEEPINTVL : return PICO_SOCKET_OPT_KEEPINTVL; 58 | } 59 | return -1; 60 | } 61 | 62 | #define pico_fd_set fd_set 63 | #define PICO_FD_SET FD_SET 64 | #define PICO_FD_CLR FD_CLR 65 | #define PICO_FD_ISSET FD_ISSET 66 | #define PICO_FD_ZERO FD_ZERO 67 | 68 | #undef fcntl 69 | #define fcntl pico_fcntl 70 | 71 | #else 72 | typedef int socklen_t; 73 | #define AF_INET (PICO_PROTO_IPV4) 74 | #define AF_INET6 (PICO_PROTO_IPV6) 75 | #define SOCK_STREAM (PICO_PROTO_TCP) 76 | #define SOCK_DGRAM (PICO_PROTO_UDP) 77 | 78 | #define IPPROTO_TCP (0) 79 | 80 | #define SOL_SOCKET (0x80) 81 | 82 | #define IP_MULTICAST_LOOP (PICO_IP_MULTICAST_LOOP) 83 | #define IP_MULTICAST_TTL (PICO_IP_MULTICAST_TTL) 84 | #define IP_MULTICAST_IF (PICO_IP_MULTICAST_IF) 85 | #define IP_ADD_MEMBERSHIP (PICO_IP_ADD_MEMBERSHIP) 86 | #define IP_DROP_MEMBERSHIP (PICO_IP_DROP_MEMBERSHIP) 87 | #define SO_RCVBUF (PICO_SOCKET_OPT_RCVBUF) 88 | #define SO_SNDBUF (PICO_SOCKET_OPT_SNDBUF) 89 | #define TCP_NODELAY (PICO_TCP_NODELAY) 90 | #define TCP_KEEPCNT (PICO_SOCKET_OPT_KEEPCNT) 91 | #define TCP_KEEPIDLE (PICO_SOCKET_OPT_KEEPIDLE) 92 | #define TCP_KEEPINTVL (PICO_SOCKET_OPT_KEEPINTVL) 93 | #define SO_ERROR (4103) 94 | #define SO_REUSEADDR (2) 95 | #define SO_BROADCAST (0x0020) 96 | 97 | #define sockopt_get_name(x) ((x)) 98 | 99 | #define INET_ADDRSTRLEN (16) 100 | #define INET6_ADDRSTRLEN (46) 101 | 102 | #define SHUT_RD PICO_SHUT_RD 103 | #define SHUT_WR PICO_SHUT_WR 104 | #define SHUT_RDWR PICO_SHUT_RDWR 105 | 106 | struct sockaddr { 107 | uint16_t sa_family; 108 | }; 109 | 110 | struct in_addr { 111 | uint32_t s_addr; 112 | }; 113 | 114 | #define INADDR_ANY ((uint32_t)0U) 115 | 116 | struct in6_addr { 117 | uint8_t s6_addr[16]; 118 | }; 119 | 120 | struct __attribute__((packed)) sockaddr_in { 121 | uint16_t sin_family; 122 | uint16_t sin_port; 123 | struct in_addr sin_addr; 124 | uint8_t _pad[SOCKSIZE - 8]; 125 | }; 126 | 127 | 128 | struct __attribute__((packed)) sockaddr_in6 { 129 | uint16_t sin6_family; 130 | uint16_t sin6_port; 131 | uint32_t sin6_flowinfo; 132 | struct in6_addr sin6_addr; 133 | uint32_t sin6_scope_id; 134 | }; 135 | 136 | struct __attribute__((packed)) sockaddr_storage { 137 | uint16_t ss_family; 138 | uint8_t _pad[(SOCKSIZE6 - sizeof(uint16_t))]; 139 | }; 140 | 141 | /* getaddrinfo */ 142 | struct addrinfo { 143 | int ai_flags; 144 | int ai_family; 145 | int ai_socktype; 146 | int ai_protocol; 147 | socklen_t ai_addrlen; 148 | struct sockaddr *ai_addr; 149 | char *ai_canonname; 150 | struct addrinfo *ai_next; 151 | }; 152 | 153 | 154 | /* hostent */ 155 | struct hostent { 156 | char *h_name; /* official name of host */ 157 | char **h_aliases; /* alias list */ 158 | int h_addrtype; /* host address type */ 159 | int h_length; /* length of address */ 160 | char **h_addr_list; /* list of addresses */ 161 | }; 162 | #define h_addr h_addr_list[0] /* for backward compatibility */ 163 | 164 | /* fd_set */ 165 | #ifndef FD_SETSIZE 166 | #define FD_SETSIZE 64 /* 64 files max, 1 bit per file -> 64bits = 8 bytes */ 167 | #endif 168 | 169 | struct pico_fd_set_s { 170 | uint8_t fds_bits[FD_SETSIZE/8]; 171 | }; 172 | 173 | typedef struct pico_fd_set_s pico_fd_set; 174 | #ifndef fd_set 175 | #define fd_set pico_fd_set 176 | #endif 177 | 178 | //typedef void sigset_t; 179 | 180 | #define PICO_FD_SET(n, p) ((p)->fds_bits[(n)/8] |= (1u << ((n) % 8))) 181 | #define PICO_FD_CLR(n, p) ((p)->fds_bits[(n)/8] &= ~(1u << ((n) % 8))) 182 | #define PICO_FD_ISSET(n, p) ((p)->fds_bits[(n)/8] & (1u << ((n) % 8))) 183 | #define PICO_FD_ZERO(p) do{memset((p)->fds_bits, 0, sizeof(struct pico_fd_set_s));}while(0) 184 | 185 | /* Not socket related */ 186 | #ifndef __time_t_defined 187 | typedef pico_time time_t; 188 | #define __time_t_defined 189 | #endif 190 | 191 | #if !defined _TIME_H && !defined _TIMEVAL_DEFINED && !defined _STRUCT_TIMEVAL 192 | struct timeval { 193 | time_t tv_sec; 194 | time_t tv_usec; 195 | }; 196 | 197 | #if !defined __timespec_defined && !defined _SYS__TIMESPEC_H_ 198 | struct timespec { 199 | long tv_sec; 200 | long tv_nsec; 201 | }; 202 | #endif 203 | 204 | struct timezone { 205 | int tz_minuteswest; /* minutes west of Greenwich */ 206 | int tz_dsttime; /* type of DST correction */ 207 | }; 208 | #define _TIMEVAL_DEFINED 209 | #else 210 | #include 211 | #endif 212 | #endif /* STDSOCKET */ 213 | 214 | #ifndef SO_REUSEPORT 215 | #define SO_REUSEPORT (15) 216 | #endif 217 | 218 | #ifndef FD_CLOEXEC 219 | #define FD_CLOEXEC 1 220 | #endif 221 | 222 | #ifndef F_DUPFD 223 | #define F_DUPFD 0 224 | #endif 225 | 226 | #ifndef F_GETFD 227 | #define F_GETFD 1 228 | #endif 229 | 230 | #ifndef F_SETFD 231 | #define F_SETFD 2 232 | #endif 233 | 234 | #ifndef F_GETFL 235 | #define F_GETFL 3 236 | #endif 237 | 238 | #ifndef F_SETFL 239 | #define F_SETFL 4 240 | #endif 241 | 242 | 243 | #ifndef O_NONBLOCK 244 | #define O_NONBLOCK 0x4000 245 | #endif 246 | 247 | #ifndef _SYS_POLL_H 248 | #define POLLIN 0x001 /* There is data to read. */ 249 | #define POLLPRI 0x002 /* There is urgent data to read. */ 250 | #define POLLOUT 0x004 /* Writing now will not block. */ 251 | #define POLLRDNORM 0x040 /* Normal data may be read. */ 252 | #define POLLRDBAND 0x080 /* Priority data may be read. */ 253 | #define POLLWRNORM 0x100 /* Writing now will not block. */ 254 | #define POLLWRBAND 0x200 /* Priority data may be written. */ 255 | 256 | #define POLLMSG 0x400 257 | #define POLLREMOVE 0x1000 258 | #define POLLRDHUP 0x2000 259 | 260 | #define POLLERR 0x008 /* Error condition. */ 261 | #define POLLHUP 0x010 /* Hung up. */ 262 | #define POLLNVAL 0x020 /* Invalid polling request. */ 263 | 264 | typedef unsigned long int nfds_t; 265 | 266 | struct pollfd { 267 | int fd; 268 | uint16_t events; 269 | uint16_t revents; 270 | }; 271 | #endif 272 | 273 | int pico_newsocket(int domain, int type, int proto); 274 | int pico_bind(int sd, struct sockaddr * local_addr, socklen_t socklen); 275 | int pico_listen(int sd, int backlog); 276 | int pico_connect(int sd, const struct sockaddr *_saddr, socklen_t socklen); 277 | int pico_isconnected(int sd); 278 | int pico_accept(int sd, struct sockaddr *_orig, socklen_t *socklen); 279 | int pico_sendto(int sd, void * buf, int len, int flags, struct sockaddr *_dst, socklen_t socklen); 280 | int pico_recvfrom(int sd, void * buf, int len, int flags, struct sockaddr *_addr, socklen_t *socklen); 281 | int pico_write(int sd, void * buf, int len); 282 | int pico_send(int sd, void * buf, int len, int flags); 283 | int pico_read(int sd, void * buf, int len); 284 | int pico_recv(int sd, void * buf, int len, int flags); 285 | int pico_close(int sd); 286 | int pico_shutdown(int sd, int how); 287 | int pico_getsockname(int sd, struct sockaddr * local_addr, socklen_t *socklen); 288 | int pico_getpeername(int sd, struct sockaddr * remote_addr, socklen_t *socklen); 289 | int pico_fcntl(int sd, int cmd, int arg); 290 | int pico_join_multicast_group(int sd, const char *address, const char *local); 291 | 292 | #ifdef PICO_SUPPORT_DNS_CLIENT 293 | struct hostent *pico_gethostbyname(const char *name); 294 | 295 | /* getaddrinfo */ 296 | int pico_getaddrinfo(const char *node, const char *service, 297 | const struct addrinfo *hints, 298 | struct addrinfo **res); 299 | 300 | void pico_freeaddrinfo(struct addrinfo *res); 301 | #endif 302 | 303 | int pico_setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen); 304 | int pico_getsockopt (int sockfd, int level, int optname, void *optval, socklen_t *optlen); 305 | 306 | int pico_select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 307 | int pico_pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, 308 | const sigset_t *sigmask); 309 | 310 | int pico_poll (struct pollfd *pfd, nfds_t npfd, int timeout); 311 | int pico_ppoll (struct pollfd *pfd, nfds_t npfd, const struct timespec *timeout_ts, const sigset_t *sigmask); 312 | 313 | #ifndef PICO_SUPPORT_SNTP_CLIENT 314 | struct pico_timeval 315 | { 316 | pico_time tv_sec; 317 | pico_time tv_msec; 318 | }; 319 | int pico_settimeofday(struct timeval *tv, struct timezone *tz); 320 | #endif 321 | 322 | int pico_gettimeofday(struct timeval *tv, struct timezone *tz); 323 | long XTIME(void); 324 | #define XGMTIME gmtime 325 | 326 | /* arpa/inet.h */ 327 | const char *pico_inet_ntop (int af, const void *src, char *dst, socklen_t size); 328 | char *pico_inet_ntoa (struct in_addr in); 329 | 330 | /* Non-POSIX */ 331 | void pico_bsd_init(void); 332 | void pico_bsd_deinit(void); 333 | void pico_bsd_stack_tick(void); 334 | void pico_bsd_stack_tick_timeout(int timeout_ms); 335 | uint16_t pico_bsd_select(struct pico_bsd_endpoint *ep); 336 | 337 | #ifdef REPLACE_STDCALLS 338 | #include "pico_bsd_syscalls.h" 339 | #endif 340 | 341 | #endif /* PICO_BSD_SOCKETS_H_ */ 342 | -------------------------------------------------------------------------------- /pico_posix_wrapper.c: -------------------------------------------------------------------------------- 1 | #include "pico_bsd_sockets.h" 2 | #define _GNU_SOURCE 3 | #define __GNU_SOURCE 4 | #define __USE_GNU 5 | #include 6 | #include 7 | #include "pico_ipv4.h" 8 | #include "pico_ipv6.h" 9 | #include "pico_stack.h" 10 | #include "pico_socket.h" 11 | #include "pico_dev_vde.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | static __thread int in_the_stack = 0; 25 | static int initialized = 0; 26 | #define ptsock_dbg printf 27 | 28 | 29 | 30 | 31 | #define swap_socketcall(call, name) \ 32 | { \ 33 | const char *msg; \ 34 | if (host_##call == NULL) { \ 35 | *(void **)(&host_##call) = dlsym(RTLD_NEXT, name); \ 36 | if ((msg = dlerror()) != NULL) \ 37 | fprintf (stderr, "%s: dlsym(%s): %s\n", "picotcp", name, msg); \ 38 | } \ 39 | } 40 | 41 | 42 | #define conditional_steal_call(call, i, ...) \ 43 | if(in_the_stack) { \ 44 | return host_##call(i, ## __VA_ARGS__); \ 45 | } else { \ 46 | if (get_pico_fd(i) > -1) { \ 47 | int __pico_retval = pico_##call(get_pico_fd(i), ## __VA_ARGS__); \ 48 | if (__pico_retval != 0) \ 49 | errno = pico_err; \ 50 | return __pico_retval; \ 51 | }else { \ 52 | return host_##call(i, ## __VA_ARGS__); \ 53 | } \ 54 | } 55 | 56 | static int max_fd = 0; 57 | static int *pico_fds = NULL; 58 | 59 | static int remap_fd(int pico_fd) 60 | { 61 | int new_fd = open("/dev/zero", O_RDONLY); 62 | int old_max = max_fd; 63 | int i; 64 | if (new_fd < 0) { 65 | abort(); 66 | } 67 | if (max_fd < new_fd + 1) 68 | max_fd = new_fd + 1; 69 | if (pico_fds == NULL) { 70 | pico_fds = malloc(sizeof(int) * max_fd); 71 | for (i = 0; i < max_fd; i++) 72 | pico_fds[i] = -1; 73 | pico_fds[new_fd] = pico_fd; 74 | return new_fd; 75 | } 76 | pico_fds = realloc(pico_fds, sizeof(int) * max_fd); 77 | for (i = old_max; i < max_fd; i++) 78 | pico_fds[i] = -1; 79 | pico_fds[new_fd] = pico_fd; 80 | return new_fd; 81 | } 82 | 83 | static int get_pico_fd(int j) 84 | { 85 | if (j >= max_fd) 86 | return -1; 87 | return pico_fds[j]; 88 | } 89 | 90 | 91 | static int (*host_socket ) (int domain, int type, int protocol) = NULL; 92 | static int (*host_bind ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); 93 | static int (*host_connect ) (int sockfd, const struct sockaddr *addr, socklen_t addrlen); 94 | static int (*host_accept ) (int sockfd, struct sockaddr *addr, socklen_t *addrlen); 95 | static int (*host_listen ) (int sockfd, int backlog); 96 | static ssize_t (*host_recvfrom) (int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, int *addrlen); 97 | static ssize_t (*host_recv ) (int sockfd, void *buf, size_t len, int flags); 98 | static ssize_t (*host_read ) (int sockfd, void *buf, size_t len); 99 | static ssize_t (*host_sendto ) (int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen); 100 | static ssize_t (*host_send ) (int sockfd, void *buf, size_t len, int flags); 101 | static ssize_t (*host_write ) (int sockfd, const void *buf, size_t len); 102 | static int (*host_close ) (int sockfd); 103 | static int (*host_shutdown) (int sockfd, int how); 104 | static int (*host_setsockopt) (int sockfd, int level, int optname, const void *optval, socklen_t optlen); 105 | static int (*host_getsockopt) (int sockfd, int level, int optname, void *optval, socklen_t *optlen); 106 | 107 | int getaddrinfo(const char *node, const char *service, 108 | const struct addrinfo *hints, 109 | struct addrinfo **res); 110 | 111 | void freeaddrinfo(struct addrinfo *res); 112 | 113 | 114 | static int (*host_getaddrinfo) (const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); 115 | static int (*host_freeaddrinfo) (struct addrinfo *res); 116 | static int (*host_poll) (struct pollfd *pfd, nfds_t npfd, int timeout); 117 | static int (*host_ppoll) (struct pollfd *pfd, nfds_t npfd, const struct timespec *timeout_ts, const sigset_t *sigmask); 118 | static int (*host_select) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); 119 | static int (*host_pselect) (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, 120 | const sigset_t *sigmask); 121 | 122 | int socket(int domain, int type, int protocol) 123 | { 124 | int new_sd, posix_fd = -1; 125 | ptsock_dbg ("Called Socket (pid=%d) in_the_stack=%d\n", getpid(), in_the_stack); 126 | if (in_the_stack) 127 | return host_socket(domain, type, protocol); 128 | if ((domain != AF_INET) && (domain != AF_INET6)) { 129 | return host_socket(domain, type, protocol); 130 | } 131 | new_sd = pico_newsocket(domain, type, protocol); 132 | if (new_sd < 0) { 133 | ptsock_dbg("socket() call failed.\n"); 134 | abort(); 135 | } 136 | posix_fd = remap_fd(new_sd); 137 | ptsock_dbg ("Socket stolen, sd=%d, fd = %d\n", new_sd, posix_fd); 138 | return posix_fd; 139 | } 140 | 141 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 142 | { 143 | conditional_steal_call(bind, sockfd, addr, addrlen); 144 | } 145 | 146 | int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) 147 | { 148 | conditional_steal_call(connect, sockfd, addr, addrlen); 149 | } 150 | 151 | int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) 152 | { 153 | if(in_the_stack) { 154 | return host_accept(sockfd, addr, addrlen); 155 | } else { 156 | int posix_fd, new_sd, listen_sd = get_pico_fd(sockfd); 157 | if (listen_sd < 0) { 158 | return host_accept(sockfd, addr, addrlen); 159 | } 160 | 161 | new_sd = pico_accept(listen_sd, addr, addrlen); 162 | if (new_sd < 0) 163 | return -1; 164 | posix_fd = remap_fd(new_sd); 165 | ptsock_dbg ("Socket accepted, sd=%d, fd = %d\n", new_sd, posix_fd); 166 | return posix_fd; 167 | } 168 | } 169 | 170 | int listen(int sockfd, int backlog) 171 | { 172 | conditional_steal_call(listen, sockfd, backlog); 173 | } 174 | 175 | ssize_t recv(int sockfd, void *buf, size_t len, int flags) 176 | { 177 | conditional_steal_call(recvfrom, sockfd, buf, len, flags, 0, 0); 178 | } 179 | 180 | ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *addrlen) 181 | { 182 | conditional_steal_call(recvfrom, sockfd, buf, len, flags, addr, addrlen); 183 | } 184 | 185 | ssize_t read(int sockfd, void *buf, size_t len) 186 | { 187 | conditional_steal_call(read, sockfd, buf, len); 188 | } 189 | 190 | ssize_t send(int sockfd, const void *buf, size_t len, int flags) 191 | { 192 | conditional_steal_call(sendto, sockfd, buf, len, flags, 0, 0); 193 | } 194 | 195 | ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t addrlen) 196 | { 197 | conditional_steal_call(sendto, sockfd, buf, len, flags, addr, addrlen); 198 | } 199 | 200 | ssize_t write(int sockfd, const void *buf, size_t len) 201 | { 202 | conditional_steal_call(write, sockfd, buf, len); 203 | } 204 | 205 | int close(int sockfd) 206 | { 207 | int pico_sd; 208 | if (in_the_stack) 209 | return host_close(sockfd); 210 | pico_sd = get_pico_fd(sockfd); 211 | if (pico_sd < 0) 212 | return host_close(sockfd); 213 | pico_close(pico_sd); 214 | pico_fds[sockfd] = -1; 215 | return 0; 216 | } 217 | 218 | int shutdown(int sockfd, int how) 219 | { 220 | int pico_sd; 221 | if (in_the_stack) 222 | return host_shutdown(sockfd, how); 223 | pico_sd = get_pico_fd(sockfd); 224 | if (pico_sd < 0) 225 | return host_shutdown(sockfd, how); 226 | 227 | if (how != SHUT_WR) 228 | pico_fds[sockfd] = -1; 229 | pico_shutdown(pico_sd, how); 230 | return 0; 231 | } 232 | 233 | int setsockopt (int sockfd, int level, int optname, const void *optval, socklen_t optlen) 234 | { 235 | conditional_steal_call(setsockopt, sockfd, level, optname, optval, optlen); 236 | } 237 | 238 | int getsockopt (int sockfd, int level, int optname, void *optval, socklen_t *optlen) 239 | { 240 | conditional_steal_call(getsockopt, sockfd, level, optname, optval, optlen); 241 | } 242 | 243 | int poll(struct pollfd *pfd, nfds_t npfd, int timeout) 244 | { 245 | if(in_the_stack) { 246 | return host_poll(pfd, npfd, timeout); 247 | } else { 248 | int i, j = 0; 249 | struct pollfd pico_pfd[npfd]; 250 | for (i = 0; i < npfd; i++) { 251 | pico_pfd[j].fd = get_pico_fd(pfd[i].fd); 252 | if (pico_pfd[j].fd >= 0) { 253 | j++; 254 | pico_pfd[j].events = pfd[i].events; 255 | } 256 | } 257 | if (j > 0) { 258 | int pico_retval = pico_poll(pico_pfd, j, timeout); 259 | if (pico_retval < 0) 260 | errno = pico_err; 261 | return pico_retval; 262 | } else { 263 | errno = EINVAL; 264 | return -1; 265 | } 266 | } 267 | } 268 | 269 | 270 | int ppoll(struct pollfd *pfd, nfds_t npfd, const struct timespec *timeout_ts, const sigset_t *sigmask) 271 | { 272 | if(in_the_stack) { 273 | return host_ppoll(pfd, npfd, timeout_ts, sigmask); 274 | } else { 275 | int i, j = 0; 276 | struct pollfd pico_pfd[npfd]; 277 | for (i = 0; i < npfd; i++) { 278 | pico_pfd[j].fd = get_pico_fd(pfd[i].fd); 279 | if (pico_pfd[j].fd >= 0) { 280 | j++; 281 | pico_pfd[j].events = pfd[i].events; 282 | } 283 | } 284 | if (j > 0) { 285 | int pico_retval = pico_ppoll(pico_pfd, j, timeout_ts, NULL); 286 | if (pico_retval < 0) 287 | errno = pico_err; 288 | return pico_retval; 289 | } else { 290 | errno = EINVAL; 291 | return -1; 292 | } 293 | } 294 | } 295 | 296 | int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) 297 | { 298 | pico_fd_set rs, ws, es; 299 | int pico_retval = -1; 300 | 301 | PICO_FD_ZERO(&rs); 302 | PICO_FD_ZERO(&ws); 303 | PICO_FD_ZERO(&es); 304 | 305 | if(in_the_stack) { 306 | return host_pselect(nfds, readfds, writefds, exceptfds, timeout, sigmask); 307 | } else { 308 | int i, max = -1; 309 | for (i = 0; i < nfds; i++) { 310 | int picofd = get_pico_fd(i); 311 | if (picofd >= 0) { 312 | if (FD_ISSET(i, readfds)) 313 | PICO_FD_SET(picofd, &rs); 314 | if (FD_ISSET(i, writefds)) 315 | PICO_FD_SET(picofd, &ws); 316 | if (FD_ISSET(i, exceptfds)) 317 | PICO_FD_SET(picofd, &es); 318 | } 319 | if (picofd > max) 320 | max = picofd; 321 | } 322 | if (max < 0) { 323 | errno = EINVAL; 324 | return -1; 325 | } 326 | max++; 327 | pico_retval = pico_pselect(max, &rs, &ws, &es, timeout, NULL); 328 | if (pico_retval < 0) 329 | errno = pico_err; 330 | else { 331 | for(i = 0; i < nfds; i++) { 332 | int picofd = get_pico_fd(i); 333 | FD_CLR(i, readfds); 334 | FD_CLR(i, writefds); 335 | FD_CLR(i, exceptfds); 336 | if (picofd >= 0) { 337 | if (FD_ISSET(picofd, &rs)) 338 | FD_SET(i, readfds); 339 | if (FD_ISSET(picofd, &ws)) 340 | FD_SET(i, writefds); 341 | if (FD_ISSET(picofd, &es)) 342 | FD_SET(i, exceptfds); 343 | } 344 | } 345 | } 346 | return pico_retval; 347 | } 348 | } 349 | 350 | int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 351 | { 352 | if(in_the_stack) { 353 | return host_select(nfds, readfds, writefds, exceptfds, timeout); 354 | } else { 355 | if (timeout) { 356 | const struct timespec ts = {timeout->tv_sec, timeout->tv_usec * 1000}; 357 | return pselect(nfds, readfds, writefds, exceptfds, &ts, NULL); 358 | } else { 359 | return pselect(nfds, readfds, writefds, exceptfds, NULL, NULL); 360 | } 361 | } 362 | } 363 | 364 | void *pico_tick_thread(void *arg) { 365 | struct pico_ip4 addr, netmask, gateway, zero = {}; 366 | struct pico_device *vde; 367 | struct pico_ip4 v4_ip_host, v4_ip_route; 368 | struct pico_ip4 v4_mask; 369 | struct pico_ip4 v4_zero={}, v4_gateway; 370 | struct pico_ip6 v6_public; 371 | struct pico_ip6 v6_netmask = {0xff,0xff,}; 372 | struct pico_device *tun; 373 | in_the_stack = 1; 374 | 375 | pico_bsd_init(); 376 | pico_stack_init(); 377 | 378 | tun = (struct pico_device *) pico_tun_create("psx0"); 379 | if (!tun) 380 | abort(); 381 | 382 | pico_string_to_ipv4("192.168.2.150",&v4_ip_host.addr); 383 | pico_string_to_ipv4("192.168.2.1",&v4_ip_route.addr); 384 | pico_string_to_ipv4("255.255.0.0",&v4_mask.addr); 385 | pico_string_to_ipv4("192.168.2.1",&v4_gateway.addr); 386 | pico_string_to_ipv6("7a55::150",v6_public.addr); 387 | 388 | pico_ipv4_link_add(tun, v4_ip_host, v4_mask); 389 | pico_ipv4_route_add(v4_ip_route, v4_mask, v4_gateway, 1, NULL); 390 | pico_ipv6_link_add(tun, v6_public, v6_netmask); 391 | 392 | for (;;) { 393 | pico_bsd_stack_tick(); 394 | usleep(1000); 395 | } 396 | } 397 | 398 | 399 | int __attribute__((constructor)) pico_wrapper_start(void) 400 | { 401 | pthread_t ticker; 402 | if (initialized++) 403 | return 0; 404 | printf("Stealing all your system calls, please wait...\n"); 405 | swap_socketcall(socket , "socket"); 406 | swap_socketcall(bind , "bind"); 407 | swap_socketcall(connect , "connect"); 408 | swap_socketcall(accept , "accept"); 409 | swap_socketcall(listen , "listen"); 410 | swap_socketcall(recvfrom, "recvfrom"); 411 | swap_socketcall(recv , "recv"); 412 | swap_socketcall(read , "read"); 413 | swap_socketcall(sendto , "sendto"); 414 | swap_socketcall(send , "send"); 415 | swap_socketcall(write , "write"); 416 | swap_socketcall(close , "close"); 417 | swap_socketcall(shutdown, "shutdown"); 418 | swap_socketcall(setsockopt, "setsockopt"); 419 | swap_socketcall(getaddrinfo, "getaddrinfo"); 420 | swap_socketcall(freeaddrinfo, "freeaddrinfo"); 421 | swap_socketcall(poll, "poll"); 422 | swap_socketcall(ppoll, "ppoll"); 423 | swap_socketcall(select, "select"); 424 | swap_socketcall(pselect, "pselect"); 425 | pthread_create(&ticker, NULL, pico_tick_thread, NULL); 426 | sleep(1); 427 | return 0; 428 | } 429 | 430 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /pico_bsd_sockets.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | PicoTCP. Copyright (c) 2013 TASS Belgium NV. Some rights reserved. 3 | See LICENSE and COPYING for usage. 4 | Do not redistribute without a written permission by the Copyright 5 | holders. 6 | 7 | Author: Maxime Vincent, Daniele Lacamera 8 | *********************************************************************/ 9 | 10 | #include "pico_defines.h" 11 | #include "pico_config.h" /* for zalloc and free */ 12 | #include "pico_bsd_sockets.h" 13 | #include "pico_osal.h" 14 | #ifdef PICO_SUPPORT_SNTP_CLIENT 15 | #include "pico_sntp_client.h" 16 | #endif 17 | 18 | #include /* should be there in C99 */ 19 | 20 | #define SOCK_OPEN 0 21 | #define SOCK_BOUND 1 22 | #define SOCK_LISTEN 2 23 | #define SOCK_CONNECTED 3 24 | #define SOCK_ERROR 4 25 | #define SOCK_RESET_BY_PEER 5 26 | #define SOCK_CLOSED 100 27 | 28 | #define bsd_dbg(...) do {} while(0) 29 | #define bsd_dbg_select(...) do {} while(0) 30 | 31 | /* Global signal sent on any event (for select) */ 32 | void * picoLock = NULL; /* pico stack lock */ 33 | void * pico_signal_select = NULL; /* pico global signal for select */ 34 | void * pico_signal_tick = NULL; /* pico tick signal, e.g. coming from a driver ISR */ 35 | 36 | struct pico_bsd_endpoint { 37 | struct pico_socket *s; 38 | int socket_fd; 39 | int posix_fd; /* TODO: ifdef... */ 40 | uint8_t in_use; 41 | uint8_t state; /* for pico_state */ 42 | uint8_t nonblocking; /* The non-blocking flag, for non-blocking socket operations */ 43 | uint16_t events; /* events that we filter for */ 44 | uint16_t revents; /* received events */ 45 | uint16_t proto; 46 | void * mutex_lock; /* mutex for clearing revents */ 47 | void * signal; /* signals new events */ 48 | uint32_t timeout; /* this is used for timeout sockets */ 49 | int error; /* used for SO_ERROR sockopt after connect() */ 50 | }; 51 | 52 | /* MACRO's */ 53 | #define VALIDATE_NULL(param) \ 54 | if(!param) \ 55 | { \ 56 | return -1; \ 57 | } 58 | 59 | #define VALIDATE_ONE(param,value) \ 60 | if(param != value) { \ 61 | pico_err = PICO_ERR_EINVAL; \ 62 | errno = pico_err; \ 63 | return -1; \ 64 | } 65 | 66 | #define VALIDATE_TWO(param,value1,value2) \ 67 | if(param != value1 && param != value2) { \ 68 | pico_err = PICO_ERR_EINVAL; \ 69 | errno = pico_err; \ 70 | return -1; \ 71 | } 72 | 73 | 74 | /* Private function prototypes */ 75 | static void pico_event_clear(struct pico_bsd_endpoint *ep, uint16_t events); 76 | static uint16_t pico_bsd_wait(struct pico_bsd_endpoint * ep, int read, int write, int close); 77 | static void pico_socket_event(uint16_t ev, struct pico_socket *s); 78 | 79 | 80 | /************************/ 81 | /* Public API functions */ 82 | /************************/ 83 | void pico_bsd_init(void) 84 | { 85 | pico_signal_select = pico_signal_init(); 86 | pico_signal_tick = pico_signal_init(); 87 | picoLock = pico_mutex_init(); 88 | } 89 | 90 | void pico_bsd_deinit(void) 91 | { 92 | pico_mutex_deinit(picoLock); 93 | } 94 | 95 | /* just ticks the stack twice */ 96 | void pico_bsd_stack_tick(void) 97 | { 98 | pico_mutex_lock(picoLock); 99 | pico_stack_tick(); 100 | pico_stack_tick(); 101 | pico_mutex_unlock(picoLock); 102 | } 103 | 104 | /* ticks the stack, but wait for a signal with a timeout (e.g. from the driver interrupt) */ 105 | void pico_bsd_stack_tick_timeout(int timeout_ms) 106 | { 107 | pico_signal_wait_timeout(pico_signal_tick, timeout_ms); 108 | pico_bsd_stack_tick(); 109 | } 110 | 111 | /** Declarations of helper functions **/ 112 | static struct pico_bsd_endpoint *pico_bsd_create_socket(void); 113 | static int get_free_sd(struct pico_bsd_endpoint *ep); 114 | static int new_sd(struct pico_bsd_endpoint *ep); 115 | static void free_up_ep(struct pico_bsd_endpoint *ep); 116 | static struct pico_bsd_endpoint *get_endpoint(int sd, int set_err); 117 | static int bsd_to_pico_addr(union pico_address *addr, const struct sockaddr *_saddr, socklen_t socklen); 118 | static uint16_t bsd_to_pico_port(const struct sockaddr *_saddr, socklen_t socklen); 119 | static int pico_addr_to_bsd(struct sockaddr *_saddr, socklen_t socklen, union pico_address *addr, uint16_t net); 120 | static int pico_port_to_bsd(struct sockaddr *_saddr, socklen_t socklen, uint16_t port); 121 | 122 | /** Global Sockets descriptors array **/ 123 | static struct pico_bsd_endpoint **PicoSockets = NULL; 124 | static int PicoSocket_max = 0; 125 | 126 | /*** Public socket functions ***/ 127 | 128 | /* Socket interface. */ 129 | int pico_newsocket(int domain, int type, int proto) 130 | { 131 | struct pico_bsd_endpoint * ep = NULL; 132 | (void)proto; 133 | 134 | #ifdef PICO_SUPPORT_IPV6 135 | VALIDATE_TWO(domain,AF_INET, AF_INET6); 136 | #else 137 | VALIDATE_ONE(domain, AF_INET); 138 | #endif 139 | VALIDATE_TWO(type,SOCK_STREAM,SOCK_DGRAM); 140 | 141 | if (AF_INET6 != PICO_PROTO_IPV6) { 142 | if (domain == AF_INET6) 143 | domain = PICO_PROTO_IPV6; 144 | else 145 | domain = PICO_PROTO_IPV4; 146 | } 147 | 148 | if (SOCK_STREAM != PICO_PROTO_TCP) { 149 | if (type == SOCK_STREAM) 150 | type = PICO_PROTO_TCP; 151 | else 152 | type = PICO_PROTO_UDP; 153 | } 154 | 155 | pico_mutex_lock(picoLock); 156 | ep = pico_bsd_create_socket(); 157 | VALIDATE_NULL(ep); 158 | ep->error = PICO_ERR_NOERR; 159 | 160 | ep->proto = type; 161 | 162 | ep->s = pico_socket_open(domain, type,&pico_socket_event); 163 | if (!ep->s) 164 | { 165 | PICO_FREE(ep); 166 | pico_mutex_unlock(picoLock); 167 | return -1; 168 | } 169 | 170 | ep->s->priv = ep; /* let priv point to the endpoint struct */ 171 | 172 | /* open picotcp endpoint */ 173 | ep->state = SOCK_OPEN; 174 | ep->mutex_lock = pico_mutex_init(); 175 | ep->signal = pico_signal_init(); 176 | ep->error = pico_err; 177 | pico_mutex_unlock(picoLock); 178 | return ep->socket_fd; 179 | } 180 | 181 | 182 | int pico_bind(int sd, struct sockaddr * local_addr, socklen_t socklen) 183 | { 184 | union pico_address addr = { .ip4 = { 0 } }; 185 | uint16_t port; 186 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 187 | 188 | VALIDATE_NULL(ep); 189 | ep->error = PICO_ERR_NOERR; 190 | VALIDATE_NULL(local_addr); 191 | VALIDATE_TWO(socklen, SOCKSIZE, SOCKSIZE6); 192 | 193 | if (bsd_to_pico_addr(&addr, local_addr, socklen) < 0) 194 | { 195 | ep->error = PICO_ERR_EINVAL; 196 | errno = pico_err; 197 | return -1; 198 | } 199 | port = bsd_to_pico_port(local_addr, socklen); 200 | 201 | pico_mutex_lock(picoLock); 202 | if(pico_socket_bind(ep->s, &addr, &port) < 0) 203 | { 204 | ep->error = pico_err; 205 | errno = pico_err; 206 | pico_mutex_unlock(picoLock); 207 | return -1; 208 | } 209 | 210 | ep->state = SOCK_BOUND; 211 | pico_mutex_unlock(picoLock); 212 | 213 | return 0; 214 | } 215 | 216 | int pico_getsockname(int sd, struct sockaddr * local_addr, socklen_t *socklen) 217 | { 218 | union pico_address addr; 219 | uint16_t port, proto; 220 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 221 | VALIDATE_NULL(ep); 222 | ep->error = PICO_ERR_NOERR; 223 | VALIDATE_NULL(local_addr); 224 | VALIDATE_NULL(socklen); 225 | pico_mutex_lock(picoLock); 226 | if(pico_socket_getname(ep->s, &addr, &port, &proto) < 0) 227 | { 228 | ep->error = pico_err; 229 | errno = pico_err; 230 | pico_mutex_unlock(picoLock); 231 | return -1; 232 | } 233 | 234 | if (proto == PICO_PROTO_IPV6) 235 | *socklen = SOCKSIZE6; 236 | else 237 | *socklen = SOCKSIZE; 238 | 239 | if (pico_addr_to_bsd(local_addr, *socklen, &addr, proto) < 0) { 240 | ep->error = pico_err; 241 | errno = pico_err; 242 | pico_mutex_unlock(picoLock); 243 | return -1; 244 | } 245 | pico_mutex_unlock(picoLock); 246 | pico_port_to_bsd(local_addr, *socklen, port); 247 | ep->error = pico_err; 248 | return 0; 249 | } 250 | 251 | int pico_getpeername(int sd, struct sockaddr * remote_addr, socklen_t *socklen) 252 | { 253 | union pico_address addr; 254 | uint16_t port, proto; 255 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 256 | VALIDATE_NULL(ep); 257 | ep->error = PICO_ERR_NOERR; 258 | VALIDATE_NULL(remote_addr); 259 | VALIDATE_NULL(socklen); 260 | pico_mutex_lock(picoLock); 261 | if(pico_socket_getpeername(ep->s, &addr, &port, &proto) < 0) 262 | { 263 | pico_mutex_unlock(picoLock); 264 | return -1; 265 | } 266 | 267 | if (proto == PICO_PROTO_IPV6) 268 | *socklen = SOCKSIZE6; 269 | else 270 | *socklen = SOCKSIZE; 271 | 272 | if (pico_addr_to_bsd(remote_addr, *socklen, &addr, proto) < 0) { 273 | pico_mutex_unlock(picoLock); 274 | return -1; 275 | } 276 | pico_mutex_unlock(picoLock); 277 | pico_port_to_bsd(remote_addr, *socklen, port); 278 | return 0; 279 | } 280 | 281 | 282 | int pico_listen(int sd, int backlog) 283 | { 284 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 285 | 286 | VALIDATE_NULL(ep); 287 | ep->error = PICO_ERR_NOERR; 288 | VALIDATE_NULL(ep->s); 289 | VALIDATE_ONE(ep->state, SOCK_BOUND); 290 | 291 | pico_mutex_lock(picoLock); 292 | 293 | if(pico_socket_listen(ep->s, backlog) < 0) 294 | { 295 | ep->error = pico_err; 296 | errno = pico_err; 297 | pico_mutex_unlock(picoLock); 298 | return -1; 299 | } 300 | ep->state = SOCK_LISTEN; 301 | 302 | ep->error = pico_err; 303 | pico_mutex_unlock(picoLock); 304 | return 0; 305 | } 306 | 307 | int pico_connect(int sd, const struct sockaddr *_saddr, socklen_t socklen) 308 | { 309 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 310 | union pico_address addr; 311 | uint16_t port; 312 | uint16_t ev = 0; 313 | int ret; 314 | 315 | VALIDATE_NULL(ep); 316 | ep->error = PICO_ERR_NOERR; 317 | VALIDATE_NULL(_saddr); 318 | if (bsd_to_pico_addr(&addr, _saddr, socklen) < 0) 319 | { 320 | ep->error = PICO_ERR_EINVAL; 321 | errno = pico_err; 322 | return -1; 323 | } 324 | port = bsd_to_pico_port(_saddr, socklen); 325 | pico_mutex_lock(picoLock); 326 | ret = pico_socket_connect(ep->s, &addr, port); 327 | pico_mutex_unlock(picoLock); 328 | if (ret < 0) { 329 | ep->error = pico_err; 330 | return -1; 331 | } 332 | 333 | if (ep->nonblocking) { 334 | pico_err = PICO_ERR_EINPROGRESS; 335 | ep->error = pico_err; 336 | } else { 337 | /* wait for event */ 338 | ev = pico_bsd_wait(ep, 0, 0, 0); /* wait for ERR, FIN and CONN */ 339 | } 340 | 341 | if(ev & PICO_SOCK_EV_CONN) 342 | { 343 | /* clear the EV_CONN event */ 344 | pico_event_clear(ep, PICO_SOCK_EV_CONN); 345 | ep->error = pico_err; 346 | return 0; 347 | } else { 348 | if (!(ep->nonblocking)) 349 | pico_socket_close(ep->s); 350 | } 351 | ep->error = pico_err; 352 | errno = pico_err; 353 | return -1; 354 | } 355 | 356 | int pico_isconnected(int sd) { 357 | struct pico_bsd_endpoint *ep = NULL; 358 | int state = 0; 359 | 360 | ep = get_endpoint(sd, 1); 361 | 362 | VALIDATE_NULL(ep); 363 | ep->error = PICO_ERR_NOERR; 364 | 365 | pico_mutex_lock(picoLock); 366 | if(ep->state == SOCK_CONNECTED) { 367 | state = 1; 368 | } 369 | pico_mutex_unlock(picoLock); 370 | 371 | return state; 372 | } 373 | 374 | int pico_accept(int sd, struct sockaddr *_orig, socklen_t *socklen) 375 | { 376 | struct pico_bsd_endpoint *ep, * client_ep = NULL; 377 | uint16_t events; 378 | union pico_address picoaddr; 379 | uint16_t port; 380 | 381 | ep = get_endpoint(sd, 1); 382 | 383 | VALIDATE_NULL(ep); 384 | ep->error = PICO_ERR_NOERR; 385 | VALIDATE_ONE(ep->state, SOCK_LISTEN); 386 | 387 | if (ep->nonblocking) 388 | events = PICO_SOCK_EV_CONN; 389 | else 390 | events = pico_bsd_wait(ep, 0, 0, 0); /* Wait for CONN, FIN and ERR */ 391 | 392 | if(events & PICO_SOCK_EV_CONN) 393 | { 394 | struct pico_socket *s; 395 | pico_mutex_lock(picoLock); 396 | s = pico_socket_accept(ep->s,&picoaddr,&port); 397 | if (!s) 398 | { 399 | ep->error = pico_err; 400 | errno = pico_err; 401 | pico_mutex_unlock(picoLock); 402 | return -1; 403 | } 404 | 405 | /* Create a new client EP, only after the accept returned succesfully */ 406 | client_ep = pico_bsd_create_socket(); 407 | if (!client_ep) 408 | { 409 | ep->error = pico_err; 410 | errno = pico_err; 411 | pico_mutex_unlock(picoLock); 412 | return -1; 413 | } 414 | client_ep->s = s; 415 | client_ep->state = SOCK_OPEN; 416 | client_ep->mutex_lock = pico_mutex_init(); 417 | client_ep->signal = pico_signal_init(); 418 | 419 | client_ep->s->priv = client_ep; 420 | pico_event_clear(ep, PICO_SOCK_EV_CONN); /* clear the CONN event the listening socket */ 421 | if (client_ep->s->net->proto_number == PICO_PROTO_IPV4) 422 | *socklen = SOCKSIZE; 423 | else 424 | *socklen = SOCKSIZE6; 425 | client_ep->state = SOCK_CONNECTED; 426 | if (pico_addr_to_bsd(_orig, *socklen, &picoaddr, client_ep->s->net->proto_number) < 0) { 427 | client_ep->in_use = 0; 428 | pico_mutex_unlock(picoLock); 429 | return -1; 430 | } 431 | pico_port_to_bsd(_orig, *socklen, port); 432 | 433 | client_ep->in_use = 1; 434 | pico_mutex_unlock(picoLock); 435 | ep->error = pico_err; 436 | return client_ep->socket_fd; 437 | } 438 | client_ep->in_use = 0; 439 | ep->error = pico_err; 440 | errno = pico_err; 441 | return -1; 442 | } 443 | 444 | int pico_sendto(int sd, void * buf, int len, int flags, struct sockaddr *_dst, socklen_t socklen) 445 | { 446 | int retval = 0; 447 | int tot_len = 0; 448 | uint16_t port; 449 | union pico_address picoaddr; 450 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 451 | 452 | VALIDATE_NULL(ep); 453 | ep->error = PICO_ERR_NOERR; 454 | 455 | if (!buf || (len <= 0)) { 456 | pico_err = PICO_ERR_EINVAL; 457 | errno = pico_err; 458 | ep->error = pico_err; 459 | return -1; 460 | } 461 | 462 | while (tot_len < len) { 463 | /* Write to the pico socket */ 464 | pico_mutex_lock(picoLock); 465 | if (_dst == NULL) { 466 | retval = pico_socket_send(ep->s, ((uint8_t *)buf) + tot_len, len - tot_len); 467 | } else { 468 | if (bsd_to_pico_addr(&picoaddr, _dst, socklen) < 0) { 469 | ep->error = PICO_ERR_EINVAL; 470 | errno = pico_err; 471 | pico_mutex_unlock(picoLock); 472 | return -1; 473 | } 474 | port = bsd_to_pico_port(_dst, socklen); 475 | retval = pico_socket_sendto(ep->s, ((uint8_t *)buf) + tot_len, len - tot_len, &picoaddr, port); 476 | } 477 | pico_event_clear(ep, PICO_SOCK_EV_WR); 478 | pico_mutex_unlock(picoLock); 479 | 480 | /* If sending failed, return an error */ 481 | if (retval < 0) 482 | { 483 | ep->error = pico_err; 484 | errno = pico_err; 485 | pico_event_clear(ep, PICO_SOCK_EV_WR); 486 | return -1; 487 | } 488 | 489 | if (retval > 0) 490 | { 491 | tot_len += retval; 492 | break; 493 | } 494 | 495 | if (ep->nonblocking) 496 | break; 497 | 498 | /* If sent bytes (retval) < len-tot_len: socket full, we need to wait for a new WR event */ 499 | if (retval < (len - tot_len)) 500 | { 501 | uint16_t ev = 0; 502 | /* wait for a new WR or CLOSE event */ 503 | ev = pico_bsd_wait(ep, 0, 1, 1); 504 | 505 | if (ev & (PICO_SOCK_EV_ERR | PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE)) 506 | { 507 | ep->error = pico_err; 508 | errno = pico_err; 509 | pico_event_clear(ep, PICO_SOCK_EV_WR); 510 | /* closing and freeing the socket is done in the event handler */ 511 | return -1; 512 | } 513 | } 514 | tot_len += retval; 515 | } 516 | ep->error = pico_err; 517 | return tot_len; 518 | } 519 | 520 | int pico_fcntl(int sd, int cmd, int arg) 521 | { 522 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 523 | if (!ep) { 524 | pico_err = PICO_ERR_EINVAL; 525 | errno = pico_err; 526 | return -1; 527 | } 528 | 529 | if (cmd == F_SETFL) { 530 | if ((arg & O_NONBLOCK) != 0) { 531 | ep->nonblocking = 1; 532 | } else { 533 | ep->nonblocking = 0; 534 | } 535 | ep->error = PICO_ERR_NOERR; 536 | return 0; 537 | } 538 | 539 | if (cmd == F_GETFL) { 540 | (void)arg; /* F_GETFL: arg is ignored */ 541 | ep->error = PICO_ERR_NOERR; 542 | if (ep->nonblocking) 543 | return O_NONBLOCK; 544 | else 545 | return 0; 546 | } 547 | 548 | if (cmd == F_SETFD) { 549 | (void)arg; 550 | ep->error = PICO_ERR_NOERR; 551 | return 0; 552 | } 553 | 554 | 555 | pico_err = PICO_ERR_EINVAL; 556 | errno = pico_err; 557 | ep->error = pico_err; 558 | return -1; 559 | } 560 | 561 | /* 562 | * RETURN VALUE 563 | * Upon successful completion, recv_from() shall return the length of the 564 | * message in bytes. If no messages are available to be received and the 565 | * peer has performed an orderly shutdown, recv() shall return 0. Otherwise, 566 | * −1 shall be returned and errno set to indicate the error. 567 | */ 568 | int pico_recvfrom(int sd, void * _buf, int len, int flags, struct sockaddr *_addr, socklen_t *socklen) 569 | { 570 | int retval = 0; 571 | int tot_len = 0; 572 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 573 | union pico_address picoaddr; 574 | uint16_t port; 575 | unsigned char *buf = (unsigned char *)_buf; 576 | bsd_dbg("Recvfrom called \n"); 577 | 578 | VALIDATE_NULL(ep); 579 | ep->error = PICO_ERR_NOERR; 580 | 581 | if (ep->state == SOCK_RESET_BY_PEER) { 582 | /* not much to do here. Peer has nothing to say. */ 583 | return 0; 584 | } 585 | 586 | if (!buf || (len <= 0)) { 587 | pico_err = PICO_ERR_EINVAL; 588 | errno = pico_err; 589 | ep->error = pico_err; 590 | return -1; 591 | } 592 | 593 | while (tot_len < len) { 594 | pico_mutex_lock(picoLock); 595 | retval = pico_socket_recvfrom(ep->s, buf + tot_len , len - tot_len, &picoaddr, &port); 596 | pico_mutex_unlock(picoLock); 597 | bsd_dbg("pico_socket_recvfrom returns %d, first bytes are %c-%c-%c-%c\n", retval, buf[0], buf[1], buf[2], buf[3]); 598 | 599 | /* pico_socket_recvfrom failed */ 600 | if (retval < 0) { 601 | /* data was received */ 602 | if (tot_len > 0) 603 | { 604 | bsd_dbg("Recvfrom returning %d\n", tot_len); 605 | ep->error = pico_err; 606 | return tot_len; 607 | } 608 | /* no data was received yet */ 609 | ep->error = pico_err; 610 | if (pico_err == PICO_ERR_ESHUTDOWN) /* If no messages are available to be received and the peer has performed an orderly shutdown, recvfrom() shall return 0. */ 611 | { 612 | return 0; 613 | } 614 | else /* Otherwise, the function shall return −1 and set errno to indicate the error. */ 615 | { 616 | return -1; 617 | } 618 | } 619 | 620 | /* If received 0 bytes, return -1 or amount of bytes received */ 621 | if (retval == 0) { 622 | pico_event_clear(ep, PICO_SOCK_EV_RD); 623 | if (tot_len > 0) { 624 | bsd_dbg("Recvfrom returning %d\n", tot_len); 625 | ep->error = pico_err; 626 | return tot_len; 627 | } 628 | } 629 | 630 | if (retval > 0) { 631 | if (ep->proto == PICO_PROTO_UDP) { 632 | if (_addr && socklen > 0) 633 | { 634 | if (pico_addr_to_bsd(_addr, *socklen, &picoaddr, ep->s->net->proto_number) < 0) { 635 | pico_err = PICO_ERR_EINVAL; 636 | errno = pico_err; 637 | ep->error = pico_err; 638 | return -1; 639 | } 640 | pico_port_to_bsd(_addr, *socklen, port); 641 | } 642 | /* If in a recvfrom call, for UDP we should return immediately after the first dgram */ 643 | ep->error = pico_err; 644 | return retval + tot_len; 645 | } else { 646 | /* TCP: continue until recvfrom = 0, socket buffer empty */ 647 | tot_len += retval; 648 | continue; 649 | } 650 | } 651 | 652 | /* Only way to reach this point is when `retval` == 0 and `tot_len` <= 0. 653 | * The event SOCK_EV_RD will aready be cleared. The socket buffer 654 | * is thus completely empty when calling this function and this 655 | * point is reached. */ 656 | 657 | if (ep->nonblocking) { 658 | if (retval == 0) { 659 | pico_err = PICO_ERR_EAGAIN; /* or EWOULDBLOCK */ 660 | ep->error = pico_err; 661 | errno = pico_err; 662 | } 663 | return -1; /* BSD-speak: -1 == 0 bytes received */ 664 | } 665 | 666 | /* We have a blocking socket. We need to wait until data becomes 667 | * available to be able to return from this function. */ 668 | 669 | /* If recv bytes (retval) < len-tot_len: socket empty, we need to wait for a new RD event */ 670 | if (retval < (len - tot_len)) 671 | { 672 | uint16_t ev = 0; 673 | /* wait for a new RD event -- also wait for CLOSE event */ 674 | ev = pico_bsd_wait(ep, 1, 0, 1); 675 | if (ev & (PICO_SOCK_EV_ERR | PICO_SOCK_EV_FIN | PICO_SOCK_EV_CLOSE)) 676 | { 677 | /* closing and freeing the socket is done in the event handler */ 678 | pico_event_clear(ep, PICO_SOCK_EV_RD); 679 | ep->error = pico_err; 680 | return 0; /* return 0 on a properly closed socket */ 681 | } 682 | } 683 | 684 | tot_len += retval; 685 | } 686 | 687 | /* We received a complete buffer of size `len`. Don't clear SOCK_EV_RD 688 | * because there might still be available in the socket buffer. 689 | * And clearing the READ event here might cause the application to run 690 | * behind all data is possibly received */ 691 | bsd_dbg("Recvfrom returning %d (full block)\n", tot_len); 692 | ep->error = pico_err; 693 | return tot_len; 694 | } 695 | 696 | int pico_write(int sd, void * buf, int len) 697 | { 698 | return pico_sendto(sd, buf, len, 0, NULL, 0); 699 | } 700 | 701 | int pico_send(int sd, void * buf, int len, int flags) 702 | { 703 | return pico_sendto(sd, buf, len, flags, NULL, 0); 704 | } 705 | 706 | int pico_read(int sd, void * buf, int len) 707 | { 708 | return pico_recvfrom(sd, buf, len, 0, NULL, 0); 709 | } 710 | 711 | int pico_recv(int sd, void * buf, int len, int flags) 712 | { 713 | return pico_recvfrom(sd, buf, len, flags, NULL, 0); 714 | } 715 | 716 | 717 | 718 | int pico_close(int sd) 719 | { 720 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 721 | VALIDATE_NULL(ep); 722 | ep->error = PICO_ERR_NOERR; 723 | 724 | if (ep->s && ep->in_use) /* valid socket, try to close it */ 725 | { 726 | pico_mutex_lock(picoLock); 727 | pico_socket_close(ep->s); 728 | ep->s->priv = NULL; 729 | pico_mutex_unlock(picoLock); 730 | } 731 | ep->in_use = 0; 732 | ep->error = pico_err; 733 | return 0; 734 | } 735 | 736 | int pico_shutdown(int sd, int how) 737 | { 738 | struct pico_bsd_endpoint *ep = get_endpoint(sd, 1); 739 | VALIDATE_NULL(ep); 740 | ep->error = PICO_ERR_NOERR; 741 | 742 | if(ep->s) /* valid socket, try to close it */ 743 | { 744 | pico_mutex_lock(picoLock); 745 | pico_socket_shutdown(ep->s, how); 746 | ep->error = pico_err; 747 | pico_mutex_unlock(picoLock); 748 | } else { 749 | ep->error = PICO_ERR_EINVAL; 750 | errno = pico_err; 751 | } 752 | return 0; 753 | } 754 | 755 | int pico_join_multicast_group(int sd, const char *address, const char *local) { 756 | 757 | int ret; 758 | struct pico_ip_mreq mreq={}; 759 | 760 | pico_string_to_ipv4(address, &mreq.mcast_group_addr.ip4.addr); 761 | pico_string_to_ipv4(local, &mreq.mcast_link_addr.ip4.addr); 762 | ret = pico_setsockopt(sd, SOL_SOCKET, PICO_IP_ADD_MEMBERSHIP, &mreq, sizeof(struct pico_ip_mreq)); 763 | 764 | return ret; 765 | } 766 | 767 | /*** Helper functions ***/ 768 | static int bsd_to_pico_addr(union pico_address *addr, const struct sockaddr *_saddr, socklen_t socklen) 769 | { 770 | VALIDATE_TWO(socklen, SOCKSIZE, SOCKSIZE6); 771 | if (socklen == SOCKSIZE6) { 772 | struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)_saddr; 773 | memcpy(&addr->ip6.addr, &saddr->sin6_addr.s6_addr, 16); 774 | saddr->sin6_family = AF_INET6; 775 | } else { 776 | struct sockaddr_in *saddr = (struct sockaddr_in *)_saddr; 777 | addr->ip4.addr = saddr->sin_addr.s_addr; 778 | saddr->sin_family = AF_INET; 779 | } 780 | return 0; 781 | } 782 | 783 | static uint16_t bsd_to_pico_port(const struct sockaddr *_saddr, socklen_t socklen) 784 | { 785 | VALIDATE_TWO(socklen, SOCKSIZE, SOCKSIZE6); 786 | if (socklen == SOCKSIZE6) { 787 | struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)_saddr; 788 | return saddr->sin6_port; 789 | } else { 790 | struct sockaddr_in *saddr = (struct sockaddr_in *)_saddr; 791 | return saddr->sin_port; 792 | } 793 | } 794 | 795 | static int pico_port_to_bsd(struct sockaddr *_saddr, socklen_t socklen, uint16_t port) 796 | { 797 | if (socklen == SOCKSIZE6) { 798 | struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)_saddr; 799 | saddr->sin6_port = port; 800 | return 0; 801 | } else { 802 | struct sockaddr_in *saddr = (struct sockaddr_in *)_saddr; 803 | saddr->sin_port = port; 804 | return 0; 805 | } 806 | pico_err = PICO_ERR_EINVAL; 807 | errno = pico_err; 808 | return -1; 809 | } 810 | 811 | static int pico_addr_to_bsd(struct sockaddr *_saddr, socklen_t socklen, union pico_address *addr, uint16_t net) 812 | { 813 | VALIDATE_TWO(socklen, SOCKSIZE, SOCKSIZE6); 814 | if ((socklen == SOCKSIZE6) && (net == PICO_PROTO_IPV6)) { 815 | struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)_saddr; 816 | memcpy(&saddr->sin6_addr.s6_addr, &addr->ip6.addr, 16); 817 | saddr->sin6_family = AF_INET6; 818 | } else if ((socklen == SOCKSIZE) && (net == PICO_PROTO_IPV4)) { 819 | struct sockaddr_in *saddr = (struct sockaddr_in *)_saddr; 820 | saddr->sin_addr.s_addr = addr->ip4.addr; 821 | saddr->sin_family = AF_INET; 822 | } 823 | return 0; 824 | } 825 | 826 | static void free_up_ep(struct pico_bsd_endpoint *ep) 827 | { 828 | if (ep->signal) 829 | pico_signal_deinit(ep->signal); 830 | if (ep->mutex_lock) 831 | pico_mutex_deinit(ep->mutex_lock); 832 | PICO_FREE(ep); 833 | } 834 | 835 | static int get_free_sd(struct pico_bsd_endpoint *ep) 836 | { 837 | int i; 838 | for (i = 0; i < PicoSocket_max; i++) { 839 | if (!PicoSockets[i]->in_use) { 840 | free_up_ep(PicoSockets[i]); 841 | PicoSockets[i] = ep; 842 | return i; 843 | } 844 | } 845 | return -1; 846 | } 847 | 848 | /* DLA TODO: make a GC for freeing up the last socket descriptor periodically if not in use */ 849 | 850 | static int new_sd(struct pico_bsd_endpoint *ep) 851 | { 852 | int sd = PicoSocket_max; 853 | struct pico_bsd_endpoint **new; 854 | new = PICO_ZALLOC(sizeof(void *) * ++PicoSocket_max); 855 | if (!new) { 856 | PicoSocket_max--; 857 | pico_err = PICO_ERR_ENOMEM; 858 | errno = pico_err; 859 | return -1; 860 | } 861 | if (sd > 0) { 862 | memcpy(new, PicoSockets, sd * sizeof(void *)); 863 | PICO_FREE(PicoSockets); 864 | } 865 | PicoSockets = new; 866 | new[sd] = ep; 867 | return sd; 868 | } 869 | 870 | /* picoLock must be taken already ! */ 871 | static struct pico_bsd_endpoint *pico_bsd_create_socket(void) 872 | { 873 | struct pico_bsd_endpoint *ep = PICO_ZALLOC(sizeof(struct pico_bsd_endpoint)); 874 | if (!ep) { 875 | pico_err = PICO_ERR_ENOMEM; 876 | errno = pico_err; 877 | } 878 | ep->in_use = 1; 879 | ep->socket_fd = get_free_sd(ep); 880 | if (ep->socket_fd < 0) { 881 | ep->socket_fd = new_sd(ep); 882 | } 883 | return ep; 884 | } 885 | 886 | 887 | #ifndef PICO_EBADFD 888 | # define PICO_EBADFD 77 /* File descriptor in bad state */ 889 | #endif 890 | 891 | static struct pico_bsd_endpoint *get_endpoint(int sd, int set_err) 892 | { 893 | if ((sd > PicoSocket_max) || (sd < 0) || 894 | (PicoSockets[sd]->in_use == 0)) { 895 | if (set_err) 896 | { 897 | pico_err = PICO_EBADFD; 898 | errno = pico_err; 899 | } 900 | return NULL; 901 | } 902 | return PicoSockets[sd]; 903 | } 904 | 905 | /* wait for one of the selected events, return any of those that occurred */ 906 | uint16_t pico_bsd_select(struct pico_bsd_endpoint *ep) 907 | { 908 | uint16_t events = ep->events & ep->revents; /* maybe an event we are waiting for, was already queued ? */ 909 | /* wait for one of the selected events... */ 910 | while (!events) 911 | { 912 | pico_signal_wait(ep->signal); 913 | events = (ep->revents & ep->events); /* filter for the events we were waiting for */ 914 | } 915 | /* the event we were waiting for happened, now report it */ 916 | return events; /* return any event(s) that occurred, that we were waiting for */ 917 | } 918 | 919 | 920 | /****************************/ 921 | /* Private helper functions */ 922 | /****************************/ 923 | static uint16_t pico_bsd_wait(struct pico_bsd_endpoint * ep, int read, int write, int close) 924 | { 925 | pico_mutex_lock(ep->mutex_lock); 926 | 927 | ep->events = PICO_SOCK_EV_ERR; 928 | ep->events |= PICO_SOCK_EV_FIN; 929 | ep->events |= PICO_SOCK_EV_CONN; 930 | if (close) 931 | ep->events |= PICO_SOCK_EV_CLOSE; 932 | if (read) 933 | ep->events |= PICO_SOCK_EV_RD; 934 | if (write) 935 | ep->events |= PICO_SOCK_EV_WR; 936 | 937 | pico_mutex_unlock(ep->mutex_lock); 938 | 939 | return pico_bsd_select(ep); 940 | } 941 | 942 | 943 | static void pico_event_clear(struct pico_bsd_endpoint *ep, uint16_t events) 944 | { 945 | pico_mutex_lock(ep->mutex_lock); 946 | ep->revents &= ~events; /* clear those events */ 947 | pico_mutex_unlock(ep->mutex_lock); 948 | } 949 | 950 | /* NOTE: __NO__ picoLock'ing here !! */ 951 | /* this is called from pico_stack_tick, so picoLock is already locked */ 952 | static void pico_socket_event(uint16_t ev, struct pico_socket *s) 953 | { 954 | struct pico_bsd_endpoint * ep = (struct pico_bsd_endpoint *)(s->priv); 955 | if (!s) 956 | return; 957 | if(!ep || !ep->s || !ep->mutex_lock || !ep->signal ) 958 | { 959 | /* DLA: do not call close upon SOCK_CLOSE, we might still write. */ 960 | if(ev & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_ERR) ) 961 | { 962 | pico_signal_send(pico_signal_select); /* Signal this event globally (e.g. for select()) */ 963 | pico_socket_close(s); 964 | } 965 | 966 | if (ev & PICO_SOCK_EV_CLOSE) 967 | pico_signal_send(pico_signal_select); 968 | 969 | /* endpoint not initialized yet! */ 970 | return; 971 | } 972 | 973 | if(ep->in_use != 1) 974 | return; 975 | 976 | pico_mutex_lock(ep->mutex_lock); /* lock over the complete body is needed, 977 | as the event might get cleared in another process.. */ 978 | ep->revents |= ev; /* set those events */ 979 | 980 | if(ev & PICO_SOCK_EV_CONN) 981 | { 982 | if(ep->state != SOCK_LISTEN) 983 | { 984 | ep->state = SOCK_CONNECTED; 985 | } 986 | } 987 | 988 | if(ev & PICO_SOCK_EV_ERR) 989 | { 990 | ep->state = SOCK_RESET_BY_PEER; 991 | } 992 | 993 | if (ev & PICO_SOCK_EV_CLOSE) { 994 | ep->state = SOCK_RESET_BY_PEER; 995 | /* DO NOT close: we might still write! */ 996 | } 997 | 998 | if (ev & PICO_SOCK_EV_FIN) { 999 | /* DO NOT set ep->s = NULL, we might still be transmitting stuff! */ 1000 | ep->state = SOCK_CLOSED; 1001 | } 1002 | 1003 | pico_signal_send(pico_signal_select); /* Signal this event globally (e.g. for select()) */ 1004 | pico_signal_send(ep->signal); /* Signal the endpoint that was blocking on this event */ 1005 | 1006 | pico_mutex_unlock(ep->mutex_lock); 1007 | } 1008 | 1009 | 1010 | #define DNSQUERY_OK 1 1011 | #define DNSQUERY_FAIL 0xFF 1012 | struct dnsquery_cookie 1013 | { 1014 | struct addrinfo **res; 1015 | void *signal; 1016 | uint8_t block; 1017 | uint8_t revents; 1018 | }; 1019 | 1020 | static struct dnsquery_cookie *dnsquery_cookie_create(struct addrinfo **res, uint8_t block) 1021 | { 1022 | struct dnsquery_cookie *ck = PICO_ZALLOC(sizeof(struct dnsquery_cookie)); 1023 | if (!ck) { 1024 | pico_err = PICO_ERR_ENOMEM; 1025 | errno = pico_err; 1026 | return NULL; 1027 | } 1028 | ck->signal = pico_signal_init(); 1029 | ck->res = res; 1030 | ck->block = block; 1031 | return ck; 1032 | } 1033 | 1034 | static int dnsquery_cookie_delete(struct dnsquery_cookie *ck) 1035 | { 1036 | if (!ck) { 1037 | pico_err = PICO_ERR_EINVAL; 1038 | errno = pico_err; 1039 | return -1; 1040 | } 1041 | if (ck->signal) 1042 | { 1043 | pico_signal_deinit(ck->signal); 1044 | ck->signal = NULL; 1045 | } 1046 | PICO_FREE(ck); 1047 | return 0; 1048 | } 1049 | 1050 | #ifdef PICO_SUPPORT_IPV6 1051 | static void dns_ip6_cb(char *ip, void *arg) 1052 | { 1053 | struct dnsquery_cookie *ck = (struct dnsquery_cookie *)arg; 1054 | struct addrinfo *new; 1055 | 1056 | if (ip) { 1057 | new = PICO_ZALLOC(sizeof(struct addrinfo)); 1058 | if (!new) { 1059 | ck->revents = DNSQUERY_FAIL; 1060 | if (ck->block) 1061 | pico_signal_send(ck->signal); 1062 | return; 1063 | } 1064 | new->ai_family = AF_INET6; 1065 | new->ai_addr = PICO_ZALLOC(sizeof(struct sockaddr_in6)); 1066 | if (!new->ai_addr) { 1067 | PICO_FREE(new); 1068 | ck->revents = DNSQUERY_FAIL; 1069 | if (ck->block) 1070 | pico_signal_send(ck->signal); 1071 | return; 1072 | } 1073 | new->ai_addrlen = sizeof(struct sockaddr_in6); 1074 | pico_string_to_ipv6(ip, (((struct sockaddr_in6*)(new->ai_addr))->sin6_addr.s6_addr)); 1075 | ((struct sockaddr_in6*)(new->ai_addr))->sin6_family = AF_INET6; 1076 | new->ai_next = *ck->res; 1077 | *ck->res = new; 1078 | ck->revents = DNSQUERY_OK; 1079 | } else { 1080 | /* No ip given, but still callback was called: timeout! */ 1081 | ck->revents = DNSQUERY_FAIL; 1082 | } 1083 | 1084 | if (ck->block) 1085 | pico_signal_send(ck->signal); 1086 | } 1087 | #endif 1088 | 1089 | static void dns_ip4_cb(char *ip, void *arg) 1090 | { 1091 | struct dnsquery_cookie *ck = (struct dnsquery_cookie *)arg; 1092 | struct addrinfo *new; 1093 | if (ip) { 1094 | new = PICO_ZALLOC(sizeof(struct addrinfo)); 1095 | if (!new) { 1096 | ck->revents = DNSQUERY_FAIL; 1097 | if (ck->block) 1098 | pico_signal_send(ck->signal); 1099 | return; 1100 | } 1101 | new->ai_family = AF_INET; 1102 | new->ai_addr = PICO_ZALLOC(sizeof(struct sockaddr_in)); 1103 | if (!new->ai_addr) { 1104 | PICO_FREE(new); 1105 | ck->revents = DNSQUERY_FAIL; 1106 | if (ck->block) 1107 | pico_signal_send(ck->signal); 1108 | return; 1109 | } 1110 | new->ai_addrlen = sizeof(struct sockaddr_in); 1111 | pico_string_to_ipv4(ip, &(((struct sockaddr_in*)new->ai_addr)->sin_addr.s_addr)); 1112 | ((struct sockaddr_in*)(new->ai_addr))->sin_family = AF_INET; 1113 | new->ai_next = *ck->res; 1114 | *ck->res = new; 1115 | ck->revents = DNSQUERY_OK; 1116 | } else { 1117 | /* No ip given, but still callback was called: timeout! */ 1118 | ck->revents = DNSQUERY_FAIL; 1119 | } 1120 | if (ck->block) 1121 | pico_signal_send(ck->signal); 1122 | } 1123 | 1124 | #ifdef PICO_SUPPORT_DNS_CLIENT 1125 | int pico_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) 1126 | { 1127 | struct dnsquery_cookie *ck4 = NULL; 1128 | struct sockaddr_in sa4; 1129 | *res = NULL; 1130 | (void)service; 1131 | bsd_dbg("Called pico_getaddrinfo, looking for %s\n", node); 1132 | 1133 | #ifdef PICO_SUPPORT_IPV6 1134 | struct dnsquery_cookie *ck6 = NULL; 1135 | struct sockaddr_in6 sa6; 1136 | if (pico_string_to_ipv6(node, sa6.sin6_addr.s6_addr) == 0) { 1137 | ck6 = dnsquery_cookie_create(res, 0); 1138 | dns_ip6_cb((char *)node, ck6); 1139 | dnsquery_cookie_delete(ck6); 1140 | return 0; 1141 | } 1142 | #endif 1143 | 1144 | if (pico_string_to_ipv4(node, &sa4.sin_addr.s_addr) == 0) { 1145 | ck4 = dnsquery_cookie_create(res, 0); 1146 | dns_ip4_cb((char*)node, ck4); 1147 | dnsquery_cookie_delete(ck4); 1148 | return 0; 1149 | } 1150 | 1151 | #ifdef PICO_SUPPORT_IPV6 1152 | { 1153 | if (!hints || (hints->ai_family == AF_INET6)) { 1154 | ck6 = dnsquery_cookie_create(res, 1); 1155 | if (!ck6) 1156 | return -1; 1157 | pico_mutex_lock(picoLock); 1158 | if (pico_dns_client_getaddr6(node, dns_ip6_cb, ck6) < 0) 1159 | { 1160 | bsd_dbg("Error resolving AAAA record %s\n", node); 1161 | dnsquery_cookie_delete(ck6); 1162 | pico_mutex_unlock(picoLock); 1163 | return -1; 1164 | } 1165 | bsd_dbg("Resolving AAAA record %s\n", node); 1166 | pico_mutex_unlock(picoLock); 1167 | } 1168 | } 1169 | #endif /* PICO_SUPPORT_IPV6 */ 1170 | 1171 | if (!hints || (hints->ai_family == AF_INET)) { 1172 | ck4 = dnsquery_cookie_create(res, 1); 1173 | pico_mutex_lock(picoLock); 1174 | if (pico_dns_client_getaddr(node, dns_ip4_cb, ck4) < 0) 1175 | { 1176 | bsd_dbg("Error resolving A record %s\n", node); 1177 | dnsquery_cookie_delete(ck4); 1178 | pico_mutex_unlock(picoLock); 1179 | return -1; 1180 | } 1181 | bsd_dbg("Resolving A record %s\n", node); 1182 | pico_mutex_unlock(picoLock); 1183 | } 1184 | 1185 | #ifdef PICO_SUPPORT_IPV6 1186 | if (ck6) { 1187 | /* Signal is always sent; either dns resolved, or timeout/failure */ 1188 | pico_signal_wait(ck6->signal); 1189 | dnsquery_cookie_delete(ck6); 1190 | } 1191 | #endif /* PICO_SUPPORT_IPV6 */ 1192 | 1193 | if (ck4) { 1194 | /* Signal is always sent; either dns resolved, or timeout/failure */ 1195 | pico_signal_wait(ck4->signal); 1196 | dnsquery_cookie_delete(ck4); 1197 | } 1198 | 1199 | if (*res) 1200 | return 0; 1201 | 1202 | return -1; 1203 | } 1204 | 1205 | void pico_freeaddrinfo(struct addrinfo *res) 1206 | { 1207 | struct addrinfo *cur = res; 1208 | struct addrinfo *nxt; 1209 | while(cur) { 1210 | if (cur->ai_addr) 1211 | PICO_FREE(cur->ai_addr); 1212 | nxt = cur->ai_next; 1213 | PICO_FREE(cur); 1214 | cur = nxt; 1215 | } 1216 | } 1217 | 1218 | /* Legacy gethostbyname call implementation */ 1219 | static struct hostent PRIV_HOSTENT = { }; 1220 | struct hostent *pico_gethostbyname(const char *name) 1221 | { 1222 | struct addrinfo *res; 1223 | struct addrinfo hint = {.ai_family = AF_INET}; 1224 | int ret; 1225 | if (!PRIV_HOSTENT.h_addr_list) { 1226 | /* Done only once: reserve space for 2 entries */ 1227 | PRIV_HOSTENT.h_addr_list = PICO_ZALLOC(2 * sizeof(void*)); 1228 | PRIV_HOSTENT.h_addr_list[1] = NULL; 1229 | } 1230 | ret = pico_getaddrinfo(name, NULL, &hint, &res); 1231 | if (ret == 0) { 1232 | if (PRIV_HOSTENT.h_name != NULL) { 1233 | PICO_FREE(PRIV_HOSTENT.h_name); 1234 | PRIV_HOSTENT.h_name = NULL; 1235 | } 1236 | if (PRIV_HOSTENT.h_addr_list[0] != NULL) { 1237 | PICO_FREE(PRIV_HOSTENT.h_addr_list[0]); 1238 | PRIV_HOSTENT.h_addr_list[0] = NULL; 1239 | } 1240 | PRIV_HOSTENT.h_name = PICO_ZALLOC(strlen(name)); 1241 | if (!PRIV_HOSTENT.h_name) { 1242 | pico_freeaddrinfo(res); 1243 | return NULL; 1244 | } 1245 | strcpy(PRIV_HOSTENT.h_name, name); 1246 | PRIV_HOSTENT.h_addrtype = res->ai_addr->sa_family; 1247 | if (PRIV_HOSTENT.h_addrtype == AF_INET) { 1248 | PRIV_HOSTENT.h_length = 4; 1249 | PRIV_HOSTENT.h_addr_list[0] = PICO_ZALLOC(4); 1250 | if (!PRIV_HOSTENT.h_addr_list[0]) { 1251 | pico_freeaddrinfo(res); 1252 | return NULL; 1253 | } 1254 | memcpy (PRIV_HOSTENT.h_addr_list[0], &(((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr), 4); 1255 | } else { 1256 | /* Only IPv4 supported by this ancient call. */ 1257 | pico_freeaddrinfo(res); 1258 | return NULL; 1259 | } 1260 | pico_freeaddrinfo(res); 1261 | return &PRIV_HOSTENT; 1262 | } 1263 | return NULL; 1264 | } 1265 | #endif 1266 | 1267 | int pico_getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen) 1268 | { 1269 | struct pico_bsd_endpoint *ep = get_endpoint(sockfd, 1); 1270 | int ret; 1271 | bsd_dbg("called getsockopt\n"); 1272 | VALIDATE_NULL(ep); 1273 | if (level != SOL_SOCKET) { 1274 | pico_err = PICO_ERR_EPROTONOSUPPORT; 1275 | errno = pico_err; 1276 | return -1; 1277 | } 1278 | if (!ep) { 1279 | pico_err = PICO_ERR_EINVAL; 1280 | errno = pico_err; 1281 | return -1; 1282 | } 1283 | if (!optval) { 1284 | pico_err = PICO_ERR_EFAULT; 1285 | errno = pico_err; 1286 | return -1; 1287 | } 1288 | 1289 | if (optname == SO_ERROR) 1290 | { 1291 | *((int*)optval) = ep->error; 1292 | ep->error = 0; 1293 | return 0; 1294 | } 1295 | 1296 | pico_mutex_lock(ep->mutex_lock); 1297 | ret = pico_socket_getoption(ep->s, sockopt_get_name(optname), optval); 1298 | pico_mutex_unlock(ep->mutex_lock); 1299 | return ret; 1300 | 1301 | } 1302 | 1303 | int pico_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) 1304 | { 1305 | 1306 | struct pico_bsd_endpoint *ep = get_endpoint(sockfd, 1); 1307 | int ret; 1308 | VALIDATE_NULL(ep); 1309 | ep->error = PICO_ERR_NOERR; 1310 | bsd_dbg("called setsockopt\n"); 1311 | if (level != SOL_SOCKET) { 1312 | pico_err = PICO_ERR_EPROTONOSUPPORT; 1313 | errno = pico_err; 1314 | return -1; 1315 | } 1316 | if (!ep) { 1317 | pico_err = PICO_ERR_EINVAL; 1318 | errno = pico_err; 1319 | return -1; 1320 | } 1321 | if (!optval) { 1322 | pico_err = PICO_ERR_EFAULT; 1323 | errno = pico_err; 1324 | return -1; 1325 | } 1326 | if ((optname == SO_REUSEADDR) || (optname == SO_REUSEPORT)) 1327 | return 0; /* Pretend it was OK. */ 1328 | if (optname == SO_ERROR) 1329 | return PICO_ERR_ENOPROTOOPT; 1330 | 1331 | pico_mutex_lock(ep->mutex_lock); 1332 | ret = pico_socket_setoption(ep->s, sockopt_get_name(optname), (void *)optval); 1333 | pico_mutex_unlock(ep->mutex_lock); 1334 | return ret; 1335 | } 1336 | #ifdef PICO_SUPPORT_SNTP_CLIENT 1337 | int pico_gettimeofday(struct timeval *tv, struct timezone *tz) 1338 | { 1339 | int ret; 1340 | (void)tz; 1341 | struct pico_timeval ptv; 1342 | 1343 | ret= pico_sntp_gettimeofday(&ptv); 1344 | 1345 | tv->tv_sec = ptv.tv_sec; 1346 | tv->tv_usec= ptv.tv_msec * 1000; /* pico_timeval uses milliseconds instead of microseconds */ 1347 | return ret; 1348 | } 1349 | 1350 | /* dummy function */ 1351 | int pico_settimeofday(struct timeval *tv, struct timezone *tz) 1352 | { 1353 | (void)tz; 1354 | (void)tv; 1355 | return 0; 1356 | } 1357 | 1358 | #else 1359 | 1360 | static struct pico_timeval ptv = {0u,0u}; 1361 | 1362 | int pico_gettimeofday(struct timeval *tv, struct timezone *tz) 1363 | { 1364 | int ret; 1365 | (void)tz; 1366 | 1367 | tv->tv_sec = ptv.tv_sec; 1368 | tv->tv_usec= ptv.tv_msec * 1000; /* pico_timeval uses milliseconds instead of microseconds */ 1369 | return 0; 1370 | } 1371 | 1372 | int pico_settimeofday(struct timeval *tv, struct timezone *tz) 1373 | { 1374 | int ret; 1375 | (void)tz; 1376 | 1377 | ptv.tv_sec = tv->tv_sec; 1378 | ptv.tv_msec= tv->tv_usec / 1000; /* pico_timeval uses milliseconds instead of microseconds */ 1379 | return 0; 1380 | } 1381 | #endif 1382 | 1383 | long XTIME(void) { 1384 | struct timeval t; 1385 | pico_gettimeofday(&t, NULL); 1386 | return (long)t.tv_sec; 1387 | } 1388 | 1389 | const char *pico_inet_ntop(int af, const void *src, char *dst, socklen_t size) 1390 | { 1391 | if ((!dst) || (!src)) 1392 | return NULL; 1393 | 1394 | switch (af) 1395 | { 1396 | case AF_INET: 1397 | if (size < INET_ADDRSTRLEN) 1398 | return NULL; 1399 | pico_ipv4_to_string(dst, *((const uint32_t *)src)); 1400 | break; 1401 | #ifdef PICO_SUPPORT_IPV6 1402 | case AF_INET6: 1403 | if (size < INET6_ADDRSTRLEN) 1404 | return NULL; 1405 | pico_ipv6_to_string(dst, ((struct in6_addr *)src)->s6_addr); 1406 | break; 1407 | #endif 1408 | default: 1409 | dst = NULL; 1410 | break; 1411 | } 1412 | return dst; 1413 | } 1414 | 1415 | char *pico_inet_ntoa(struct in_addr in) 1416 | { 1417 | static char ipbuf[INET_ADDRSTRLEN]; 1418 | pico_ipv4_to_string(ipbuf, (uint32_t)in.s_addr); 1419 | return ipbuf; 1420 | } 1421 | 1422 | 1423 | 1424 | int pico_pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask) 1425 | { 1426 | /* 1427 | * EV_READ: sets the readfds 1428 | * EV_WRITE: sets the writefds 1429 | * EV_CONN: sets the readfds (a.k.a. someone connects to your listening socket) 1430 | * EV_CLOSE: sets the readfds, then next recv() returns 0; 1431 | * EV_FIN: sets the readfds, then next recv() returns 0; 1432 | * EV_ERR: sets the exceptfds 1433 | */ 1434 | 1435 | int i = 0; /* socket fds */ 1436 | int nfds_out = 0; /* amount of changed sockets */ 1437 | (void) sigmask; 1438 | 1439 | bsd_dbg_select("=== IN: PICO SELECT === readfds[0]: 0x%x -- writefds[0]: 0x%x\n", readfds?(*(uint8_t *)readfds):0, writefds?(*(uint8_t *)writefds):0); 1440 | 1441 | pico_fd_set readfds_out = {}; 1442 | pico_fd_set writefds_out = {}; 1443 | pico_fd_set exceptfds_out = {}; 1444 | /* First, loop over all possible file descriptors, check if one has an event pending that we're waiting for */ 1445 | while (nfds_out == 0) 1446 | { 1447 | for (i = 0; i < nfds; i++) 1448 | { 1449 | struct pico_bsd_endpoint *ep = get_endpoint(i, 0); 1450 | bsd_dbg_select("\t~~~ SELECT: fds %d - ep:%p ", i, ep); 1451 | if (ep) 1452 | { 1453 | /* Is this endpoint still valid? */ 1454 | if (!ep->in_use) 1455 | { 1456 | bsd_dbg_select(" ep->in_use = 0\n"); 1457 | break; 1458 | } 1459 | 1460 | /* READ event needed and available? */ 1461 | if (readfds && PICO_FD_ISSET(i,readfds) && (ep->revents & (PICO_SOCK_EV_CONN | PICO_SOCK_EV_CLOSE | PICO_SOCK_EV_RD))) 1462 | { 1463 | bsd_dbg_select("- READ_EV - "); 1464 | nfds_out++; 1465 | PICO_FD_SET(i, &readfds_out); 1466 | } 1467 | 1468 | /* Force write events on empty udp sockets */ 1469 | if ((ep->proto == PICO_PROTO_UDP) && (ep->s->q_out.size < ep->s->q_out.max_size)) 1470 | ep->revents |= PICO_SOCK_EV_WR; 1471 | 1472 | /* WRITE event needed? and available? */ 1473 | if (writefds && PICO_FD_ISSET(i,writefds) && (ep->revents & (PICO_SOCK_EV_WR))) 1474 | { 1475 | bsd_dbg_select("- WRITE_EV - "); 1476 | nfds_out++; 1477 | PICO_FD_SET(i, &writefds_out); 1478 | } 1479 | 1480 | /* EXCEPTION event needed and available? */ 1481 | if (exceptfds && PICO_FD_ISSET(i,exceptfds) && (ep->revents & (PICO_SOCK_EV_ERR))) 1482 | { 1483 | bsd_dbg_select("- EXCEPT_EV - "); 1484 | nfds_out++; 1485 | PICO_FD_SET(i, &exceptfds_out); 1486 | } 1487 | } 1488 | 1489 | if (ep) 1490 | bsd_dbg_select("- s:%p - ev:%x", ep->s, ep->revents); 1491 | bsd_dbg_select("\n"); 1492 | } 1493 | 1494 | /* If there was a hit, break out of the loop */ 1495 | if (nfds_out) 1496 | break; 1497 | 1498 | /* If not, wait for a semaphore signaling an event from the stack */ 1499 | if (pico_signal_wait_timeout(pico_signal_select, (timeout->tv_sec * 1000) + ((timeout->tv_nsec) / 1000000)) == -1) 1500 | { 1501 | /* On timeout, break out of the loop */ 1502 | bsd_dbg_select("\t~~~ SELECT: TIMEOUT\n"); 1503 | break; 1504 | } else { 1505 | /* Process the received event -> re-iterate */ 1506 | bsd_dbg_select("\t~~~ SELECT: Socket event, re-iterating fds\n"); 1507 | } 1508 | } 1509 | 1510 | /* Copy back result only if descriptor was valid */ 1511 | if (readfds) 1512 | memcpy(readfds, &readfds_out, sizeof(pico_fd_set)); 1513 | if (writefds) 1514 | memcpy(writefds, &writefds_out, sizeof(pico_fd_set)); 1515 | if (exceptfds) 1516 | memcpy(exceptfds, &exceptfds_out, sizeof(pico_fd_set)); 1517 | 1518 | bsd_dbg_select("=== OUT: PICO SELECT === fds changed: %d\n", nfds_out); 1519 | 1520 | return nfds_out; 1521 | } 1522 | 1523 | int pico_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) 1524 | { 1525 | struct timespec ts; 1526 | if (timeout) { 1527 | ts.tv_sec = timeout->tv_sec; 1528 | ts.tv_nsec = timeout->tv_usec * 1000; 1529 | return pico_pselect(nfds, readfds, writefds, exceptfds, &ts, NULL); 1530 | } else 1531 | return pico_pselect(nfds, readfds, writefds, exceptfds, NULL, NULL); 1532 | } 1533 | 1534 | int pico_ppoll(struct pollfd *pfd, nfds_t npfd, const struct timespec *timeout, const sigset_t *sigmask) { 1535 | int i; 1536 | int ret = 0; 1537 | (void) sigmask; 1538 | 1539 | while (ret == 0) { 1540 | for (i = 0; i < npfd; i++) { 1541 | struct pico_bsd_endpoint *ep = get_endpoint(pfd[i].fd, 0); 1542 | pfd[i].revents = 0u; 1543 | 1544 | /* Always polled events */ 1545 | if (!ep) { 1546 | pfd[i].revents |= POLLNVAL; 1547 | } 1548 | if (!ep->in_use) { 1549 | pfd[i].revents |= POLLNVAL; 1550 | } 1551 | if (ep->revents & (PICO_SOCK_EV_FIN | PICO_SOCK_EV_ERR)) { 1552 | pfd[i].revents |= POLLERR; 1553 | ret++; 1554 | } 1555 | if (ep->revents & PICO_SOCK_EV_CLOSE) 1556 | pfd[i].revents |= POLLHUP; /* XXX: I am sure we mean POLLRDHUP ! see man 2 poll */ 1557 | 1558 | /* Checking POLLIN */ 1559 | if ((pfd[i].events & POLLIN) && (ep->revents & (PICO_SOCK_EV_RD | PICO_SOCK_EV_CONN))) { 1560 | pfd[i].revents |= POLLIN; 1561 | if (pfd[i].events & POLLRDNORM) 1562 | pfd[i].revents |= POLLRDNORM; 1563 | } 1564 | /* Checking POLLOUT */ 1565 | if ((pfd[i].events & POLLOUT) && (ep->revents & (PICO_SOCK_EV_WR))) { 1566 | pfd[i].revents |= POLLOUT; 1567 | if (pfd[i].events & POLLWRNORM) 1568 | pfd[i].revents |= POLLWRNORM; 1569 | } 1570 | 1571 | if (pfd[i].revents != 0) 1572 | ret++; 1573 | } /* End for loop */ 1574 | if ((ret == 0) && timeout && (pico_signal_wait_timeout(pico_signal_select, (timeout->tv_sec * 1000) + ((timeout->tv_nsec) / 1000000)) == -1)) 1575 | return 0; /* Timeout */ 1576 | } /* End while loop */ 1577 | return ret; 1578 | } 1579 | 1580 | int pico_poll(struct pollfd *pfd, nfds_t npfd, int timeout) 1581 | { 1582 | struct timespec ts = {0U, 0U}; 1583 | if (timeout >= 0) { 1584 | ts.tv_sec = timeout / 1000; 1585 | ts.tv_nsec = (timeout % 1000) * 1000000; 1586 | return pico_ppoll(pfd, npfd, &ts, NULL); 1587 | } else { 1588 | return pico_ppoll(pfd, npfd, NULL, NULL); 1589 | } 1590 | } 1591 | --------------------------------------------------------------------------------